void InitBatches() { if (_waveShader == null) { _waveShader = Shader.Find("Crest/Inputs/Animated Waves/Gerstner Batch"); Debug.Assert(_waveShader, "Could not load Gerstner wave shader, make sure it is packaged in the build."); if (_waveShader == null) { return; } } _batches = new GerstnerBatch[LodDataMgr.MAX_LOD_COUNT]; for (int i = 0; i < _batches.Length; i++) { _batches[i] = new GerstnerBatch(_waveShader, _directTowardsPoint); } // 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. var registered = RegisterLodDataInputBase.GetRegistrar(typeof(LodDataMgrAnimWaves)); foreach (var batch in _batches) { registered.Add(batch); } }
void UpdateBatch(GerstnerBatch batch, int batchIdx) { #if UNITY_EDITOR if (_spectrum == null) { return; } #endif // Default to disabling all batches batch.HasWaves = false; if (OceanRenderer.Instance == null) { return; } UpdateData(); if (_wavelengths.Length == 0) { return; } int lodIdx = Mathf.Min(batchIdx, OceanRenderer.Instance.CurrentLodCount - 1); int componentIdx = 0; // seek forward to first wavelength that is big enough to render into current LODs float minWl = OceanRenderer.Instance._lodTransform.MaxWavelength(batchIdx) / 2f; while (componentIdx < _wavelengths.Length && _wavelengths[componentIdx] < minWl) { componentIdx++; } // Assemble wavelengths into current batch int startCompIdx = componentIdx; while (componentIdx < _wavelengths.Length && _wavelengths[componentIdx] < 2f * minWl) { componentIdx++; } // One or more wavelengths - update the batch if (componentIdx > startCompIdx) { //Debug.Log($"Batch {batch}, lodIdx {lodIdx}, range: {minWl} -> {2f * minWl}, indices: {startCompIdx} -> {componentIdx}"); UpdateBatch(lodIdx, startCompIdx, componentIdx, batch); } }
/// <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 InitBatches() { // Get the wave MeshRenderer rend = GetComponent <MeshRenderer>(); if (_mode == GerstnerMode.Geometry) { rend.enabled = false; #if UNITY_EDITOR // Cleanup render proxy used for global mode after switching. if (_renderProxy != null) { DestroyImmediate(_renderProxy); } #endif } else if (_mode == GerstnerMode.Global) { // Create render proxy only if we don't already have one. if (_renderProxy == null) { // Create a proxy MeshRenderer to feed the rendering _renderProxy = GameObject.CreatePrimitive(PrimitiveType.Quad); #if UNITY_EDITOR DestroyImmediate(_renderProxy.GetComponent <Collider>()); #else Destroy(_renderProxy.GetComponent <Collider>()); #endif _renderProxy.hideFlags = HideFlags.HideAndDontSave; _renderProxy.transform.parent = transform; rend = _renderProxy.GetComponent <MeshRenderer>(); rend.enabled = false; var waveShader = Shader.Find("Hidden/Crest/Inputs/Animated Waves/Gerstner Batch Global"); Debug.Assert(waveShader, "Could not load Gerstner wave shader, make sure it is packaged in the build."); if (waveShader == null) { enabled = false; return; } rend.material = new Material(waveShader); } else { rend = _renderProxy.GetComponent <MeshRenderer>(); } } var registered = RegisterLodDataInputBase.GetRegistrar(typeof(LodDataMgrAnimWaves)); #if UNITY_EDITOR // Unregister after switching modes in the editor. if (_batches != null) { foreach (var batch in _batches) { registered.Remove(batch); } } #endif _batches = new GerstnerBatch[LodDataMgr.MAX_LOD_COUNT]; for (int i = 0; i < _batches.Length; i++) { _batches[i] = new GerstnerBatch(this, i, rend, _directTowardsPoint); } // 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. foreach (var batch in _batches) { registered.Add(0, batch); } }
void InitBatches() { // Get the wave MeshRenderer rend = null; if (_mode == GerstnerMode.Geometry) { rend = GetComponent <MeshRenderer>(); if (!rend) { Debug.LogError($"Gerstner input '{gameObject.name}' has Mode set to Geometry, but no MeshRenderer component is attached. Please attach a MeshRenderer to provide the geometry for rendering the Gerstner waves.", this); enabled = false; return; } if (!rend.sharedMaterial) { Debug.LogError($"Gerstner input '{gameObject.name}' has Mode set to Geometry, but the geometry has no material assigned. Please assign a material that uses one of the Gerstner input shaders.", this); enabled = false; return; } rend.enabled = false; } else if (_mode == GerstnerMode.Global) { if (GetComponent <MeshRenderer>() != null) { Debug.LogWarning($"Gerstner input '{gameObject.name}' has MeshRenderer component that will be ignored because the Mode is set to Global.", this); } // Create a proxy MeshRenderer to feed the rendering var renderProxy = GameObject.CreatePrimitive(PrimitiveType.Quad); Destroy(renderProxy.GetComponent <Collider>()); renderProxy.hideFlags = HideFlags.HideAndDontSave; renderProxy.transform.parent = transform; rend = renderProxy.GetComponent <MeshRenderer>(); rend.enabled = false; var waveShader = Shader.Find("Hidden/Crest/Inputs/Animated Waves/Gerstner Batch Global"); Debug.Assert(waveShader, "Could not load Gerstner wave shader, make sure it is packaged in the build."); if (waveShader == null) { enabled = false; return; } rend.material = new Material(waveShader); } _batches = new GerstnerBatch[LodDataMgr.MAX_LOD_COUNT]; for (int i = 0; i < _batches.Length; i++) { _batches[i] = new GerstnerBatch(rend, _directTowardsPoint); } // 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. var registered = RegisterLodDataInputBase.GetRegistrar(typeof(LodDataMgrAnimWaves)); foreach (var batch in _batches) { registered.Add(0, batch); } }