Compare commits
3 Commits
8682942102
...
a5078b0f2b
Author | SHA1 | Date |
---|---|---|
Jarrod Doyle | a5078b0f2b | |
Jarrod Doyle | 4b3016d895 | |
Jarrod Doyle | df8cb6f1ca |
|
@ -699,20 +699,11 @@ public class LightMapper
|
||||||
|
|
||||||
var light = _lights[lightIdx - 1];
|
var light = _lights[lightIdx - 1];
|
||||||
|
|
||||||
// Check if plane normal is facing towards the light
|
// If the light is behind the plane we'll never be directly lit by this light.
|
||||||
// If it's not then we're never going to be (directly) lit by this
|
// Additionally, if the distance from the plane is more than the light's radius
|
||||||
// light.
|
// we know no points on the plane will be lit.
|
||||||
var centerDirection = renderPoly.Center - light.Position;
|
var planeDist = MathUtils.DistanceFromPlane(plane, light.Position);
|
||||||
if (Vector3.Dot(plane.Normal, centerDirection) >= 0)
|
if (planeDist <= MathUtils.Epsilon || planeDist > light.Radius)
|
||||||
{
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -739,7 +730,7 @@ public class LightMapper
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TraceRay(light.Position, point))
|
if (!TraceOcclusion(light.Position, point))
|
||||||
{
|
{
|
||||||
strength += targetWeights[idx] * light.StrengthAtPoint(point, plane, settings.AnimLightCutoff);
|
strength += targetWeights[idx] * light.StrengthAtPoint(point, plane, settings.AnimLightCutoff);
|
||||||
}
|
}
|
||||||
|
@ -827,26 +818,15 @@ 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 it's outside the world. We need to clip the point to slightly
|
// then we need to clip the point to slightly inside the poly
|
||||||
// inside the poly and retrace to avoid three problems:
|
// and retrace to avoid two 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
|
||||||
// 3. Darkened spots where centers are on the exact edge of a poly
|
var occluded = TraceOcclusion(polyCenter + planeMapper.Normal * 0.25f, pos);
|
||||||
// which can sometimes cause Embree to miss casts
|
if (occluded)
|
||||||
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);
|
||||||
|
@ -859,48 +839,36 @@ public class LightMapper
|
||||||
return tracePoints;
|
return tracePoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TraceRay(Vector3 origin, Vector3 target)
|
private bool TraceOcclusion(Vector3 origin, Vector3 target)
|
||||||
{
|
{
|
||||||
var hitDistanceFromTarget = float.MinValue;
|
var direction = target - origin;
|
||||||
var hitSurfaceType = SurfaceType.Water;
|
var ray = new Ray
|
||||||
while (hitDistanceFromTarget < -MathUtils.Epsilon && hitSurfaceType == SurfaceType.Water)
|
|
||||||
{
|
{
|
||||||
var direction = target - origin;
|
Origin = origin,
|
||||||
var hitResult = _scene.Trace(new Ray
|
Direction = Vector3.Normalize(direction),
|
||||||
{
|
};
|
||||||
Origin = origin,
|
|
||||||
Direction = Vector3.Normalize(direction),
|
|
||||||
});
|
|
||||||
|
|
||||||
hitDistanceFromTarget = hitResult.Distance - direction.Length();
|
// Epsilon is used here to avoid occlusion when origin lies exactly on a poly
|
||||||
hitSurfaceType = _triangleTypeMap[(int)hitResult.PrimId];
|
return _scene.IsOccluded(new ShadowRay(ray, direction.Length() - MathUtils.Epsilon));
|
||||||
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: Can this be merged with the above?
|
// TODO: direction should already be normalised here
|
||||||
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 hitSurfaceType = SurfaceType.Water;
|
var hitResult = _scene.Trace(new Ray
|
||||||
while (hitSurfaceType == SurfaceType.Water)
|
|
||||||
{
|
{
|
||||||
var hitResult = _scene.Trace(new Ray
|
Origin = origin,
|
||||||
{
|
Direction = Vector3.Normalize(direction),
|
||||||
Origin = origin,
|
});
|
||||||
Direction = Vector3.Normalize(direction),
|
|
||||||
});
|
|
||||||
|
|
||||||
hitSurfaceType = _triangleTypeMap[(int)hitResult.PrimId];
|
if (hitResult)
|
||||||
origin = hitResult.Position += direction * MathUtils.Epsilon;
|
{
|
||||||
|
return _triangleTypeMap[(int)hitResult.PrimId] == SurfaceType.Sky;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
return hitSurfaceType == SurfaceType.Sky;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetAnimLightCellMaps()
|
private void SetAnimLightCellMaps()
|
||||||
|
|
|
@ -43,9 +43,8 @@ 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 3 types of poly that we need to include in the mesh:
|
// There's 2 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.
|
||||||
|
@ -56,7 +55,8 @@ public class MeshBuilder
|
||||||
}
|
}
|
||||||
else if (polyIdx < numRenderPolys)
|
else if (polyIdx < numRenderPolys)
|
||||||
{
|
{
|
||||||
primType = SurfaceType.Water;
|
// we no longer want water polys :)
|
||||||
|
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: {Path}", modelPath);
|
Log.Warning("Failed to find model file: {Name}", modelName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue