Ejemplo n.º 1
0
        public static void GetSphericalHarmonicsL1FromIndex(ref SphericalHarmonicsL1 sh, ref ProbeVolumePayload payload, int indexProbe)
        {
            int strideSHL01        = GetDataSHL01Stride();
            int indexDataBaseSHL01 = indexProbe * strideSHL01;
            int indexDataEndSHL01  = indexDataBaseSHL01 + strideSHL01;

            Debug.Assert(payload.dataSHL01 != null);
            Debug.Assert(payload.dataSHL01.Length >= indexDataEndSHL01);

            // Constant (DC terms):
            sh.shAr.w = payload.dataSHL01[indexDataBaseSHL01 + 0]; // shAr.w
            sh.shAg.w = payload.dataSHL01[indexDataBaseSHL01 + 1]; // shAg.w
            sh.shAb.w = payload.dataSHL01[indexDataBaseSHL01 + 2]; // shAb.w

            // Linear: (used by L1 and L2)
            // Swizzle the coefficients to be in { x, y, z } order.
            sh.shAr.x = payload.dataSHL01[indexDataBaseSHL01 + 3];  // shAr.x
            sh.shAr.y = payload.dataSHL01[indexDataBaseSHL01 + 4];  // shAr.y
            sh.shAr.z = payload.dataSHL01[indexDataBaseSHL01 + 5];  // shAr.z

            sh.shAg.x = payload.dataSHL01[indexDataBaseSHL01 + 6];  // shAg.x
            sh.shAg.y = payload.dataSHL01[indexDataBaseSHL01 + 7];  // shAg.y
            sh.shAg.z = payload.dataSHL01[indexDataBaseSHL01 + 8];  // shAg.z

            sh.shAb.x = payload.dataSHL01[indexDataBaseSHL01 + 9];  // shAb.x
            sh.shAb.y = payload.dataSHL01[indexDataBaseSHL01 + 10]; // shAb.y
            sh.shAb.z = payload.dataSHL01[indexDataBaseSHL01 + 11]; // shAb.z
        }
Ejemplo n.º 2
0
        private static void DilateInvalidProbes(Vector3[] probePositions,
                                                List <Brick> bricks, SphericalHarmonicsL1[] sh, float[] validity, ProbeDilationSettings dilationSettings)
        {
            // For each brick
            List <DilationProbe> culledProbes = new List <DilationProbe>();
            List <DilationProbe> nearProbes   = new List <DilationProbe>(dilationSettings.maxDilationSamples);

            for (int brickIdx = 0; brickIdx < bricks.Count; brickIdx++)
            {
                // Find probes that are in bricks nearby
                CullDilationProbes(brickIdx, bricks, validity, dilationSettings, culledProbes);

                // Iterate probes in current brick
                for (int probeOffset = 0; probeOffset < 64; probeOffset++)
                {
                    int probeIdx = brickIdx * 64 + probeOffset;

                    // Skip valid probes
                    if (validity[probeIdx] <= dilationSettings.dilationValidityThreshold)
                    {
                        continue;
                    }

                    // Find distance weighted probes nearest to current probe
                    FindNearProbes(probeIdx, probePositions, dilationSettings, culledProbes, nearProbes, out float invDistSum);

                    // Set invalid probe to weighted average of found neighboring probes
                    var shAverage = new SphericalHarmonicsL1();
                    for (int nearProbeIdx = 0; nearProbeIdx < nearProbes.Count; nearProbeIdx++)
                    {
                        var   nearProbe = nearProbes[nearProbeIdx];
                        float weight    = nearProbe.dist / invDistSum;
                        var   target    = sh[nearProbe.idx];
                        shAverage.shAr += target.shAr * weight;
                        shAverage.shAg += target.shAg * weight;
                        shAverage.shAb += target.shAb * weight;
                    }

                    sh[probeIdx]       = shAverage;
                    validity[probeIdx] = validity[probeIdx];
                }
            }
        }
Ejemplo n.º 3
0
        private static void OnAdditionalProbesBakeCompleted()
        {
            UnityEditor.Experimental.Lightmapping.additionalBakedProbesCompleted -= OnAdditionalProbesBakeCompleted;

            var numCells = bakingCells.Count;

            // Fetch results of all cells
            for (int c = 0; c < numCells; ++c)
            {
                var cell = bakingCells[c];

                if (cell.probePositions == null)
                {
                    continue;
                }

                int numProbes = cell.probePositions.Length;
                Debug.Assert(numProbes > 0);

                var sh       = new NativeArray <SphericalHarmonicsL2>(numProbes, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
                var validity = new NativeArray <float>(numProbes, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
                var bakedProbeOctahedralDepth = new NativeArray <float>(numProbes * 64, Allocator.Temp, NativeArrayOptions.UninitializedMemory);

                UnityEditor.Experimental.Lightmapping.GetAdditionalBakedProbes(cell.index, sh, validity, bakedProbeOctahedralDepth);

                cell.sh       = new SphericalHarmonicsL1[numProbes];
                cell.validity = new float[numProbes];
                for (int i = 0; i < numProbes; ++i)
                {
                    Vector4[] channels = new Vector4[3];

                    // compare to SphericalHarmonicsL2::GetShaderConstantsFromNormalizedSH
                    channels[0] = new Vector4(sh[i][0, 3], sh[i][0, 1], sh[i][0, 2], sh[i][0, 0]);
                    channels[1] = new Vector4(sh[i][1, 3], sh[i][1, 1], sh[i][1, 2], sh[i][1, 0]);
                    channels[2] = new Vector4(sh[i][2, 3], sh[i][2, 1], sh[i][2, 2], sh[i][2, 0]);

                    // It can be shown that |L1_i| <= |2*L0|
                    // Precomputed Global Illumination in Frostbite by Yuriy O'Donnell.
                    // https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/gdc2018-precomputedgiobalilluminationinfrostbite.pdf
                    //
                    // So divide by L0 brings us to [-2, 2],
                    // divide by 4 brings us to [-0.5, 0.5],
                    // and plus by 0.5 brings us to [0, 1].
                    for (int channel = 0; channel < 3; ++channel)
                    {
                        var l0 = channels[channel][3];

                        if (l0 != 0.0f)
                        {
                            for (int axis = 0; axis < 3; ++axis)
                            {
                                channels[channel][axis] = channels[channel][axis] / (l0 * 4.0f) + 0.5f;
                                Debug.Assert(channels[channel][axis] >= 0.0f && channels[channel][axis] <= 1.0f);
                            }
                        }
                    }

                    SphericalHarmonicsL1 sh1 = new SphericalHarmonicsL1();
                    sh1.shAr = channels[0];
                    sh1.shAg = channels[1];
                    sh1.shAb = channels[2];

                    cell.sh[i]       = sh1;
                    cell.validity[i] = validity[i];
                }

                // Reset index
                UnityEditor.Experimental.Lightmapping.SetAdditionalBakedProbes(cell.index, null);

                DilateInvalidProbes(cell.probePositions, cell.bricks, cell.sh, cell.validity, bakingReferenceVolumeAuthoring.GetDilationSettings());

                ProbeReferenceVolume.instance.cells[cell.index] = cell;
            }

            // Map from each scene to an existing reference volume
            var scene2RefVol = new Dictionary <Scene, ProbeReferenceVolumeAuthoring>();

            foreach (var refVol in GameObject.FindObjectsOfType <ProbeReferenceVolumeAuthoring>())
            {
                if (refVol.enabled)
                {
                    scene2RefVol[refVol.gameObject.scene] = refVol;
                }
            }

            // Map from each reference volume to its asset
            var refVol2Asset = new Dictionary <ProbeReferenceVolumeAuthoring, ProbeVolumeAsset>();

            foreach (var refVol in scene2RefVol.Values)
            {
                refVol2Asset[refVol] = ProbeVolumeAsset.CreateAsset(refVol.gameObject.scene);
            }

            // Put cells into the respective assets
            foreach (var cell in ProbeReferenceVolume.instance.cells.Values)
            {
                foreach (var scene in cellIndex2SceneReferences[cell.index])
                {
                    // This scene has a reference volume authoring component in it?
                    ProbeReferenceVolumeAuthoring refVol = null;
                    if (scene2RefVol.TryGetValue(scene, out refVol))
                    {
                        var asset = refVol2Asset[refVol];
                        asset.cells.Add(cell);
                    }
                }
            }

            // Connect the assets to their components
            foreach (var pair in refVol2Asset)
            {
                var refVol = pair.Key;
                var asset  = pair.Value;

                refVol.volumeAsset = asset;

                if (UnityEditor.Lightmapping.giWorkflowMode != UnityEditor.Lightmapping.GIWorkflowMode.Iterative)
                {
                    UnityEditor.EditorUtility.SetDirty(refVol);
                    UnityEditor.EditorUtility.SetDirty(refVol.volumeAsset);
                }
            }

            UnityEditor.AssetDatabase.SaveAssets();
            UnityEditor.AssetDatabase.Refresh();

            foreach (var refVol in refVol2Asset.Keys)
            {
                if (refVol.enabled && refVol.gameObject.activeSelf)
                {
                    refVol.QueueAssetLoading();
                }
            }
        }
Ejemplo n.º 4
0
        public static void SetSphericalHarmonicsL1FromIndex(ref ProbeVolumePayload payload, SphericalHarmonicsL1 sh, int indexProbe)
        {
            int strideSHL01        = GetDataSHL01Stride();
            int indexDataBaseSHL01 = indexProbe * strideSHL01;
            int indexDataEndSHL01  = indexDataBaseSHL01 + strideSHL01;

            Debug.Assert(payload.dataSHL01 != null);
            Debug.Assert(payload.dataSHL01.Length >= indexDataEndSHL01);

            int strideSHL2        = GetDataSHL2Stride();
            int indexDataBaseSHL2 = indexProbe * strideSHL2;
            int indexDataEndSHL2  = indexDataBaseSHL2 + strideSHL2;

            Debug.Assert(payload.dataSHL2 != null);
            Debug.Assert(payload.dataSHL2.Length >= indexDataEndSHL2);

            // Constant (DC terms):
            payload.dataSHL01[indexDataBaseSHL01 + 0] = sh.shAr.w;
            payload.dataSHL01[indexDataBaseSHL01 + 1] = sh.shAg.w;
            payload.dataSHL01[indexDataBaseSHL01 + 2] = sh.shAb.w;

            // Linear: (used by L1 and L2)
            // Swizzle the coefficients to be in { x, y, z } order.
            payload.dataSHL01[indexDataBaseSHL01 + 3] = sh.shAr.x;
            payload.dataSHL01[indexDataBaseSHL01 + 4] = sh.shAr.y;
            payload.dataSHL01[indexDataBaseSHL01 + 5] = sh.shAr.z;

            payload.dataSHL01[indexDataBaseSHL01 + 6] = sh.shAg.x;
            payload.dataSHL01[indexDataBaseSHL01 + 7] = sh.shAg.y;
            payload.dataSHL01[indexDataBaseSHL01 + 8] = sh.shAg.z;

            payload.dataSHL01[indexDataBaseSHL01 + 9]  = sh.shAb.x;
            payload.dataSHL01[indexDataBaseSHL01 + 10] = sh.shAb.y;
            payload.dataSHL01[indexDataBaseSHL01 + 11] = sh.shAb.z;

            // Quadratic: (used by L2)
            payload.dataSHL2[indexDataBaseSHL2 + 0] = 0.0f;  // shBr.x
            payload.dataSHL2[indexDataBaseSHL2 + 1] = 0.0f;  // shBr.y
            payload.dataSHL2[indexDataBaseSHL2 + 2] = 0.0f;  // shBr.z
            payload.dataSHL2[indexDataBaseSHL2 + 3] = 0.0f;  // shBr.w

            payload.dataSHL2[indexDataBaseSHL2 + 4] = 0.0f;  // shBg.x
            payload.dataSHL2[indexDataBaseSHL2 + 5] = 0.0f;  // shBg.y
            payload.dataSHL2[indexDataBaseSHL2 + 6] = 0.0f;  // shBg.z
            payload.dataSHL2[indexDataBaseSHL2 + 7] = 0.0f;  // shBg.w

            payload.dataSHL2[indexDataBaseSHL2 + 8]  = 0.0f; // shBb.x
            payload.dataSHL2[indexDataBaseSHL2 + 9]  = 0.0f; // shBb.y
            payload.dataSHL2[indexDataBaseSHL2 + 10] = 0.0f; // shBb.z
            payload.dataSHL2[indexDataBaseSHL2 + 11] = 0.0f; // shBb.w

            payload.dataSHL2[indexDataBaseSHL2 + 12] = 0.0f; // shCr.x
            payload.dataSHL2[indexDataBaseSHL2 + 13] = 0.0f; // shCr.y
            payload.dataSHL2[indexDataBaseSHL2 + 14] = 0.0f; // shCr.z
        }
Ejemplo n.º 5
0
        internal void OnProbesBakeCompleted()
        {
            if (this.gameObject == null || !this.gameObject.activeInHierarchy)
            {
                return;
            }

            int numProbes = parameters.resolutionX * parameters.resolutionY * parameters.resolutionZ;

            SphericalHarmonicsL1[] data = new SphericalHarmonicsL1[numProbes];
            float[] dataValidity        = new float[numProbes];
            float[] dataOctahedralDepth = new float[numProbes * 8 * 8];

            var sh              = new NativeArray <SphericalHarmonicsL2>(numProbes, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            var validity        = new NativeArray <float>(numProbes, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
            var octahedralDepth = new NativeArray <float>(numProbes * 8 * 8, Allocator.Temp, NativeArrayOptions.UninitializedMemory);

            if (UnityEditor.Experimental.Lightmapping.GetAdditionalBakedProbes(GetID(), sh, validity, octahedralDepth))
            {
                // TODO: Remove this data copy.
                for (int i = 0, iLen = data.Length; i < iLen; ++i)
                {
                    data[i].shAr = new Vector4(sh[i][0, 3], sh[i][0, 1], sh[i][0, 2], sh[i][0, 0] - sh[i][0, 6]);
                    data[i].shAg = new Vector4(sh[i][1, 3], sh[i][1, 1], sh[i][1, 2], sh[i][1, 0] - sh[i][1, 6]);
                    data[i].shAb = new Vector4(sh[i][2, 3], sh[i][2, 1], sh[i][2, 2], sh[i][2, 0] - sh[i][2, 6]);

                    dataValidity[i] = validity[i];

                    for (int j = 0; j < 64; ++j)
                    {
                        dataOctahedralDepth[i * 64 + j] = octahedralDepth[i * 64 + j];
                    }
                }

                if (!probeVolumeAsset || GetID() != probeVolumeAsset.instanceID)
                {
                    probeVolumeAsset = ProbeVolumeAsset.CreateAsset(GetID());
                }

                probeVolumeAsset.instanceID          = GetID();
                probeVolumeAsset.dataSH              = data;
                probeVolumeAsset.dataValidity        = dataValidity;
                probeVolumeAsset.dataOctahedralDepth = dataOctahedralDepth;
                probeVolumeAsset.resolutionX         = parameters.resolutionX;
                probeVolumeAsset.resolutionY         = parameters.resolutionY;
                probeVolumeAsset.resolutionZ         = parameters.resolutionZ;

                if (UnityEditor.Lightmapping.giWorkflowMode != UnityEditor.Lightmapping.GIWorkflowMode.Iterative)
                {
                    UnityEditor.EditorUtility.SetDirty(probeVolumeAsset);
                }

                UnityEditor.AssetDatabase.Refresh();

                dataUpdated = true;
            }

            sh.Dispose();
            validity.Dispose();
            octahedralDepth.Dispose();
        }