private void waterWeatherBtn_Click(object sender, EventArgs e) { waterWeatherBtn.Enabled = false; btnNoise.Enabled = false; // parames that the errosion class needed see droplet class for more info ErosionParams erosionParams = new ErosionParams(); erosionParams.Kq = 10; erosionParams.Kw = 0.001f; erosionParams.Kr = 0.9f; erosionParams.Kd = 0.02f; erosionParams.Ki = 0.1f; erosionParams.minSlope = 0.05f; erosionParams.g = 20; // how many droplets you want int iterations = (int)nudWeatheringDroplets.Value; // run it Droplet droplet = new Droplet(); droplet.genDropletErosion(iterations, erosionParams, heightMap.noiseMap); // draw it DrawMap(); waterWeatherBtn.Enabled = true; btnNoise.Enabled = true; //seamlessMeridianBtn.Enabled = true; }
public void genDropletErosion(int iterations, ErosionParams erosionParams, double[,] hMap) { Random rnd = new Random(); float Kq = erosionParams.Kq, Kw = erosionParams.Kw, Kr = erosionParams.Kr, Kd = erosionParams.Kd, Ki = erosionParams.Ki, minSlope = erosionParams.minSlope, Kg = erosionParams.g * 2; //TempData<Point2[HMAP_SIZE*HMAP_SIZE]> erosion; float flt = 0; //erosion.fillMem32(*(uint32_t*)&flt); int MAX_PATH_LEN = hMap.GetLength(0) * 4; //int t0 = get_ref_time(); uint longPaths = 0, randomDirs = 0, sumLen = 0; for (int iter = 0; iter < iterations; ++iter) { //if ((iter&0x3FFF) == 0 && iter!=0) show_splash("Calculating erosion", (iter+0.5f)/iterations); int xi = rnd.Next(0, hMap.GetLength(0) - 1); int zi = rnd.Next(0, hMap.GetLength(1) - 1); float xp = xi, zp = zi; float xf = 0, zf = 0; float h = (float)hMap[xi, zi]; float s = 0, v = 0, w = 1; //vec4f scolor = zero4f(); //if (xi + 1 >= hMap.GetLength(0)) xi = 0; //if (zi + 1 >= hMap.GetLength(1)) zi = 0; float h00 = h; float h10 = (float)hMap[xi + 1, zi]; float h01 = (float)hMap[xi, zi + 1]; float h11 = (float)hMap[xi + 1, zi + 1]; float dx = 0, dz = 0; uint numMoves = 0; for (; numMoves < MAX_PATH_LEN; ++numMoves) { // calc gradient float gx = h00 + h01 - h10 - h11; float gz = h00 + h10 - h01 - h11; //== better interpolated gradient? // calc next pos dx = (dx - gx) * Ki + gx; dz = (dz - gz) * Ki + gz; float dl = (float)Math.Sqrt(dx * dx + dz * dz); if (dl <= float.Epsilon) { // pick random dir float a = (float)(rnd.Next() * (Math.PI * 2)); dx = (float)Math.Cos(a); dz = (float)Math.Sin(a); ++randomDirs; } else { dx /= dl; dz /= dl; } float nxp = xp + dx; float nzp = zp + dz; // sample next height int nxi = (int)Math.Floor(nxp); int nzi = (int)Math.Floor(nzp); float nxf = nxp - nxi; float nzf = nzp - nzi; if (nxi + 1 >= hMap.GetLength(0)) { nxi = 0; } if (nxi < 0) { nxi = hMap.GetLength(0) - 2; } if (nzi + 1 >= hMap.GetLength(1)) { nzi = 0; } if (nzi < 0) { nzi = hMap.GetLength(1) - 2; } float nh00 = (float)hMap[nxi, nzi]; float nh10 = (float)hMap[nxi + 1, nzi]; float nh01 = (float)hMap[nxi, nzi + 1]; float nh11 = (float)hMap[nxi + 1, nzi + 1]; float nh = (nh00 * (1 - nxf) + nh10 * nxf) * (1 - nzf) + (nh01 * (1 - nxf) + nh11 * nxf) * nzf; // if higher than current, try to deposit sediment up to neighbour height if (nh >= h) { float tds = (nh - h) + 0.001f; if (tds >= s) { // deposit all sediment and stop tds = s; DEPOSIT_AT(xi, zi, (1 - xf) * (1 - zf), hMap, tds); DEPOSIT_AT(xi + 1, zi, xf * (1 - zf), hMap, tds); DEPOSIT_AT(xi, zi + 1, (1 - xf) * zf, hMap, tds); DEPOSIT_AT(xi + 1, zi + 1, xf * zf, hMap, tds); (h) += tds; s = 0; break; } DEPOSIT_AT(xi, zi, (1 - xf) * (1 - zf), hMap, tds); DEPOSIT_AT(xi + 1, zi, xf * (1 - zf), hMap, tds); DEPOSIT_AT(xi, zi + 1, (1 - xf) * zf, hMap, tds); DEPOSIT_AT(xi + 1, zi + 1, xf * zf, hMap, tds); (h) += tds; s -= tds; v = 0; } // compute transport capacity float dh = h - nh; float slope = dh; //float slope=dh/sqrtf(dh*dh+1); float q = Math.Max(slope, minSlope) * v * w * Kq; // deposit/erode (don't erode more than dh) float ds = s - q; if (ds >= 0) { // deposit ds *= Kd; //ds=minval(ds, 1.0f); DEPOSIT_AT(xi, zi, (1 - xf) * (1 - zf), hMap, ds); DEPOSIT_AT(xi + 1, zi, xf * (1 - zf), hMap, ds); DEPOSIT_AT(xi, zi + 1, (1 - xf) * zf, hMap, ds); DEPOSIT_AT(xi + 1, zi + 1, xf * zf, hMap, ds); (dh) += ds; s -= ds; } else { // erode ds *= -Kr; ds = Math.Min(ds, dh * 0.99f); for (int z = zi - 1; z <= zi + 2; ++z) { float zo = z - zp; float zo2 = zo * zo; for (int x = xi - 1; x <= xi + 2; ++x) { float xo = x - xp; float tw = 1 - (xo * xo + zo2) * 0.25f; if (tw <= 0) { continue; } tw *= 0.1591549430918953f; ERODE(x, z, tw, hMap, ds); } } dh -= ds; s += ds; } // move to the neighbour v = (float)Math.Sqrt(v * v + Kg * dh); w *= 1 - Kw; xp = nxp; zp = nzp; xi = nxi; zi = nzi; xf = nxf; zf = nzf; h = nh; h00 = nh00; h10 = nh10; h01 = nh01; h11 = nh11; } if (numMoves >= MAX_PATH_LEN) { //debug("droplet #%d path is too long!", iter); ++longPaths; } sumLen += numMoves; } }