public void GetChunk(int x, int y, int z, VoxelVolume chunk) { if (!started) { Init(); started = true; } //for (var xx = 0; xx < ChunkManager.CHUNK_SIZE; xx++) // for (var zz = 0; zz < ChunkManager.CHUNK_SIZE; zz++) // chunk[xx, 0, zz] = 0xffffff; //chunk[0, 1, 0] = 0xffffff; //chunk[0, 1, 1] = 0xffffff; //chunk[0, 1, 2] = 0xffffff; //chunk[0, 1, 3] = 0xffffff; ////chunk[1, 2, 1] = 0xffffff; ////chunk[1, 2, 2] = 0xffffff; ////chunk[2, 2, 2] = 0xffffff; ////chunk[1, 0, 1] = 0xffffff; ////chunk[1, 0, 2] = 0xffffff; ////chunk[2, 0, 2] = 0xffffff; //return; bool addCaves = false; // (bool)m.GetOption("DefaultGenCaves"); bool addCaveLava = false; // (bool)m.GetOption("DefaultGenLavaCaves"); int ChunkSize = Constants.CHUNK_SIZE;// m.GetChunkSize(); x *= ChunkSize; y *= ChunkSize; z *= ChunkSize; int chunksize = ChunkSize; var noise = new FastNoise(); noise.Frequency = 0.01; for (int xx = 0; xx < chunksize; xx++) { for (int yy = 0; yy < chunksize; yy++) { int currentHeight = (byte)((finalTerrain.GetValue((xx + x) / 100.0f, 0, (yy + y) / 100.0f) * 60) + 64); int ymax = currentHeight; int biome = (int)(BiomeSelect.GetValue((x + xx) / 100.0f, 0, (y + yy) / 100.0f) * 2); //MD * 2 uint toplayer = BLOCK_DIRT; if (biome == 0) { toplayer = BLOCK_DIRT; } if (biome == 1) { toplayer = BLOCK_SAND; } if (biome == 2) { toplayer = BLOCK_DIRT; } if (biome == 3) { toplayer = BLOCK_DIRT; } if (biome == 4) { toplayer = BLOCK_DIRT; } if (biome == 5) { toplayer = BLOCK_CLAY; } int stoneHeight = (int)currentHeight - ((64 - (currentHeight % 64)) / 8) + 1; if (ymax < seaLevel) { ymax = seaLevel; } ymax++; if (ymax > z + chunksize - 1) { ymax = z + chunksize - 1; } for (int bY = z; bY <= ymax; bY++) { uint curBlock = 0; // Place bedrock if (bY == 0) { curBlock = BLOCK_BEDROCK; } else if (bY < currentHeight) { if (bY < stoneHeight) { curBlock = BLOCK_STONE; // Add caves if (addCaves) { if (caveNoise.GetValue((x + xx) / 4.0f, (bY) / 1.5f, (y + yy) / 4.0f) > cavestreshold) { if (bY < 10 && addCaveLava) { curBlock = BLOCK_LAVA; } else { curBlock = BLOCK_AIR; } } } } else { curBlock = toplayer; } } else if ((currentHeight + 1) == bY && bY > seaLevel && biome == 3) { curBlock = BLOCK_SNOW; continue; } else if ((currentHeight + 1) == bY && bY > seaLevel + 1) { if (biome == 1 || biome == 0) { continue; } double f = flowers.GetValue(x + xx / 10.0f, 0, y + yy / 10.0f); if (f < -0.999) { curBlock = BLOCK_RED_ROSE; } else if (f > 0.999) { curBlock = BLOCK_YELLOW_FLOWER; } else if (f < 0.001 && f > -0.001) { curBlock = BLOCK_PUMPKIN; } } else if (currentHeight == bY) { if (bY == seaLevel || bY == seaLevel - 1 || bY == seaLevel - 2) { curBlock = BLOCK_SAND; // FF } else if (bY < seaLevel - 1) { curBlock = BLOCK_GRAVEL; // FF } else if (toplayer == BLOCK_DIRT) { curBlock = BLOCK_GRASS; } else { curBlock = toplayer; // FF } } else { if (bY <= seaLevel) { curBlock = BLOCK_WATER; // FF } else { curBlock = BLOCK_AIR; // FF } if (bY == seaLevel && biome == 3) { curBlock = BLOCK_ICE; } } //var idx = xx + chunksize * ((yy) + chunksize * (bY - z)); chunk[xx, bY - z, yy] = curBlock; //chunk[idx] = curBlock; //chunk[m.Index3d(xx, yy, bY - z, chunksize, chunksize)] = curBlock; } } } }
public static int ExtractMesh(VoxelVolume volume, bool disableGreedyMeshing = false, bool disableAO = false) { volume.PrepareMesh(); VertexPositionColorNormal[] vertices = new VertexPositionColorNormal[5]; var dims = volume.dims; var f = new Func<int, int, int, uint>((i, j, k) => { if (i < 0 || j < 0 || k < 0 || i >= dims[0] || j >= dims[1] || k >= dims[2]) return volume.GetRelativeVoxel(i, j, k); //return cm.GetVoxelByRelative(volume.X, volume.Y, volume.Z, i, j, k); var r = volume[i + dims[0] * (j + dims[1] * k)]; if (r > 0 && (r & 0x1000000u) > 0u) { r = 0; } return r; }); //Sweep over 3-axes // d0 = x, d1 = y, d2 = z for (var d = 0; d < 3; ++d) { int i, j, k, l, w, h , u = (d + 1) % 3 , v = (d + 2) % 3; int[] x = { 0, 0, 0 }; int[] q = { 0, 0, 0 }; int[,] posArea = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; int[,] negArea = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; if (mask.Length < dims[u] * dims[v]) { mask = new uint[dims[u] * dims[v]]; maskLayout = new MaskLayout[dims[u] * dims[v]]; } q[d] = 1; posArea[0, u] = -1; posArea[1, v] = -1; posArea[2, u] = 1; posArea[3, v] = 1; negArea[0, v] = -1; negArea[1, u] = -1; negArea[2, v] = 1; negArea[3, u] = 1; for (x[d] = -1; x[d] < dims[d]; ) { //Compute mask var n = 0; for (x[v] = 0; x[v] < dims[v]; ++x[v]) { for (x[u] = 0; x[u] < dims[u]; ++x[u], ++n) { var a = f(x[0], x[1], x[2]); var b = f(x[0] + q[0], x[1] + q[1], x[2] + q[2]); maskLayout[n].data = 0u; if ((a != 0) == (b != 0)) { mask[n] = 0; } else if (a != 0) { mask[n] = x[d] > -1 ? a : 0; maskLayout[n].BackFace = false; } else { mask[n] = x[d] < dims[d] - 1 ? b : 0; maskLayout[n].BackFace = true; } if (disableAO || mask[n] == 0) { //maskLayout[n].data = 4095u; } else { uint side1 = 0, side2 = 0, corner = 0; var neighbors = new uint[4]; for (var t = 0; t < 4; ++t) { var tt = (t + 1) % 4; if (a != 0) { side1 = (f(x[0] + q[0] + posArea[t, 0], x[1] + q[1] + posArea[t, 1], x[2] + q[2] + posArea[t, 2]) > 0u ? 1u : 0u); side2 = (f(x[0] + q[0] + posArea[tt, 0], x[1] + q[1] + posArea[tt, 1], x[2] + q[2] + posArea[tt, 2]) > 0u ? 1u : 0u); } else { side1 = (f(x[0] + negArea[t, 0], x[1] + negArea[t, 1], x[2] + negArea[t, 2]) > 0u ? 1u : 0u); side2 = (f(x[0] + negArea[tt, 0], x[1] + negArea[tt, 1], x[2] + negArea[tt, 2]) > 0u ? 1u : 0u); } if (side1 > 0 && side2 > 0) { neighbors[t] = 0; } else { if (a != 0) { corner = (f(x[0] + q[0] + posArea[t, 0] + posArea[tt, 0], x[1] + q[1] + posArea[t, 1] + posArea[tt, 1], x[2] + q[2] + posArea[t, 2] + posArea[tt, 2]) > 0u ? 1u : 0u); } else { corner = (f(x[0] + negArea[t, 0] + negArea[tt, 0], x[1] + negArea[t, 1] + negArea[tt, 1], x[2] + negArea[t, 2] + negArea[tt, 2]) > 0u ? 1u : 0u); } neighbors[t] = 3u - (side1 + side2 + corner); } maskLayout[n].SetOcclusion(t, neighbors[t]); } uint a00 = neighbors[1], a01 = neighbors[2], a11 = neighbors[3], a10 = neighbors[0]; //if (a00 + a01 + a11 + a10 != 12) // maskLayout[n].AOFace = true; } } } //Increment x[d] ++x[d]; //Generate mesh for mask using lexicographic ordering n = 0; for (j = 0; j < dims[v]; ++j) { for (i = 0; i < dims[u]; ) { var c = mask[n]; if (c != 0) { var a = maskLayout[n]; if (disableGreedyMeshing || a.AOFace) { w = 1; h = 1; } else { //Compute width for (w = 1; c == mask[n + w] && (a.data == (maskLayout[n + w].data)) && i + w < dims[u]; ++w) { } //Compute height (this is slightly awkward var done = false; for (h = 1; j + h < dims[v]; ++h) { for (k = 0; k < w; ++k) { if (c != mask[n + k + h * dims[u]] || a.data != maskLayout[n + k + h * dims[u]].data) { done = true; break; } } if (done) { break; } } } //Add quad x[u] = i; x[v] = j; int[] du = { 0, 0, 0 }; int[] dv = { 0, 0, 0 }; var normal = new Vector3(q[0], q[1], q[2]); var aoFace = maskLayout[n].AOFace; if (!maskLayout[n].BackFace) { dv[v] = h; du[u] = w; } else { du[v] = h; dv[u] = w; normal = -normal; } var cr = ((c >> 16) & 0xff) / 255f; var cg = ((c >> 8) & 0xff) / 255f; var cb = (c & 0xff) / 255f; var ao = 0f; var AOcurve = new float[] { 0.45f, 0.65f, 0.85f, 1.0f }; var auCurveFactor = new float[] { 1f, 0.99f, 0.98f, 0.97f, 0.96f }; var aoFactor = auCurveFactor[maskLayout[n].TotalOcclusion()]; for (var o = 0; o < 4; ++o) { var pao = disableAO ? 1f : AOcurve[maskLayout[n].GetOcclusion(o)]; //vertices[o].Color = new Color(cr * pao, cg * pao, cb * pao); vertices[o].Color = new Color(cr * aoFactor, cg * aoFactor, cb * aoFactor); vertices[o].Normal = normal; ao += pao; } ao /= 4f; if (aoFace) { vertices[0].Position = new Vector3(x[0], x[1], x[2]); vertices[1].Position = new Vector3(x[0] + du[0], x[1] + du[1], x[2] + du[2]); vertices[2].Position = new Vector3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1], x[2] + du[2] + dv[2]); vertices[3].Position = new Vector3(x[0] + dv[0], x[1] + dv[1], x[2] + dv[2]); vertices[4].Position = (vertices[0].Position + vertices[1].Position + vertices[2].Position + vertices[3].Position) / 4; vertices[4].Normal = normal; vertices[4].Color = new Color(cr * ao, cg * ao, cb * ao); } else { vertices[0].Position = new Vector3(x[0], x[1], x[2]); vertices[1].Position = new Vector3(x[0] + du[0], x[1] + du[1], x[2] + du[2]); vertices[2].Position = new Vector3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1], x[2] + du[2] + dv[2]); vertices[3].Position = new Vector3(x[0] + dv[0], x[1] + dv[1], x[2] + dv[2]); } var v0 = (ushort)volume.opaqueMesh.Add(vertices[0]); var v1 = (ushort)volume.opaqueMesh.Add(vertices[1]); var v2 = (ushort)volume.opaqueMesh.Add(vertices[2]); var v3 = (ushort)volume.opaqueMesh.Add(vertices[3]); if (aoFace) { var v4 = (ushort)volume.opaqueMesh.Add(vertices[4]); volume.opaqueMesh.Triangle(v0, v4, v1); volume.opaqueMesh.Triangle(v1, v4, v2); volume.opaqueMesh.Triangle(v2, v4, v3); volume.opaqueMesh.Triangle(v3, v4, v0); } else { volume.opaqueMesh.Quad(v0, v1, v2, v3); } //Zero-out mask for (l = 0; l < h; ++l) { for (k = 0; k < w; ++k) { mask[n + k + l * dims[u]] = 0; maskLayout[n + k + l * dims[u]].data = 4095u; } } //Increment counters and continue i += w; n += w; } else { ++i; ++n; } } } } } volume.opaqueMesh.Update(); return volume.opaqueMesh.VertexCount; }
/// <summary> /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// </summary> protected override void Initialize() { // TODO: Add your initialization logic here instance = this; base.Initialize(); _chunkManager = new ChunkManager(this.GraphicsDevice); //var data = new uint[3 * 3 *3]; //for(var i =0;i < data.Length;i++){ // if((i % 4) == 0) // data[i] = 0xffffff; //} //_volume = new Volume(_chunkManager, 0, 0, 0, data, new Dimensions(new int[] { 3, 3, 3 })); sceneCamera = new Camera(this.GraphicsDevice); //float tilt = MathHelper.ToRadians(0); // 0 degree angle //// Use the world matrix to tilt the cube along x and y axes. //worldMatrix = Matrix.CreateRotationX(tilt) * Matrix.CreateRotationY(tilt); //viewMatrix = Matrix.CreateLookAt(new Vector3(zoom, zoom, zoom), Vector3.Zero, Vector3.Up); //projectionMatrix = Matrix.CreatePerspectiveFieldOfView( // MathHelper.ToRadians(45), // 45 degree angle // (float)GraphicsDevice.Viewport.Width / // (float)GraphicsDevice.Viewport.Height, // 1.0f, 10000.0f); basicEffect = new BasicEffect(graphics.GraphicsDevice); basicEffect.World = Matrix.Identity; basicEffect.View = Matrix.Identity; basicEffect.Projection = sceneCamera.Projection; // primitive color basicEffect.AmbientLightColor = new Vector3(0.1f, 0.1f, 0.1f); basicEffect.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f); basicEffect.SpecularColor = new Vector3(0.25f, 0.25f, 0.25f); basicEffect.SpecularPower = 5.0f; basicEffect.Alpha = 1.0f; basicEffect.VertexColorEnabled = true; //basicEffect.FogEnabled = true; //basicEffect.FogColor = new Vector3(0, 0, 0); //basicEffect.FogStart = 10; //basicEffect.FogEnd = 100; wireFrame = new BasicEffect(graphics.GraphicsDevice); wireFrame.World = Matrix.Identity; wireFrame.View = Matrix.Identity; wireFrame.Projection = sceneCamera.Projection; // primitive color wireFrame.AmbientLightColor = new Vector3(0.1f, 0.1f, 0.1f); wireFrame.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f); wireFrame.SpecularColor = new Vector3(0.25f, 0.25f, 0.25f); wireFrame.SpecularPower = 5.0f; wireFrame.Alpha = 1.0f; wireFrame.VertexColorEnabled = false; wireFrame.LightingEnabled = true; basicEffect.LightingEnabled = true; if (basicEffect.LightingEnabled) { basicEffect.DirectionalLight0.Enabled = true; // enable each light individually if (basicEffect.DirectionalLight0.Enabled) { // x direction basicEffect.AmbientLightColor = new Vector3(1, 1, 1); basicEffect.DirectionalLight0.DiffuseColor = new Vector3(0.1f, 0.1f, 0.1f); // range is 0 to 1 basicEffect.DirectionalLight0.Direction = Vector3.Normalize(new Vector3(-0.25f, -1, -0.5f)); // points from the light to the origin of the scene basicEffect.DirectionalLight0.SpecularColor = Vector3.Zero; //basicEffect.DirectionalLight0.SpecularColor = Vector3.One; } } mouseState = Mouse.GetState(); keyboardState = Keyboard.GetState(); //_chunkManager.Initialize(); var generator = new DefaultWorldGenerator(); world = new World(GraphicsDevice, 192, 128); world.Generate(generator); arialFont = Content.Load<SpriteFont>("fonts/arial"); voxelEffect = Content.Load<Effect>("shaders/voxelshader"); selection = new VoxelVolume(this.GraphicsDevice, new Dimensions(new int[] { world.Size, 1, world.Size })); }