Beispiel #1
0
        static void DrawSim <SimType>(LodDataMgr lodData, bool actualSize, ref bool doDraw, ref float offset, float bias = 0f, float scale = 1f) where SimType : LodDataMgr
        {
            if (lodData == null)
            {
                return;
            }

            var type = typeof(SimType);

            if (!s_simNames.ContainsKey(type))
            {
                s_simNames.Add(type, type.Name.Substring(10));
            }

            float togglesBegin = Screen.height - _bottomPanelHeight;
            float b            = 7f;
            float h            = actualSize ? lodData.DataTexture.height : togglesBegin / (float)lodData.DataTexture.volumeDepth;
            float w            = h + b;
            float x            = Screen.width - w * offset + b * (offset - 1f);

            if (doDraw)
            {
                // Background behind slices
                GUI.color = _guiColor;
                GUI.DrawTexture(new Rect(x, 0, offset == 1f ? w : w - b, Screen.height - _bottomPanelHeight), Texture2D.whiteTexture);
                GUI.color = Color.white;

                // Only use Graphics.DrawTexture in EventType.Repaint events if called in OnGUI
                if (Event.current.type.Equals(EventType.Repaint))
                {
                    for (int idx = 0; idx < lodData.DataTexture.volumeDepth; idx++)
                    {
                        float y = idx * h;
                        if (offset == 1f)
                        {
                            w += b;
                        }

                        s_textureArrayMaterials.TryGetValue(lodData.DataTexture, out var material);
                        if (material == null)
                        {
                            material = new Material(Shader.Find("Hidden/Crest/Debug/TextureArray"));
                            s_textureArrayMaterials.Add(lodData.DataTexture, material);
                        }

                        // Render specific slice of 2D texture array
                        material.SetInt("_Depth", idx);
                        material.SetFloat("_Scale", scale);
                        material.SetFloat("_Bias", bias);
                        Graphics.DrawTexture(new Rect(x + b, y + b / 2f, h - b, h - b), lodData.DataTexture, material);
                    }
                }
            }

            doDraw = GUI.Toggle(new Rect(x + b, togglesBegin, w - 2f * b, _bottomPanelHeight), doDraw, s_simNames[type]);

            offset++;
        }
Beispiel #2
0
        static void DrawSims <SimType>(LodDataMgr lodData, bool showByDefault, ref float offset) where SimType : LodDataMgr
        {
            if (lodData == null)
            {
                return;
            }

            var type = typeof(SimType);

            if (!_drawTargets.ContainsKey(type))
            {
                _drawTargets.Add(type, showByDefault);
            }
            if (!_simNames.ContainsKey(type))
            {
                _simNames.Add(type, type.Name.Substring(10));
            }

            float togglesBegin = Screen.height - _bottomPanelHeight;
            float b            = 7f;
            float h            = togglesBegin / (float)lodData.DataTexture.volumeDepth;
            float w            = h + b;
            float x            = Screen.width - w * offset + b * (offset - 1f);

            if (_drawTargets[type])
            {
                GUI.color = _guiColor;
                GUI.DrawTexture(new Rect(x, 0, offset == 1f ? w : w - b, Screen.height - _bottomPanelHeight), Texture2D.whiteTexture);
                GUI.color = Color.white;

                // Only use Graphics.DrawTexture in EventType.Repaint events if called in OnGUI
                if (Event.current.type.Equals(EventType.Repaint))
                {
                    for (int idx = 0; idx < lodData.DataTexture.volumeDepth; idx++)
                    {
                        float y = idx * h;
                        if (offset == 1f)
                        {
                            w += b;
                        }

                        // Render specific slice of 2D texture array
                        textureArrayMaterial.SetInt("_Depth", idx);
                        Graphics.DrawTexture(new Rect(x + b, y + b / 2f, h - b, h - b), lodData.DataTexture, textureArrayMaterial);
                    }
                }
            }


            _drawTargets[type] = GUI.Toggle(new Rect(x + b, togglesBegin, w - 2f * b, _bottomPanelHeight), _drawTargets[type], _simNames[type]);

            offset++;
        }
Beispiel #3
0
        /// <summary>
        /// Called when a compute buffer has been read back from the GPU to the CPU.
        /// </summary>
        void DataArrived(AsyncGPUReadbackRequest req)
        {
            // Can get callbacks after disable, so detect this.
            if (!_queryResults.IsCreated)
            {
                _requests.Clear();
                return;
            }

            // Remove any error requests
            for (int i = _requests.Count - 1; i >= 0; --i)
            {
                if (_requests[i]._request.hasError)
                {
                    _requests.RemoveAt(i);
                    _segmentRegistrarRingBuffer.ReleaseLast();
                }
            }

            // Find the last request that was completed
            var lastDoneIndex = _requests.Count - 1;

            while (lastDoneIndex >= 0 && !_requests[lastDoneIndex]._request.done)
            {
                --lastDoneIndex;
            }

            // If there is a completed request, process it
            if (lastDoneIndex >= 0)
            {
                // Update "last" results
                LodDataMgr.Swap(ref _queryResults, ref _queryResultsLast);
                _queryResultsTimeLast = _queryResultsTime;
                _resultSegmentsLast   = _resultSegments;

                var data = _requests[lastDoneIndex]._request.GetData <Vector3>();
                data.CopyTo(_queryResults);
                _queryResultsTime = _requests[lastDoneIndex]._dataTimestamp;
                _resultSegments   = _requests[lastDoneIndex]._segments;
            }

            // Remove all the requests up to the last completed one
            for (int i = lastDoneIndex; i >= 0; --i)
            {
                _requests.RemoveAt(i);
                _segmentRegistrarRingBuffer.ReleaseLast();
            }
        }
Beispiel #4
0
        public static void GenerateMesh(OceanRenderer ocean, int lodDataResolution, int geoDownSampleFactor, int lodCount)
        {
            if (lodCount < 1)
            {
                Debug.LogError("Invalid LOD count: " + lodCount.ToString(), ocean);
                return;
            }

#if UNITY_EDITOR
            if (!UnityEditor.EditorApplication.isPlaying)
            {
                Debug.LogError("Ocean mesh meant to be (re)generated in play mode", ocean);
                return;
            }
#endif

            int oceanLayer = LayerMask.NameToLayer(ocean.LayerName);
            if (oceanLayer == -1)
            {
                Debug.LogError("Invalid ocean layer: " + ocean.LayerName + " please add this layer.", ocean);
                oceanLayer = 0;
            }

#if PROFILE_CONSTRUCTION
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();
#endif

            // create mesh data
            Mesh[] meshInsts = new Mesh[(int)PatchType.Count];
            // 4 tiles across a LOD, and support lowering density by a factor
            var tileResolution = Mathf.Round(0.25f * lodDataResolution / geoDownSampleFactor);
            for (int i = 0; i < (int)PatchType.Count; i++)
            {
                meshInsts[i] = BuildOceanPatch((PatchType)i, tileResolution);
            }

            ocean._lodTransform = ocean.gameObject.AddComponent <LodTransform>();
            ocean._lodTransform.InitLODData(lodCount);

            // Create the LOD data managers
            ocean._lodDataAnimWaves = LodDataMgr.Create <LodDataMgrAnimWaves, SimSettingsAnimatedWaves>(ocean.gameObject, ref ocean._simSettingsAnimatedWaves);
            if (ocean.CreateDynamicWaveSim)
            {
                ocean._lodDataDynWaves = LodDataMgr.Create <LodDataMgrDynWaves, SimSettingsWave>(ocean.gameObject, ref ocean._simSettingsDynamicWaves);
            }
            if (ocean.CreateFlowSim)
            {
                ocean._lodDataFlow = LodDataMgr.Create <LodDataMgrFlow, SimSettingsFlow>(ocean.gameObject, ref ocean._simSettingsFlow);
            }
            if (ocean.CreateFoamSim)
            {
                ocean._lodDataFoam = LodDataMgr.Create <LodDataMgrFoam, SimSettingsFoam>(ocean.gameObject, ref ocean._simSettingsFoam);
            }
            if (ocean.CreateShadowData)
            {
                ocean._lodDataShadow = LodDataMgr.Create <LodDataMgrShadow, SimSettingsShadow>(ocean.gameObject, ref ocean._simSettingsShadow);
            }
            if (ocean.CreateSeaFloorDepthData)
            {
                ocean._lodDataSeaDepths = ocean.gameObject.AddComponent <LodDataMgrSeaFloorDepth>();
            }
            if (ocean.CreateClipSurfaceData)
            {
                ocean._lodDataClipSurface = ocean.gameObject.AddComponent <LodDataMgrClipSurface>();
            }

            // Add any required GPU readbacks
            {
                var ssaw = ocean._simSettingsAnimatedWaves;
                if (ssaw && ssaw.CollisionSource == SimSettingsAnimatedWaves.CollisionSources.ComputeShaderQueries)
                {
                    ocean.gameObject.AddComponent <QueryDisplacements>();
                }

                if (ocean.CreateFlowSim)
                {
                    ocean.gameObject.AddComponent <QueryFlow>();
                }
            }

            // Remove existing LODs
            for (int i = 0; i < ocean.transform.childCount; i++)
            {
                var child = ocean.transform.GetChild(i);
                if (child.name.StartsWith("Tile_L"))
                {
                    child.parent = null;
                    Object.Destroy(child.gameObject);
                    i--;
                }
            }

            for (int i = 0; i < lodCount; i++)
            {
                CreateLOD(ocean, i, lodCount, meshInsts, lodDataResolution, geoDownSampleFactor, oceanLayer);
            }

#if PROFILE_CONSTRUCTION
            sw.Stop();
            Debug.Log("Finished generating " + lodCount.ToString() + " LODs, time: " + (1000.0 * sw.Elapsed.TotalSeconds).ToString(".000") + "ms");
#endif
        }
Beispiel #5
0
        public static void GenerateMesh(OceanRenderer ocean, int lodDataResolution, int geoDownSampleFactor, int lodCount)
        {
            if (lodCount < 1)
            {
                Debug.LogError("Invalid LOD count: " + lodCount.ToString(), ocean);
                return;
            }

#if UNITY_EDITOR
            if (!UnityEditor.EditorApplication.isPlaying)
            {
                Debug.LogError("Ocean mesh meant to be (re)generated in play mode", ocean);
                return;
            }
#endif

            int oceanLayer = LayerMask.NameToLayer(ocean.LayerName);
            if (oceanLayer == -1)
            {
                Debug.LogError("Invalid ocean layer: " + ocean.LayerName + " please add this layer.", ocean);
                oceanLayer = 0;
            }

#if PROFILE_CONSTRUCTION
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();
#endif

            // create mesh data
            Mesh[] meshInsts = new Mesh[(int)PatchType.Count];
            // 4 tiles across a LOD, and support lowering density by a factor
            var tileResolution = Mathf.Round(0.25f * lodDataResolution / geoDownSampleFactor);
            for (int i = 0; i < (int)PatchType.Count; i++)
            {
                meshInsts[i] = BuildOceanPatch((PatchType)i, tileResolution);
            }

            ocean._lods = new LodTransform[lodCount];

            // Create the LOD data managers
            ocean._lodDataAnimWaves = LodDataMgr.Create <LodDataMgrAnimWaves, SimSettingsAnimatedWaves>(ocean.gameObject, ref ocean._simSettingsAnimatedWaves);
            if (ocean.CreateDynamicWaveSim)
            {
                ocean._lodDataDynWaves = LodDataMgr.Create <LodDataMgrDynWaves, SimSettingsWave>(ocean.gameObject, ref ocean._simSettingsDynamicWaves);
            }
            if (ocean.CreateFlowSim)
            {
                ocean._lodDataFlow = LodDataMgr.Create <LodDataMgrFlow, SimSettingsFlow>(ocean.gameObject, ref ocean._simSettingsFlow);
            }
            if (ocean.CreateFoamSim)
            {
                ocean._lodDataFoam = LodDataMgr.Create <LodDataMgrFoam, SimSettingsFoam>(ocean.gameObject, ref ocean._simSettingsFoam);
            }
            if (ocean.CreateShadowData)
            {
                ocean._lodDataShadow = LodDataMgr.Create <LodDataMgrShadow, SimSettingsShadow>(ocean.gameObject, ref ocean._simSettingsShadow);
            }
            if (ocean.CreateSeaFloorDepthData)
            {
                ocean._lodDataSeaDepths = ocean.gameObject.AddComponent <LodDataMgrSeaFloorDepth>();
            }

            // Add any required GPU readbacks
            {
                var ssaw = ocean._simSettingsAnimatedWaves;
                if (ssaw && ssaw.CollisionSource == SimSettingsAnimatedWaves.CollisionSources.OceanDisplacementTexturesGPU)
                {
                    ocean.gameObject.AddComponent <GPUReadbackDisps>();
                }

                if (ocean.CreateFlowSim)
                {
                    var ssf = ocean._simSettingsFlow;
                    if (ssf && ssf._readbackData)
                    {
                        ocean.gameObject.AddComponent <GPUReadbackFlow>();
                    }
                }
            }

            // Remove existing LODs
            for (int i = 0; i < ocean.transform.childCount; i++)
            {
                var child = ocean.transform.GetChild(i);
                if (child.name.StartsWith("LOD"))
                {
                    child.parent = null;
                    Object.Destroy(child.gameObject);
                    i--;
                }
            }

            int startLevel = 0;
            for (int i = 0; i < lodCount; i++)
            {
                bool       biggestLOD = i == lodCount - 1;
                GameObject nextLod    = CreateLOD(ocean, i, lodCount, biggestLOD, meshInsts, lodDataResolution, geoDownSampleFactor, oceanLayer);
                nextLod.transform.parent = ocean.transform;

                // scale only horizontally, otherwise culling bounding box will be scaled up in y
                float horizScale = Mathf.Pow(2f, (float)(i + startLevel));
                nextLod.transform.localScale = new Vector3(horizScale, 1f, horizScale);
            }

#if PROFILE_CONSTRUCTION
            sw.Stop();
            Debug.Log("Finished generating " + parms._lodCount.ToString() + " LODs, time: " + (1000.0 * sw.Elapsed.TotalSeconds).ToString(".000") + "ms");
#endif
        }
Beispiel #6
0
        public void PopulateCache()
        {
            if (_type == OceanDepthCacheType.Baked)
            {
                return;
            }

            var layerMask  = 0;
            var errorShown = false;

            foreach (var layer in _layerNames)
            {
                if (string.IsNullOrEmpty(layer))
                {
                    Debug.LogError("OceanDepthCache: An empty layer name was provided. Please provide a valid layer name. Click this message to highlight the cache in question.", this);
                    errorShown = true;
                    continue;
                }

                int layerIdx = LayerMask.NameToLayer(layer);
                if (layerIdx == -1)
                {
                    Debug.LogError("OceanDepthCache: Invalid layer specified: \"" + layer +
                                   "\". Please add this layer to the project by putting the name in an empty layer slot in Edit/Project Settings/Tags and Layers. Click this message to highlight the cache in question.", this);

                    errorShown = true;
                }
                else
                {
                    layerMask = layerMask | (1 << layerIdx);
                }
            }

            if (layerMask == 0)
            {
                if (!errorShown)
                {
                    Debug.LogError("No valid layers for populating depth cache, aborting. Click this message to highlight the cache in question.", this);
                }

                return;
            }

#if UNITY_EDITOR
            if (_type == OceanDepthCacheType.Realtime && _checkTerrainDrawInstancedOption)
            {
                // This issue only affects the built-in render pipeline. Issue 158: https://github.com/crest-ocean/crest/issues/158

                var terrains = FindObjectsOfType <Terrain>();
                foreach (var terrain in terrains)
                {
                    var mask = (int)Mathf.Pow(2f, terrain.gameObject.layer);

                    if ((mask & layerMask) == 0)
                    {
                        continue;
                    }

                    if (terrain.drawInstanced)
                    {
                        Debug.LogError($"Terrain {terrain.gameObject.name} has 'Draw Instanced' enabled. This terrain will not populate into the depth cache and therefore will not contribute to shorelines and shallow water. This option must be disabled on the terrain when the depth cache is populated (but can be enabled afterwards).", terrain);
                    }
                }
            }
#endif

            if (_depthCacheTexture == null)
            {
                RenderTextureFormat fmt;
                if (_generateSDF)
                {
                    fmt = RenderTextureFormat.RGHalf;
                }
                else
                {
#if UNITY_EDITOR_WIN
                    fmt = RenderTextureFormat.DefaultHDR;
#else
                    fmt = RenderTextureFormat.RHalf;
#endif
                }

                Debug.Assert(SystemInfo.SupportsRenderTextureFormat(fmt), "The graphics device does not support the render texture format " + fmt.ToString());
                _depthCacheTexture                   = new RenderTexture(_resolution, _resolution, 0);
                _depthCacheTexture.name              = gameObject.name + "_oceanDepth";
                _depthCacheTexture.format            = fmt;
                _depthCacheTexture.useMipMap         = false;
                _depthCacheTexture.anisoLevel        = 0;
                _depthCacheTexture.enableRandomWrite = _generateSDF;
                _depthCacheTexture.Create();
            }

            if (_depthCacheCamera == null)
            {
                _depthCacheCamera = GenerateCacheCamera(
                    layerMask,
                    _generateSDF ? "DepthSdfCam" : "DepthCacheCam",
                    _cameraMaxTerrainHeight,
                    transform,
                    _depthCacheTexture,
                    _hideDepthCacheCam
                    );
            }


            // Make sure this global is set - I found this was necessary to set it here. However this can cause glitchiness in editor
            // as it messes with this global vector, so only do it if not in edit mode
#if UNITY_EDITOR
            if (EditorApplication.isPlaying)
#endif
            {
                // Shader needs sea level to determine water depth
                var centerPoint = Vector3.zero;
                if (OceanRenderer.Instance != null)
                {
                    centerPoint.y = OceanRenderer.Instance.Root.position.y;
                }
                else
                {
                    centerPoint.y = transform.position.y;
                }

                Shader.SetGlobalVector("_OceanCenterPosWorld", centerPoint);
            }

            _depthCacheCamera.RenderWithShader(Shader.Find("Crest/Inputs/Depth/Ocean Depth From Geometry"), null);

            if (_generateSDF)
            {
                RenderTextureFormat fmt = RenderTextureFormat.RGHalf;
                RenderTexture       voronoiPingPongTexture0 = new RenderTexture(_resolution, _resolution, 0);
                voronoiPingPongTexture0.name              = gameObject.name + "_voronoiPingPong0";
                voronoiPingPongTexture0.format            = fmt;
                voronoiPingPongTexture0.useMipMap         = false;
                voronoiPingPongTexture0.anisoLevel        = 0;
                voronoiPingPongTexture0.enableRandomWrite = true;
                voronoiPingPongTexture0.Create();

                RenderTexture voronoiPingPongTexture1 = new RenderTexture(_resolution, _resolution, 0);
                voronoiPingPongTexture1.name              = gameObject.name + "_voronoiPingPong1";
                voronoiPingPongTexture1.format            = fmt;
                voronoiPingPongTexture1.useMipMap         = false;
                voronoiPingPongTexture1.anisoLevel        = 0;
                voronoiPingPongTexture1.enableRandomWrite = true;
                voronoiPingPongTexture1.Create();

                using (CommandBuffer jumpFloodCommandBuffer = new CommandBuffer())
                {
                    var  cameraToWorldMatrix     = _depthCacheCamera.cameraToWorldMatrix;
                    var  projectionMatrix        = _depthCacheCamera.projectionMatrix;
                    var  projectionToWorldMatrix = cameraToWorldMatrix * projectionMatrix.inverse;
                    uint textureDimension        = (uint)voronoiPingPongTexture0.width;
                    {
                        ComputeShader initJumpFloodShader = ComputeShaderHelpers.LoadShader("SdfInitJumpFlood");
                        int           initJumpFloodKernel = initJumpFloodShader.FindKernel("SdfInitJumpFlood");
                        jumpFloodCommandBuffer.SetComputeTextureParam(initJumpFloodShader, initJumpFloodKernel, sp_FromTexture, _depthCacheTexture);
                        jumpFloodCommandBuffer.SetComputeTextureParam(initJumpFloodShader, initJumpFloodKernel, sp_ToTexture, voronoiPingPongTexture0);
                        jumpFloodCommandBuffer.SetComputeIntParam(initJumpFloodShader, sp_textureDimension, (int)textureDimension);
                        jumpFloodCommandBuffer.SetComputeMatrixParam(initJumpFloodShader, sp_projectionToWorld, projectionToWorldMatrix);
                        jumpFloodCommandBuffer.DispatchCompute(
                            initJumpFloodShader,
                            initJumpFloodKernel,
                            _depthCacheTexture.width / 8,
                            _depthCacheTexture.height / 8,
                            1
                            );
                    }
                    ComputeShader jumpFloodShader = ComputeShaderHelpers.LoadShader("SdfJumpFlood");
                    int           jumpFloodKernel = jumpFloodShader.FindKernel("SdfJumpFlood");

                    ComputeShader sdfGradientShader = ComputeShaderHelpers.LoadShader("SdfApply");
                    int           sdfKernel         = sdfGradientShader.FindKernel("SdfApply");


                    jumpFloodCommandBuffer.name = "Jump Flood";
                    for (uint jumpSize = (uint)textureDimension / 2; jumpSize > 0; jumpSize /= 2)
                    {
                        ApplyJumpFlood(
                            jumpFloodCommandBuffer, jumpFloodShader, jumpFloodKernel,
                            sp_jumpSize, jumpSize,
                            sp_textureDimension, textureDimension,
                            sp_projectionToWorld, projectionToWorldMatrix,
                            sp_FromTexture, voronoiPingPongTexture0,
                            sp_ToTexture, voronoiPingPongTexture1
                            );
                        LodDataMgr.Swap(ref voronoiPingPongTexture1, ref voronoiPingPongTexture0);
                    }

                    for (uint roundNum = 0; roundNum < _additionalJumpFloodRounds; roundNum++)
                    {
                        uint jumpSize = (uint)1 << (int)roundNum;
                        ApplyJumpFlood(
                            jumpFloodCommandBuffer, jumpFloodShader, jumpFloodKernel,
                            sp_jumpSize, jumpSize,
                            sp_textureDimension, textureDimension,
                            sp_projectionToWorld, projectionToWorldMatrix,
                            sp_FromTexture, voronoiPingPongTexture0,
                            sp_ToTexture, voronoiPingPongTexture1
                            );
                        LodDataMgr.Swap(ref voronoiPingPongTexture1, ref voronoiPingPongTexture0);
                    }

                    jumpFloodCommandBuffer.SetComputeTextureParam(sdfGradientShader, sdfKernel, sp_FromTexture, voronoiPingPongTexture0);
                    jumpFloodCommandBuffer.SetComputeTextureParam(sdfGradientShader, sdfKernel, sp_ToTexture, _depthCacheTexture);
                    jumpFloodCommandBuffer.SetComputeIntParam(sdfGradientShader, sp_textureDimension, (int)textureDimension);
                    jumpFloodCommandBuffer.SetComputeMatrixParam(sdfGradientShader, sp_projectionToWorld, projectionToWorldMatrix);
                    jumpFloodCommandBuffer.DispatchCompute(
                        sdfGradientShader,
                        sdfKernel,
                        voronoiPingPongTexture0.width / 8,
                        voronoiPingPongTexture0.height / 8,
                        1
                        );
                    Graphics.ExecuteCommandBuffer(jumpFloodCommandBuffer);
                }
                DrawCacheQuad(ref _drawDepthCacheQuad, "SDFCache_", OceanDepthCacheType.Baked, _type == OceanDepthCacheType.Baked ? (Texture)_savedCache : _depthCacheTexture);

                voronoiPingPongTexture0.DiscardContents();
                voronoiPingPongTexture1.DiscardContents();
            }
            else
            {
                DrawCacheQuad(ref _drawDepthCacheQuad, "DepthCache_", _type, _type == OceanDepthCacheType.Baked ? (Texture)_savedCache : _depthCacheTexture);
            }
        }