Beispiel #1
0
        static public void CreateInfluenceVolumes(Vector3Int cellPos,
                                                  Renderer[] renderers, ProbeVolume[] probeVolumes,
                                                  ProbeReferenceVolumeAuthoring settings, Matrix4x4 cellTrans, out List <ProbeReferenceVolume.Volume> culledVolumes, out Dictionary <Scene, int> sceneRefs)
        {
            ProbeReferenceVolume.Volume cellVolume = new ProbeReferenceVolume.Volume();
            cellVolume.corner = new Vector3(cellPos.x * settings.cellSize, cellPos.y * settings.cellSize, cellPos.z * settings.cellSize);
            cellVolume.X      = new Vector3(settings.cellSize, 0, 0);
            cellVolume.Y      = new Vector3(0, settings.cellSize, 0);
            cellVolume.Z      = new Vector3(0, 0, settings.cellSize);
            cellVolume.Transform(cellTrans);

            // Keep track of volumes and which scene they originated from
            sceneRefs = new Dictionary <Scene, int>();

            // Extract all influencers inside the cell
            List <ProbeReferenceVolume.Volume> influenceVolumes = new List <ProbeReferenceVolume.Volume>();

            RenderersToVolumes(ref renderers, ref cellVolume, ref influenceVolumes, ref sceneRefs);
            NavPathsToVolumes(ref cellVolume, ref influenceVolumes, ref sceneRefs);
            ImportanceVolumesToVolumes(ref cellVolume, ref influenceVolumes, ref sceneRefs);
            LightsToVolumes(ref cellVolume, ref influenceVolumes, ref sceneRefs);

            // Extract all ProbeVolumes inside the cell
            List <ProbeReferenceVolume.Volume> indicatorVolumes = new List <ProbeReferenceVolume.Volume>();

            ProbeVolumesToVolumes(ref probeVolumes, ref cellVolume, ref indicatorVolumes, ref sceneRefs);

            // Cull all influencers against ProbeVolumes
            culledVolumes = new List <ProbeReferenceVolume.Volume>();
            CullVolumes(ref influenceVolumes, ref indicatorVolumes, ref culledVolumes);
        }
        public void OnSceneGUI()
        {
            ProbeReferenceVolumeAuthoring pvra = target as ProbeReferenceVolumeAuthoring;

            if (Event.current.type == EventType.Layout)
            {
                pvra.DrawProbeGizmos();
            }
        }
Beispiel #3
0
        private static void OnBakeStarted()
        {
            bakingReferenceVolumeAuthoring = GetCardinalAuthoringComponent();

            if (bakingReferenceVolumeAuthoring == null)
            {
                Debug.Log("Scene(s) have multiple inconsistent ProbeReferenceVolumeAuthoring components. Please ensure they use identical profiles and transforms before baking.");
                return;
            }

            RunPlacement();
        }
Beispiel #4
0
        private static void OnBakeStarted()
        {
            var refVolAuthList = GameObject.FindObjectsOfType <ProbeReferenceVolumeAuthoring>();

            if (refVolAuthList.Length == 0)
            {
                return;
            }

            bakingReferenceVolumeAuthoring = GetCardinalAuthoringComponent(refVolAuthList);

            if (bakingReferenceVolumeAuthoring == null)
            {
                Debug.Log("Scene(s) have multiple inconsistent ProbeReferenceVolumeAuthoring components. Please ensure they use identical profiles and transforms before baking.");
                return;
            }

            RunPlacement();
        }
Beispiel #5
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].cell;

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

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

                int numUniqueProbes = bakingCells[c].numUniqueProbes;

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

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

                cell.sh       = new SphericalHarmonicsL2[numProbes];
                cell.validity = new float[numProbes];

                for (int i = 0; i < numProbes; ++i)
                {
                    int j = bakingCells[c].probeIndices[i];
                    SphericalHarmonicsL2 shv = sh[j];

                    // Compress the range of all coefficients but the DC component to [0..1]
                    // Upper bounds taken from http://ppsloan.org/publications/Sig20_Advances.pptx
                    // Divide each coefficient by DC*f to get to [-1,1] where f is from slide 33
                    for (int rgb = 0; rgb < 3; ++rgb)
                    {
                        var l0 = sh[j][rgb, 0];

                        if (l0 == 0.0f)
                        {
                            continue;
                        }

                        // TODO: We're working on irradiance instead of radiance coefficients
                        //       Add safety margin 2 to avoid out-of-bounds values
                        float l1scale = 1.7320508f; // 3/(2*sqrt(3)) * 2
                        float l2scale = 3.5777088f; // 4/sqrt(5) * 2

                        // L_1^m
                        shv[rgb, 1] = sh[j][rgb, 1] / (l0 * l1scale * 2.0f) + 0.5f;
                        shv[rgb, 2] = sh[j][rgb, 2] / (l0 * l1scale * 2.0f) + 0.5f;
                        shv[rgb, 3] = sh[j][rgb, 3] / (l0 * l1scale * 2.0f) + 0.5f;

                        // L_2^-2
                        shv[rgb, 4] = sh[j][rgb, 4] / (l0 * l2scale * 2.0f) + 0.5f;
                        shv[rgb, 5] = sh[j][rgb, 5] / (l0 * l2scale * 2.0f) + 0.5f;
                        shv[rgb, 6] = sh[j][rgb, 6] / (l0 * l2scale * 2.0f) + 0.5f;
                        shv[rgb, 7] = sh[j][rgb, 7] / (l0 * l2scale * 2.0f) + 0.5f;
                        shv[rgb, 8] = sh[j][rgb, 8] / (l0 * l2scale * 2.0f) + 0.5f;

                        // Assert coefficient range
                        for (int coeff = 1; coeff < 9; ++coeff)
                        {
                            Debug.Assert(shv[rgb, coeff] >= 0.0f && shv[rgb, coeff] <= 1.0f);
                        }
                    }

                    SphericalHarmonicsL2Utils.SetL0(ref cell.sh[i], new Vector3(shv[0, 0], shv[1, 0], shv[2, 0]));
                    SphericalHarmonicsL2Utils.SetL1R(ref cell.sh[i], new Vector3(shv[0, 3], shv[0, 1], shv[0, 2]));
                    SphericalHarmonicsL2Utils.SetL1G(ref cell.sh[i], new Vector3(shv[1, 3], shv[1, 1], shv[1, 2]));
                    SphericalHarmonicsL2Utils.SetL1B(ref cell.sh[i], new Vector3(shv[2, 3], shv[2, 1], shv[2, 2]));

                    cell.validity[i] = validity[j];
                }

                for (int i = 0; i < numProbes; ++i)
                {
                    int j = bakingCells[c].probeIndices[i];

                    SphericalHarmonicsL2Utils.SetCoefficient(ref cell.sh[i], 4, new Vector3(sh[j][0, 4], sh[j][1, 4], sh[j][2, 4]));
                    SphericalHarmonicsL2Utils.SetCoefficient(ref cell.sh[i], 5, new Vector3(sh[j][0, 5], sh[j][1, 5], sh[j][2, 5]));
                    SphericalHarmonicsL2Utils.SetCoefficient(ref cell.sh[i], 6, new Vector3(sh[j][0, 6], sh[j][1, 6], sh[j][2, 6]));
                    SphericalHarmonicsL2Utils.SetCoefficient(ref cell.sh[i], 7, new Vector3(sh[j][0, 7], sh[j][1, 7], sh[j][2, 7]));
                    SphericalHarmonicsL2Utils.SetCoefficient(ref cell.sh[i], 8, new Vector3(sh[j][0, 8], sh[j][1, 8], sh[j][2, 8]));
                }

                // 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();
                }
            }
        }
Beispiel #6
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].cell;

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

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

                int numUniqueProbes = bakingCells[c].numUniqueProbes;

                var sh       = new NativeArray <SphericalHarmonicsL2>(numUniqueProbes, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
                var validity = new NativeArray <float>(numUniqueProbes, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
                var bakedProbeOctahedralDepth = new NativeArray <float>(numUniqueProbes * 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];

                    int j = bakingCells[c].probeIndices[i];

                    // compare to SphericalHarmonicsL2::GetShaderConstantsFromNormalizedSH
                    channels[0] = new Vector4(sh[j][0, 3], sh[j][0, 1], sh[j][0, 2], sh[j][0, 0]);
                    channels[1] = new Vector4(sh[j][1, 3], sh[j][1, 1], sh[j][1, 2], sh[j][1, 0]);
                    channels[2] = new Vector4(sh[j][2, 3], sh[j][2, 1], sh[j][2, 2], sh[j][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[j];
                }

                // 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();
                }
            }
        }
Beispiel #7
0
        public override void OnInspectorGUI()
        {
            var renderPipelineAsset = GraphicsSettings.renderPipelineAsset;

            if (renderPipelineAsset != null && renderPipelineAsset.GetType().Name == "HDRenderPipelineAsset")
            {
                serializedObject.Update();

                var  probeReferenceVolumes = FindObjectsOfType <ProbeReferenceVolumeAuthoring>();
                bool foundInconsistency    = false;
                if (probeReferenceVolumes.Length > 1)
                {
                    foreach (var o1 in probeReferenceVolumes)
                    {
                        foreach (var o2 in probeReferenceVolumes)
                        {
                            if (!o1.profile.IsEquivalent(o2.profile) && !foundInconsistency)
                            {
                                EditorGUILayout.HelpBox("Multiple Probe Reference Volume components are loaded, but they have different profiles. "
                                                        + "This is unsupported, please make sure all loaded Probe Reference Volume have the same profile or profiles with equal values.", MessageType.Error, wide: true);
                                foundInconsistency = true;
                            }
                            if (foundInconsistency)
                            {
                                break;
                            }
                        }
                    }
                }

                EditorGUI.BeginChangeCheck();

                // The layout system breaks alignment when mixing inspector fields with custom layout'd
                // fields, do the layout manually instead
                int   buttonWidth   = 60;
                float indentOffset  = EditorGUI.indentLevel * 15f;
                var   lineRect      = EditorGUILayout.GetControlRect();
                var   labelRect     = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset, lineRect.height);
                var   fieldRect     = new Rect(labelRect.xMax, lineRect.y, lineRect.width - labelRect.width - buttonWidth, lineRect.height);
                var   buttonNewRect = new Rect(fieldRect.xMax, lineRect.y, buttonWidth, lineRect.height);

                GUIContent guiContent = EditorGUIUtility.TrTextContent("Profile", "A reference to a profile asset.");
                EditorGUI.PrefixLabel(labelRect, guiContent);

                using (var scope = new EditorGUI.ChangeCheckScope())
                {
                    EditorGUI.BeginProperty(fieldRect, GUIContent.none, m_Profile);

                    m_Profile.objectReferenceValue = (ProbeReferenceVolumeProfile)EditorGUI.ObjectField(fieldRect, m_Profile.objectReferenceValue, typeof(ProbeReferenceVolumeProfile), false);

                    EditorGUI.EndProperty();
                }

                if (GUI.Button(buttonNewRect, EditorGUIUtility.TrTextContent("New", "Create a new profile."), EditorStyles.miniButton))
                {
                    // By default, try to put assets in a folder next to the currently active
                    // scene file. If the user isn't a scene, put them in root instead.
                    var targetName = actualTarget.name;
                    var scene      = actualTarget.gameObject.scene;
                    var asset      = ProbeReferenceVolumeAuthoring.CreateReferenceVolumeProfile(scene, targetName);
                    m_Profile.objectReferenceValue = asset;
                }

                m_VolumeAsset.objectReferenceValue = EditorGUILayout.ObjectField(s_DataAssetLabel, m_VolumeAsset.objectReferenceValue, typeof(ProbeVolumeAsset), false);

                DebugVisualizationGroupEnabled = EditorGUILayout.BeginFoldoutHeaderGroup(DebugVisualizationGroupEnabled, "Debug Visualization");
                if (DebugVisualizationGroupEnabled)
                {
                    m_DrawCells.boolValue  = EditorGUILayout.Toggle("Draw Cells", m_DrawCells.boolValue);
                    m_DrawBricks.boolValue = EditorGUILayout.Toggle("Draw Bricks", m_DrawBricks.boolValue);
                    m_DrawProbes.boolValue = EditorGUILayout.Toggle("Draw Probes", m_DrawProbes.boolValue);
                    EditorGUI.BeginDisabledGroup(!m_DrawProbes.boolValue);
                    m_ProbeShading.enumValueIndex = EditorGUILayout.Popup("Probe Shading Mode", m_ProbeShading.enumValueIndex, ProbeShadingModes);
                    EditorGUI.BeginDisabledGroup(m_ProbeShading.enumValueIndex != 1);
                    m_ExposureCompensation.floatValue = EditorGUILayout.FloatField("Probe Exposure Compensation", m_ExposureCompensation.floatValue);
                    EditorGUI.EndDisabledGroup();
                    EditorGUI.EndDisabledGroup();
                    m_CullingDistance.floatValue = EditorGUILayout.FloatField("Culling Distance", m_CullingDistance.floatValue);
                }
                EditorGUILayout.EndFoldoutHeaderGroup();

                DilationGroupEnabled = EditorGUILayout.BeginFoldoutHeaderGroup(DilationGroupEnabled, "Dilation");
                if (DilationGroupEnabled)
                {
                    m_Dilate.boolValue = EditorGUILayout.Toggle("Dilate", m_Dilate.boolValue);
                    EditorGUI.BeginDisabledGroup(!m_Dilate.boolValue);
                    m_MaxDilationSamples.intValue          = EditorGUILayout.IntField("Max Dilation Samples", m_MaxDilationSamples.intValue);
                    m_MaxDilationSampleDistance.floatValue = EditorGUILayout.FloatField("Max Dilation Sample Distance", m_MaxDilationSampleDistance.floatValue);
                    DilationValidityThresholdInverted      = EditorGUILayout.Slider("Dilation Validity Threshold", DilationValidityThresholdInverted, 0f, 1f);
                    m_GreedyDilation.boolValue             = EditorGUILayout.Toggle("Greedy Dilation", m_GreedyDilation.boolValue);
                    EditorGUI.EndDisabledGroup();
                }
                EditorGUILayout.EndFoldoutHeaderGroup();

                if (EditorGUI.EndChangeCheck())
                {
                    Constrain();
                    serializedObject.ApplyModifiedProperties();
                }
            }
            else
            {
                EditorGUILayout.HelpBox("Probe Volume is not a supported feature by this SRP.", MessageType.Error, wide: true);
            }
        }