static VoxelData Read(BinaryReader reader) { var magic = reader.ReadUInt32(); var version = reader.ReadInt32(); if (magic != VOX_) { return(null); } var voxelData = null as VoxelData; var colors = null as Color[]; while (reader.PeekChar() != -1) { var chunkId = reader.ReadUInt32(); var chunkSize = reader.ReadInt32(); var childChunks = reader.ReadInt32(); switch (chunkId) { case SIZE: var sx = reader.ReadInt32(); var sy = reader.ReadInt32(); var sz = reader.ReadInt32(); reader.ReadBytes(chunkSize - sizeof(int) * 3); voxelData = new VoxelData(new XYZ(sx, sy, sz), new Color[256]); break; case XYZI: var n = reader.ReadInt32(); for (var i = 0; i < n; ++i) { var x = reader.ReadByte(); var y = reader.ReadByte(); var z = reader.ReadByte(); var c = reader.ReadByte(); voxelData[new XYZ(x, y, z)] = new Voxel() { Index = c }; } break; case RGBA: colors = new Color[256]; // last color is not used, so we only need to read 255 colors for (var i = 1; i < 256; ++i) { byte r = reader.ReadByte(); byte g = reader.ReadByte(); byte b = reader.ReadByte(); byte a = reader.ReadByte(); voxelData.Colors[i] = new Color(r, g, b, a); } // NOTICE : skip the last reserved color reader.ReadUInt32(); break; default: reader.ReadBytes(chunkSize); break; } } if (voxelData != null && colors == null) { for (var i = 0; i < DefaultColors.Length; ++i) { voxelData.Colors[i] = new Color(DefaultColors[i]); } } return(voxelData); }
void RenderQuad(VoxelData voxelData, XYZ p, Color color, float lightLevel, XYZ faceUp) { // Only render quad if face it isn't hidden by voxel above it if (voxelData[p + faceUp].Index == 0) { // Calculate adjacent voxels var adjacent = new XYZ[] { XYZ.Zero, XYZ.Zero, XYZ.Zero, XYZ.Zero }; if (faceUp == -XYZ.OneX) { adjacent = new[] { XYZ.OneY, XYZ.OneZ, -XYZ.OneY, -XYZ.OneZ }; } if (faceUp == -XYZ.OneY) { adjacent = new[] { XYZ.OneZ, XYZ.OneX, -XYZ.OneZ, -XYZ.OneX }; } if (faceUp == -XYZ.OneZ) { adjacent = new[] { XYZ.OneX, XYZ.OneY, -XYZ.OneX, -XYZ.OneY }; } if (faceUp == XYZ.OneX) { adjacent = new[] { XYZ.OneZ, XYZ.OneY, -XYZ.OneZ, -XYZ.OneY }; } if (faceUp == XYZ.OneY) { adjacent = new[] { XYZ.OneX, XYZ.OneZ, -XYZ.OneX, -XYZ.OneZ }; } if (faceUp == XYZ.OneZ) { adjacent = new[] { XYZ.OneY, XYZ.OneX, -XYZ.OneY, -XYZ.OneX }; } // Calculate ambient occlusion vertex colors var a00 = AmbientOcclusion.CalculateAO(voxelData, p, adjacent[0], adjacent[1], faceUp); var a01 = AmbientOcclusion.CalculateAO(voxelData, p, adjacent[1], adjacent[2], faceUp); var a11 = AmbientOcclusion.CalculateAO(voxelData, p, adjacent[2], adjacent[3], faceUp); var a10 = AmbientOcclusion.CalculateAO(voxelData, p, adjacent[3], adjacent[0], faceUp); // Ignore shadow face there is no occlusion if (p.Z == -1 && (a00 + a01 + a11 + a10) == 12) { return; } // Store vertex colors colors.AddRange(new[] { color *lightLevel, color *lightLevel, color *lightLevel, color *lightLevel }); // Calculate occlusion values occlusion.Add(AmbientOcclusion.AOToOcclusion(a00)); occlusion.Add(AmbientOcclusion.AOToOcclusion(a01)); occlusion.Add(AmbientOcclusion.AOToOcclusion(a11)); occlusion.Add(AmbientOcclusion.AOToOcclusion(a10)); // Calculate quad vertices based on adjacent voxels var v0 = p + (adjacent[0] + adjacent[1] + faceUp + XYZ.One) / 2; var v1 = p + (adjacent[1] + adjacent[2] + faceUp + XYZ.One) / 2; var v2 = p + (adjacent[2] + adjacent[3] + faceUp + XYZ.One) / 2; var v3 = p + (adjacent[3] + adjacent[0] + faceUp + XYZ.One) / 2; var n = vertices.Count; vertices.AddRange(new[] { v0, v1, v2, v3 }); // Populate Normals normals.AddRange(new[] { faceUp, faceUp, faceUp, faceUp }); // Add face primitives for MeshType var i0 = (n + 0); var i1 = (n + 1); var i2 = (n + 2); var i3 = (n + 3); switch (settings.MeshType) { case MeshType.Triangles: // Change quad -> triangle face orientation based on ambient occlusion if (a00 + a11 <= a01 + a10) { faces.AddRange(new[] { i1, i2, i3, i3, i0, i1 }); } else { faces.AddRange(new[] { i0, i1, i2, i2, i3, i0 }); } break; case MeshType.Quads: faces.AddRange(new [] { i0, i1, i2, i3 }); break; } } }
public static void Write(Stream stream, VoxelData voxelData) { Write(new BinaryWriter(stream), voxelData); }
public MeshBuilder(VoxelData voxelData, MeshSettings settings) { this.settings = settings; CreateMesh(voxelData); }