Exemplo n.º 1
0
        void Awake()
        {
            if (!VerifyRequirements())
            {
                enabled = false;
                return;
            }

            Instance = this;
            Scale    = Mathf.Clamp(Scale, _minScale, _maxScale);

            OceanBuilder.GenerateMesh(this, _lodDataResolution, _geometryDownSampleFactor, _lodCount);

            if (null == GetComponent <BuildCommandBufferBase>())
            {
                gameObject.AddComponent <BuildCommandBuffer>();
            }

            InitViewpoint();
            InitTimeProvider();

            if (_attachDebugGUI && GetComponent <OceanDebugGUI>() == null)
            {
                gameObject.AddComponent <OceanDebugGUI>();
            }
        }
        /// <summary>
        /// Submit draws to create the Gerstner waves. LODs from 0 to N-2 render the Gerstner waves from their lod. Additionally, any waves
        /// in the biggest lod, or too big for the biggest lod, are rendered into both of the last two LODs N-1 and N-2, as this allows us to
        /// move these waves between LODs without pops when the camera changes heights and the LODs need to change scale.
        /// </summary>
        public void BuildCommandBuffer(int lodIdx, OceanRenderer ocean, CommandBuffer buf)
        {
            var lodCount = ocean.CurrentLodCount;

            // LODs up to but not including the last lod get the normal sets of waves
            if (lodIdx < lodCount - 1 && _drawLOD[lodIdx])
            {
                if (_rasterMesh)
                {
                    buf.DrawMesh(_rasterMesh, Matrix4x4.identity, _materials[lodIdx]);
                }
            }

            // The second-to-last lod will transition content into it from the last lod
            if (lodIdx == lodCount - 2 && _drawLODTransitionWaves)
            {
                buf.DrawMesh(_rasterMesh, Matrix4x4.identity, _materialBigWaveTransition);
            }

            // Last lod gets the big wavelengths
            if (lodIdx == lodCount - 1 && _drawLOD[lodIdx])
            {
                buf.DrawMesh(_rasterMesh, Matrix4x4.identity, _materials[OceanRenderer.Instance.CurrentLodCount - 1]);
            }
        }
Exemplo n.º 3
0
        public override void BuildCommandBuffer(OceanRenderer ocean, CommandBuffer buf)
        {
            base.BuildCommandBuffer(ocean, buf);

            // if there is nothing in the scene tagged up for depth rendering, and we have cleared the RTs, then we can early out
            var drawList = RegisterLodDataInputBase.GetRegistrar(GetType());

            if (drawList.Count == 0 && _targetsClear)
            {
                return;
            }

            for (int lodIdx = OceanRenderer.Instance.CurrentLodCount - 1; lodIdx >= 0; lodIdx--)
            {
                buf.SetRenderTarget(_targets, 0, CubemapFace.Unknown, lodIdx);
                buf.ClearRenderTarget(false, true, Color.black);
                buf.SetGlobalInt(sp_LD_SliceIndex, lodIdx);
                SubmitDraws(lodIdx, buf);
            }

            // targets have now been cleared, we can early out next time around
            if (drawList.Count == 0)
            {
                _targetsClear = true;
            }
        }
Exemplo n.º 4
0
 // 変更
 public void SetOcean(int num, OceanRenderer ocean)
 {
     // 最初
     Debug.Log("最初");
     oceans[num] = ocean;
     Debug.Log("num:" + num);
 }
Exemplo n.º 5
0
        void Start()
        {
            _instance = this;

            _oceanBuilder = FindObjectOfType <OceanBuilder>();
            _oceanBuilder.GenerateMesh(MakeBuildParams());
        }
Exemplo n.º 6
0
        void Awake()
        {
            if (!VerifyRequirements())
            {
                enabled = false;
                return;
            }

#if UNITY_EDITOR
            if (_verifySRPVersionInEditor)
            {
                // Fire off a request to get the URP version, as early versions are not compatible
                _request = Client.List(true, false);
            }
#endif

            Instance = this;
            Scale    = Mathf.Clamp(Scale, _minScale, _maxScale);

            OceanBuilder.GenerateMesh(this, _lodDataResolution, _geometryDownSampleFactor, _lodCount);

            if (null == GetComponent <BuildCommandBufferBase>())
            {
                gameObject.AddComponent <BuildCommandBuffer>();
            }

            InitViewpoint();
            InitTimeProvider();

            if (_attachDebugGUI && GetComponent <OceanDebugGUI>() == null)
            {
                gameObject.AddComponent <OceanDebugGUI>();
            }
        }
Exemplo n.º 7
0
        public bool Validate(OceanRenderer ocean)
        {
            if (_type == OceanDepthCacheType.Baked)
            {
                if (_savedCache == null)
                {
                    Debug.LogError("Validation: Depth cache type is 'Saved Cache' but no saved cache data is provided. Click this message to highlight the cache in question.", this);
                }
            }
            else
            {
                if ((_layerNames == null || _layerNames.Length == 0))
                {
                    Debug.LogError("Validation: No layers specified for rendering into depth cache, and no geometries manually provided. Click this message to highlight the cache in question.", this);
                }

                if (_forceAlwaysUpdateDebug)
                {
                    Debug.LogWarning("Validation: Force Always Update Debug option is enabled on depth cache " + gameObject.name + ", which means it will render every frame instead of running from the cache. Click this message to highlight the cache in question.", this);
                }

                foreach (var layerName in _layerNames)
                {
                    var layer = LayerMask.NameToLayer(layerName);
                    if (layer == -1)
                    {
                        Debug.LogError("Invalid layer specified for objects/geometry providing the ocean depth: \"" + layerName +
                                       "\". Does this layer need to be added to the project (Edit/Project Settings/Tags and Layers)? Click this message to highlight the cache in question.", this);
                    }
                }

                if (_resolution < 4)
                {
                    Debug.LogError("Cache resolution " + _resolution + " is very low. Is this intentional? Click this message to highlight the cache in question.", this);
                }

                // We used to test if nothing is present that would render into the cache, but these could probably come from other scenes, and AssignLayer means
                // objects can be tagged up at run-time.
            }

            if (transform.lossyScale.magnitude < 5f)
            {
                Debug.LogWarning("Validation: Ocean depth cache transform scale is small and will capture a small area of the world. The scale sets the size of the area that will be cached, and this cache is set to render a very small area. Click this message to highlight the cache in question.", this);
            }

            if (Mathf.Abs(transform.position.y - ocean.transform.position.y) > 0.00001f)
            {
                Debug.LogWarning("Validation: It is recommended that the cache is placed at the same height (y component of position) as the ocean, i.e. at the sea level. If the cache is created before the ocean is present, the cache height will inform the sea level. Click this message to highlight the cache in question.", this);
            }

            var rend = GetComponentInChildren <Renderer>();

            if (rend != null)
            {
                Debug.LogWarning("Validation: It is not expected that a depth cache object has a renderer component in its hierarchy. The cache is typically attached to an empty GameObject. Please refer to the example content.", rend);
            }

            return(true);
        }
        public override void BuildCommandBuffer(OceanRenderer ocean, CommandBuffer buf)
        {
            base.BuildCommandBuffer(ocean, buf);

            var lodCount = ocean.CurrentLodCount;

            float substepDt;
            int   numSubsteps;

            GetSimSubstepData(ocean.DeltaTime, out numSubsteps, out substepDt);

            for (int stepi = 0; stepi < numSubsteps; stepi++)
            {
                Swap(ref _sources, ref _targets);

                _renderSimProperties.Initialise(buf, _shader, krnl_ShaderSim);

                _renderSimProperties.SetFloat(sp_SimDeltaTime, substepDt);
                _renderSimProperties.SetFloat(sp_SimDeltaTimePrev, _substepDtPrevious);

                // compute which lod data we are sampling source data from. if a scale change has happened this can be any lod up or down the chain.
                // this is only valid on the first update step, after that the scale src/target data are in the right places.
                var srcDataIdxChange = ((stepi == 0) ? ScaleDifferencePow2 : 0);

                // only take transform from previous frame on first substep
                var usePreviousFrameTransform = stepi == 0;

                // bind data to slot 0 - previous frame data
                ValidateSourceData(usePreviousFrameTransform);
                BindSourceData(_renderSimProperties, false, usePreviousFrameTransform, true);

                SetAdditionalSimParams(_renderSimProperties);

                buf.SetGlobalFloat(sp_LODChange, srcDataIdxChange);

                _renderSimProperties.SetTexture(
                    sp_LD_TexArray_Target,
                    DataTexture
                    );

                _renderSimProperties.DispatchShaderMultiLOD();

                for (var lodIdx = lodCount - 1; lodIdx >= 0; lodIdx--)
                {
                    buf.SetRenderTarget(_targets, _targets.depthBuffer, 0, CubemapFace.Unknown, lodIdx);
                    SubmitDraws(lodIdx, buf);
                }

                _substepDtPrevious = substepDt;
            }

            // any post-sim steps. the dyn waves updates the copy sim material, which the anim wave will later use to copy in
            // the dyn waves results.
            for (var lodIdx = lodCount - 1; lodIdx >= 0; lodIdx--)
            {
                BuildCommandBufferInternal(lodIdx);
            }
        }
Exemplo n.º 9
0
        public static Transform GenerateMesh(OceanRenderer ocean, List <OceanChunkRenderer> tiles, int lodDataResolution, int geoDownSampleFactor, int lodCount)
        {
            if (lodCount < 1)
            {
                Debug.LogError("Invalid LOD count: " + lodCount.ToString(), ocean);
                return(null);
            }

            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

            ClearOutTiles(ocean, tiles);

            var root = new GameObject("Root");
            Debug.Assert(root != null, "The ocean Root transform could not be immediately constructed. Please report this issue to the Crest developers via our support email or GitHub at https://github.com/wave-harmonic/crest/issues .");

            root.hideFlags               = ocean._hideOceanTileGameObjects ? HideFlags.HideAndDontSave : HideFlags.DontSave;
            root.transform.parent        = ocean.transform;
            root.transform.localPosition = Vector3.zero;
            root.transform.localRotation = Quaternion.identity;
            root.transform.localScale    = Vector3.one;

            if (!OceanRenderer.RunningHeadless && !OceanRenderer.RunningWithoutGPU)
            {
                // create mesh data
                Mesh[]   meshInsts  = new Mesh[(int)PatchType.Count];
                Bounds[] meshBounds = new Bounds[(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, out meshBounds[i]);
                }

                for (int i = 0; i < lodCount; i++)
                {
                    CreateLOD(ocean, tiles, root.transform, i, lodCount, meshInsts, meshBounds, 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

            return(root.transform);
        }
        public override void BuildCommandBuffer(OceanRenderer ocean, CommandBuffer buf)
        {
            base.BuildCommandBuffer(ocean, buf);

            var lodCount  = OceanRenderer.Instance.CurrentLodCount;
            var steps     = GetNumSubsteps(Time.deltaTime);
            var substepDt = Time.deltaTime / steps;

            for (int stepi = 0; stepi < steps; stepi++)
            {
                for (var lodIdx = lodCount - 1; lodIdx >= 0; lodIdx--)
                {
                    SwapRTs(ref _sources[lodIdx], ref _targets[lodIdx]);
                }

                for (var lodIdx = lodCount - 1; lodIdx >= 0; lodIdx--)
                {
                    _renderSimMaterial[stepi, lodIdx].SetFloat("_SimDeltaTime", substepDt);
                    _renderSimMaterial[stepi, lodIdx].SetFloat("_SimDeltaTimePrev", _substepDtPrevious);

                    _renderSimMaterial[stepi, lodIdx].SetFloat("_GridSize", OceanRenderer.Instance._lods[lodIdx]._renderData._texelWidth);

                    // compute which lod data we are sampling source data from. if a scale change has happened this can be any lod up or down the chain.
                    // this is only valid on the first update step, after that the scale src/target data are in the right places.
                    var srcDataIdx = lodIdx + ((stepi == 0) ? ScaleDifferencePow2 : 0);

                    // only take transform from previous frame on first substep
                    var usePreviousFrameTransform = stepi == 0;

                    if (srcDataIdx >= 0 && srcDataIdx < lodCount)
                    {
                        // bind data to slot 0 - previous frame data
                        BindSourceData(srcDataIdx, 0, _renderSimMaterial[stepi, lodIdx], false, usePreviousFrameTransform);
                    }
                    else
                    {
                        // no source data - bind params only
                        BindSourceData(lodIdx, 0, _renderSimMaterial[stepi, lodIdx], true, usePreviousFrameTransform);
                    }

                    SetAdditionalSimParams(lodIdx, _renderSimMaterial[stepi, lodIdx]);

                    buf.Blit(null, DataTexture(lodIdx), _renderSimMaterial[stepi, lodIdx]);

                    SubmitDraws(lodIdx, buf);
                }

                _substepDtPrevious = substepDt;
            }

            // any post-sim steps. the dyn waves updates the copy sim material, which the anim wave will later use to copy in
            // the dyn waves results.
            for (var lodIdx = lodCount - 1; lodIdx >= 0; lodIdx--)
            {
                BuildCommandBufferInternal(lodIdx);
            }
        }
Exemplo n.º 11
0
        void Start()
        {
            _instance = this;

            _oceanBuilder = GetComponent <OceanBuilder>();
            _oceanBuilder.GenerateMesh(MakeBuildParams());

            SetSmoothLODsShaderParam();
        }
Exemplo n.º 12
0
        public IFlowProvider CreateFlowProvider(OceanRenderer ocean)
        {
            // Flow is GPU only, and can only be queried using the compute path
            if (ocean._lodDataFlow != null)
            {
                return(new QueryFlow());
            }

            return(new FlowProviderNull());
        }
Exemplo n.º 13
0
        public void Validate(OceanRenderer ocean)
        {
            if ((_geometryToRenderIntoCache == null || _geometryToRenderIntoCache.Length == 0) &&
                (_layerNames == null || _layerNames.Length == 0))
            {
                Debug.LogError("Validation: No layers specified for rendering into depth cache, and no geometries manually provided. Click this message to highlight the cache in question.", this);
            }

            if (transform.lossyScale.magnitude < 5f)
            {
                Debug.LogWarning("Validation: Ocean depth cache transform scale is small and will capture a small area of the world. The scale sets the size of the area that will be cached, and this cache is set to render a very small area. Click this message to highlight the cache in question.", this);
            }

            if (_forceAlwaysUpdateDebug)
            {
                Debug.LogWarning("Validation: Force Always Update Debug option is enabled on depth cache " + gameObject.name + ", which means it will render every frame instead of running from the cache. Click this message to highlight the cache in question.", this);
            }

            if (Mathf.Abs(transform.position.y - ocean.transform.position.y) > 0.00001f)
            {
                Debug.LogWarning("Validation: It is recommended that the cache is placed at the same height (y component of position) as the ocean, i.e. at the sea level. If the cache is created before the ocean is present, the cache height will inform the sea level. Click this message to highlight the cache in question.", this);
            }

            var numObjectsFound = 0;

            foreach (var layerName in _layerNames)
            {
                var layer = LayerMask.NameToLayer(layerName);
                if (layer == -1)
                {
                    Debug.LogError("Invalid layer specified: \"" + layerName +
                                   "\". Please specify valid layers for objects/geometry that provide the ocean depth. Click this message to highlight the cache in question.", this);
                }

                var renderers = FindObjectsOfType <MeshRenderer>();
                foreach (var renderer in renderers)
                {
                    if (renderer.gameObject.layer == layer)
                    {
                        numObjectsFound++;
                    }
                }
            }

            if (numObjectsFound == 0 && _geometryToRenderIntoCache.Length == 0)
            {
                Debug.LogWarning("No objects will render into depth cache as there are no geometries specified, and no objects match the layer names. Click this message to highlight the cache in question.", this);
            }

            if (_resolution < 4)
            {
                Debug.LogError("Cache resolution " + _resolution + " is very low. Is this intentional? Click this message to highlight the cache in question.", this);
            }
        }
Exemplo n.º 14
0
        public override void BuildCommandBuffer(OceanRenderer ocean, CommandBuffer buf)
        {
            base.BuildCommandBuffer(ocean, buf);

            // if there is nothing in the scene tagged up for depth rendering, and we have cleared the RTs, then we can early out
            var drawList = RegisterLodDataInputBase.GetRegistrar(GetType());

            if (drawList.Count == 0 && _targetsClear)
            {
                return;
            }

            if (UseGeometryShader)
            {
                buf.SetRenderTarget(_targets, 0, CubemapFace.Unknown, -1);
                buf.ClearRenderTarget(false, true, Color.white * 1000f);

                Matrix4x4[] matrixArray = new Matrix4x4[MAX_LOD_COUNT];

                var lt = OceanRenderer.Instance._lodTransform;
                for (int lodIdx = OceanRenderer.Instance.CurrentLodCount - 1; lodIdx >= 0; lodIdx--)
                {
                    lt._renderData[lodIdx].Validate(0, this);
                    Matrix4x4 platformProjectionMatrix = GL.GetGPUProjectionMatrix(lt.GetProjectionMatrix(lodIdx), true);
                    Matrix4x4 worldToClipPos           = platformProjectionMatrix * lt.GetWorldToCameraMatrix(lodIdx);
                    matrixArray[lodIdx] = worldToClipPos;
                }

                buf.SetGlobalMatrixArray(sp_SliceViewProjMatrices, matrixArray);
                buf.SetGlobalInt(sp_CurrentLodCount, OceanRenderer.Instance.CurrentLodCount);

                foreach (var draw in drawList)
                {
                    draw.Draw(buf, 1f, 0);
                }
            }
            else
            {
                for (int lodIdx = OceanRenderer.Instance.CurrentLodCount - 1; lodIdx >= 0; lodIdx--)
                {
                    buf.SetRenderTarget(_targets, 0, CubemapFace.Unknown, lodIdx);
                    buf.ClearRenderTarget(false, true, Color.white * 1000f);
                    buf.SetGlobalFloat(OceanRenderer.sp_LD_SliceIndex, lodIdx);
                    SubmitDraws(lodIdx, buf);
                }
            }

            // targets have now been cleared, we can early out next time around
            if (drawList.Count == 0)
            {
                _targetsClear = true;
            }
        }
        void Start()
        {
            _instance = this;

            _oceanBuilder = FindObjectOfType <OceanBuilder>();
            _oceanBuilder.GenerateMesh(_baseVertDensity, _lodCount);

            if (_viewpoint == null)
            {
                _viewpoint = Camera.main.transform;
            }
        }
Exemplo n.º 16
0
        public override void BuildCommandBuffer(OceanRenderer ocean, CommandBuffer buf)
        {
            base.BuildCommandBuffer(ocean, buf);

            Shader.SetGlobalFloat(sp_AttenuationInShallows, Settings.AttenuationInShallows);

            var lodCount = OceanRenderer.Instance.CurrentLodCount;

            // Validation
            for (int lodIdx = 0; lodIdx < OceanRenderer.Instance.CurrentLodCount; lodIdx++)
            {
                OceanRenderer.Instance._lodTransform._renderData[lodIdx].Validate(0, SimName);
            }

            foreach (var gerstner in _gerstners)
            {
                gerstner.CrestUpdate(buf);
            }

            // lod-dependent data
            _filterWavelength._lodCount = lodCount;
            for (int lodIdx = lodCount - 1; lodIdx >= 0; lodIdx--)
            {
                buf.SetRenderTarget(_waveBuffers, 0, CubemapFace.Unknown, lodIdx);
                buf.ClearRenderTarget(false, true, new Color(0f, 0f, 0f, 0f));

                // draw any data with lod preference
                _filterWavelength._lodIdx              = lodIdx;
                _filterWavelength._lodMaxWavelength    = OceanRenderer.Instance._lodTransform.MaxWavelength(lodIdx);
                _filterWavelength._lodMinWavelength    = _filterWavelength._lodMaxWavelength / 2f;
                _filterWavelength._globalMaxWavelength = OceanRenderer.Instance._lodTransform.MaxWavelength(OceanRenderer.Instance.CurrentLodCount - 1);
                SubmitDrawsFiltered(lodIdx, buf, _filterWavelength);
            }

            // Combine the LODs - copy results from biggest LOD down to LOD 0
            if (_shapeCombinePassPingPong)
            {
                CombinePassPingPong(buf);
            }
            else
            {
                CombinePassCompute(buf);
            }

            // lod-independent data
            for (int lodIdx = lodCount - 1; lodIdx >= 0; lodIdx--)
            {
                buf.SetRenderTarget(_targets, 0, CubemapFace.Unknown, lodIdx);

                // draw any data that did not express a preference for one lod or another
                SubmitDrawsFiltered(lodIdx, buf, _filterNoLodPreference);
            }
        }
Exemplo n.º 17
0
        public virtual void ApplySchedule(OceanRenderer ocean)
        {
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Flow camera renders first
            for (int i = 0; i < ocean.CurrentLodCount && ocean._camsFlow[i] != null; i++)
            {
                ocean._camsFlow[i].depth = -50 - i;
            }

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Dynamic waves camera renders second
            for (int i = 0; i < ocean.CurrentLodCount && ocean._camsDynWaves[i] != null; i++)
            {
                ocean._camsDynWaves[i].depth = -40 - i;
            }


            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Animated waves next
            for (int i = 0; i < ocean.CurrentLodCount; i++)
            {
                ocean._camsAnimWaves[i].depth = -30 - i;

                /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                // --- Copy dynamic waves into animated waves (convert to displacements in the process)
                if (ocean._camsDynWaves[i] != null)
                {
                    ocean._camsDynWaves[i].GetComponent <LodDataDynamicWaves>().HookCombinePass(ocean._camsAnimWaves[i], CameraEvent.AfterForwardAlpha);
                }
            }


            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Do combine passes to carry long wavelengths/low detail up the chain into the high detail lods
            ocean._lodDataAnimWaves[0].HookCombinePass(ocean._camsAnimWaves[0], CameraEvent.AfterEverything);


            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Foam takes the final combined waves as input and generates foam
            for (int i = 0; i < ocean.CurrentLodCount && ocean._camsFoam[i] != null; i++)
            {
                ocean._camsFoam[i].depth = -20 - i;
            }


            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- User cameras render the ocean surface at depth ~0 - above data should be ready to go!


            // warn if main camera scheduled early
            CheckMainCameraDepth();
        }
Exemplo n.º 18
0
        public static Transform GenerateMesh(OceanRenderer ocean, int lodDataResolution, int geoDownSampleFactor, int lodCount)
        {
            if (lodCount < 1)
            {
                Debug.LogError("Invalid LOD count: " + lodCount.ToString(), ocean);
                return(null);
            }

            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);
            }

            ClearOutTiles(ocean);

            var root = new GameObject("Root");
            root.hideFlags               = ocean._hideOceanTileGameObjects ? HideFlags.HideAndDontSave : HideFlags.DontSave;
            root.transform.parent        = ocean.transform;
            root.transform.localPosition = Vector3.zero;
            root.transform.localRotation = Quaternion.identity;
            root.transform.localScale    = Vector3.one;

            for (int i = 0; i < lodCount; i++)
            {
                CreateLOD(ocean, root.transform, 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

            return(root.transform);
        }
Exemplo n.º 19
0
        private void OnDisable()
        {
#if UNITY_EDITOR
            // We don't run in "prefab scenes", i.e. when editing a prefab. Bail out if prefab scene is detected.
            if (PrefabStageUtility.GetCurrentPrefabStage() != null)
            {
                return;
            }
#endif

            CleanUp();

            Instance = null;
        }
Exemplo n.º 20
0
        public bool Validate(OceanRenderer ocean)
        {
            if (string.IsNullOrEmpty(_layerName))
            {
                Debug.LogError("Validation: Layer name required by AssignLayer script. Click this error to see the script in question.", this);
                return(false);
            }

            if (LayerMask.NameToLayer(_layerName) < 0)
            {
                Debug.LogError("Validation: Layer " + _layerName + " does not exist in the project, please add it.", this);
                return(false);
            }

            return(true);
        }
        // Velocity of the sphere, relative to the water. Computes on the fly, discards if teleport detected.
        Vector3 LateUpdateComputeVelRelativeToWater(OceanRenderer ocean)
        {
            Vector3 vel;

            var rnd = 1f + _noiseAmp * (2f * Mathf.PerlinNoise(_noiseFreq * ocean.CurrentTime, 0.5f) - 1f);

            // feed in water velocity
            vel = (transform.position - _posLast) / ocean.DeltaTimeDynamics;
            if (ocean.DeltaTimeDynamics < 0.0001f)
            {
                vel = Vector3.zero;
            }

            if (QueryFlow.Instance)
            {
                _sampleFlowHelper.Init(transform.position, _object.ObjectWidth);
                Vector2 surfaceFlow = Vector2.zero;
                _sampleFlowHelper.Sample(ref surfaceFlow);
                vel -= new Vector3(surfaceFlow.x, 0, surfaceFlow.y);
            }
            vel.y *= _weightUpDownMul;

            var speedKmh = vel.magnitude * 3.6f;

            if (speedKmh > _teleportSpeed)
            {
                // teleport detected
                vel *= 0f;

                if (_warnOnTeleport)
                {
                    Debug.LogWarning("Teleport detected (speed = " + speedKmh.ToString() + "), velocity discarded.", this);
                }
            }
            else if (speedKmh > _maxSpeed)
            {
                // limit speed to max
                vel *= _maxSpeed / speedKmh;

                if (_warnOnSpeedClamp)
                {
                    Debug.LogWarning("Speed (" + speedKmh.ToString() + ") exceeded max limited, clamped.", this);
                }
            }

            return(vel);
        }
Exemplo n.º 22
0
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            var target = this.target as OceanRenderer;

            if (GUILayout.Button("Rebuild Ocean"))
            {
                target.enabled = false;
                target.enabled = true;
            }

            if (GUILayout.Button("Validate Setup"))
            {
                OceanRenderer.RunValidation(target);
            }
        }
Exemplo n.º 23
0
        void Start()
        {
            _instance = this;

            _oceanBuilder = FindObjectOfType <OceanBuilder>();
            _oceanBuilder.GenerateMesh(_baseVertDensity, _lodCount);

            _collProvider = new CollProviderDispTexs();
            if (_cachedCpuOceanQueries)
            {
                _collProvider = new CollProviderCache(_collProvider);
            }

            if (_viewpoint == null)
            {
                _viewpoint = Camera.main.transform;
            }
        }
Exemplo n.º 24
0
        void BuildLodData(OceanRenderer ocean, CommandBuffer buf)
        {
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Ocean depths
            if (ocean._lodDataSeaDepths != null && ocean._lodDataSeaDepths.enabled)
            {
                ocean._lodDataSeaDepths.BuildCommandBuffer(ocean, buf);
            }

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Flow data
            if (ocean._lodDataFlow != null && ocean._lodDataFlow.enabled)
            {
                ocean._lodDataFlow.BuildCommandBuffer(ocean, buf);
            }

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Dynamic wave simulations
            if (ocean._lodDataDynWaves != null && ocean._lodDataDynWaves.enabled)
            {
                ocean._lodDataDynWaves.BuildCommandBuffer(ocean, buf);
            }

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Animated waves next
            if (ocean._lodDataAnimWaves != null && ocean._lodDataAnimWaves.enabled)
            {
                ocean._lodDataAnimWaves.BuildCommandBuffer(ocean, buf);
            }

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Foam simulation
            if (ocean._lodDataFoam != null && ocean._lodDataFoam.enabled)
            {
                ocean._lodDataFoam.BuildCommandBuffer(ocean, buf);
            }

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Clip surface
            if (ocean._lodDataClipSurface != null && ocean._lodDataClipSurface.enabled)
            {
                ocean._lodDataClipSurface.BuildCommandBuffer(ocean, buf);
            }
        }
Exemplo n.º 25
0
        public static void ClearOutTiles(OceanRenderer ocean)
        {
            if (ocean.Root == null)
            {
                return;
            }

            // Remove existing LODs
            for (int i = 0; i < ocean.Root.childCount; i++)
            {
                var child = ocean.Root.GetChild(i);
                if (child.name.StartsWith("Tile_L"))
                {
                    DestroyGO(child);

                    i--;
                }
            }

            DestroyGO(ocean.Root);
        }
Exemplo n.º 26
0
        void Awake()
        {
            if (!_primaryLight && _searchForPrimaryLightOnStartup)
            {
                _primaryLight = RenderSettings.sun;
            }

            if (!VerifyRequirements())
            {
                enabled = false;
                return;
            }

            Instance = this;
            Scale    = Mathf.Clamp(Scale, _minScale, _maxScale);

            // Resolution is 4 tiles across.
            var baseMeshDensity = _lodDataResolution * 0.25f / _geometryDownSampleFactor;

            // 0.4f is the "best" value when base mesh density is 8. Scaling down from there produces results similar to
            // hand crafted values which looked good when the ocean is flat.
            _lodAlphaBlackPointFade = 0.4f / (baseMeshDensity / 8f);
            // We could calculate this in the shader, but we can save two subtractions this way.
            _lodAlphaBlackPointWhitePointFade = 1f - _lodAlphaBlackPointFade - _lodAlphaBlackPointFade;

            OceanBuilder.GenerateMesh(this, _lodDataResolution, _geometryDownSampleFactor, _lodCount);

            if (null == GetComponent <BuildCommandBufferBase>())
            {
                gameObject.AddComponent <BuildCommandBuffer>();
            }

            InitViewpoint();
            InitTimeProvider();

            if (_attachDebugGUI && GetComponent <OceanDebugGUI>() == null)
            {
                gameObject.AddComponent <OceanDebugGUI>();
            }
        }
Exemplo n.º 27
0
        void Build(OceanRenderer ocean, CommandBuffer buf)
        {
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Ocean depths
            if (ocean._lodDataSeaDepths)
            {
                ocean._lodDataSeaDepths.BuildCommandBuffer(ocean, buf);
            }

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Flow data
            if (ocean._lodDataFlow)
            {
                ocean._lodDataFlow.BuildCommandBuffer(ocean, buf);
            }

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Dynamic wave simulations
            if (ocean._lodDataDynWaves)
            {
                ocean._lodDataDynWaves.BuildCommandBuffer(ocean, buf);
            }

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Animated waves next
            if (ocean._lodDataAnimWaves)
            {
                ocean._lodDataAnimWaves.BuildCommandBuffer(ocean, buf);
            }

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // --- Foam simulation
            if (ocean._lodDataFoam)
            {
                ocean._lodDataFoam.BuildCommandBuffer(ocean, buf);
            }
        }
        public override void BuildCommandBuffer(OceanRenderer ocean, CommandBuffer buf)
        {
            base.BuildCommandBuffer(ocean, buf);

            // if there is nothing in the scene tagged up for depth rendering, and we have cleared the RTs, then we can early out
            if (_drawList.Count == 0 && _targetsClear)
            {
                return;
            }

            for (int lodIdx = OceanRenderer.Instance.CurrentLodCount - 1; lodIdx >= 0; lodIdx--)
            {
                buf.SetRenderTarget(_targets[lodIdx]);
                buf.ClearRenderTarget(false, true, Color.black);

                SubmitDraws(lodIdx, buf);
            }

            // targets have now been cleared, we can early out next time around
            if (_drawList.Count == 0)
            {
                _targetsClear = true;
            }
        }
Exemplo n.º 29
0
        public override void BuildCommandBuffer(OceanRenderer ocean, CommandBuffer buf)
        {
            base.BuildCommandBuffer(ocean, buf);

            // If there is nothing in the scene tagged up for depth rendering, and we have cleared the RTs, then we can early out
            var drawList = RegisterLodDataInputBase.GetRegistrar(GetType());

            if (drawList.Count == 0 && _targetsClear)
            {
                return;
            }

            for (int lodIdx = OceanRenderer.Instance.CurrentLodCount - 1; lodIdx >= 0; lodIdx--)
            {
                buf.SetRenderTarget(_targets, 0, CubemapFace.Unknown, lodIdx);
                var defaultToClip = OceanRenderer.Instance._defaultClippingState == OceanRenderer.DefaultClippingState.EverythingClipped;
                buf.ClearRenderTarget(false, true, defaultToClip ? Color.white : Color.black);
                buf.SetGlobalInt(sp_LD_SliceIndex, lodIdx);
                SubmitDraws(lodIdx, buf);
            }

            // Targets are only clear if nothing was drawn
            _targetsClear = drawList.Count == 0;
        }
Exemplo n.º 30
0
        static void CreateLOD(OceanRenderer ocean, int lodIndex, int lodCount, Mesh[] meshData, int lodDataResolution, int geoDownSampleFactor, int oceanLayer)
        {
            float horizScale = Mathf.Pow(2f, lodIndex);

            bool isBiggestLOD  = lodIndex == lodCount - 1;
            bool generateSkirt = isBiggestLOD && !ocean._disableSkirt;

            Vector2[]   offsets;
            PatchType[] patchTypes;

            PatchType leadSideType    = generateSkirt ? PatchType.FatXOuter : PatchType.SlimX;
            PatchType trailSideType   = generateSkirt ? PatchType.FatXOuter : PatchType.FatX;
            PatchType leadCornerType  = generateSkirt ? PatchType.FatXZOuter : PatchType.SlimXZ;
            PatchType trailCornerType = generateSkirt ? PatchType.FatXZOuter : PatchType.FatXZ;
            PatchType tlCornerType    = generateSkirt ? PatchType.FatXZOuter : PatchType.SlimXFatZ;
            PatchType brCornerType    = generateSkirt ? PatchType.FatXZOuter : PatchType.FatXSlimZ;

            if (lodIndex != 0)
            {
                // instance indices:
                //    0  1  2  3
                //    4        5
                //    6        7
                //    8  9  10 11
                offsets = new Vector2[] {
                    new Vector2(-1.5f, 1.5f), new Vector2(-0.5f, 1.5f), new Vector2(0.5f, 1.5f), new Vector2(1.5f, 1.5f),
                    new Vector2(-1.5f, 0.5f), new Vector2(1.5f, 0.5f),
                    new Vector2(-1.5f, -0.5f), new Vector2(1.5f, -0.5f),
                    new Vector2(-1.5f, -1.5f), new Vector2(-0.5f, -1.5f), new Vector2(0.5f, -1.5f), new Vector2(1.5f, -1.5f),
                };

                // usually rings have an extra side of verts that point inwards. the outermost ring has both the inward
                // verts and also and additional outwards set of verts that go to the horizon
                patchTypes = new PatchType[] {
                    tlCornerType, leadSideType, leadSideType, leadCornerType,
                    trailSideType, leadSideType,
                    trailSideType, leadSideType,
                    trailCornerType, trailSideType, trailSideType, brCornerType,
                };
            }
            else
            {
                // first LOD has inside bit as well:
                //    0  1  2  3
                //    4  5  6  7
                //    8  9  10 11
                //    12 13 14 15
                offsets = new Vector2[] {
                    new Vector2(-1.5f, 1.5f), new Vector2(-0.5f, 1.5f), new Vector2(0.5f, 1.5f), new Vector2(1.5f, 1.5f),
                    new Vector2(-1.5f, 0.5f), new Vector2(-0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(1.5f, 0.5f),
                    new Vector2(-1.5f, -0.5f), new Vector2(-0.5f, -0.5f), new Vector2(0.5f, -0.5f), new Vector2(1.5f, -0.5f),
                    new Vector2(-1.5f, -1.5f), new Vector2(-0.5f, -1.5f), new Vector2(0.5f, -1.5f), new Vector2(1.5f, -1.5f),
                };


                // all interior - the "side" types have an extra skirt that points inwards - this means that this inner most
                // section doesn't need any skirting. this is good - this is the highest density part of the mesh.
                patchTypes = new PatchType[] {
                    tlCornerType, leadSideType, leadSideType, leadCornerType,
                    trailSideType, PatchType.Interior, PatchType.Interior, leadSideType,
                    trailSideType, PatchType.Interior, PatchType.Interior, leadSideType,
                    trailCornerType, trailSideType, trailSideType, brCornerType,
                };
            }

            // debug toggle to force all patches to be the same. they'll be made with a surrounding skirt to make sure patches
            // overlap
            if (ocean._uniformTiles)
            {
                for (int i = 0; i < patchTypes.Length; i++)
                {
                    patchTypes[i] = PatchType.Fat;
                }
            }

            // create the ocean patches
            for (int i = 0; i < offsets.Length; i++)
            {
                // instantiate and place patch
                var patch = new GameObject(string.Format("Tile_L{0}", lodIndex));
                patch.layer            = oceanLayer;
                patch.transform.parent = ocean.transform;
                Vector2 pos = offsets[i];
                patch.transform.localPosition = horizScale * new Vector3(pos.x, 0f, pos.y);
                // scale only horizontally, otherwise culling bounding box will be scaled up in y
                patch.transform.localScale = new Vector3(horizScale, 1f, horizScale);

                patch.AddComponent <OceanChunkRenderer>().SetInstanceData(lodIndex, lodCount, lodDataResolution, geoDownSampleFactor);
                patch.AddComponent <MeshFilter>().mesh = meshData[(int)patchTypes[i]];

                var mr = patch.AddComponent <MeshRenderer>();

                // Sorting order to stop unity drawing it back to front. make the innermost 4 tiles draw first, followed by
                // the rest of the tiles by LOD index. all this happens before layer 0 - the sorting layer takes priority over the
                // render queue it seems! ( https://cdry.wordpress.com/2017/04/28/unity-render-queues-vs-sorting-layers/ ). This pushes
                // ocean rendering way early, so transparent objects will by default render afterwards, which is typical for water rendering.
                mr.sortingOrder = -lodCount + (patchTypes[i] == PatchType.Interior ? -1 : lodIndex);

                // I don't think one would use light probes for a purely specular water surface? (although diffuse foam shading would benefit)
                mr.lightProbeUsage            = UnityEngine.Rendering.LightProbeUsage.Off;
                mr.shadowCastingMode          = UnityEngine.Rendering.ShadowCastingMode.Off; // arbitrary - could be turned on if desired
                mr.receiveShadows             = false;                                       // this setting is ignored by unity for the transparent ocean shader
                mr.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion;
                mr.material = ocean.OceanMaterial;

                // rotate side patches to point the +x side outwards
                bool rotateXOutwards = patchTypes[i] == PatchType.FatX || patchTypes[i] == PatchType.FatXOuter || patchTypes[i] == PatchType.SlimX || patchTypes[i] == PatchType.SlimXFatZ;
                if (rotateXOutwards)
                {
                    if (Mathf.Abs(pos.y) >= Mathf.Abs(pos.x))
                    {
                        patch.transform.localEulerAngles = -Vector3.up * 90f * Mathf.Sign(pos.y);
                    }
                    else
                    {
                        patch.transform.localEulerAngles = pos.x < 0f ? Vector3.up * 180f : Vector3.zero;
                    }
                }

                // rotate the corner patches so the +x and +z sides point outwards
                bool rotateXZOutwards = patchTypes[i] == PatchType.FatXZ || patchTypes[i] == PatchType.SlimXZ || patchTypes[i] == PatchType.FatXSlimZ || patchTypes[i] == PatchType.FatXZOuter;
                if (rotateXZOutwards)
                {
                    // xz direction before rotation
                    Vector3 from = new Vector3(1f, 0f, 1f).normalized;
                    // target xz direction is outwards vector given by local patch position - assumes this patch is a corner (checked below)
                    Vector3 to = patch.transform.localPosition.normalized;
                    if (Mathf.Abs(patch.transform.localPosition.x) < 0.0001f || Mathf.Abs(Mathf.Abs(patch.transform.localPosition.x) - Mathf.Abs(patch.transform.localPosition.z)) > 0.001f)
                    {
                        Debug.LogWarning("Skipped rotating a patch because it isn't a corner, click here to highlight.", patch);
                        continue;
                    }

                    // Detect 180 degree rotations as it doesn't always rotate around Y
                    if (Vector3.Dot(from, to) < -0.99f)
                    {
                        patch.transform.localEulerAngles = Vector3.up * 180f;
                    }
                    else
                    {
                        patch.transform.localRotation = Quaternion.FromToRotation(from, to);
                    }
                }
            }
        }