Compare commits
	
		
			7 Commits
		
	
	
		
			ce7002477e
			...
			196e97a8fd
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | 196e97a8fd | |
|  | fa360b02cc | |
|  | b480753c13 | |
|  | ef32b47e02 | |
|  | 422630c2d9 | |
|  | 2c74cc5594 | |
|  | 5957b5b53f | 
|  | @ -4,6 +4,8 @@ namespace KeepersCompound.Lightmapper; | ||||||
| 
 | 
 | ||||||
| public static class MathUtils | public static class MathUtils | ||||||
| { | { | ||||||
|  |     public const float Epsilon = 0.001f; | ||||||
|  | 
 | ||||||
|     public readonly struct Aabb |     public readonly struct Aabb | ||||||
|     { |     { | ||||||
|         public readonly Vector3 Min; |         public readonly Vector3 Min; | ||||||
|  | @ -52,64 +54,76 @@ public static class MathUtils | ||||||
|         return Math.Abs(Vector3.Dot(plane.Normal, point) + plane.D) / plane.Normal.Length(); |         return Math.Abs(Vector3.Dot(plane.Normal, point) + plane.D) / plane.Normal.Length(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// <summary> |     public record PlanePointMapper | ||||||
|     /// Expects poly to be convex. Given a point |  | ||||||
|     /// </summary> |  | ||||||
|     public static Vector3 ClipPointToPoly3d(Vector3 point, Vector3[] vertices, Plane projectionPlane) |  | ||||||
|     { |     { | ||||||
|         // Shouldn't need to pass 3d. We can just pass the luxel coord, and then we only need the  |         Vector3 _origin; | ||||||
|  |         Vector3 _xAxis; | ||||||
|  |         Vector3 _yAxis; | ||||||
| 
 | 
 | ||||||
|         var (p2d, v2ds) = LocalPlaneCoords(point, vertices, projectionPlane); |         public PlanePointMapper(Vector3 normal, Vector3 p0, Vector3 p1) | ||||||
| 
 |  | ||||||
|         // !HACK: Replace this shit |  | ||||||
|         var origin = vertices[0]; |  | ||||||
|         var locX = vertices[1] - origin; |  | ||||||
|         var locY = Vector3.Cross(projectionPlane.Normal, locX); |  | ||||||
|         locX = Vector3.Normalize(locX); |  | ||||||
|         locY = Vector3.Normalize(locY); |  | ||||||
| 
 |  | ||||||
|         var inside = true; |  | ||||||
|         for (var i = 0; i < v2ds.Length; i++) |  | ||||||
|         { |         { | ||||||
|             var a = v2ds[i]; |             _origin = p0; | ||||||
|             var b = v2ds[(i + 1) % v2ds.Length]; |             _xAxis = p1 - _origin; | ||||||
|  |             _yAxis = Vector3.Cross(normal, _xAxis); | ||||||
|  | 
 | ||||||
|  |             _xAxis = Vector3.Normalize(_xAxis); | ||||||
|  |             _yAxis = Vector3.Normalize(_yAxis); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public Vector2 MapTo2d(Vector3 point) | ||||||
|  |         { | ||||||
|  |             var offset = point - _origin; | ||||||
|  |             var x = Vector3.Dot(offset, _xAxis); | ||||||
|  |             var y = Vector3.Dot(offset, _yAxis); | ||||||
|  |             return new Vector2(x, y); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public Vector2[] MapTo2d(Vector3[] points) | ||||||
|  |         { | ||||||
|  |             var points2d = new Vector2[points.Length]; | ||||||
|  |             for (var i = 0; i < points.Length; i++) | ||||||
|  |             { | ||||||
|  |                 points2d[i] = MapTo2d(points[i]); | ||||||
|  |             } | ||||||
|  |             return points2d; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public Vector3 MapTo3d(Vector2 point) | ||||||
|  |         { | ||||||
|  |             return _origin + point.X * _xAxis + point.Y * _yAxis; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public Vector3[] MapTo3d(Vector2[] points) | ||||||
|  |         { | ||||||
|  |             var points3d = new Vector3[points.Length]; | ||||||
|  |             for (var i = 0; i < points.Length; i++) | ||||||
|  |             { | ||||||
|  |                 points3d[i] = MapTo3d(points[i]); | ||||||
|  |             } | ||||||
|  |             return points3d; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static Vector2 ClipPointToPoly2d(Vector2 point, Vector2[] vertices) | ||||||
|  |     { | ||||||
|  |         var vertexCount = vertices.Length; | ||||||
|  |         for (var i = 0; i < vertexCount; i++) | ||||||
|  |         { | ||||||
|  |             var a = vertices[i]; | ||||||
|  |             var b = vertices[(i + 1) % vertexCount]; | ||||||
|             var segment = b - a; |             var segment = b - a; | ||||||
|             var offset = p2d - a; |             var offset = point - a; | ||||||
|             var norm = Vector2.Normalize(new Vector2(-segment.Y, segment.X)); |             var norm = Vector2.Normalize(new Vector2(-segment.Y, segment.X)); | ||||||
|             var side = Vector2.Dot(norm, offset); |             var side = Vector2.Dot(norm, offset); | ||||||
|             if (side >= -0.001) |             if (side >= -Epsilon) | ||||||
|             { |             { | ||||||
|                 p2d -= norm * (side + 0.0015f); |                 // We apply epsilon so that we push slightly into the poly. If we only | ||||||
|                 inside = false; |                 // push to the edge then Embree sometimes misses casts. The reason | ||||||
|  |                 // it's 2 epsilon is so Side == -Epsilon still gets pushed in properly | ||||||
|  |                 point -= norm * (side + 2 * Epsilon); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // return p2d; |         return point; | ||||||
| 
 |  | ||||||
|         return origin + p2d.X * locX + p2d.Y * locY; |  | ||||||
| 
 |  | ||||||
|         // return Vector3.One; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // TODO: Only do this once per poly |  | ||||||
|     public static (Vector2, Vector2[]) LocalPlaneCoords(Vector3 point, Vector3[] ps, Plane plane) |  | ||||||
|     { |  | ||||||
|         var origin = ps[0]; |  | ||||||
|         var locX = ps[1] - origin; |  | ||||||
|         var locY = Vector3.Cross(plane.Normal, locX); |  | ||||||
| 
 |  | ||||||
|         locX = Vector3.Normalize(locX); |  | ||||||
|         locY = Vector3.Normalize(locY); |  | ||||||
| 
 |  | ||||||
|         var offset = point - origin; |  | ||||||
|         var p2d = new Vector2(Vector3.Dot(offset, locX), Vector3.Dot(offset, locY)); |  | ||||||
|         var p2ds = new Vector2[ps.Length]; |  | ||||||
|         for (var i = 0; i < ps.Length; i++) |  | ||||||
|         { |  | ||||||
|             var p = ps[i] - origin; |  | ||||||
|             p2ds[i] = new Vector2(Vector3.Dot(p, locX), Vector3.Dot(p, locY)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return (p2d, p2ds); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -22,7 +22,7 @@ class Program | ||||||
|         Timing.Reset(); |         Timing.Reset(); | ||||||
| 
 | 
 | ||||||
|         var misPath = "/stuff/Games/thief/drive_c/GOG Games/TG ND 1.27 (MAPPING)/FMs/JAYRUDE_Tests/lm_test.cow"; |         var misPath = "/stuff/Games/thief/drive_c/GOG Games/TG ND 1.27 (MAPPING)/FMs/JAYRUDE_Tests/lm_test.cow"; | ||||||
|         misPath = "/stuff/Games/thief/drive_c/GOG Games/TG ND 1.27 (MAPPING)/FMs/AtdV/miss20.mis"; |         // misPath = "/stuff/Games/thief/drive_c/GOG Games/TG ND 1.27 (MAPPING)/FMs/AtdV/miss20.mis"; | ||||||
|         misPath = "/stuff/Games/thief/drive_c/GOG Games/TG ND 1.27 (MAPPING)/FMs/TDP20AC_a_burrick_in_a_room/miss20.mis"; |         misPath = "/stuff/Games/thief/drive_c/GOG Games/TG ND 1.27 (MAPPING)/FMs/TDP20AC_a_burrick_in_a_room/miss20.mis"; | ||||||
|         Timing.TimeStage("Total", () => LightmapMission(misPath)); |         Timing.TimeStage("Total", () => LightmapMission(misPath)); | ||||||
| 
 | 
 | ||||||
|  | @ -117,9 +117,11 @@ class Program | ||||||
|                     { |                     { | ||||||
|                         propLightColor ??= new PropLightColor { Hue = 0, Saturation = 0 }; |                         propLightColor ??= new PropLightColor { Hue = 0, Saturation = 0 }; | ||||||
| 
 | 
 | ||||||
|  |                         // TODO: There's still some lights that aren't positioned right such as Streetlamp. | ||||||
|  |                         //       Perhaps there's a light point specified in model files? | ||||||
|                         var light = new Light |                         var light = new Light | ||||||
|                         { |                         { | ||||||
|                             position = brush.position, |                             position = brush.position + propLight.Offset, | ||||||
|                             color = HsbToRgb(propLightColor.Hue, propLightColor.Saturation, propLight.Brightness), |                             color = HsbToRgb(propLightColor.Hue, propLightColor.Saturation, propLight.Brightness), | ||||||
|                             radius = propLight.Radius, |                             radius = propLight.Radius, | ||||||
|                             r2 = propLight.Radius * propLight.Radius, |                             r2 = propLight.Radius * propLight.Radius, | ||||||
|  | @ -243,7 +245,7 @@ class Program | ||||||
|                 var info = cell.LightList[polyIdx]; |                 var info = cell.LightList[polyIdx]; | ||||||
|                 var lightmap = cell.Lightmaps[polyIdx]; |                 var lightmap = cell.Lightmaps[polyIdx]; | ||||||
| 
 | 
 | ||||||
|                 ResetLightmap(ambientLight, lightmap); |                 ResetLightmap(ambientLight, lightmap, hdr); | ||||||
| 
 | 
 | ||||||
|                 // Get world position of lightmap (0, 0) (+0.5 so we cast from the center of a pixel) |                 // Get world position of lightmap (0, 0) (+0.5 so we cast from the center of a pixel) | ||||||
|                 var topLeft = cell.Vertices[cell.Indices[cellIdxOffset]]; |                 var topLeft = cell.Vertices[cell.Indices[cellIdxOffset]]; | ||||||
|  | @ -265,6 +267,8 @@ class Program | ||||||
|                 { |                 { | ||||||
|                     vs[i] = cell.Vertices[cell.Indices[cellIdxOffset + i]]; |                     vs[i] = cell.Vertices[cell.Indices[cellIdxOffset + i]]; | ||||||
|                 } |                 } | ||||||
|  |                 var planeMapper = new MathUtils.PlanePointMapper(plane.Normal, vs[0], vs[1]); | ||||||
|  |                 var v2ds = planeMapper.MapTo2d(vs); | ||||||
| 
 | 
 | ||||||
|                 foreach (var light in lights) |                 foreach (var light in lights) | ||||||
|                 { |                 { | ||||||
|  | @ -301,7 +305,17 @@ class Program | ||||||
|                             pos += x * 0.25f * renderPoly.TextureVectors.Item1; |                             pos += x * 0.25f * renderPoly.TextureVectors.Item1; | ||||||
|                             pos += y * 0.25f * renderPoly.TextureVectors.Item2; |                             pos += y * 0.25f * renderPoly.TextureVectors.Item2; | ||||||
| 
 | 
 | ||||||
|                             pos = MathUtils.ClipPointToPoly3d(pos, vs, plane); |                             // We need to clip the point to slightly inside of the poly | ||||||
|  |                             // to avoid three problems: | ||||||
|  |                             // 1. Darkened spots from lightmap pixels who's center is outside | ||||||
|  |                             //    of the polygon but is partially contained in the polygon | ||||||
|  |                             // 2. Darkened spots from linear filtering of points outside of the | ||||||
|  |                             //    polygon which have missed | ||||||
|  |                             // 3. Darkened spots where centers are on the exact edge of a poly | ||||||
|  |                             //    which can sometimes cause Embree to miss casts | ||||||
|  |                             var p2d = planeMapper.MapTo2d(pos); | ||||||
|  |                             p2d = MathUtils.ClipPointToPoly2d(p2d, v2ds); | ||||||
|  |                             pos = planeMapper.MapTo3d(p2d); | ||||||
| 
 | 
 | ||||||
|                             // If we're out of range there's no point casting a ray |                             // If we're out of range there's no point casting a ray | ||||||
|                             // There's probably a better way to discard the entire lightmap |                             // There's probably a better way to discard the entire lightmap | ||||||
|  | @ -322,7 +336,7 @@ class Program | ||||||
| 
 | 
 | ||||||
|                             // cheeky epsilon |                             // cheeky epsilon | ||||||
|                             // TODO: Some pixels aren't hitting and I'm not sure why |                             // TODO: Some pixels aren't hitting and I'm not sure why | ||||||
|                             var hit = hitResult && Math.Abs(hitResult.Distance - direction.Length()) < 0.001; |                             var hit = hitResult && Math.Abs(hitResult.Distance - direction.Length()) < MathUtils.Epsilon; | ||||||
|                             if (hit) |                             if (hit) | ||||||
|                             { |                             { | ||||||
|                                 // Calculate light strength at a given point. As far as I can tell |                                 // Calculate light strength at a given point. As far as I can tell | ||||||
|  | @ -367,18 +381,24 @@ class Program | ||||||
|         Console.Write("\n"); |         Console.Write("\n"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static void ResetLightmap(Vector3 ambientLight, WorldRep.Cell.Lightmap lightmap) |     private static void ResetLightmap(Vector3 ambientLight, WorldRep.Cell.Lightmap lightmap, bool hdr) | ||||||
|     { |     { | ||||||
|         for (var i = 0; i < lightmap.Pixels.Length; i++) |         for (var i = 0; i < lightmap.Pixels.Length; i++) | ||||||
|         { |         { | ||||||
|             lightmap.Pixels[i] = 0; |             lightmap.Pixels[i] = 0; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         var c = ambientLight; | ||||||
|  |         if (hdr) | ||||||
|  |         { | ||||||
|  |             c /= 2.0f; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         for (var y = 0; y < lightmap.Height; y++) |         for (var y = 0; y < lightmap.Height; y++) | ||||||
|         { |         { | ||||||
|             for (var x = 0; x < lightmap.Width; x++) |             for (var x = 0; x < lightmap.Width; x++) | ||||||
|             { |             { | ||||||
|                 lightmap.AddLight(0, x, y, (byte)ambientLight.X, (byte)ambientLight.Y, (byte)ambientLight.Z); |                 lightmap.AddLight(0, x, y, (byte)c.X, (byte)c.Y, (byte)c.Z); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue