Compare commits
No commits in common. "a5078b0f2be1110a88c28e57f57b91f4a0f7197b" and "86829421023cd79d1cb76715fecf73410de98412" have entirely different histories.
a5078b0f2b
...
8682942102
|
@ -699,11 +699,20 @@ public class LightMapper
|
||||||
|
|
||||||
var light = _lights[lightIdx - 1];
|
var light = _lights[lightIdx - 1];
|
||||||
|
|
||||||
// If the light is behind the plane we'll never be directly lit by this light.
|
// Check if plane normal is facing towards the light
|
||||||
// Additionally, if the distance from the plane is more than the light's radius
|
// If it's not then we're never going to be (directly) lit by this
|
||||||
// we know no points on the plane will be lit.
|
// light.
|
||||||
var planeDist = MathUtils.DistanceFromPlane(plane, light.Position);
|
var centerDirection = renderPoly.Center - light.Position;
|
||||||
if (planeDist <= MathUtils.Epsilon || planeDist > light.Radius)
|
if (Vector3.Dot(plane.Normal, centerDirection) >= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there aren't *any* points on the plane that are in range of the light
|
||||||
|
// then none of the lightmap points will be so we can discard.
|
||||||
|
// The more compact a map is the less effective this is
|
||||||
|
var planeDist = Math.Abs(MathUtils.DistanceFromPlane(plane, light.Position));
|
||||||
|
if (planeDist > light.Radius)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -730,7 +739,7 @@ public class LightMapper
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TraceOcclusion(light.Position, point))
|
if (TraceRay(light.Position, point))
|
||||||
{
|
{
|
||||||
strength += targetWeights[idx] * light.StrengthAtPoint(point, plane, settings.AnimLightCutoff);
|
strength += targetWeights[idx] * light.StrengthAtPoint(point, plane, settings.AnimLightCutoff);
|
||||||
}
|
}
|
||||||
|
@ -817,58 +826,81 @@ public class LightMapper
|
||||||
{
|
{
|
||||||
var offset = offsets[i];
|
var offset = offsets[i];
|
||||||
var pos = basePosition + offset;
|
var pos = basePosition + offset;
|
||||||
|
|
||||||
|
// Embree has robustness issues when hitting poly edges which
|
||||||
|
// results in false misses. To alleviate this we pre-push everything
|
||||||
|
// slightly towards the center of the poly.
|
||||||
|
var centerOffset = polyCenter - pos;
|
||||||
|
if (centerOffset.LengthSquared() > MathUtils.Epsilon)
|
||||||
|
{
|
||||||
|
pos += Vector3.Normalize(centerOffset) * MathUtils.Epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
// If we can't see our target point from the center of the poly
|
// If we can't see our target point from the center of the poly
|
||||||
// then we need to clip the point to slightly inside the poly
|
// then it's outside the world. We need to clip the point to slightly
|
||||||
// and retrace to avoid two problems:
|
// inside the poly and retrace to avoid three problems:
|
||||||
// 1. Darkened spots from lightmap pixels whose center is outside
|
// 1. Darkened spots from lightmap pixels whose center is outside
|
||||||
// the polygon but is partially contained in the polygon
|
// the polygon but is partially contained in the polygon
|
||||||
// 2. Darkened spots from linear filtering of points outside the
|
// 2. Darkened spots from linear filtering of points outside the
|
||||||
// polygon which have missed
|
// polygon which have missed
|
||||||
var occluded = TraceOcclusion(polyCenter + planeMapper.Normal * 0.25f, pos);
|
// 3. Darkened spots where centers are on the exact edge of a poly
|
||||||
if (occluded)
|
// which can sometimes cause Embree to miss casts
|
||||||
|
var inPoly = TraceRay(polyCenter + planeMapper.Normal * 0.25f, pos);
|
||||||
|
if (!inPoly)
|
||||||
{
|
{
|
||||||
var p2d = planeMapper.MapTo2d(pos);
|
var p2d = planeMapper.MapTo2d(pos);
|
||||||
p2d = MathUtils.ClipPointToPoly2d(p2d, v2ds);
|
p2d = MathUtils.ClipPointToPoly2d(p2d, v2ds);
|
||||||
pos = planeMapper.MapTo3d(p2d);
|
pos = planeMapper.MapTo3d(p2d);
|
||||||
}
|
}
|
||||||
|
|
||||||
tracePoints[i] = pos;
|
tracePoints[i] = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tracePoints;
|
return tracePoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TraceOcclusion(Vector3 origin, Vector3 target)
|
private bool TraceRay(Vector3 origin, Vector3 target)
|
||||||
{
|
{
|
||||||
var direction = target - origin;
|
var hitDistanceFromTarget = float.MinValue;
|
||||||
var ray = new Ray
|
var hitSurfaceType = SurfaceType.Water;
|
||||||
|
while (hitDistanceFromTarget < -MathUtils.Epsilon && hitSurfaceType == SurfaceType.Water)
|
||||||
{
|
{
|
||||||
Origin = origin,
|
var direction = target - origin;
|
||||||
Direction = Vector3.Normalize(direction),
|
var hitResult = _scene.Trace(new Ray
|
||||||
};
|
{
|
||||||
|
Origin = origin,
|
||||||
// Epsilon is used here to avoid occlusion when origin lies exactly on a poly
|
Direction = Vector3.Normalize(direction),
|
||||||
return _scene.IsOccluded(new ShadowRay(ray, direction.Length() - MathUtils.Epsilon));
|
});
|
||||||
|
|
||||||
|
hitDistanceFromTarget = hitResult.Distance - direction.Length();
|
||||||
|
hitSurfaceType = _triangleTypeMap[(int)hitResult.PrimId];
|
||||||
|
origin = hitResult.Position += direction * MathUtils.Epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A large epsilon is used here to fix shadow acne on sloped surfaces :)
|
||||||
|
return Math.Abs(hitDistanceFromTarget) < 10 * MathUtils.Epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: direction should already be normalised here
|
// TODO: Can this be merged with the above?
|
||||||
private bool TraceSunRay(Vector3 origin, Vector3 direction)
|
private bool TraceSunRay(Vector3 origin, Vector3 direction)
|
||||||
{
|
{
|
||||||
// Avoid self intersection
|
// Avoid self intersection
|
||||||
origin += direction * MathUtils.Epsilon;
|
origin += direction * MathUtils.Epsilon;
|
||||||
|
|
||||||
var hitResult = _scene.Trace(new Ray
|
var hitSurfaceType = SurfaceType.Water;
|
||||||
|
while (hitSurfaceType == SurfaceType.Water)
|
||||||
{
|
{
|
||||||
Origin = origin,
|
var hitResult = _scene.Trace(new Ray
|
||||||
Direction = Vector3.Normalize(direction),
|
{
|
||||||
});
|
Origin = origin,
|
||||||
|
Direction = Vector3.Normalize(direction),
|
||||||
if (hitResult)
|
});
|
||||||
{
|
|
||||||
return _triangleTypeMap[(int)hitResult.PrimId] == SurfaceType.Sky;
|
hitSurfaceType = _triangleTypeMap[(int)hitResult.PrimId];
|
||||||
|
origin = hitResult.Position += direction * MathUtils.Epsilon;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
return hitSurfaceType == SurfaceType.Sky;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetAnimLightCellMaps()
|
private void SetAnimLightCellMaps()
|
||||||
|
|
|
@ -43,8 +43,9 @@ public class MeshBuilder
|
||||||
var cellIdxOffset = 0;
|
var cellIdxOffset = 0;
|
||||||
for (var polyIdx = 0; polyIdx < numPolys; polyIdx++)
|
for (var polyIdx = 0; polyIdx < numPolys; polyIdx++)
|
||||||
{
|
{
|
||||||
// There's 2 types of poly that we need to include in the mesh:
|
// There's 3 types of poly that we need to include in the mesh:
|
||||||
// - Terrain
|
// - Terrain
|
||||||
|
// - Water surfaces
|
||||||
// - Door vision blockers
|
// - Door vision blockers
|
||||||
//
|
//
|
||||||
// Door vision blockers are the interesting one. They're not RenderPolys at all, just flagged Polys.
|
// Door vision blockers are the interesting one. They're not RenderPolys at all, just flagged Polys.
|
||||||
|
@ -55,8 +56,7 @@ public class MeshBuilder
|
||||||
}
|
}
|
||||||
else if (polyIdx < numRenderPolys)
|
else if (polyIdx < numRenderPolys)
|
||||||
{
|
{
|
||||||
// we no longer want water polys :)
|
primType = SurfaceType.Water;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
else if ((cell.Flags & 8) != 0)
|
else if ((cell.Flags & 8) != 0)
|
||||||
{
|
{
|
||||||
|
@ -118,7 +118,7 @@ public class MeshBuilder
|
||||||
var modelPath = campaignResources.GetResourcePath(ResourceType.Object, modelName);
|
var modelPath = campaignResources.GetResourcePath(ResourceType.Object, modelName);
|
||||||
if (modelPath == null)
|
if (modelPath == null)
|
||||||
{
|
{
|
||||||
Log.Warning("Failed to find model file: {Name}", modelName);
|
Log.Warning("Failed to find model file: {Path}", modelPath);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue