Compare commits
	
		
			No commits in common. "196e97a8fdfed3c3bfbeefcd7573c3a651b1efdb" and "ce7002477e94451bda3434984a4ab87a4beebbc7" have entirely different histories.
		
	
	
		
			196e97a8fd
			...
			ce7002477e
		
	
		|  | @ -4,8 +4,6 @@ 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; | ||||||
|  | @ -54,76 +52,64 @@ 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(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public record PlanePointMapper |     /// <summary> | ||||||
|  |     /// Expects poly to be convex. Given a point | ||||||
|  |     /// </summary> | ||||||
|  |     public static Vector3 ClipPointToPoly3d(Vector3 point, Vector3[] vertices, Plane projectionPlane) | ||||||
|     { |     { | ||||||
|         Vector3 _origin; |         // Shouldn't need to pass 3d. We can just pass the luxel coord, and then we only need the  | ||||||
|         Vector3 _xAxis; |  | ||||||
|         Vector3 _yAxis; |  | ||||||
| 
 | 
 | ||||||
|         public PlanePointMapper(Vector3 normal, Vector3 p0, Vector3 p1) |         var (p2d, v2ds) = LocalPlaneCoords(point, vertices, projectionPlane); | ||||||
|         { |  | ||||||
|             _origin = p0; |  | ||||||
|             _xAxis = p1 - _origin; |  | ||||||
|             _yAxis = Vector3.Cross(normal, _xAxis); |  | ||||||
| 
 | 
 | ||||||
|             _xAxis = Vector3.Normalize(_xAxis); |         // !HACK: Replace this shit | ||||||
|             _yAxis = Vector3.Normalize(_yAxis); |         var origin = vertices[0]; | ||||||
|         } |         var locX = vertices[1] - origin; | ||||||
|  |         var locY = Vector3.Cross(projectionPlane.Normal, locX); | ||||||
|  |         locX = Vector3.Normalize(locX); | ||||||
|  |         locY = Vector3.Normalize(locY); | ||||||
| 
 | 
 | ||||||
|         public Vector2 MapTo2d(Vector3 point) |         var inside = true; | ||||||
|  |         for (var i = 0; i < v2ds.Length; i++) | ||||||
|         { |         { | ||||||
|             var offset = point - _origin; |             var a = v2ds[i]; | ||||||
|             var x = Vector3.Dot(offset, _xAxis); |             var b = v2ds[(i + 1) % v2ds.Length]; | ||||||
|             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 = point - a; |             var offset = p2d - 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 >= -Epsilon) |             if (side >= -0.001) | ||||||
|             { |             { | ||||||
|                 // We apply epsilon so that we push slightly into the poly. If we only |                 p2d -= norm * (side + 0.0015f); | ||||||
|                 // push to the edge then Embree sometimes misses casts. The reason |                 inside = false; | ||||||
|                 // it's 2 epsilon is so Side == -Epsilon still gets pushed in properly |  | ||||||
|                 point -= norm * (side + 2 * Epsilon); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return point; |         // return p2d; | ||||||
|  | 
 | ||||||
|  |         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,11 +117,9 @@ 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 + propLight.Offset, |                             position = brush.position, | ||||||
|                             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, | ||||||
|  | @ -245,7 +243,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, hdr); |                 ResetLightmap(ambientLight, lightmap); | ||||||
| 
 | 
 | ||||||
|                 // 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]]; | ||||||
|  | @ -267,8 +265,6 @@ 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) | ||||||
|                 { |                 { | ||||||
|  | @ -305,17 +301,7 @@ 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; | ||||||
| 
 | 
 | ||||||
|                             // We need to clip the point to slightly inside of the poly |                             pos = MathUtils.ClipPointToPoly3d(pos, vs, plane); | ||||||
|                             // 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 | ||||||
|  | @ -336,7 +322,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()) < MathUtils.Epsilon; |                             var hit = hitResult && Math.Abs(hitResult.Distance - direction.Length()) < 0.001; | ||||||
|                             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 | ||||||
|  | @ -381,24 +367,18 @@ class Program | ||||||
|         Console.Write("\n"); |         Console.Write("\n"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static void ResetLightmap(Vector3 ambientLight, WorldRep.Cell.Lightmap lightmap, bool hdr) |     private static void ResetLightmap(Vector3 ambientLight, WorldRep.Cell.Lightmap lightmap) | ||||||
|     { |     { | ||||||
|         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)c.X, (byte)c.Y, (byte)c.Z); |                 lightmap.AddLight(0, x, y, (byte)ambientLight.X, (byte)ambientLight.Y, (byte)ambientLight.Z); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue