/// <summary> /// Light probe runtime data is auto-computed when lightprobes are added/removed. If you move them at runtime, please call this method. /// </summary> /// <remarks> /// This will also update coefficients. /// </remarks> public void UpdateLightProbePositions() { RuntimeData = null; needPositionUpdate = false; // Initial load try { // Collect LightProbes var lightProbes = new FastList <LightProbeComponent>(); foreach (var lightProbe in ComponentDatas) { lightProbes.Add(lightProbe.Key); } // Need at least 4 light probes to form a tetrahedron if (lightProbes.Count < 4) { return; } RuntimeData = LightProbeGenerator.GenerateRuntimeData(lightProbes); } catch { // Allow failures // TODO: Log } }
public static unsafe void UpdateCoefficients(LightProbeRuntimeData runtimeData) { fixed(Color3 *destColors = runtimeData.Coefficients) { for (var lightProbeIndex = 0; lightProbeIndex < runtimeData.LightProbes.Length; lightProbeIndex++) { var lightProbe = runtimeData.LightProbes[lightProbeIndex]; // Copy coefficients if (lightProbe.Coefficients != null) { var lightProbeCoefStart = lightProbeIndex * LambertHamonicOrder * LambertHamonicOrder; for (var index = 0; index < LambertHamonicOrder * LambertHamonicOrder; index++) { destColors[lightProbeCoefStart + index] = index < lightProbe.Coefficients.Count ? lightProbe.Coefficients[index] : new Color3(); } } } } }
public static unsafe LightProbeRuntimeData GenerateRuntimeData(FastList <LightProbeComponent> lightProbes) { // TODO: Better check: coplanar, etc... (maybe the check inside BowyerWatsonTetrahedralization might be enough -- tetrahedron won't be in positive order) if (lightProbes.Count < 4) { throw new InvalidOperationException("Can't generate lightprobes if less than 4 of them exists."); } var lightProbePositions = new FastList <Vector3>(); var lightProbeCoefficients = new Color3[lightProbes.Count * LambertHamonicOrder * LambertHamonicOrder]; fixed(Color3 *destColors = lightProbeCoefficients) { for (var lightProbeIndex = 0; lightProbeIndex < lightProbes.Count; lightProbeIndex++) { var lightProbe = lightProbes[lightProbeIndex]; // Copy light position lightProbePositions.Add(lightProbe.Entity.Transform.WorldMatrix.TranslationVector); // Copy coefficients if (lightProbe.Coefficients != null) { var lightProbeCoefStart = lightProbeIndex * LambertHamonicOrder * LambertHamonicOrder; for (var index = 0; index < LambertHamonicOrder * LambertHamonicOrder; index++) { destColors[lightProbeCoefStart + index] = index < lightProbe.Coefficients.Count ? lightProbe.Coefficients[index] : new Color3(); } } } } // Generate light probe structure var tetra = new BowyerWatsonTetrahedralization(); var tetraResult = tetra.Compute(lightProbePositions); var matrices = new Vector4[tetraResult.Tetrahedra.Count * 3]; var probeIndices = new Int4[tetraResult.Tetrahedra.Count]; // Prepare data for GPU: matrices and indices for (int i = 0; i < tetraResult.Tetrahedra.Count; ++i) { var tetrahedron = tetraResult.Tetrahedra[i]; var tetrahedronMatrix = Matrix.Identity; // Compute the tetrahedron matrix // https://en.wikipedia.org/wiki/Barycentric_coordinate_system#Barycentric_coordinates_on_tetrahedra var vertex3 = tetraResult.Vertices[tetrahedron.Vertices[3]]; *((Vector3 *)&tetrahedronMatrix.M11) = tetraResult.Vertices[tetrahedron.Vertices[0]] - vertex3; *((Vector3 *)&tetrahedronMatrix.M12) = tetraResult.Vertices[tetrahedron.Vertices[1]] - vertex3; *((Vector3 *)&tetrahedronMatrix.M13) = tetraResult.Vertices[tetrahedron.Vertices[2]] - vertex3; tetrahedronMatrix.Invert(); // TODO: Optimize 3x3 invert tetrahedronMatrix.Transpose(); // Store position of last vertex in last row tetrahedronMatrix.M41 = vertex3.X; tetrahedronMatrix.M42 = vertex3.Y; tetrahedronMatrix.M43 = vertex3.Z; matrices[i * 3 + 0] = tetrahedronMatrix.Column1; matrices[i * 3 + 1] = tetrahedronMatrix.Column2; matrices[i * 3 + 2] = tetrahedronMatrix.Column3; probeIndices[i] = *(Int4 *)tetrahedron.Vertices; } var lightProbesCopy = new LightProbeComponent[lightProbes.Count]; for (int i = 0; i < lightProbes.Count; ++i) { lightProbesCopy[i] = lightProbes[i]; } var result = new LightProbeRuntimeData { LightProbes = lightProbesCopy, Vertices = tetraResult.Vertices, UserVertexCount = tetraResult.UserVertexCount, Tetrahedra = tetraResult.Tetrahedra, Faces = tetraResult.Faces, Coefficients = lightProbeCoefficients, Matrices = matrices, LightProbeIndices = probeIndices, }; return(result); }