private void CleanUp() { foreach (var lodData in _lodDatas) { lodData.OnDisable(); } _lodDatas.Clear(); #if UNITY_EDITOR if (!EditorApplication.isPlaying && Root != null) { DestroyImmediate(Root.gameObject); } else #endif if (Root != null) { Destroy(Root.gameObject); } Root = null; _lodTransform = null; _lodDataAnimWaves = null; _lodDataClipSurface = null; _lodDataDynWaves = null; _lodDataFlow = null; _lodDataFoam = null; _lodDataSeaDepths = null; _lodDataShadow = null; }
protected override void SetAdditionalSimParams(IPropertyWrapper simMaterial) { base.SetAdditionalSimParams(simMaterial); simMaterial.SetFloat(sp_Damping, Settings._damping); simMaterial.SetFloat(sp_Gravity, OceanRenderer.Instance.Gravity * Settings._gravityMultiplier); float laplacianKernelAngle = _rotateLaplacian ? Mathf.PI * 2f * Random.value : 0f; simMaterial.SetVector(sp_LaplacianAxisX, new Vector2(Mathf.Cos(laplacianKernelAngle), Mathf.Sin(laplacianKernelAngle))); // assign sea floor depth - to slot 1 current frame data. minor bug here - this depth will actually be from the previous frame, // because the depth is scheduled to render just before the animated waves, and this sim happens before animated waves. if (OceanRenderer.Instance._lodDataSeaDepths != null) { OceanRenderer.Instance._lodDataSeaDepths.BindResultData(simMaterial); } else { LodDataMgrSeaFloorDepth.BindNull(simMaterial); } if (OceanRenderer.Instance._lodDataFlow != null) { OceanRenderer.Instance._lodDataFlow.BindResultData(simMaterial); } else { LodDataMgrFlow.BindNull(simMaterial); } }
protected override void SetAdditionalSimParams(int lodIdx, IPropertyWrapper simMaterial) { base.SetAdditionalSimParams(lodIdx, simMaterial); simMaterial.SetFloat(sp_FoamFadeRate, Settings._foamFadeRate); simMaterial.SetFloat(sp_WaveFoamStrength, Settings._waveFoamStrength); simMaterial.SetFloat(sp_WaveFoamCoverage, Settings._waveFoamCoverage); simMaterial.SetFloat(sp_ShorelineFoamMaxDepth, Settings._shorelineFoamMaxDepth); simMaterial.SetFloat(sp_ShorelineFoamStrength, Settings._shorelineFoamStrength); // assign animated waves - to slot 1 current frame data OceanRenderer.Instance._lodDataAnimWaves.BindResultData(lodIdx, 1, simMaterial); // assign sea floor depth - to slot 1 current frame data if (OceanRenderer.Instance._lodDataSeaDepths) { OceanRenderer.Instance._lodDataSeaDepths.BindResultData(lodIdx, 1, simMaterial); } else { LodDataMgrSeaFloorDepth.BindNull(1, simMaterial); } // assign flow - to slot 1 current frame data if (OceanRenderer.Instance._lodDataFlow) { OceanRenderer.Instance._lodDataFlow.BindResultData(lodIdx, 1, simMaterial); } else { LodDataMgrFlow.BindNull(1, simMaterial); } }
protected override void SetAdditionalSimParams(int lodIdx, Material simMaterial) { base.SetAdditionalSimParams(lodIdx, simMaterial); simMaterial.SetFloat("_Damping", Settings._damping); simMaterial.SetFloat("_Gravity", OceanRenderer.Instance.Gravity); float laplacianKernelAngle = _rotateLaplacian ? Mathf.PI * 2f * Random.value : 0f; simMaterial.SetVector("_LaplacianAxisX", new Vector2(Mathf.Cos(laplacianKernelAngle), Mathf.Sin(laplacianKernelAngle))); // assign sea floor depth - to slot 1 current frame data. minor bug here - this depth will actually be from the previous frame, // because the depth is scheduled to render just before the animated waves, and this sim happens before animated waves. if (OceanRenderer.Instance._createSeaFloorDepthData) { OceanRenderer.Instance._lodDataSeaDepths.BindResultData(lodIdx, 1, simMaterial); } else { LodDataMgrSeaFloorDepth.BindNull(1, simMaterial); } if (OceanRenderer.Instance._createFlowSim) { OceanRenderer.Instance._lodDataFlow.BindResultData(lodIdx, 1, simMaterial); } else { LodDataMgrFlow.BindNull(1, simMaterial); } }
private void LateUpdate() { if (OceanRenderer.Instance == null) { _rend.enabled = false; return; } float heightOffset = OceanRenderer.Instance.ViewerHeightAboveWater; // Disable skirt when camera not close to water. In the first few frames collision may not be avail, in that case no choice // but to assume enabled. In the future this could detect if camera is far enough under water, render a simple quad to avoid // finding the intersection line. _rend.enabled = heightOffset < _maxHeightAboveWater; if (_rend.enabled) { if (_copyParamsEachFrame) { _rend.material.CopyPropertiesFromMaterial(OceanRenderer.Instance.OceanMaterial); } // Assign lod0 shape - trivial but bound every frame because lod transform comes from here if (_mpb == null) { _mpb = new PropertyWrapperMPB(); } _rend.GetPropertyBlock(_mpb.materialPropertyBlock); // Underwater rendering uses displacements for intersecting the waves with the near plane, and ocean depth/shadows for ScatterColour() _mpb.SetInt(LodDataMgr.sp_LD_SliceIndex, 0); OceanRenderer.Instance._lodDataAnimWaves.BindResultData(_mpb); if (OceanRenderer.Instance._lodDataSeaDepths) { OceanRenderer.Instance._lodDataSeaDepths.BindResultData(_mpb); } else { LodDataMgrSeaFloorDepth.BindNull(_mpb); } if (OceanRenderer.Instance._lodDataShadow) { OceanRenderer.Instance._lodDataShadow.BindResultData(_mpb); } else { LodDataMgrShadow.BindNull(_mpb); } _mpb.SetFloat(sp_HeightOffset, heightOffset); _mpb.SetVector(sp_InstanceData, new Vector4(OceanRenderer.Instance.ViewerAltitudeLevelAlpha, 0f, 0f, OceanRenderer.Instance.CurrentLodCount)); _rend.SetPropertyBlock(_mpb.materialPropertyBlock); } }
private void LateUpdate() { #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 if (OceanRenderer.Instance == null || !ShowEffect()) { _rend.enabled = false; return; } // Pass true in last arg for a crap reason - in edit mode LateUpdate can be called very frequently, and the height sampler mistakenly thinks // this is erroneous and complains. _sampleWaterHeight.Init(transform.position, 0f, true); _sampleWaterHeight.Sample(out var waterHeight); float heightOffset = transform.position.y - waterHeight; // Disable skirt when camera not close to water. In the first few frames collision may not be avail, in that case no choice // but to assume enabled. In the future this could detect if camera is far enough under water, render a simple quad to avoid // finding the intersection line. _rend.enabled = heightOffset < _maxHeightAboveWater; if (_rend.enabled) { // Only execute when playing to stop CopyPropertiesFromMaterial from corrupting and breaking the material. if (!isMeniscus && _copyParamsEachFrame) { _rend.material.CopyPropertiesFromMaterial(OceanRenderer.Instance.OceanMaterial); } // Assign lod0 shape - trivial but bound every frame because lod transform comes from here if (_mpb == null) { _mpb = new PropertyWrapperMPB(); } _rend.GetPropertyBlock(_mpb.materialPropertyBlock); // Underwater rendering uses displacements for intersecting the waves with the near plane, and ocean depth/shadows for ScatterColour() _mpb.SetInt(LodDataMgr.sp_LD_SliceIndex, 0); LodDataMgrAnimWaves.Bind(_mpb); LodDataMgrSeaFloorDepth.Bind(_mpb); LodDataMgrShadow.Bind(_mpb); _mpb.SetFloat(sp_HeightOffset, heightOffset); _rend.SetPropertyBlock(_mpb.materialPropertyBlock); } }
protected override void SetAdditionalSimParams(IPropertyWrapper simMaterial) { base.SetAdditionalSimParams(simMaterial); simMaterial.SetFloat(sp_Damping, Settings._damping); simMaterial.SetFloat(sp_Gravity, OceanRenderer.Instance.Gravity * Settings._gravityMultiplier); simMaterial.SetFloat(sp_CourantNumber, Settings._courantNumber); // assign sea floor depth - to slot 1 current frame data. minor bug here - this depth will actually be from the previous frame, // because the depth is scheduled to render just before the animated waves, and this sim happens before animated waves. LodDataMgrSeaFloorDepth.Bind(simMaterial); LodDataMgrFlow.Bind(simMaterial); }
private void LateUpdate() { if (OceanRenderer.Instance == null) { _rend.enabled = false; return; } float heightOffset = OceanRenderer.Instance.ViewerHeightAboveWater; if (_rend.enabled) { //if (_copyParamsEachFrame) //{ // _rend.material.CopyPropertiesFromMaterial(OceanRenderer.Instance.OceanMaterial); //} // Assign lod0 shape - trivial but bound every frame because lod transform comes from here if (_mpb == null) { _mpb = new MaterialPropertyBlock(); } _rend.GetPropertyBlock(_mpb); // Underwater rendering uses displacements for intersecting the waves with the near plane, and ocean depth/shadows for ScatterColour() OceanRenderer.Instance._lodDataAnimWaves.BindResultData(0, 0, _mpb); if (OceanRenderer.Instance._lodDataSeaDepths) { OceanRenderer.Instance._lodDataSeaDepths.BindResultData(0, 0, _mpb); } else { LodDataMgrSeaFloorDepth.BindNull(0, _mpb); } if (OceanRenderer.Instance._lodDataShadow) { OceanRenderer.Instance._lodDataShadow.BindResultData(0, 0, _mpb); } else { LodDataMgrShadow.BindNull(0, _mpb); } _mpb.SetFloat("_HeightOffset", heightOffset); _rend.SetPropertyBlock(_mpb); } }
private void LateUpdate() { float heightOffset = OceanRenderer.Instance.ViewerHeightAboveWater; // Disable skirt when camera not close to water. In the first few frames collision may not be avail, in that case no choice // but to assume enabled. In the future this could detect if camera is far enough under water, render a simple quad to avoid // finding the intersection line. _rend.enabled = heightOffset < _maxHeightAboveWater; if (_rend.enabled) { if (_copyParamsEachFrame) { _rend.material.CopyPropertiesFromMaterial(OceanRenderer.Instance.OceanMaterial); } // Assign lod0 shape - trivial but bound every frame because lod transform comes from here if (_mpb == null) { _mpb = new MaterialPropertyBlock(); } _rend.GetPropertyBlock(_mpb); // Underwater rendering uses displacements for intersecting the waves with the near plane, and ocean depth/shadows for ScatterColour() OceanRenderer.Instance._lodDataAnimWaves.BindResultData(0, 0, _mpb); if (OceanRenderer.Instance._createSeaFloorDepthData) { OceanRenderer.Instance._lodDataSeaDepths.BindResultData(0, 0, _mpb); } else { LodDataMgrSeaFloorDepth.BindNull(0, _mpb); } if (OceanRenderer.Instance._createShadowData) { OceanRenderer.Instance._lodDataShadow.BindResultData(0, 0, _mpb); } else { LodDataMgrShadow.BindNull(0, _mpb); } _mpb.SetFloat("_HeightOffset", heightOffset); _rend.SetPropertyBlock(_mpb); } }
protected override void SetAdditionalSimParams(IPropertyWrapper simMaterial) { base.SetAdditionalSimParams(simMaterial); simMaterial.SetFloat(sp_FoamFadeRate, Settings._foamFadeRate); simMaterial.SetFloat(sp_WaveFoamStrength, Settings._waveFoamStrength); simMaterial.SetFloat(sp_WaveFoamCoverage, Settings._waveFoamCoverage); simMaterial.SetFloat(sp_ShorelineFoamMaxDepth, Settings._shorelineFoamMaxDepth); simMaterial.SetFloat(sp_ShorelineFoamStrength, Settings._shorelineFoamStrength); // assign animated waves - to slot 1 current frame data LodDataMgrAnimWaves.Bind(simMaterial); // assign sea floor depth - to slot 1 current frame data LodDataMgrSeaFloorDepth.Bind(simMaterial); // assign flow - to slot 1 current frame data LodDataMgrFlow.Bind(simMaterial); }
// Called when visible to a camera void OnWillRenderObject() { if (OceanRenderer.Instance == null || Rend == null) { return; } // check if built-in pipeline being used if (Camera.current != null) { _currentCamera = Camera.current; } // Depth texture is used by ocean shader for transparency/depth fog, and for fading out foam at shoreline. _currentCamera.depthTextureMode |= DepthTextureMode.Depth; if (Rend.sharedMaterial != OceanRenderer.Instance.OceanMaterial) { Rend.sharedMaterial = OceanRenderer.Instance.OceanMaterial; } // per instance data if (_mpb == null) { _mpb = new PropertyWrapperMPB(); } Rend.GetPropertyBlock(_mpb.materialPropertyBlock); // blend LOD 0 shape in/out to avoid pop, if the ocean might scale up later (it is smaller than its maximum scale) var needToBlendOutShape = _lodIndex == 0 && OceanRenderer.Instance.ScaleCouldIncrease; var meshScaleLerp = needToBlendOutShape ? OceanRenderer.Instance.ViewerAltitudeLevelAlpha : 0f; // blend furthest normals scale in/out to avoid pop, if scale could reduce var needToBlendOutNormals = _lodIndex == _totalLodCount - 1 && OceanRenderer.Instance.ScaleCouldDecrease; var farNormalsWeight = needToBlendOutNormals ? OceanRenderer.Instance.ViewerAltitudeLevelAlpha : 1f; _mpb.SetVector(sp_InstanceData, new Vector3(meshScaleLerp, farNormalsWeight, _lodIndex)); // geometry data // compute grid size of geometry. take the long way to get there - make sure we land exactly on a power of two // and not inherit any of the lossy-ness from lossyScale. var scale_pow_2 = OceanRenderer.Instance.CalcLodScale(_lodIndex); var gridSizeGeo = scale_pow_2 / (0.25f * _lodDataResolution / _geoDownSampleFactor); var gridSizeLodData = gridSizeGeo / _geoDownSampleFactor; var mul = 1.875f; // fudge 1 var pow = 1.4f; // fudge 2 var normalScrollSpeed0 = Mathf.Pow(Mathf.Log(1f + 2f * gridSizeLodData) * mul, pow); var normalScrollSpeed1 = Mathf.Pow(Mathf.Log(1f + 4f * gridSizeLodData) * mul, pow); _mpb.SetVector(sp_GeomData, new Vector4(gridSizeLodData, gridSizeGeo, normalScrollSpeed0, normalScrollSpeed1)); // Assign LOD data to ocean shader var ldaws = OceanRenderer.Instance._lodDataAnimWaves; var ldsds = OceanRenderer.Instance._lodDataSeaDepths; var ldclip = OceanRenderer.Instance._lodDataClipSurface; var ldfoam = OceanRenderer.Instance._lodDataFoam; var ldflow = OceanRenderer.Instance._lodDataFlow; var ldshadows = OceanRenderer.Instance._lodDataShadow; _mpb.SetInt(LodDataMgr.sp_LD_SliceIndex, _lodIndex); if (ldaws != null) { ldaws.BindResultData(_mpb); } if (ldflow != null) { ldflow.BindResultData(_mpb); } else { LodDataMgrFlow.BindNull(_mpb); } if (ldfoam != null) { ldfoam.BindResultData(_mpb); } else { LodDataMgrFoam.BindNull(_mpb); } if (ldsds != null) { ldsds.BindResultData(_mpb); } else { LodDataMgrSeaFloorDepth.BindNull(_mpb); } if (ldclip != null) { ldclip.BindResultData(_mpb); } else { LodDataMgrClipSurface.BindNull(_mpb); } if (ldshadows != null) { ldshadows.BindResultData(_mpb); } else { LodDataMgrShadow.BindNull(_mpb); } var reflTex = PreparedReflections.GetRenderTexture(_currentCamera.GetHashCode()); if (reflTex) { _mpb.SetTexture(sp_ReflectionTex, reflTex); } else { _mpb.SetTexture(sp_ReflectionTex, Texture2D.blackTexture); } // Hack - due to SV_IsFrontFace occasionally coming through as true for back faces, // add a param here that forces ocean to be in underwater state. I think the root // cause here might be imprecision or numerical issues at ocean tile boundaries, although // i'm not sure why cracks are not visible in this case. var heightOffset = OceanRenderer.Instance.ViewerHeightAboveWater; _mpb.SetFloat(sp_ForceUnderwater, heightOffset < -2f ? 1f : 0f); Rend.SetPropertyBlock(_mpb.materialPropertyBlock); }
/// <summary> /// Computes Gerstner params for a set of waves, for the given lod idx. Writes shader data to the given property. /// Returns number of wave components rendered in this batch. /// </summary> void UpdateBatch(int lodIdx, int firstComponent, int lastComponentNonInc, GerstnerBatch batch) { batch.HasWaves = false; int numComponents = lastComponentNonInc - firstComponent; int numInBatch = 0; int dropped = 0; float twopi = 2f * Mathf.PI; float one_over_2pi = 1f / twopi; // register any nonzero components for (int i = 0; i < numComponents; i++) { float wl = _wavelengths[firstComponent + i]; // compute amp - contains logic for shifting wave components between last two LODs... float amp = _amplitudes[firstComponent + i]; if (amp >= 0.001f) { if (numInBatch < BATCH_SIZE) { int vi = numInBatch / 4; int ei = numInBatch - vi * 4; UpdateBatchScratchData._twoPiOverWavelengthsBatch[vi][ei] = 2f * Mathf.PI / wl; UpdateBatchScratchData._ampsBatch[vi][ei] = amp; float chopScale = _spectrum._chopScales[(firstComponent + i) / _componentsPerOctave]; UpdateBatchScratchData._chopAmpsBatch[vi][ei] = -chopScale * _spectrum._chop * amp; float angle = Mathf.Deg2Rad * (_windDirectionAngle + _angleDegs[firstComponent + i]); UpdateBatchScratchData._waveDirXBatch[vi][ei] = Mathf.Cos(angle); UpdateBatchScratchData._waveDirZBatch[vi][ei] = Mathf.Sin(angle); // It used to be this, but I'm pushing all the stuff that doesn't depend on position into the phase. //half4 angle = k * (C * _CrestTime + x) + _Phases[vi]; float gravityScale = _spectrum._gravityScales[(firstComponent + i) / _componentsPerOctave]; float gravity = OceanRenderer.Instance.Gravity * _spectrum._gravityScale; float C = Mathf.Sqrt(wl * gravity * gravityScale * one_over_2pi); float k = twopi / wl; // Repeat every 2pi to keep angle bounded - helps precision on 16bit platforms UpdateBatchScratchData._phasesBatch[vi][ei] = Mathf.Repeat(_phases[firstComponent + i] + k * C * OceanRenderer.Instance.CurrentTime, Mathf.PI * 2f); numInBatch++; } else { dropped++; } } } if (dropped > 0) { Debug.LogWarning(string.Format("Gerstner LOD{0}: Batch limit reached, dropped {1} wavelengths. To support bigger batch sizes, see the comment around the BATCH_SIZE declaration.", lodIdx, dropped), this); numComponents = BATCH_SIZE; } if (numInBatch == 0) { // no waves to draw - abort return; } // if we did not fill the batch, put a terminator signal after the last position if (numInBatch < BATCH_SIZE) { int vi_last = numInBatch / 4; int ei_last = numInBatch - vi_last * 4; for (int vi = vi_last; vi < BATCH_SIZE / 4; vi++) { for (int ei = ei_last; ei < 4; ei++) { UpdateBatchScratchData._twoPiOverWavelengthsBatch[vi][ei] = 1f; // wary of NaNs UpdateBatchScratchData._ampsBatch[vi][ei] = 0f; UpdateBatchScratchData._waveDirXBatch[vi][ei] = 0f; UpdateBatchScratchData._waveDirZBatch[vi][ei] = 0f; UpdateBatchScratchData._phasesBatch[vi][ei] = 0f; UpdateBatchScratchData._chopAmpsBatch[vi][ei] = 0f; } ei_last = 0; } } // apply the data to the shape property for (int i = 0; i < 2; i++) { var mat = batch.GetMaterial(i); mat.SetVectorArray(sp_TwoPiOverWavelengths, UpdateBatchScratchData._twoPiOverWavelengthsBatch); mat.SetVectorArray(sp_Amplitudes, UpdateBatchScratchData._ampsBatch); mat.SetVectorArray(sp_WaveDirX, UpdateBatchScratchData._waveDirXBatch); mat.SetVectorArray(sp_WaveDirZ, UpdateBatchScratchData._waveDirZBatch); mat.SetVectorArray(sp_Phases, UpdateBatchScratchData._phasesBatch); mat.SetVectorArray(sp_ChopAmps, UpdateBatchScratchData._chopAmpsBatch); mat.SetFloat(sp_NumInBatch, numInBatch); mat.SetFloat(sp_AttenuationInShallows, OceanRenderer.Instance._lodDataAnimWaves.Settings.AttenuationInShallows); int numVecs = (numInBatch + 3) / 4; mat.SetInt(sp_NumWaveVecs, numVecs); mat.SetInt(LodDataMgr.sp_LD_SliceIndex, lodIdx - i); OceanRenderer.Instance._lodDataAnimWaves.BindResultData(mat); if (OceanRenderer.Instance._lodDataSeaDepths != null) { OceanRenderer.Instance._lodDataSeaDepths.BindResultData(mat, false); } else { LodDataMgrSeaFloorDepth.BindNull(mat, false); } if (_directTowardsPoint) { mat.SetVector(sp_TargetPointData, new Vector4(_pointPositionXZ.x, _pointPositionXZ.y, _pointRadii.x, _pointRadii.y)); } } batch.HasWaves = true; }
void CreateDestroySubSystems() { { if (_lodDataAnimWaves == null) { _lodDataAnimWaves = new LodDataMgrAnimWaves(this); _lodDatas.Add(_lodDataAnimWaves); } } if (CreateClipSurfaceData) { if (_lodDataClipSurface == null) { _lodDataClipSurface = new LodDataMgrClipSurface(this); _lodDatas.Add(_lodDataClipSurface); } } else { if (_lodDataClipSurface != null) { _lodDataClipSurface.OnDisable(); _lodDatas.Remove(_lodDataClipSurface); _lodDataClipSurface = null; } } if (CreateDynamicWaveSim) { if (_lodDataDynWaves == null) { _lodDataDynWaves = new LodDataMgrDynWaves(this); _lodDatas.Add(_lodDataDynWaves); } } else { if (_lodDataDynWaves != null) { _lodDataDynWaves.OnDisable(); _lodDatas.Remove(_lodDataDynWaves); _lodDataDynWaves = null; } } if (CreateFlowSim) { if (_lodDataFlow == null) { _lodDataFlow = new LodDataMgrFlow(this); _lodDatas.Add(_lodDataFlow); } if (FlowProvider != null && !(FlowProvider is QueryFlow)) { FlowProvider.CleanUp(); FlowProvider = null; } } else { if (_lodDataFlow != null) { _lodDataFlow.OnDisable(); _lodDatas.Remove(_lodDataFlow); _lodDataFlow = null; } if (FlowProvider != null && FlowProvider is QueryFlow) { FlowProvider.CleanUp(); FlowProvider = null; } } if (FlowProvider == null) { FlowProvider = _lodDataAnimWaves.Settings.CreateFlowProvider(this); } if (CreateFoamSim) { if (_lodDataFoam == null) { _lodDataFoam = new LodDataMgrFoam(this); _lodDatas.Add(_lodDataFoam); } } else { if (_lodDataFoam != null) { _lodDataFoam.OnDisable(); _lodDatas.Remove(_lodDataFoam); _lodDataFoam = null; } } if (CreateSeaFloorDepthData) { if (_lodDataSeaDepths == null) { _lodDataSeaDepths = new LodDataMgrSeaFloorDepth(this); _lodDatas.Add(_lodDataSeaDepths); } } else { if (_lodDataSeaDepths != null) { _lodDataSeaDepths.OnDisable(); _lodDatas.Remove(_lodDataSeaDepths); _lodDataSeaDepths = null; } } if (CreateShadowData) { if (_lodDataShadow == null) { _lodDataShadow = new LodDataMgrShadow(this); _lodDatas.Add(_lodDataShadow); } } else { if (_lodDataShadow != null) { _lodDataShadow.OnDisable(); _lodDatas.Remove(_lodDataShadow); _lodDataShadow = null; } } // Potential extension - add 'type' field to collprovider and change provider if settings have changed - this would support runtime changes. if (CollisionProvider == null) { CollisionProvider = _lodDataAnimWaves.Settings.CreateCollisionProvider(); } }
internal static void UpdatePostProcessMaterial( RenderTexture source, Camera camera, PropertyWrapperMaterial underwaterPostProcessMaterialWrapper, UnderwaterSphericalHarmonicsData sphericalHarmonicsData, bool isMeniscusEnabled, bool copyParamsFromOceanMaterial, bool debugViewPostProcessMask, float horizonSafetyMarginMultiplier, float farPlaneMultiplier, int dataSliceOffset ) { Material underwaterPostProcessMaterial = underwaterPostProcessMaterialWrapper.material; if (copyParamsFromOceanMaterial) { // Measured this at approx 0.05ms on dell laptop underwaterPostProcessMaterial.CopyPropertiesFromMaterial(OceanRenderer.Instance.OceanMaterial); } // Enable/Disable meniscus. if (isMeniscusEnabled) { underwaterPostProcessMaterial.EnableKeyword("CREST_MENISCUS"); } else { underwaterPostProcessMaterial.DisableKeyword("CREST_MENISCUS"); } // Enabling/disabling keywords each frame don't seem to have large measurable overhead if (debugViewPostProcessMask) { underwaterPostProcessMaterial.EnableKeyword(DEBUG_VIEW_OCEAN_MASK); } else { underwaterPostProcessMaterial.DisableKeyword(DEBUG_VIEW_OCEAN_MASK); } underwaterPostProcessMaterial.SetFloat(LodDataMgr.sp_LD_SliceIndex, 0); underwaterPostProcessMaterial.SetVector(sp_InstanceData, new Vector4(OceanRenderer.Instance.ViewerAltitudeLevelAlpha, 0f, 0f, OceanRenderer.Instance.CurrentLodCount)); LodDataMgrAnimWaves.Bind(underwaterPostProcessMaterialWrapper); LodDataMgrSeaFloorDepth.Bind(underwaterPostProcessMaterialWrapper); LodDataMgrShadow.Bind(underwaterPostProcessMaterialWrapper); float seaLevel = OceanRenderer.Instance.SeaLevel; { // We only apply the horizon safety margin multiplier to horizon if and only if // concrete height of the camera relative to the water and the height of the camera // relative to the sea-level are the same. This ensures that in incredibly turbulent // water - if in doubt - use the neutral horizon. float seaLevelHeightDifference = camera.transform.position.y - seaLevel; if (seaLevelHeightDifference >= 0.0f ^ OceanRenderer.Instance.ViewerHeightAboveWater >= 0.0f) { horizonSafetyMarginMultiplier = 0.0f; } } { underwaterPostProcessMaterial.SetFloat(sp_OceanHeight, seaLevel); underwaterPostProcessMaterial.SetInt(sp_DataSliceOffset, dataSliceOffset); float maxOceanVerticalDisplacement = OceanRenderer.Instance.MaxVertDisplacement * 0.5f; float cameraYPosition = camera.transform.position.y; float nearPlaneFrustumWorldHeight; { float current = camera.ViewportToWorldPoint(new Vector3(0f, 0f, camera.nearClipPlane)).y; float maxY = current, minY = current; current = camera.ViewportToWorldPoint(new Vector3(0f, 1f, camera.nearClipPlane)).y; maxY = Mathf.Max(maxY, current); minY = Mathf.Min(minY, current); current = camera.ViewportToWorldPoint(new Vector3(1f, 0f, camera.nearClipPlane)).y; maxY = Mathf.Max(maxY, current); minY = Mathf.Min(minY, current); current = camera.ViewportToWorldPoint(new Vector3(1f, 1f, camera.nearClipPlane)).y; maxY = Mathf.Max(maxY, current); minY = Mathf.Min(minY, current); nearPlaneFrustumWorldHeight = maxY - minY; } // We don't both setting the horizon value if we know we are going to be having to apply the post-processing // effect full-screen anyway. bool forceFullShader = (cameraYPosition + nearPlaneFrustumWorldHeight + maxOceanVerticalDisplacement) <= seaLevel; underwaterPostProcessMaterial.SetFloat(sp_OceanHeight, seaLevel); if (forceFullShader) { underwaterPostProcessMaterial.EnableKeyword(FULL_SCREEN_EFFECT); } else { underwaterPostProcessMaterial.DisableKeyword(FULL_SCREEN_EFFECT); } } // Have to set these explicitly as the built-in transforms aren't in world-space for the blit function if (XRHelpers.IsSinglePass) { XRHelpers.SetViewProjectionMatrices(camera); Matrix4x4 cameraProjectionMatrix = camera.projectionMatrix; camera.projectionMatrix = XRHelpers.LeftEyeProjectionMatrix; var inverseViewProjectionMatrix = (XRHelpers.LeftEyeProjectionMatrix * camera.worldToCameraMatrix).inverse; underwaterPostProcessMaterial.SetMatrix(sp_InvViewProjection, inverseViewProjectionMatrix); { GetHorizonPosNormal(camera, Camera.MonoOrStereoscopicEye.Left, seaLevel, horizonSafetyMarginMultiplier, farPlaneMultiplier, out Vector2 pos, out Vector2 normal); underwaterPostProcessMaterial.SetVector(sp_HorizonPosNormal, new Vector4(pos.x, pos.y, normal.x, normal.y)); } camera.projectionMatrix = XRHelpers.RightEyeProjectionMatrix; var inverseViewProjectionMatrixRightEye = (XRHelpers.RightEyeProjectionMatrix * camera.worldToCameraMatrix).inverse; underwaterPostProcessMaterial.SetMatrix(sp_InvViewProjectionRight, inverseViewProjectionMatrixRightEye); { GetHorizonPosNormal(camera, Camera.MonoOrStereoscopicEye.Right, seaLevel, horizonSafetyMarginMultiplier, farPlaneMultiplier, out Vector2 pos, out Vector2 normal); underwaterPostProcessMaterial.SetVector(sp_HorizonPosNormalRight, new Vector4(pos.x, pos.y, normal.x, normal.y)); } // Revert to original matrix. Not sure if we need to do this. camera.projectionMatrix = cameraProjectionMatrix; } else { if (XRHelpers.IsNewSDKRunning) { XRHelpers.SetViewProjectionMatrices(camera); } var inverseViewProjectionMatrix = (camera.projectionMatrix * camera.worldToCameraMatrix).inverse; underwaterPostProcessMaterial.SetMatrix(sp_InvViewProjection, inverseViewProjectionMatrix); { GetHorizonPosNormal(camera, Camera.MonoOrStereoscopicEye.Mono, seaLevel, horizonSafetyMarginMultiplier, farPlaneMultiplier, out Vector2 pos, out Vector2 normal); underwaterPostProcessMaterial.SetVector(sp_HorizonPosNormal, new Vector4(pos.x, pos.y, normal.x, normal.y)); } } // Not sure why we need to do this - blit should set it...? underwaterPostProcessMaterial.SetTexture(sp_MainTex, source); // Compute ambient lighting SH { // We could pass in a renderer which would prime this lookup. However it doesnt make sense to use an existing render // at different position, as this would then thrash it and negate the priming functionality. We could create a dummy invis GO // with a dummy Renderer which might be enoguh, but this is hacky enough that we'll wait for it to become a problem // rather than add a pre-emptive hack. UnityEngine.Profiling.Profiler.BeginSample("Underwater sample spherical harmonics"); LightProbes.GetInterpolatedProbe(OceanRenderer.Instance.ViewCamera.transform.position, null, out SphericalHarmonicsL2 sphericalHarmonicsL2); sphericalHarmonicsL2.Evaluate(sphericalHarmonicsData._shDirections, sphericalHarmonicsData._ambientLighting); underwaterPostProcessMaterial.SetVector(sp_AmbientLighting, sphericalHarmonicsData._ambientLighting[0]); UnityEngine.Profiling.Profiler.EndSample(); } }
void CreateDestroyLodDatas() { { if (_lodDataAnimWaves == null) { _lodDataAnimWaves = new LodDataMgrAnimWaves(this); _lodDatas.Add(_lodDataAnimWaves); } } if (CreateClipSurfaceData) { if (_lodDataClipSurface == null) { _lodDataClipSurface = new LodDataMgrClipSurface(this); _lodDatas.Add(_lodDataClipSurface); } } else { if (_lodDataClipSurface != null) { _lodDataClipSurface.OnDisable(); _lodDatas.Remove(_lodDataClipSurface); _lodDataClipSurface = null; } } if (CreateDynamicWaveSim) { if (_lodDataDynWaves == null) { _lodDataDynWaves = new LodDataMgrDynWaves(this); _lodDatas.Add(_lodDataDynWaves); } } else { if (_lodDataDynWaves != null) { _lodDataDynWaves.OnDisable(); _lodDatas.Remove(_lodDataDynWaves); _lodDataDynWaves = null; } } if (CreateFlowSim) { if (_lodDataFlow == null) { _lodDataFlow = new LodDataMgrFlow(this); _lodDatas.Add(_lodDataFlow); } } else { if (_lodDataFlow != null) { _lodDataFlow.OnDisable(); _lodDatas.Remove(_lodDataFlow); _lodDataFlow = null; } } if (CreateFoamSim) { if (_lodDataFoam == null) { _lodDataFoam = new LodDataMgrFoam(this); _lodDatas.Add(_lodDataFoam); } } else { if (_lodDataFoam != null) { _lodDataFoam.OnDisable(); _lodDatas.Remove(_lodDataFoam); _lodDataFoam = null; } } if (CreateSeaFloorDepthData) { if (_lodDataSeaDepths == null) { _lodDataSeaDepths = new LodDataMgrSeaFloorDepth(this); _lodDatas.Add(_lodDataSeaDepths); } } else { if (_lodDataSeaDepths != null) { _lodDataSeaDepths.OnDisable(); _lodDatas.Remove(_lodDataSeaDepths); _lodDataSeaDepths = null; } } if (CreateShadowData) { if (_lodDataShadow == null) { _lodDataShadow = new LodDataMgrShadow(this); _lodDatas.Add(_lodDataShadow); } } else { if (_lodDataShadow != null) { _lodDataShadow.OnDisable(); _lodDatas.Remove(_lodDataShadow); _lodDataShadow = null; } } }
private void LateUpdate() { if (OceanRenderer.Instance == null) { _rend.enabled = false; return; } float waterHeight = OceanRenderer.Instance.SeaLevel; // Pass true in last arg for a crap reason - in edit mode LateUpdate can be called very frequently, and the height sampler mistakenly thinks // this is erroneous and complains. _sampleWaterHeight.Init(transform.position, 0f, true); _sampleWaterHeight.Sample(ref waterHeight); float heightOffset = transform.position.y - waterHeight; // Disable skirt when camera not close to water. In the first few frames collision may not be avail, in that case no choice // but to assume enabled. In the future this could detect if camera is far enough under water, render a simple quad to avoid // finding the intersection line. _rend.enabled = heightOffset < _maxHeightAboveWater; if (_rend.enabled) { if (_copyParamsEachFrame) { _rend.sharedMaterial.CopyPropertiesFromMaterial(OceanRenderer.Instance.OceanMaterial); } // Assign lod0 shape - trivial but bound every frame because lod transform comes from here if (_mpb == null) { _mpb = new PropertyWrapperMPB(); } _rend.GetPropertyBlock(_mpb.materialPropertyBlock); // Underwater rendering uses displacements for intersecting the waves with the near plane, and ocean depth/shadows for ScatterColour() _mpb.SetInt(LodDataMgr.sp_LD_SliceIndex, 0); OceanRenderer.Instance._lodDataAnimWaves.BindResultData(_mpb); if (OceanRenderer.Instance._lodDataSeaDepths != null) { OceanRenderer.Instance._lodDataSeaDepths.BindResultData(_mpb); } else { LodDataMgrSeaFloorDepth.BindNull(_mpb); } if (OceanRenderer.Instance._lodDataShadow != null) { OceanRenderer.Instance._lodDataShadow.BindResultData(_mpb); } else { LodDataMgrShadow.BindNull(_mpb); } _mpb.SetFloat(sp_HeightOffset, heightOffset); _mpb.SetVector(OceanChunkRenderer.sp_InstanceData, new Vector3(OceanRenderer.Instance.ViewerAltitudeLevelAlpha, 0f, 0f)); _rend.SetPropertyBlock(_mpb.materialPropertyBlock); } }