private Vector3 GetGradient(ErosionRegion region) { Dictionary <Vector3, float> heightDiffs = new Dictionary <Vector3, float>(); float totalHeightDiff = 0; foreach (ErosionRegion adjacentNode in region.AdjacentRegions) { float heightDiff = adjacentNode.Elevation - position.Elevation; heightDiffs.Add(Vector3.Normalize(adjacentNode.Center - position.Center), heightDiff); totalHeightDiff += Math.Abs(heightDiff); } Vector3 gradient = new Vector3(0, 0, 0); foreach (Vector3 direction in heightDiffs.Keys) { gradient += direction * heightDiffs[direction] / totalHeightDiff; } if (gradient == Vector3.Zero || totalHeightDiff == 0) { gradient.X = (float)(random.NextDouble() * 2 - 1); gradient.Y = (float)(random.NextDouble() * 2 - 1); gradient = Vector3.Normalize(gradient) * Settings.inertia / (1 - Settings.inertia); return(gradient); } return(Vector3.Normalize(gradient)); }
private void UpdateValues(ErosionRegion newPosition, Vector3 newDirection, float newVelocity, float newVolume) { position = newPosition; direction = newDirection; velocity = newVelocity; volume = newVolume; }
private void Simulate() { WaterDroplet.Settings = ReadSettings(); ErosionRegion.SetErosionRadius(root.Q <SliderInt>("erosionRadius").value); int numDrops = root.Q <SliderInt>("numDrops").value; bool useGPU = root.Q <Toggle>("useGPU").value; display.Simulate(numDrops, useGPU); }
private void Erode(float dropSedimentCapacity, float heightDiff) { float erosit = Math.Min((dropSedimentCapacity - sediment) * Settings.erosion, -heightDiff); foreach (KeyValuePair <ErosionRegion, float> kvp in position.ErosionWeights) { ErosionRegion location = kvp.Key; float weight = kvp.Value; location.Elevation -= erosit * weight; } sediment += erosit; }
private void SimulationStep() { Vector3 gradient = GetGradient(position); Vector3 newDirection = Vector3.Normalize(direction * Settings.inertia - gradient * (1f - Settings.inertia)); ErosionRegion newPosition = FindNextLocation(newDirection); float heightDiff = newPosition.Elevation - position.Elevation; SimulateHydraulicAction(heightDiff); float newVelocity = (float)Math.Sqrt(Math.Max(0, Math.Pow(velocity, 2) - heightDiff * Settings.gravity)); float newVolume = volume * (1 - Settings.evaporation); UpdateValues(newPosition, newDirection, newVelocity, newVolume); }
private ErosionRegion FindNextLocation(Vector3 newDirection) { ErosionRegion newPosition = position; float maxCosTheta = float.MinValue; foreach (ErosionRegion adjacentRegion in position.AdjacentRegions) { Vector3 direction = Vector3.Normalize(adjacentRegion.Center - position.Center); float cosTheta = Vector3.Dot(direction, newDirection); if (cosTheta > maxCosTheta) { maxCosTheta = cosTheta; newPosition = adjacentRegion; } } return(newPosition); }
public void SimulateErosionComputeShader(int numIterations) { GenerateHexagon(); if (numIterations == 0) { return; } int numThreads = System.Math.Max(numIterations / 1024, 1); ErosionRegion[] values = erosionRegions.Values.ToArray(); Dictionary <ErosionRegion, int> regionMap = new Dictionary <ErosionRegion, int>(); for (int i = 0; i < values.Length; i++) { regionMap.Add(values[i], i); } int[] randomRegionIndicies = new int[numIterations]; Random.InitState(0); for (int i = 0; i < numIterations; i++) { randomRegionIndicies[i] = Random.Range(0, values.Length); } ComputeBuffer randomBuffer = new ComputeBuffer(numIterations, sizeof(int)); randomBuffer.SetData(randomRegionIndicies); erosion.SetBuffer(0, "random", randomBuffer); ComputeBuffer regionBuffer = new ComputeBuffer(values.Length, sizeof(float) * 4 + sizeof(int) * 7); ErosionRegionCompute[] computeRegions = new ErosionRegionCompute[values.Length]; for (int i = 0; i < values.Length; i++) { ErosionRegion region = values[i]; ErosionRegionCompute r = new ErosionRegionCompute { position = new Vector3(region.Center.X, region.Center.Y, region.Center.Z), elevation = region.Elevation }; for (int j = 0; j < 6; j++) { ErosionRegion erosionRegion = region; try { erosionRegion = region.AdjacentRegions[j]; } catch (System.Exception) { // Less than 6 adjacent regions, ignore } int index = regionMap[erosionRegion]; switch (j) { case 0: r.adjacentRegion1 = index; break; case 1: r.adjacentRegion2 = index; break; case 2: r.adjacentRegion3 = index; break; case 3: r.adjacentRegion4 = index; break; case 4: r.adjacentRegion5 = index; break; case 5: r.adjacentRegion6 = index; break; } } r.numAdjRegions = region.AdjacentRegions.Count; computeRegions[i] = r; } regionBuffer.SetData(computeRegions); erosion.SetBuffer(0, "regions", regionBuffer); erosion.SetInt("lifetime", WaterDroplet.Settings.lifetime); erosion.SetFloat("inertia", WaterDroplet.Settings.inertia); erosion.SetFloat("gravity", WaterDroplet.Settings.gravity); erosion.SetFloat("evaporation", WaterDroplet.Settings.evaporation); erosion.SetFloat("capacity", WaterDroplet.Settings.capacity); erosion.SetFloat("erosion", WaterDroplet.Settings.erosion); erosion.SetFloat("deposition", WaterDroplet.Settings.deposition); erosion.SetFloat("minErosion", WaterDroplet.Settings.minErosion); erosion.Dispatch(0, numThreads, 1, 1); regionBuffer.GetData(computeRegions); for (int i = 0; i < computeRegions.Length; i++) { values[i].Elevation = computeRegions[i].elevation; } regionBuffer.Release(); randomBuffer.Release(); }
public WaterDroplet(ErosionRegion region) { position = region; random = new Random((int)(position.Center.X * position.Center.Y)); direction = Vector3.Normalize(new Vector3((float)(random.NextDouble() * 2 - 1), (float)(random.NextDouble() * 2 - 1), 0)); }