Example #1
0
        // --------------------------------------------------
        // BAKE

#if UNITY_EDITOR
        private IEnumerator BakePortalData()
        {
            // Generate Portal data
            m_Completion    = 0.0f;
            m_BakeTime      = 0.0f;
            m_BakeStartTime = Time.realtimeSinceStartup;
            m_BakeState     = BakeState.Occluders;
            var occluders = PortalPrepareUtil.GetOccluderData();

            m_BakeState = BakeState.Volumes;
            var volumes = PortalPrepareUtil.GetVolumeData(m_VolumeMode, m_Subdivisions);

            m_BakeState = BakeState.Visibility;
            List <VisbilityData> visibilityTable = null;

            yield return(EditorCoroutines.StartCoroutine(GenerateVisibilityTable(occluders, volumes, value => visibilityTable = value), this));

            // Serialize
            m_PortalData = new SerializablePortalData()
            {
                occluders       = occluders,
                volumes         = volumes,
                visibilityTable = visibilityTable
            };

            // Finalize
            m_BakeState  = BakeState.Active;
            m_Completion = 1.0f;
            m_BakeTime   = Time.realtimeSinceStartup - m_BakeStartTime;
            UnityEditor.SceneView.RepaintAll();
            UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty();
        }
Example #2
0
        public void OnClickBake()
        {
            var passedRenderers = new List <MeshRenderer>();
            var rays            = new List <RayDebug>();

            m_Completion = 0.0f;
            m_BakeState  = BakeState.Volumes;
            var staticRenderers = PortalPrepareUtil.GetStaticOccludeeRenderers();

            m_SerializableVolumes = PortalPrepareUtil.GetVolumeData(VolumeMode.Auto, 0);

            m_BakeState = BakeState.Visibility;
            var rayCount = PortalVisibilityUtil.CalculateRayCount(m_RayDensity, m_SerializableVolumes[0].scaleWS);

            for (int r = 0; r < rayCount; r++)
            {
                var rayPosition  = PortalVisibilityUtil.GetRandomPointWithinVolume(m_SerializableVolumes[0]);
                var rayDirection = PortalVisibilityUtil.RandomSphericalDistributionVector();
                rays.Add(new RayDebug(rayPosition, rayDirection));

                foreach (MeshRenderer renderer in staticRenderers)
                {
                    if (PortalVisibilityUtil.CheckAABBIntersection(rayPosition, rayDirection, renderer.bounds))
                    {
                        passedRenderers.AddIfUnique(renderer);
                    }
                }
            }
            m_PassedRenderers = passedRenderers.ToArray();
            m_Rays            = rays.ToArray();
            m_BakeState       = BakeState.Active;
            m_Completion      = 1.0f;
            UnityEditor.SceneView.RepaintAll();
            UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty();
        }
 public void OnClickCancel()
 {
     EditorCoroutines.StopAllCoroutines(this);
     ClearOccluderData();
     ClearVolumeData();
     m_BakeState  = BakeState.Empty;
     m_Completion = 0;
 }
Example #4
0
 public void OnClickCancel()
 {
     m_SerializableOccluders = null;
     m_BakeState             = BakeState.Empty;
     m_Completion            = 0.0f;
     UnityEditor.SceneView.RepaintAll();
     UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty();
 }
Example #5
0
 public void OnClickBake()
 {
     m_Completion            = 0.0f;
     m_BakeState             = BakeState.Occluders;
     m_SerializableOccluders = PortalPrepareUtil.GetOccluderData();
     m_BakeState             = BakeState.Active;
     m_Completion            = 1.0f;
     UnityEditor.SceneView.RepaintAll();
     UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty();
 }
Example #6
0
 public void OnClickBake()
 {
     m_Completion          = 0.0f;
     m_BakeState           = BakeState.Volumes;
     m_SerializableVolumes = PortalPrepareUtil.GetVolumeData(m_VolumeMode, m_Subdivisions);
     m_BakeState           = BakeState.Active;
     m_Completion          = 1.0f;
     UnityEditor.SceneView.RepaintAll();
     UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty();
 }
        private IEnumerator GenerateOcclusion()
        {
            m_StaticRenderers = Utils.GetStaticRenderers();

            // Generate Occluder Data
            m_BakeState = BakeState.Occluders;
            ClearOccluderData();
            yield return(EditorCoroutines.StartCoroutine(Utils.BuildOccluderProxyGeometry(transform, m_StaticRenderers, value => m_Occluders = value, this, m_OccluderTag), this));

            // Generate Volume Data
            m_BakeState = BakeState.Volumes;
            ClearVolumeData();
            switch (m_VolumeMode)
            {
            case VolumeMode.Automatic:
                // Generate Hierarchical Volume Grid
                Bounds bounds = Utils.GetSceneBounds(m_StaticRenderers);
                yield return(EditorCoroutines.StartCoroutine(Utils.BuildHierarchicalVolumeGrid(bounds, m_VolumeDensity, value => m_VolumeData = value, this), this));

                break;

            case VolumeMode.Manual:
                // Generate Manual Volumes
                yield return(EditorCoroutines.StartCoroutine(Utils.BuildManualVolumeGrid(m_ManualVolumes, value => m_VolumeData = value), this));

                break;
            }

            if (m_VolumeData != null)
            {
                // Generate Occlusion Data
                m_BakeState = BakeState.Occlusion;
                int          volumeDensity   = m_VolumeMode == VolumeMode.Automatic ? m_VolumeDensity : 1;
                VolumeData[] smallestVolumes = Utils.GetLowestSubdivisionVolumes(m_VolumeData, volumeDensity);
                for (int i = 0; i < smallestVolumes.Length; i++)
                {
                    m_Completion   = (float)(i + 1) / (float)smallestVolumes.Length;
                    m_ActiveVolume = smallestVolumes[i];
                    yield return(EditorCoroutines.StartCoroutine(Utils.BuildOcclusionForVolume(smallestVolumes[i].bounds, m_RayDensity, m_StaticRenderers, m_Occluders, value => smallestVolumes[i].renderers = value, this, m_FilterAngle), this));
                }
                m_BakeState = BakeState.Active;
            }
            else
            {
                Debug.LogError("Occlusion Bake Failed. Check Settings.");
                m_BakeState  = BakeState.Empty;
                m_Completion = 0;
            }
            m_ActiveVolume = null;
            yield return(null);
        }
Example #8
0
        /// <summary>
        /// Cancel any active bake and clear all data. Editor only.
        /// </summary>
        public void OnClickCancel()
        {
            // Abort if in play mode as save actions arent valid
            if (Application.isPlaying)
            {
                Debug.LogWarning("Cannot modifiy Portal data while in Play mode. Aborting.");
                return;
            }

            // Reset all
            EditorCoroutines.StopAllCoroutines(this);
            m_BakeState  = BakeState.Empty;
            m_PortalData = null;
            m_Completion = 0;
            UnityEditor.SceneView.RepaintAll();
            UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty();
        }
Example #9
0
        private IEnumerator GenerateVisibilityTable(SerializableOccluder[] occluders, SerializableVolume[] volumes, Action <List <VisbilityData> > result)
        {
            // Abort bake if input data is invalid
            if (occluders == null || volumes == null)
            {
                Debug.LogError("Bake prepare data is invalid. Check bake output and retry.");
                m_BakeState  = BakeState.Empty;
                m_Completion = 0;
                yield return(null);
            }

            // Setup
            m_BakeState = BakeState.Visibility;
            var visibilityTable = new List <VisbilityData>();
            int totalRays       = 0;
            int passedRays      = 0;
            int occludedRays    = 0;

            // Get Occluder proxies, volumes and occludees
            var occluderProxies          = PortalPrepareUtil.GetOccluderProxies(occluders);
            var lowestSubdivisionVolumes = PortalPrepareUtil.FilterVolumeDataNoChildren(volumes);
            var occludees = PortalPrepareUtil.GetStaticOccludeeRenderers();

            // Build Visibility for Volumes
            for (int v = 0; v < lowestSubdivisionVolumes.Length; v++)
            {
                // Setup
                m_Completion = (float)(v + 1) / (float)lowestSubdivisionVolumes.Length;
                var volume        = lowestSubdivisionVolumes[v];
                var passedObjects = new List <GameObject>();
                var debugData     = new List <VisbilityData.Debug>();

                // Iterate random rays based on volume density
                var rayCount = PortalVisibilityUtil.CalculateRayCount(m_RayDensity, volume.scaleWS);
                totalRays += rayCount;
                for (int r = 0; r < rayCount; r++)
                {
                    // Get a random ray and a list of cone filtered renderers to test
                    var rayPosition       = PortalVisibilityUtil.GetRandomPointWithinVolume(volume);
                    var rayDirection      = PortalVisibilityUtil.RandomSphericalDistributionVector();
                    var filteredOccludees = PortalVisibilityUtil.FilterRenderersByConeAngle(occludees, rayPosition, rayDirection, m_ConeAngle);
                    for (int f = 0; f < filteredOccludees.Length; f++)
                    {
                        // Test ray against renderer AABB
                        if (PortalVisibilityUtil.CheckAABBIntersection(rayPosition, rayDirection, filteredOccludees[f].bounds))
                        {
                            // Test ray against occluders
                            Vector3 hitPos;
                            bool    passed = PortalVisibilityUtil.CheckOcclusion(occluderProxies, filteredOccludees[f], rayPosition, rayDirection, out hitPos);
                            switch (passed)
                            {
                            case true:
                                passedObjects.AddIfUnique(filteredOccludees[f].gameObject);
                                passedRays++;
                                break;

                            case false:
                                occludedRays++;
                                break;
                            }

                            // Track visibility debug data
                            debugData.Add(new VisbilityData.Debug()
                            {
                                source    = rayPosition,
                                hit       = hitPos,
                                direction = rayDirection,
                                distance  = Vector3.Distance(rayPosition, filteredOccludees[f].transform.position),
                                isHit     = !passed,
                            });
                        }
                    }
                }

                // Add to VisibilityTable
                visibilityTable.Add(new VisbilityData(volume, passedObjects.ToArray(), debugData.ToArray()));
                yield return(null);
            }

            // Clear Occluder proxies
            for (int i = 0; i < occluderProxies.Length; i++)
            {
                PortalCoreUtil.Destroy(occluderProxies[i].gameObject);
            }

            // Save statistics
            var occludeeCount = PortalCoreUtil.GetUniqueOccludeeCount(visibilityTable);

            m_OccludeeStatistics = new Vector2(occludeeCount, occludees.Length);
            m_RayStatistics      = new Vector3(passedRays, occludedRays, totalRays);

            // Finalize
            result(visibilityTable);
        }
        private IEnumerator CookieBaking()
        {
            yield return(null);

            var resolution = s_resolutionOptions[s_selectedCookieResolution];


            // We only want to use GameObjects that are within the outer radius that we have set. So, a quick test
            // to see if something is within the ball park would be to check if their bounding box insersects with
            // a bounding box that contains the outer radius. Once that has been done, we can take a closer look at
            // what's left.
            var meshRenders        = FindObjectsOfType <MeshRenderer>();
            var lightCenter        = s_currentLightComponent.transform.position;
            var lightBoundingBox   = new Bounds(lightCenter, 2.0f * s_outerRadius * Vector3.one);
            var intersectingBounds = new List <MeshRenderer>();

            foreach (var meshRenderer in meshRenders)
            {
                var otherBounds = meshRenderer.bounds;
                if (otherBounds.Intersects(lightBoundingBox))
                {
                    intersectingBounds.Add(meshRenderer);
                }
            }

            yield return(null);

            // Now, we can limit things a bit more by finding the point within our mesh bounds that is nearset to
            // the light's center. We then check this point to see if it's within the distance of our outer radius.
            var intersectingOuterRadius = new List <MeshRenderer>();

            foreach (var meshRenderer in intersectingBounds)
            {
                var otherBounds         = meshRenderer.bounds;
                var nearsetPointToLight = otherBounds.ClosestPoint(lightCenter);
                if ((nearsetPointToLight - lightCenter).sqrMagnitude <= (s_outerRadius * s_outerRadius))
                {
                    intersectingOuterRadius.Add(meshRenderer);
                }
            }

            yield return(null);

            var processMeshRenderer = intersectingBounds;
            var processMeshFilter   = new List <MeshFilter>();

            // We're reusing the List from intersectingBounds and placing it under a more appropriate name.
            // Basically, we're reusing a piece of memory that's no longer needed instead of allocating a new List
            // with a new array. Also, this array shouldn't need to be resized to something larger because it
            // already a capacity that is greater than or equal to the number of items we will be processing.
            processMeshRenderer.Clear();
            intersectingBounds = null;


            // Also, while we're at it, lets make sure that we are only baking items that are static. After all,
            // what's the point of baking the shadow casting item that might not be there?
            foreach (var meshRender in intersectingOuterRadius)
            {
                var gameObject = meshRender.gameObject;

                // If the gameObject isn't static, than it can be moved. Since we are not updating the cookie at
                // runtime, having a moving object would be bad.
                if (!gameObject.isStatic)
                {
                    continue;
                }

                // The mesh for our object is inside the MeshFilter, so we need that to get the mesh. Also, since we're
                // dealing with static meshes, then we really shouldn't be dealing with any Skinned Mesh Renderers.
                var meshFilter = gameObject.GetComponent <MeshFilter>();
                if (meshFilter == null)
                {
                    continue;
                }

                // If there's no mesh, then what are we even bothering with this?
                if (meshFilter.sharedMesh == null)
                {
                    continue;
                }

                processMeshRenderer.Add(meshRender);
                processMeshFilter.Add(meshFilter);
            }

            yield return(null);

            RenderTexture renderTexture = new RenderTexture(resolution,                                                         // Width
                                                            resolution,                                                         // Height
                                                            0,                                                                  // Depth buffer (none)
                                                            RenderTextureFormat.ARGBFloat,                                      // Use a full 32-bit float for each pixel chanel
                                                            RenderTextureReadWrite.Linear)                                      // Use linear lighting instead of gama
            {
                anisoLevel        = 0,
                antiAliasing      = 1,
                autoGenerateMips  = false,
                enableRandomWrite = true,
                filterMode        = FilterMode.Point,
                memorylessMode    = RenderTextureMemoryless.None,                               // We want to be able to read this back into the system memory, so setting this to not use memory is not an option.
                wrapMode          = TextureWrapMode.Clamp
            };

            renderTexture.Create();


            // Todo: With this design, items that use the same mesh will replicate the mesh verts and triangle index
            //		 arrays. I need to add a way to check if we have already added a mesh and if so, pull up the triangle
            //		 index array information to pass along to the meshRefDatum.
            var meshObjecRefData = new List <MeshObject>(processMeshRenderer.Count);
            var indexList        = new List <int>();
            var vertexList       = new List <Vector3>(processMeshRenderer.Count * 50);

            for (int i = 0; i < processMeshRenderer.Count; i++)
            {
                var mesh                = processMeshFilter[i].sharedMesh;
                var meshVerts           = mesh.vertices;
                var meshTriangleIndices = mesh.triangles;

                var meshRefDatum = new MeshObject()
                {
                    LocalToWorldMatrix = processMeshRenderer[i].localToWorldMatrix,
                    IndicesOffset      = indexList.Count,                                       // The starting index of the vert-index for this object's mesh.
                    IndicesCount       = meshTriangleIndices.Length,                            // The number of indices used to form all of the mesh triangles.
                    VerticesOffset     = vertexList.Count
                };

                meshObjecRefData.Add(meshRefDatum);
                vertexList.AddRange(meshVerts);
                indexList.AddRange(meshTriangleIndices);
            }

            yield return(null);

            ComputeBuffer objectBuffer = new ComputeBuffer(meshObjecRefData.Count, 76);
            ComputeBuffer vertexBuffer = new ComputeBuffer(vertexList.Count, 12);
            ComputeBuffer indexBuffer  = new ComputeBuffer(indexList.Count, 4);

            objectBuffer.SetData(meshObjecRefData);
            vertexBuffer.SetData(vertexList);
            indexBuffer.SetData(indexList);

            yield return(null);

            // Most of the values will only get set once, so there's no point in storing hash-key value of their
            // property names. For the few items that will be set quite a few times, storing the hash-key value
            // will speed things up for us. It's just a tiny bit, but it will be faster.
            int uvOffsetKey = Shader.PropertyToID("_UvOffset");

            s_computeShader.SetVector(uvOffsetKey, new Vector4(0.5f, 0.5f, 0.0f, 0.0f));

            s_computeShader.SetFloat("_SampleCount", (float)s_sampleCount);
            s_computeShader.SetInt("_MaxSegments", s_maxBounceCount);
            s_computeShader.SetFloat("_SpotLightAngle", s_currentLightComponent.spotAngle / 2.0f);
            s_computeShader.SetFloat("_ShadowFocusDistance", s_shadowFocusDistance);
            s_computeShader.SetTexture(0, "Result", renderTexture);
            s_computeShader.SetVector("_LightPosition", lightCenter.Position());
            s_computeShader.SetVector("_LightForwardDir", s_currentLightComponent.transform.forward.Direction());
            s_computeShader.SetVector("_LightUpwardDir", s_currentLightComponent.transform.up.Direction());
            s_computeShader.SetFloat("_InnerRange", s_innerRadius);
            s_computeShader.SetFloat("_OuterRange", s_outerRadius);

            yield return(null);

            s_computeShader.SetBuffer(0, "_ObjectData", objectBuffer);
            s_computeShader.SetBuffer(0, "_Vertices", vertexBuffer);
            s_computeShader.SetBuffer(0, "_Indices", indexBuffer);

            yield return(null);


            // I wanted to use Unity's Random class for this, but the comments said that the random floats were
            // [0.0, 1.0] when what I want is [0.0, 1.0). Using a random function that can generate a 1.0 is bad
            // for our uv coordinate random sampling. That said, casting a double to a float might also give us a
            // 1.0 due to rounding from loss of precission.
            // -FCT
            System.Random r = new System.Random(0);

            s_currentBakeState = BakeState.Bake;
            yield return(null);

            for (int i = 0; i < s_sampleCount; i++)
            {
                s_bakeProgress = i;
                s_computeShader.Dispatch(0,                                                     // We only have the one kernal, so it will have an ID of 0
                                         resolution / 8,                                        // All of our resolution options are divisible by 8, so we don't need to worry about things like
                                         resolution / 8,                                        // adding an extra thread group when you have a (resolution % 8) != 0
                                         1);                                                    // We only need one thread group for 'Z' because having more won't simplify any of our math.
                yield return(null);

                s_computeShader.SetVector(uvOffsetKey, new Vector4(RandomU.value, RandomU.value));
                yield return(null);

                yield return(null);
            }


            s_currentBakeState = BakeState.Finalize;
            yield return(null);

            objectBuffer.Release();
            vertexBuffer.Release();
            indexBuffer.Release();

            yield return(null);



            ///
            /// Code for saving our results into the project and applying them to the light component.
            ///

            // Create a Texture2D to place our results into. This Texture2D will be added to the project's assets
            // and it will be applied to the light source we were raytracing.
            Texture2D finalResults = new Texture2D(resolution, resolution, TextureFormat.RGBAFloat, false, true)
            {
                alphaIsTransparency = true,
                filterMode          = FilterMode.Point,
                wrapMode            = TextureWrapMode.Clamp,
                name = s_currentLightComponent.name + "_ShadowCookie_" + resolution.ToString()
            };

            yield return(null);


            var prevActiveRendTexture = RenderTexture.active;                   // Just in case something was there for some reason.

            RenderTexture.active = renderTexture;
            finalResults.ReadPixels(new Rect(0, 0, resolution, resolution), 0, 0, false);
            finalResults.Apply();

            RenderTexture.active = prevActiveRendTexture;

            yield return(null);


            // Check for the location where we will be saving the Texture2D. If that location doesn't exist, then
            // create it.
            var assetFolderPath = "Assets/Light_Cookies/" + s_currentLightComponent.gameObject.scene.name;

            if (!Directory.Exists(assetFolderPath))
            {
                if (!Directory.Exists("Assets/Light_Cookies"))
                {
                    AssetDatabase.CreateFolder("Assets", "Light_Cookies");
                    yield return(null);
                }
                AssetDatabase.CreateFolder("Assets/Light_Cookies", s_currentLightComponent.gameObject.scene.name);
            }
            yield return(null);


            // Save the Texture2D as a project asset.
            var assetPath = assetFolderPath + "/" + finalResults.name + ".asset";

            AssetDatabase.CreateAsset(finalResults, assetPath);

            yield return(null);

            // Apply the Texture2D to the light as a cooke, then finish cleaning up.
            s_currentLightComponent.cookie = finalResults;
            EditorUtility.SetDirty(s_currentLightComponent.gameObject);
            s_bakingCoroutine = null;                       // The coroutines for MonoBehaviors have the option to manipulate them from the outside, which I have
            // made use of. With a bit of luck, those functions will be added to the EditorCoroutines at some point
            // in time.
            // -FCT
            yield return(null);

            s_currentBakeState = BakeState.SettingSelection;
        }
        private void DrawSettingSelection()
        {
            #region State Checking

            //
            // Making sure we have all the valid inputs needed for drawing User Inputs.
            //

            if (EditorApplication.isPlaying || EditorApplication.isCompiling || EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isUpdating)
            {
                GUILayout.Label("Unity Editor is currently busy.");
                return;
            }

            var activeGameObject = Selection.activeGameObject;

            if (activeGameObject == null)
            {
                GUILayout.Label("Please select a valid light source in the scene.");
                return;
            }

            var selectedLightComponent = activeGameObject.GetComponent <Light>();
            if (selectedLightComponent == null)
            {
                GUILayout.Label("Please select a valid light source in the scene.");
                return;
            }

            switch (selectedLightComponent.type)
            {
            case LightType.Spot:
                break;

            // I'm planning to support Point lights in the future, so I'm separating this from default.
            // -FCT
            case LightType.Point:
            default:
                GUILayout.Label("Please select a valid light source in the scene.");
                return;
            }

            // Check some HDRP relectaed things.
            HDAdditionalLightData additionalLightData = activeGameObject.GetComponent <HDAdditionalLightData>();
            if (additionalLightData == null)
            {
                // Not an light in HDRP (I think).
                GUILayout.Label("Please select a valid light source in the scene.");
                return;
            }
            switch (additionalLightData.lightTypeExtent)
            {
            case LightTypeExtent.Rectangle:
            case LightTypeExtent.Tube:
                GUILayout.Label("Please select a valid light source in the scene.");
                return;
            }

            // I know that at the moment, Spot light is the only light that will make it this far, but I'm planning
            // to have this plugin work with Point lights too. Doing this now, is one less change I'll need to make
            // later on.
            // -FCT
            if (selectedLightComponent.type == LightType.Spot)
            {
                switch (additionalLightData.spotLightShape)
                {
                // So, it turns out that the cookie for Cone and Pyramid are used in the exact same way. The only real
                // difference is that the cone will do less lighting based on the cone shape, but the cookie (which
                // we're creating) is used in the exact same way.
                // -FCT
                case SpotLightShape.Cone:
                case SpotLightShape.Pyramid:
                    break;

                default:
                    GUILayout.Label("Please select a valid light source in the scene.");
                    return;
                }
            }

            #endregion

            CookieBakerEditorWindow.s_currentLightComponent = selectedLightComponent;

            GUIContent guiContent = null;

            EditorGUILayout.LabelField("Object Selection:");
            EditorGUI.indentLevel++;
            ///
            /// Get the range over which we'll be raytracing.
            ///
            EditorGUILayout.BeginHorizontal();
            guiContent = new GUIContent("Bake Item Range:", "Only items within the selected range can affect the results of the raytracing.");
            EditorGUILayout.MinMaxSlider(guiContent, ref s_innerRadius, ref s_outerRadius, 0.001f, 1.0f);
            EditorGUILayout.EndHorizontal();
            EditorGUI.indentLevel--;

            EditorGUILayout.Space();

            EditorGUILayout.LabelField("Quality Options:");
            EditorGUI.indentLevel++;

            EditorGUILayout.BeginHorizontal();
            guiContent       = new GUIContent("Max Segment Count:", "This controls the maximum number of times a sample light ray may bounce off of items.");
            s_maxBounceCount = EditorGUILayout.IntSlider(guiContent, s_maxBounceCount, 1, 16);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            guiContent    = new GUIContent("Sample Count:", "This controls the number of samples we take. Higher sample counts lead to better quality and longer bake times.");
            s_sampleCount = EditorGUILayout.IntSlider(guiContent, s_sampleCount, 1, 500);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            guiContent            = new GUIContent("Shadow Focus Distance:", "This is the distance at which we measure if a light sample will add to the cookie-texture.");
            s_shadowFocusDistance = EditorGUILayout.Slider(guiContent, s_shadowFocusDistance, 1.01f, 2000.0f);
            EditorGUILayout.EndHorizontal();

            ///
            /// Get the resolution for the generated cookie.
            ///
            EditorGUILayout.BeginHorizontal();
            guiContent = new GUIContent("Cookie Resolution:");
            var resOptions = s_resolutionOptions.Select(res => { return(new GUIContent(res.ToString())); });
            s_selectedCookieResolution = EditorGUILayout.Popup(guiContent, s_selectedCookieResolution, resOptions.ToArray());
            EditorGUILayout.EndHorizontal();

            EditorGUI.indentLevel--;

            if (GUILayout.Button("Start Baking."))
            {
                s_currentBakeState = BakeState.Prep;
                s_bakingCoroutine  = this.StartCoroutine(CookieBaking());
            }
        }
Example #12
0
        private IEnumerator CookieBaking()
        {
            yield return(null);

            var resolution = s_resolutionOptions[s_selectedCookieResolution];


            // We only want to use GameObjects that are within the outer radius that we have set. So, a quick test
            // to see if something is within the ball park would be to check if their bounding box insersects with
            // a bounding box that contains the outer radius. Once that has been done, we can take a closer look at
            // what's left.
            var meshRenders        = FindObjectsOfType <MeshRenderer>();
            var lightCenter        = s_currentLightComponent.transform.position;
            var lightBoundingBox   = new UnityEngine.Bounds(lightCenter, 2.0f * s_outerRadius * Vector3.one);
            var intersectingBounds = new List <MeshRenderer>();

            foreach (var meshRenderer in meshRenders)
            {
                var otherBounds = meshRenderer.bounds;
                if (otherBounds.Intersects(lightBoundingBox))
                {
                    intersectingBounds.Add(meshRenderer);
                }
            }

            yield return(null);

            // Now, we can limit things a bit more by finding the point within our mesh bounds that is nearset to
            // the light's center. We then check this point to see if it's within the distance of our outer radius.
            var intersectingOuterRadius = new List <MeshRenderer>();

            foreach (var meshRenderer in intersectingBounds)
            {
                var otherBounds         = meshRenderer.bounds;
                var nearsetPointToLight = otherBounds.ClosestPoint(lightCenter);
                if ((nearsetPointToLight - lightCenter).sqrMagnitude <= (s_outerRadius * s_outerRadius))
                {
                    intersectingOuterRadius.Add(meshRenderer);
                }
            }

            yield return(null);

            var processMeshRenderer = intersectingBounds;
            var processMeshFilter   = new List <MeshFilter>();

            // We're reusing the List from intersectingBounds and placing it under a more appropriate name.
            // Basically, we're reusing a piece of memory that's no longer needed instead of allocating a new List
            // with a new array. Also, this array shouldn't need to be resized to something larger because it
            // already a capacity that is greater than or equal to the number of items we will be processing.
            processMeshRenderer.Clear();
            intersectingBounds = null;


            // Also, while we're at it, lets make sure that we are only baking items that are static. After all,
            // what's the point of baking the shadow casting item that might not be there?
            foreach (var meshRender in intersectingOuterRadius)
            {
                var gameObject = meshRender.gameObject;

                // If the gameObject isn't static, than it can be moved. Since we are not updating the cookie at
                // runtime, having a moving object would be bad.
                if (!gameObject.isStatic)
                {
                    continue;
                }

                // The mesh for our object is inside the MeshFilter, so we need that to get the mesh. Also, since we're
                // dealing with static meshes, then we really shouldn't be dealing with any Skinned Mesh Renderers.
                var meshFilter = gameObject.GetComponent <MeshFilter>();
                if (meshFilter == null)
                {
                    continue;
                }

                // If there's no mesh, then what are we even bothering with this?
                if (meshFilter.sharedMesh == null)
                {
                    continue;
                }

                processMeshRenderer.Add(meshRender);
                processMeshFilter.Add(meshFilter);
            }

            yield return(null);


            // Todo: With this design, items that use the same mesh will replicate the mesh verts and triangle index
            //		 arrays. I need to add a way to check if we have already added a mesh and if so, pull up the triangle
            //		 index array information to pass along to the meshRefDatum.
            var meshObjecRefData = new List <MeshObjectData>(processMeshRenderer.Count);
            var indexList        = new List <int>();
            var vertexList       = new List <Vector3>(processMeshRenderer.Count * 50);

            for (int i = 0; i < processMeshRenderer.Count; i++)
            {
                var mesh                = processMeshFilter[i].sharedMesh;
                var meshVerts           = mesh.vertices;
                var meshTriangleIndices = mesh.triangles;

                var meshRefDatum = new MeshObjectData()
                {
                    LocalToWorldMatrix = processMeshRenderer[i].localToWorldMatrix,
                    IndicesOffset      = indexList.Count,                                       // The starting index of the vert-index for this object's mesh.
                    IndicesCount       = meshTriangleIndices.Length,                            // The number of indices used to form all of the mesh triangles.
                    VerticesOffset     = vertexList.Count,
                    Bounds             = new Bounds()
                    {
                        Center = processMeshRenderer[i].bounds.center,
                        Extent = processMeshRenderer[i].bounds.extents
                    }
                };

                meshObjecRefData.Add(meshRefDatum);
                vertexList.AddRange(meshVerts);
                indexList.AddRange(meshTriangleIndices);
            }

            yield return(null);

            ///
            /// Try adding tracing code here.
            ///
            var backgroundWorkerArgs = new BackgroundWorkerArgs()
            {
                Indices    = indexList,
                ObjectData = meshObjecRefData,
                Vertices   = vertexList,

                LightPosition = lightCenter,
                LightForward  = s_currentLightComponent.transform.forward,
                LightUpward   = s_currentLightComponent.transform.up
            };

            yield return(null);

            using (var backgroundWorker = new BackgroundWorker())
            {
                backgroundWorker.DoWork += BackgroundWorker_DoWork;
                backgroundWorker.RunWorkerAsync(backgroundWorkerArgs);

                while (!backgroundWorkerArgs.Complete)
                {
                    yield return(new EditorWaitForSeconds(0.15f));
                }
            }

            s_currentBakeState = BakeState.Finalize;

            yield return(null);


            ///
            /// Code for saving our results into the project and applying them to the light component.
            ///

            // Create a Texture2D to place our results into. This Texture2D will be added to the project's assets
            // and it will be applied to the light source we were raytracing.
            Texture2D finalResults = new Texture2D(resolution, resolution, TextureFormat.RGBAFloat, false, true)
            {
                alphaIsTransparency = true,
                filterMode          = FilterMode.Point,
                wrapMode            = TextureWrapMode.Clamp,
                name = s_currentLightComponent.name + "_ShadowCookie_" + resolution.ToString()
            };

            yield return(null);

            //finalResults.SetPixels(threadArgs.Result);
            yield return(null);


            // Check for the location where we will be saving the Texture2D. If that location doesn't exist, then
            // create it.
            var assetFolderPath = "Assets/Light_Cookies/" + s_currentLightComponent.gameObject.scene.name;

            if (!Directory.Exists(assetFolderPath))
            {
                if (!Directory.Exists("Assets/Light_Cookies"))
                {
                    AssetDatabase.CreateFolder("Assets", "Light_Cookies");
                    yield return(null);
                }
                AssetDatabase.CreateFolder("Assets/Light_Cookies", s_currentLightComponent.gameObject.scene.name);
            }
            yield return(null);


            // Save the Texture2D as a project asset.
            var assetPath = assetFolderPath + "/" + finalResults.name + ".asset";

            AssetDatabase.CreateAsset(finalResults, assetPath);

            yield return(null);

            // Apply the Texture2D to the light as a cooke, then finish cleaning up.
            s_currentLightComponent.cookie = finalResults;
            EditorUtility.SetDirty(s_currentLightComponent.gameObject);
            s_bakingCoroutine = null;                           // The coroutines for MonoBehaviors have the option to manipulate them from the outside, which I have
            // made use of. With a bit of luck, those functions will be added to the EditorCoroutines at some point
            // in time.
            // -FCT
            yield return(null);

            s_currentBakeState = BakeState.SettingSelection;
        }
Example #13
0
    public void ChangeWeather()
    {
#if UNITY_EDITOR
        if (Bake)
        {
            switch (mBakeState)
            {
            case BakeState.BakeStop:
                if (Lightmapping.isRunning != true)
                {
                    mLightColorMemo          = RenderSettings.sun.color;
                    RenderSettings.sun.color = LightColor.gamma;
                    Lightmapping.BakeAsync();
                    mBakeState = BakeState.Baking;
                }
                break;

            case BakeState.Baking:
                if (Lightmapping.isRunning == true)
                {
                    Bake = true;
                }
                else
                {
                    Bake       = false;
                    mBakeState = BakeState.BakeStop;
                    RenderSettings.sun.color = mLightColorMemo;
                }
                break;

            default:
                break;
            }
        }
#endif
        //if (Set == true)
        //GlobalSetting
        {
            if (BRDFTex != null)
            {
                Shader.SetGlobalTexture("_BRDFTex", BRDFTex);
            }
            if (NoiseTex != null)
            {
                Shader.SetGlobalTexture("_NoiseTex", NoiseTex);
            }
            //Shader.SetGlobalFloat("_Shininess", Shininess);

            if (CharaLightModelDiff != null)
            {
                Shader.SetGlobalTexture("_MatCap", CharaLightModelDiff);
            }

            if (CharaLightModel != null)
            {
                Shader.SetGlobalTexture("_LightModel", CharaLightModel);
            }

            /*if (CharaLightModelSpec != null)
             *  Shader.SetGlobalTexture("_MatCapSpec", CharaLightModelSpec);*/
            if (CameraFogStart == false)
            {
                Shader.SetGlobalFloat("_StartY", FogStartY);
            }
            else
            {
                Shader.SetGlobalFloat("_StartY", transform.position.y);
            }
            Shader.SetGlobalFloat("_FogMass", FogMass);
            Shader.SetGlobalFloat("_VFogVariation", VFogVariation1);

            Shader.SetGlobalFloat("_DFogHeight", DFogHeight);
            Shader.SetGlobalFloat("_DFogMass", DFogMass);
            Shader.SetGlobalFloat("_Wetness", Wetness);
            Shader.SetGlobalFloat("_RainForce", RainForce);
            Shader.SetGlobalFloat("_EndY", FogHeight);
#if UNITY_IOS
            Shader.SetGlobalFloat("_FinalSaturation", Saturation);
#else
            Shader.SetGlobalFloat("_FinalSaturation", Saturation);
#endif
            Shader.SetGlobalFloat("_FarFogDistance", FarFogDistance);

            Shader.SetGlobalFloat("_SODarkFresnel", _SODarkFresnel);
            Shader.SetGlobalFloat("_SODarkFresnelFar", _SODarkFresnelFar);
            Shader.SetGlobalFloat("_SODarkFresnelFarForce", _SODarkFresnelFarForce);
            Shader.SetGlobalFloat("_SOLightFresnel", _SOLightFresnel);
            Shader.SetGlobalFloat("_SOLightFresnelFar", _SOLightFresnelFar);
            Shader.SetGlobalFloat("_SOLightFresnelFarForce", _SOLightFresnelFarForce);
            Shader.SetGlobalColor("_FresnelDarkColor", _FresnelDarkColor);
            Shader.SetGlobalColor("_FresnelLightColor", _FresnelLightColor);


            if (Player != null)
            {
                Shader.SetGlobalVector("_PlayerPos", Player.position);
            }
            if (CloudNoiseTex != null)
            {
                Shader.SetGlobalTexture("_CloudNoiseTex", CloudNoiseTex);
            }
        }

        if (IsColorSetter)
        {
            int timePixel = (int)(42.22f * TimeHour);
            if (Setters.Length > FirstIndex && Setters.Length > SecondIndex)
            {
                mCloudyColor = Color.Lerp(Color.white, LerpColor(timePixel, 362), RainForce * 1.667f);

                mTmpColor = LerpColor(timePixel, 533);
                Shader.SetGlobalColor("_LightColorC", mTmpColor * mCloudyColor);
                mTmpColor = LerpColor(timePixel, 576);
                Shader.SetGlobalColor("_ShadowColor", mTmpColor * mCloudyColor);

                mTmpColor = LerpColor(timePixel, 619);
                Shader.SetGlobalColor("_DFogColorFar", mTmpColor * mCloudyColor);
                mTmpColor = LerpColor(timePixel, 662);
                Shader.SetGlobalColor("_DFogColorNear", mTmpColor * mCloudyColor);
                mTmpColor = LerpColor(timePixel, 705);
                Shader.SetGlobalColor("_VFogColorLow", mTmpColor * mCloudyColor);
                mTmpColor = LerpColor(timePixel, 748);
                Shader.SetGlobalColor("_VFogColorHigh", mTmpColor * mCloudyColor);

                mTmpColor = LerpColor(timePixel, 791);
                Shader.SetGlobalColor("_CloudColor", mTmpColor * mCloudyColor);

                mTmpColor = LerpColor(timePixel, 834);
                Shader.SetGlobalColor("_BodyColor", mTmpColor * mCloudyColor);
                mTmpColor = LerpColor(timePixel, 877);
                Shader.SetGlobalColor("_ShadowColor1", mTmpColor * mCloudyColor);
                mTmpColor = LerpColor(timePixel, 920);
                Shader.SetGlobalColor("_ShadowColor2", mTmpColor * mCloudyColor);

                if (SkyBoxMat != null)
                {
                    mTmpColor = LerpColor(timePixel, 963);
                    SkyBoxMat.SetColor("_SkyLowColor", mTmpColor * mCloudyColor);
                    mTmpColor = LerpColor(timePixel, 1006);
                    SkyBoxMat.SetColor("_SkyHighColor", mTmpColor * mCloudyColor);
                }
                LerpFloat();
                Shader.SetGlobalFloat("_Rotationbbb", RotationSun);
                Shader.SetGlobalFloat("_RotationeeeX", RotationMoonX);
                Shader.SetGlobalFloat("_RotationeeeY", RotationMoonY);


                mTmpColor = IsUiChara ? UiCharaLight : LerpColor(timePixel, 491) * mCloudyColor;
                Shader.SetGlobalColor("_LightColorMapping", mTmpColor);
                mTmpColor = IsUiChara ? UiCharaDark : LerpColor(timePixel, 448) * mCloudyColor;
                Shader.SetGlobalColor("_DarkColorMapping", mTmpColor);
                mTmpColor = IsUiChara ? UiCharaSkinDark : LerpColor(timePixel, 405) * mCloudyColor;
                Shader.SetGlobalColor("_SkinDarkColorMapping", mTmpColor);


                mTmpColor = LerpColor(timePixel, 362);
                Shader.SetGlobalColor("_GrassColor", mTmpColor * mCloudyColor);

                mTmpColor = LerpColor(timePixel, 319);
                Shader.SetGlobalColor("_SMShadowColor", mTmpColor * mCloudyColor);


                /*Debug Show Color*/

                /*LightColor =  ColorSelectorTex.GetPixel(timePixel, 533);
                 * ShadowColor =  ColorSelectorTex.GetPixel(timePixel, 576);
                 *
                 * FogFar =  ColorSelectorTex.GetPixel(timePixel, 619);
                 * FogNear = ColorSelectorTex.GetPixel(timePixel, 662);
                 * FogLow = ColorSelectorTex.GetPixel(timePixel, 705);
                 * FogHigh = ColorSelectorTex.GetPixel(timePixel, 748);
                 *
                 * CloudShadowColor = ColorSelectorTex.GetPixel(timePixel, 791);
                 *
                 * CloudLight = ColorSelectorTex.GetPixel(timePixel, 834);
                 * CloudDark = ColorSelectorTex.GetPixel(timePixel, 877);
                 * CloudDarkControl = ColorSelectorTex.GetPixel(timePixel, 920);
                 *
                 * if (SkyBoxMat != null)
                 * {
                 *  SkyLowColor = ColorSelectorTex.GetPixel(timePixel, 963);
                 *  SkyHighColor = ColorSelectorTex.GetPixel(timePixel, 1006);
                 * }
                 *
                 * //Shader.SetGlobalColor("_SkyLowColor", ColorSelectorTex.GetPixel(timePixel, 533);
                 * //Shader.SetGlobalColor("_SkyHighColor", ColorSelectorTex.GetPixel(timePixel, 576);
                 *
                 * CharaLight = ColorSelectorTex.GetPixel(timePixel, 491);
                 * CharaDark = ColorSelectorTex.GetPixel(timePixel, 448);
                 * CharaSkinDark = ColorSelectorTex.GetPixel(timePixel, 405);*/

                if (!CameraFogOn)
                {
                    Shader.SetGlobalFloat("_DFogDensity", 0);
                    Shader.SetGlobalFloat("_VFogDensity", 0);
                }
                else
                {
                    DFogDensityValue = LerpList(Setters[FirstIndex].DFogDensityList, Setters[SecondIndex].DFogDensityList);
                    Shader.SetGlobalFloat("_DFogDensity", DFogDensityValue * 0.1f);

                    VFogDensityValue = LerpList(Setters[FirstIndex].VFogDensityList, Setters[SecondIndex].VFogDensityList);
                    Shader.SetGlobalFloat("_VFogDensity", VFogDensityValue * 0.1f);
                }



                LightMapSliderValue = LerpList(Setters[FirstIndex].LightMapSliderList, Setters[SecondIndex].LightMapSliderList);
                Shader.SetGlobalFloat("_HemiSlider", LightMapSliderValue * (1 + Wetness * 0.5f));

                BrightnessValue = LerpList(Setters[FirstIndex].BrightnessList, Setters[SecondIndex].BrightnessList);
                Shader.SetGlobalFloat("_Brightness", BrightnessValue);

                FogShowSkyValue = LerpList(Setters[FirstIndex].FogShowSkyList, Setters[SecondIndex].FogShowSkyList);
                Shader.SetGlobalFloat("_ShowSky", FogShowSkyValue);
            }
        }
        else
        {
            mCloudyColor = Color.Lerp(Color.white, CloudyColor, RainForce * 1.667f);

            Shader.SetGlobalColor("_LightColorC", LightColor * mCloudyColor);
            Shader.SetGlobalColor("_ShadowColor", ShadowColor * mCloudyColor);
            RenderSettings.ambientLight = ShadowColor;

            Shader.SetGlobalFloat("_HemiSlider", LightmapSlider * (1 + Wetness * 0.5f));

            Shader.SetGlobalColor("_DFogColorNear", FogNear * mCloudyColor);
            Shader.SetGlobalColor("_DFogColorFar", FogFar * mCloudyColor);
            Shader.SetGlobalColor("_VFogColorLow", FogLow * mCloudyColor);
            Shader.SetGlobalColor("_VFogColorHigh", FogHigh * mCloudyColor);
            Shader.SetGlobalColor("_SDFogColorFar", SencondFogFar * mCloudyColor);

            if (float.IsNaN(DFogDensity) || DFogDensity < 0)
            {
                DFogDensity = 0;
            }
            if (!CameraFogOn)
            {
                Shader.SetGlobalFloat("_DFogDensity", 0);
                Shader.SetGlobalFloat("_VFogDensity", 0);
                Shader.SetGlobalFloat("_SecondLevelFogForce", 0);
            }
            else
            {
                Shader.SetGlobalFloat("_DFogDensity", DFogDensity * 0.1f);
                Shader.SetGlobalFloat("_VFogDensity", VFogDensity * 0.1f);
                Shader.SetGlobalFloat("_SecondLevelFogDistance", SecondLevelFogDistance);
                Shader.SetGlobalFloat("_SecondLevelFogForce", SecondLevelFogForce);
            }

            Shader.SetGlobalFloat("_CloudShadow", CloudShadow);

            Shader.SetGlobalColor("_BodyColor", CloudLight * mCloudyColor);
            Shader.SetGlobalColor("_RimColor", CloudLight * mCloudyColor);
            Shader.SetGlobalColor("_ShadowColor1", CloudDark * mCloudyColor);
            Shader.SetGlobalColor("_ShadowColor2", CloudDarkControl * mCloudyColor);
            Shader.SetGlobalFloat("_Coverage", CloudCoverage);

            Shader.SetGlobalColor("_LightColorMapping", IsUiChara ? UiCharaLight : (CharaLight * mCloudyColor));
            Shader.SetGlobalColor("_DarkColorMapping", IsUiChara ? UiCharaDark : (CharaDark * mCloudyColor));
            Shader.SetGlobalColor("_SkinDarkColorMapping", IsUiChara ? UiCharaSkinDark : (CharaSkinDark * mCloudyColor));

            Shader.SetGlobalColor("_GrassColor", GrassColor * mCloudyColor);
            Shader.SetGlobalColor("_SMShadowColor", GrassShadowColor * mCloudyColor);
            Shader.SetGlobalColor("_LmMultiply", LmMultiply * mCloudyColor);


            Shader.SetGlobalFloat("_BackLight", CharaBackLight);
            Shader.SetGlobalFloat("_RotDiff", CharaLightRot);
            if (IsUiChara)
            {
                Shader.SetGlobalFloat("_LmShadowForce", 0);
                Shader.SetGlobalFloat("_LmLightForceInShadow", 0);
                Shader.SetGlobalFloat("_LmLightForceInLight", 0);
            }
            else
            {
                Shader.SetGlobalFloat("_LmShadowForce", CharaLmShadowForce);
                Shader.SetGlobalFloat("_LmLightForceInShadow", LmLightForceInShadow);
                Shader.SetGlobalFloat("_LmLightForceInLight", LmLightForceInLight);
            }

            if (SkyBoxMat != null)
            {
                SkyBoxMat.SetColor("_SkyLowColor", SkyLowColor * mCloudyColor);
                SkyBoxMat.SetColor("_SkyHighColor", SkyHighColor * mCloudyColor);
            }

            Shader.SetGlobalFloat("_Rotationbbb", RotationSun);
            Shader.SetGlobalFloat("_RotationeeeX", RotationMoonX);
            Shader.SetGlobalFloat("_RotationeeeY", RotationMoonY);

            Shader.SetGlobalColor("_SkyLowColor", SkyLowColor * mCloudyColor);
            Shader.SetGlobalColor("_SkyHighColor", SkyHighColor * mCloudyColor);
            Shader.SetGlobalFloat("_Brightness", Brightness);
            Shader.SetGlobalFloat("_RtLightOnLm", RealTimeLightOnLightmap);
            Shader.SetGlobalFloat("_LmShadow", ShadowOnLightmap);
            Shader.SetGlobalFloat("_ShowSky", FogShowSky);
        }
    }