Example #1
0
        /// <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
            }
        }
Example #2
0
        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();
                        }
                    }
                }
            }
        }
Example #3
0
        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);
        }