/// <summary>
        /// Initializes a new instance of the <see cref="DynamicWaterMesh"/> class.
        /// </summary>
        /// <param name="resolution">
        /// The number of grid nodes along the bigger side of the mesh.
        /// </param>
        /// <param name="size">The width and length of the mesh</param>
        /// <param name="settings">
        /// DynamicWaterSettings instance representing the public settings properties of <see cref="DynamicWater"/> class.
        /// </param>
        /// <param name="fieldObstruction">
        /// The array of <c>byte</c> indicating whether the water is obstructed by an object. \n
        /// <c>0</c> means the grid node is obstructed by an object, so the simulation is not updated;
        /// <c>255</c> means the grid node is not obstructed, and the simulation can proceed freely.
        /// Intermediate values represent the additional dampening value in that node.
        /// </param>
        public DynamicWaterMesh(int resolution,
                                Vector2 size,
                                IDynamicWaterSettings settings,
                                byte[] fieldObstruction = null)
        {
            IsReady = false;

            _settings = settings;

            _size = size;
            GridMath.CalculateGrid(resolution, size, out _grid, out _nodeSize);

            // Some failsafe
            if (_size.x < Vector3.kEpsilon || _size.y < Vector3.kEpsilon) {
                _grid = new Vector2Int(1, 1);
            }

            _mesh = new Mesh();
            _mesh.name = "DynamicWaterMesh";
            #if !UNITY_3_5
            _mesh.MarkDynamic();
            #endif
            AllocateMeshArrays();
            CreateMeshGrid(fieldObstruction);
            AssignMesh();
            _mesh.RecalculateBounds();

            IsReady = true;
        }
        /// <summary>
        /// The initialization method. Automatically called by <see cref="DynamicWater"/>.
        /// </summary>
        /// <param name="gridSize">
        /// Simulation grid resolution.
        /// </param>
        /// <seealso cref="DynamicWater"/>
        public override void Initialize(Vector2Int gridSize) {
            base.Initialize(gridSize);

            FieldSim = new float[_grid.x * _grid.y];
            FieldSimNew = new float[_grid.x * _grid.y];
            FieldSimSpeed = new float[_grid.x * _grid.y];

            // Initial state
            Field = FieldSim;
        }
        /// <summary>
        /// The initialization method. Called by <see cref="DynamicWater"/>.
        /// </summary>
        /// <param name="gridSize">
        /// The simulation grid resolution.
        /// </param>
        /// <seealso cref="DynamicWater"/>
        public override void Initialize(Vector2Int gridSize) {
            base.Initialize(gridSize);

            _fieldSum = new float[_grid.x * _grid.y];

            // Initial state
            _field = _fieldSum;

            _canInteract = !OnlyAmbient;
        }
        /// <summary>
        /// Performs the wave simulation step.
        /// </summary>
        /// <param name="field">
        /// Represents the current simulation state.
        /// </param>
        /// <param name="fieldNew">
        /// Represents the updated simulation state.
        /// </param>
        /// <param name="fieldSpeed">
        /// Represents the simulation state difference.
        /// </param>
        /// <param name="fieldObstruction">
        /// Array of <c>bool</c> indicating whether the water is obstructed by an object. \n
        /// <c>true</c> means the grid node is obstructed by an object, so the simulation is not updated;
        /// <c>false</c> means the grid node is not obstructed, and the simulation can proceed freely.
        /// </param>
        /// <param name="gridSize">
        /// Actual simulation grid resolution.
        /// </param>
        /// <param name="timeDelta">
        /// Time delta in seconds.
        /// </param>
        /// <param name="damping">
        /// Damping value. Must be clamped to the 0-1 range. 
        /// </param>
        /// <param name="maxValue">
        /// Value representing maximal absolute wave height.
        /// </param>
        public static void Solve(float[] field, float[] fieldNew, float[] fieldSpeed,
                                 byte[] fieldObstruction, Vector2Int gridSize, float timeDelta, float damping,
                                 out float maxValue)
        {
            maxValue = float.NegativeInfinity;

            bool isFieldObstructionNull = fieldObstruction == null;
            float obstructionValue = 1f;
            for (int j = 0; j < gridSize.y; j++) {
                int index = j * gridSize.x;
                for (int i = 0; i < gridSize.x; i++) {
                    // Not updating borders and obstructions
                    if (!(i <= 0 || j <= 0 || i >= gridSize.x - 1 || j >= gridSize.y - 1 || (!isFieldObstructionNull && fieldObstruction[index] == byte.MinValue))) {
                        // Obstruction value (0-1) determined by obstruction geometry and obstruction mask
                        if (!isFieldObstructionNull) {
                            obstructionValue = fieldObstruction[index] * FastFunctions.InvertedByteMaxValue;
                        }

                        float laplasian = (field[index - 1] +
                                           field[index + 1] +
                                           field[index + gridSize.x] +
                                           field[index - gridSize.x]) * 0.25f -
                                           field[index];

                        fieldSpeed[index] += laplasian * timeDelta;
                        fieldNew[index] = (field[index] + fieldSpeed[index]) * damping * obstructionValue;

                        float valueAbs;
                        if (fieldNew[index] > 0f) {
                            valueAbs = fieldNew[index];
                        } else {
                            valueAbs = -fieldNew[index];
                        }
                        if (valueAbs > maxValue) {
                            maxValue = valueAbs;
                        }
                    }

                    index++;
                }
            }
        }
Example #5
0
 public static void CalculateGrid(int resolution, Vector2 size, out Vector2Int grid, out float nodeSize) {
     nodeSize = Mathf.Max(size.x, size.y) / resolution;
     grid.x = Mathf.FloorToInt(size.x / nodeSize + 1);
     grid.y = Mathf.FloorToInt(size.y / nodeSize + 1);
 }
        /// <summary>
        /// The initialization method. Automatically called by <see cref="DynamicWater"/>.
        /// </summary>
        /// <param name="gridSize">
        /// The size in nodes of simulation grid.
        /// </param>
        /// <seealso cref="DynamicWater"/>
        public virtual void Initialize(Vector2Int gridSize) {
            _isInitialized = true;

            _grid = gridSize;
        }
        private void CreateSplashLine(Vector2Int start, Vector2Int end, float radius, float force) {
            int dx = Math.Abs(end.x - start.x);
            int dy = Math.Abs(end.y - start.y);

            int sx, sy;

            if (start.x < end.x) {
                sx = 1;
            } else {
                sx = -1;
            }
            if (start.y < end.y) {
                sy = 1;
            } else {
                sy = -1;
            }

            int err = dx - dy;
            bool splashMade = false;
            while (true) {
                if (start.x == end.x && start.y == end.y) {
                    break;
                }

                Vector2 startf;
                startf.x = start.x;
                startf.y = start.y;
                CreateSplashNormalized(startf, radius, force);

                splashMade = true;

                int e2 = 2 * err;

                if (e2 > -dy) {
                    err = err - dy;
                    start.x = start.x + sx;
                }

                if (e2 < dx) {
                    err = err + dx;
                    start.y = start.y + sy;
                }
            }

            // Make sure we have made at least one splash
            if (!splashMade) {
                CreateSplashNormalized(new Vector2(start.x, start.y), radius, force);
            }
        }