/// <summary> /// Executes the wave simulation step. /// </summary> /// <param name="speed"> /// Overall simulation speed factor. /// </param> /// <param name="damping"> /// The damping value (range 0-1). /// </param> public override void StepSimulation(float speed, float damping) { if (!_isDirty || !_isInitialized) { return; } _simulationSpeedNormalizationFactor = (_grid.x + _grid.y) / 128f; // assume 64 grid as normal float dt = Mathf.Clamp(Time.deltaTime * speed * _simulationSpeedNormalizationFactor, 0f, LinearWaveEqueationSolver.MaxDt); float max; #if !UNITY_FLASH bool useNative = DynamicWaterNativeLibrary.CanUseNative; #else const bool useNative = false; #endif if (useNative) { #if !UNITY_FLASH if (_switchField) { DynamicWaterNativeLibrary.SolveWaveEquationNative(_grid.x, _grid.y, dt, damping, out max, FieldSim, FieldSimNew, FieldSimSpeed, _fieldObstruction); _field = FieldSimNew; } else { DynamicWaterNativeLibrary.SolveWaveEquationNative(_grid.x, _grid.y, dt, damping, out max, FieldSimNew, FieldSim, FieldSimSpeed, _fieldObstruction); _field = FieldSim; } #endif } else { if (_switchField) { LinearWaveEqueationSolver.Solve(FieldSim, FieldSimNew, FieldSimSpeed, _fieldObstruction, _grid, dt, damping, out max); _field = FieldSimNew; } else { LinearWaveEqueationSolver.Solve(FieldSimNew, FieldSim, FieldSimSpeed, _fieldObstruction, _grid, dt, damping, out max); _field = FieldSim; } } _switchField = !_switchField; _isDirty = max > DirtyThreshold; }
/// <summary> /// Updates the mesh state using the simulation state field <paramref name="field"/> /// and (optional) the obstruction field. /// </summary> /// <param name="field"> /// The simulation state field. /// </param> /// <param name="fieldObstruction"> /// The array of <c>bool</c> indicating whether the water is obstructed by an object. /// </param> public void UpdateMesh(float[] field, byte[] fieldObstruction) { if (!_isDirty || !IsReady) { return; } #if !UNITY_FLASH bool useNative = DynamicWaterNativeLibrary.CanUseNative; #else const bool useNative = false; #endif // Caching some values to avoid expensive calls bool isFieldObstructionNull = fieldObstruction == null; bool calculateNormals = _settings.CalculateNormals; bool useFastNormals = _settings.UseFastNormals; if (useNative) { #if !UNITY_FLASH DynamicWaterNativeLibrary.UpdateMesh(calculateNormals, useFastNormals, _nodeSize, _grid.x, _grid.y, field, fieldObstruction, _meshStruct.Vertices, _meshStruct.Normals); #endif } else { // We can't run native, run C# then Vector3 up = Vector3.up; Vector3 normal = up; float doubleNodeSize = 2f * _nodeSize; // Minimal node value to calculate normals for (in case of using approximate normals). const float normalThreshold = 0.0001f; // If not using fast normals, then all we need is to update the vertices if (!useFastNormals) { for (int j = 0; j < _grid.y; j++) { int index = j * _grid.x; for (int i = 0; i < _grid.x; i++) { _meshStruct.Vertices[index].y = field[index]; index++; } } } else { // Otherwise, calculate the normals too for (int j = 0; j < _grid.y; j++) { int index = j * _grid.x; for (int i = 0; i < _grid.x; i++) { if ((i == 0 || j == 0 || i >= _grid.x - 1 || j >= _grid.y - 1) || (!isFieldObstructionNull && fieldObstruction[index] == byte.MinValue)) { normal = up; } else { float valAbs; if (field[index] > 0f) { valAbs = field[index]; } else { valAbs = -field[index]; } if (valAbs > normalThreshold) { normal.x = field[index - 1] - field[index + 1]; normal.z = field[index - _grid.x] - field[index + _grid.x]; normal.y = doubleNodeSize; // Fast approximate Vector3 normalization // See also: LostPolygon.DynamicWaterSystem.FastFunctions.FastInvSqrt() float invLength = normal.x * normal.x + normal.y * normal.y + normal.z * normal.z; FastFunctions.FloatIntUnion u; u.i = 0; u.f = invLength; float xhalf = 0.5f * invLength; u.i = 0x5f3759df - (u.i >> 1); invLength = u.f * (1.5f - xhalf * u.f * u.f); normal.x *= invLength; normal.y *= invLength; normal.z *= invLength; } else { normal = up; } } _meshStruct.Normals[index] = normal; _meshStruct.Vertices[index].y = field[index]; index++; } } } } // Actually updating the mesh _mesh.vertices = _meshStruct.Vertices; if (calculateNormals) { if (useFastNormals) { _mesh.normals = _meshStruct.Normals; } else { _mesh.RecalculateNormals(); } } _isDirty = false; }