/// <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> int UpdateBatch(int lodIdx, int firstComponent, int lastComponentNonInc, IPropertyWrapper property) { int numComponents = lastComponentNonInc - firstComponent; int numInBatch = 0; int dropped = 0; float twopi = 2f * Mathf.PI; float one_over_2pi = 1f / twopi; float minWavelengthThisBatch = OceanRenderer.Instance._lods[lodIdx].MaxWavelength() / 2f; float maxWavelengthCurrentlyRendering = OceanRenderer.Instance._lods[OceanRenderer.Instance.CurrentLodCount - 1].MaxWavelength(); float viewerAltitudeLevelAlpha = OceanRenderer.Instance.ViewerAltitudeLevelAlpha; // 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]; bool renderingIntoLastTwoLods = minWavelengthThisBatch * 4.01f > maxWavelengthCurrentlyRendering; // no special weighting needed for any lods except the last 2 if (renderingIntoLastTwoLods) { bool renderingIntoLastLod = minWavelengthThisBatch * 2.01f > maxWavelengthCurrentlyRendering; if (renderingIntoLastLod) { // example: fade out the last lod as viewer drops in altitude, so there is no pop when the lod chain shifts in scale amp *= viewerAltitudeLevelAlpha; } else { // rendering to second-to-last lod. nothing required unless we are dealing with large wavelengths, which we want to transition into // this second-to-last lod when the viewer drops in altitude, ready for a seamless transition when the lod chain shifts in scale amp *= (wl < 2f * minWavelengthThisBatch) ? 1f : 1f - viewerAltitudeLevelAlpha; } } 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 * (OceanRenderer.Instance._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(numInBatch); } // 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 property.SetVectorArray(sp_TwoPiOverWavelengths, UpdateBatchScratchData._twoPiOverWavelengthsBatch); property.SetVectorArray(sp_Amplitudes, UpdateBatchScratchData._ampsBatch); property.SetVectorArray(sp_WaveDirX, UpdateBatchScratchData._waveDirXBatch); property.SetVectorArray(sp_WaveDirZ, UpdateBatchScratchData._waveDirZBatch); property.SetVectorArray(sp_Phases, UpdateBatchScratchData._phasesBatch); property.SetVectorArray(sp_ChopAmps, UpdateBatchScratchData._chopAmpsBatch); property.SetFloat(sp_NumInBatch, numInBatch); property.SetFloat(sp_AttenuationInShallows, OceanRenderer.Instance._simSettingsAnimatedWaves.AttenuationInShallows); int numVecs = (numInBatch + 3) / 4; property.SetInt(sp_NumWaveVecs, numVecs); OceanRenderer.Instance._lodDataAnimWaves.BindResultData(lodIdx, 0, property); if (OceanRenderer.Instance._lodDataSeaDepths) { OceanRenderer.Instance._lodDataSeaDepths.BindResultData(lodIdx, 0, property, false); } return(numInBatch); }