public static Vector3 CalculateNormal(HeightSampler sampler, float x, float y, float d = 1.0f) { float dy0 = sampler(x + d, y) - sampler(x - d, y); float dy1 = sampler(x, y + d) - sampler(x, y - d); Vector3 result = new Vector3(-dy0, d, -dy1); result.Normalize(); return result; }
public static Vector3 CalculateTangent(HeightSampler sampler, float x, float y, float d = 1.0f) { float dy0 = sampler(x + d, y) - sampler(x - d, y); Vector3 result = new Vector3(d * 2.0f, dy0, 0.0f); result.Normalize(); return result; //return Vector3.UnitX; }
public static Mesh BuildHeightmap(HeightSampler sampler, int width, int height, float tilesize, int subdivide = 1) { // Determine sizes int totalW = width * subdivide; int totalH = height * subdivide; float invtotalW = 1.0f / totalW; float invtotalH = 1.0f / totalH; // Precache an array of heights float[,] heights = new float[totalW, totalH]; for (int x = 0; x < totalW; x++) { float fX = x * invtotalW * width; for (int y = 0; y < totalH; y++) { float fY = y * invtotalH * height; heights[x, y] = sampler(fX, fY); } } // Recreate the sampler to use the cache sampler = new HeightSampler((x, y) => { int ix = (int)(x * subdivide); int iy = (int)(y * subdivide); if (ix < 0) ix = 0; if (iy < 0) iy = 0; if (ix >= totalW) ix = totalW - 1; if (iy >= totalH) iy = totalH - 1; return heights[ix, iy]; }); // Prepare the builder MeshBuilder builder = new MeshBuilder(); builder.UseNormals = true; builder.UseTangents = true; // Perform the loop for (int x = 0; x < totalW; x++) { float fX = x * invtotalW * width; for (int y = 0; y < totalH; y++) { float fY = y * invtotalH * height; builder.AddPosition(new Vector3(fX * tilesize, sampler(fX, fY), fY * tilesize)); builder.AddNormal(CalculateNormal(sampler, fX, fY)); builder.AddTangent(CalculateTangent(sampler, fX, fY)); if ((x < totalW - 1) && (y < totalH - 1)) { int idx = (x * totalH) + y; builder.AddIndex((ushort)idx); builder.AddIndex((ushort)(idx + 1)); builder.AddIndex((ushort)(idx + totalH + 1)); builder.AddIndex((ushort)(idx + totalH + 1)); builder.AddIndex((ushort)(idx + totalH)); builder.AddIndex((ushort)idx); } } } return builder.Build(); }