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 const float Epsilon = 0.001f; | ||||
| 
 | ||||
|     public readonly struct Aabb | ||||
|     { | ||||
|         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(); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// Expects poly to be convex. Given a point | ||||
|     /// </summary> | ||||
|     public static Vector3 ClipPointToPoly3d(Vector3 point, Vector3[] vertices, Plane projectionPlane) | ||||
|     public record PlanePointMapper | ||||
|     { | ||||
|         // 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); | ||||
| 
 | ||||
|         // !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++) | ||||
|         public PlanePointMapper(Vector3 normal, Vector3 p0, Vector3 p1) | ||||
|         { | ||||
|             var a = v2ds[i]; | ||||
|             var b = v2ds[(i + 1) % v2ds.Length]; | ||||
|             _origin = p0; | ||||
|             _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 offset = p2d - a; | ||||
|             var offset = point - a; | ||||
|             var norm = Vector2.Normalize(new Vector2(-segment.Y, segment.X)); | ||||
|             var side = Vector2.Dot(norm, offset); | ||||
|             if (side >= -0.001) | ||||
|             if (side >= -Epsilon) | ||||
|             { | ||||
|                 p2d -= norm * (side + 0.0015f); | ||||
|                 inside = false; | ||||
|                 // We apply epsilon so that we push slightly into the poly. If we only | ||||
|                 // 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 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); | ||||
|         return point; | ||||
|     } | ||||
| } | ||||
|  | @ -22,7 +22,7 @@ class Program | |||
|         Timing.Reset(); | ||||
| 
 | ||||
|         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"; | ||||
|         Timing.TimeStage("Total", () => LightmapMission(misPath)); | ||||
| 
 | ||||
|  | @ -117,9 +117,11 @@ class Program | |||
|                     { | ||||
|                         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 | ||||
|                         { | ||||
|                             position = brush.position, | ||||
|                             position = brush.position + propLight.Offset, | ||||
|                             color = HsbToRgb(propLightColor.Hue, propLightColor.Saturation, propLight.Brightness), | ||||
|                             radius = propLight.Radius, | ||||
|                             r2 = propLight.Radius * propLight.Radius, | ||||
|  | @ -243,7 +245,7 @@ class Program | |||
|                 var info = cell.LightList[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) | ||||
|                 var topLeft = cell.Vertices[cell.Indices[cellIdxOffset]]; | ||||
|  | @ -265,6 +267,8 @@ class Program | |||
|                 { | ||||
|                     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) | ||||
|                 { | ||||
|  | @ -301,7 +305,17 @@ class Program | |||
|                             pos += x * 0.25f * renderPoly.TextureVectors.Item1; | ||||
|                             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 | ||||
|                             // There's probably a better way to discard the entire lightmap | ||||
|  | @ -322,7 +336,7 @@ class Program | |||
| 
 | ||||
|                             // cheeky epsilon | ||||
|                             // 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) | ||||
|                             { | ||||
|                                 // Calculate light strength at a given point. As far as I can tell | ||||
|  | @ -367,18 +381,24 @@ class Program | |||
|         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++) | ||||
|         { | ||||
|             lightmap.Pixels[i] = 0; | ||||
|         } | ||||
| 
 | ||||
|         var c = ambientLight; | ||||
|         if (hdr) | ||||
|         { | ||||
|             c /= 2.0f; | ||||
|         } | ||||
| 
 | ||||
|         for (var y = 0; y < lightmap.Height; y++) | ||||
|         { | ||||
|             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