/// <summary> /// Loads this SBM model /// </summary> /// <returns></returns> public bool Load(out string err) { // Check the file exists if (!File.Exists(filename)) { err = "File not found"; return false; } // Load it using (FileStream strm = File.OpenRead(filename)) { // Create reader BinaryReader rdr = new BinaryReader(strm); // Read header string magic = new string(rdr.ReadChars(4)); if (magic != "SBM\0") { err = "Specified file is not an SBM file"; return false; } int version = rdr.ReadInt32(); if (version != 1) { err = "Unsupported SBM version"; return false; } int num_materials = rdr.ReadInt32(); int num_meshes = rdr.ReadInt32(); // Read all materials string[] materials = new string[num_materials]; for (int i = 0; i < num_materials; i++) materials[i] = rdr.ReadNullTerminatedString(); // Read all meshes meshes = new SBMMesh[num_meshes]; for (int i = 0; i < num_meshes; i++) { // Read mesh header int num_vertices = rdr.ReadInt32(); int num_submeshes = rdr.ReadInt32(); // Create mesh builder MeshBuilder builder = new MeshBuilder(); builder.UseNormals = true; builder.UseTexCoords = true; builder.UseTangents = true; // Read all vertices for (int j = 0; j < num_vertices; j++) { builder.AddPosition(new Vector3(rdr.ReadSingle(), rdr.ReadSingle(), rdr.ReadSingle())); builder.AddNormal(new Vector3(rdr.ReadSingle(), rdr.ReadSingle(), rdr.ReadSingle())); builder.AddTextureCoord(new Vector2(rdr.ReadSingle(), rdr.ReadSingle())); builder.AddTangent(new Vector3(rdr.ReadSingle(), rdr.ReadSingle(), rdr.ReadSingle())); } // Loop each submesh string[] meshmats = new string[num_submeshes]; for (int j = 0; j < num_submeshes; j++) { // Read submesh header int num_indices = rdr.ReadInt32(); int material_index = rdr.ReadInt32(); meshmats[j] = materials[material_index]; // Read all indices for (int k = 0; k < num_indices; k++) builder.AddIndex(j, rdr.ReadUInt32()); } // Add element to mesh array SBMMesh sbmmesh = new SBMMesh(); sbmmesh.Mesh = builder.Build(); sbmmesh.Materials = meshmats; meshes[i] = sbmmesh; } } // Success err = null; return true; }
private static void MergeMeshes(SBMLoader loader, out Mesh result, out string[] materials) { if (loader.MeshCount == 0) { result = null; materials = null; return; } if (loader.MeshCount == 1) { loader.GetMesh(0, out result, out materials); return; } List<string> finalmaterials = new List<string>(); MeshBuilder merged = new MeshBuilder(); merged.UseNormals = true; merged.UseTangents = true; merged.UseTexCoords = true; int totalsubmeshes = 0; for (int i = 0; i < loader.MeshCount; i++) { Mesh cmesh; string[] curmats; loader.GetMesh(i, out cmesh, out curmats); totalsubmeshes += cmesh.Submeshes.Length; int baseindex = merged.CurrentVertexCount; merged.AddPositions(cmesh.Positions); merged.AddNormals(cmesh.Normals); merged.AddTextureCoords(cmesh.TextureCoordinates); merged.AddTangents(cmesh.Tangents); for (int j = 0; j < cmesh.Submeshes.Length; j++) { int submeshindex; if (finalmaterials.Contains(curmats[j])) submeshindex = finalmaterials.IndexOf(curmats[j]); else { submeshindex = finalmaterials.Count; finalmaterials.Add(curmats[j]); } merged.AddIndices(submeshindex, cmesh.Submeshes[j], (uint)baseindex); } } Console.WriteLine("Merged {0} meshes with a total of {1} submeshes into 1 mesh with a total of {2} submeshes.", loader.MeshCount, totalsubmeshes, finalmaterials.Count); result = merged.Build(); materials = finalmaterials.ToArray(); }
public static Mesh CombineMeshes(params Mesh[] meshes) { MeshBuilder builder = new MeshBuilder(); if (meshes[0].TextureCoordinates != null) builder.UseTexCoords = true; if (meshes[0].Normals != null) builder.UseNormals = true; uint indexpos = 0; for (int i = 0; i < meshes.Length; i++) { var mesh = meshes[i]; if (builder.UseTexCoords) builder.AddTextureCoords(mesh.TextureCoordinates); if (builder.UseNormals) builder.AddNormals(mesh.Normals); for (int j = 0; j < mesh.Submeshes.Length; j++) builder.AddIndices(j, mesh.Submeshes[j]); builder.AddPositions(mesh.Positions); indexpos += (uint)mesh.Positions.Length; } return builder.Build(); }
public static Mesh BuildCube() { // Create mesh builder MeshBuilder builder = new MeshBuilder(); builder.UseTexCoords = true; builder.UseNormals = true; // X facing sides builder.AddQuad(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f), new Vector3(0.0f, 1.0f, 1.0f), new Vector3(0.0f, 1.0f, 0.0f), new Vector2(1.0f, 1.0f), new Vector2(0.0f, 1.0f), new Vector2(0.0f, 0.0f), new Vector2(1.0f, 0.0f), false); builder.AddQuad(new Vector3(1.0f, 0.0f, 0.0f), new Vector3(1.0f, 0.0f, 1.0f), new Vector3(1.0f, 1.0f, 1.0f), new Vector3(1.0f, 1.0f, 0.0f), new Vector2(0.0f, 1.0f), new Vector2(1.0f, 1.0f), new Vector2(1.0f, 0.0f), new Vector2(0.0f, 0.0f), true); // Y facing sides builder.AddQuad(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f), new Vector3(1.0f, 0.0f, 1.0f), new Vector3(0.0f, 0.0f, 1.0f), new Vector2(0.0f, 0.0f), new Vector2(1.0f, 0.0f), new Vector2(1.0f, 1.0f), new Vector2(0.0f, 1.0f), false); builder.AddQuad(new Vector3(0.0f, 1.0f, 0.0f), new Vector3(1.0f, 1.0f, 0.0f), new Vector3(1.0f, 1.0f, 1.0f), new Vector3(0.0f, 1.0f, 1.0f), new Vector2(1.0f, 0.0f), new Vector2(0.0f, 0.0f), new Vector2(0.0f, 1.0f), new Vector2(1.0f, 1.0f), true); // Z facing sides builder.AddQuad(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f), new Vector3(1.0f, 1.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f), new Vector2(0.0f, 1.0f), new Vector2(0.0f, 0.0f), new Vector2(1.0f, 0.0f), new Vector2(1.0f, 1.0f), false); builder.AddQuad(new Vector3(0.0f, 0.0f, 1.0f), new Vector3(0.0f, 1.0f, 1.0f), new Vector3(1.0f, 1.0f, 1.0f), new Vector3(1.0f, 0.0f, 1.0f), new Vector2(1.0f, 1.0f), new Vector2(1.0f, 0.0f), new Vector2(0.0f, 0.0f), new Vector2(0.0f, 1.0f), true); // Done return builder.Build(); }
public static Mesh BuildSkybox() { MeshBuilder builder = new MeshBuilder(); builder.AddPosition(new Vector3(-1.0f, -1.0f, -1.0f)); // 0 builder.AddPosition(new Vector3(-1.0f, -1.0f, 1.0f)); // 1 builder.AddPosition(new Vector3(1.0f, -1.0f, 1.0f)); // 2 builder.AddPosition(new Vector3(1.0f, -1.0f, -1.0f)); // 3 builder.AddPosition(new Vector3(-1.0f, 1.0f, -1.0f)); // 4 builder.AddPosition(new Vector3(-1.0f, 1.0f, 1.0f)); // 5 builder.AddPosition(new Vector3(1.0f, 1.0f, 1.0f)); // 6 builder.AddPosition(new Vector3(1.0f, 1.0f, -1.0f)); // 7 // North builder.AddIndex(1); builder.AddIndex(5); builder.AddIndex(6); builder.AddIndex(6); builder.AddIndex(2); builder.AddIndex(1); // East builder.AddIndex(2); builder.AddIndex(6); builder.AddIndex(7); builder.AddIndex(7); builder.AddIndex(3); builder.AddIndex(2); // South builder.AddIndex(3); builder.AddIndex(7); builder.AddIndex(4); builder.AddIndex(4); builder.AddIndex(0); builder.AddIndex(3); // West builder.AddIndex(0); builder.AddIndex(4); builder.AddIndex(5); builder.AddIndex(5); builder.AddIndex(2); builder.AddIndex(0); // Up builder.AddIndex(5); builder.AddIndex(4); builder.AddIndex(7); builder.AddIndex(7); builder.AddIndex(6); builder.AddIndex(5); // Down builder.AddIndex(0); builder.AddIndex(1); builder.AddIndex(2); builder.AddIndex(2); builder.AddIndex(3); builder.AddIndex(0); // Build mesh return builder.Build(); }
public static Mesh BuildSphere(float radius, int subdivisions, bool usetexcoords, bool usetangents) { // Starting points var A = new Vector3(-1.0f, -(1.0f / Root3), -(1.0f / Root6)); var B = new Vector3(0.0f, 2.0f / Root3, -1.0f / Root6); var C = new Vector3(1.0f, -(1.0f / Root3), -(1.0f / Root6)); var D = new Vector3(0.0f, 0.0f, 3.0f / Root6); // Build a triangular based pyramid var tris = new List<Triangle>(); tris.Add(new Triangle(A, B, C)); tris.Add(new Triangle(C, D, A)); tris.Add(new Triangle(B, D, C)); tris.Add(new Triangle(A, D, B)); var tmplist = new List<Triangle>(); // Run subdivide passes for (int i = 0; i < subdivisions; i++) { // Normalise all vertices for (int j = 0; j < tris.Count; j++) { Triangle tri = tris[j]; tri.A.Normalize(); tri.A *= radius; tri.B.Normalize(); tri.B *= radius; tri.C.Normalize(); tri.C *= radius; tris[j] = tri; } // Check for last pass if (i == subdivisions - 1) break; // Subdivide all triangles tmplist.Clear(); for (int j = 0; j < tris.Count; j++) { Triangle tri = tris[j]; Vector3 midAB = (tri.A + tri.B) * 0.5f; Vector3 midBC = (tri.B + tri.C) * 0.5f; Vector3 midCA = (tri.C + tri.A) * 0.5f; tmplist.Add(new Triangle(tri.A, midAB, midCA)); tmplist.Add(new Triangle(midAB, midBC, midCA)); tmplist.Add(new Triangle(midCA, midBC, tri.C)); tmplist.Add(new Triangle(midAB, tri.B, midBC)); } // Swap the lists var tmp = tris; tris = tmplist; tmplist = tmp; } // Create builder var builder = new MeshBuilder(); builder.UseNormals = true; builder.UseTexCoords = usetexcoords; builder.UseTangents = usetangents; for (int i = 0; i < tris.Count; i++) { Triangle tri = tris[i]; builder.AddPosition(tri.A); builder.AddPosition(tri.B); builder.AddPosition(tri.C); builder.AddNormal(GetNormal(tri.A)); builder.AddNormal(GetNormal(tri.B)); builder.AddNormal(GetNormal(tri.C)); if (usetangents) { builder.AddTangent(GetSphereTangent(tri.A)); builder.AddTangent(GetSphereTangent(tri.B)); builder.AddTangent(GetSphereTangent(tri.C)); } if (usetexcoords) { // TODO: This builder.AddTextureCoord(new Vector2(0.0f, 0.0f)); builder.AddTextureCoord(new Vector2(0.0f, 0.0f)); builder.AddTextureCoord(new Vector2(0.0f, 0.0f)); } builder.AddIndex((ushort)(i * 3)); builder.AddIndex((ushort)(i * 3 + 1)); builder.AddIndex((ushort)(i * 3 + 2)); } // Create mesh return builder.Build(); }
public static Mesh BuildPlane(bool texcoords, bool tangents) { // Create mesh builder MeshBuilder builder = new MeshBuilder(); builder.UseNormals = true; builder.UseTexCoords = texcoords; builder.UseTangents = tangents; // Add vertices builder.AddPosition(new Vector3(0.0f, 0.0f, 0.0f)); builder.AddPosition(new Vector3(0.0f, 0.0f, 1.0f)); builder.AddPosition(new Vector3(1.0f, 0.0f, 1.0f)); builder.AddPosition(new Vector3(1.0f, 0.0f, 0.0f)); builder.AddNormal(Vector3.UnitY); builder.AddNormal(Vector3.UnitY); builder.AddNormal(Vector3.UnitY); builder.AddNormal(Vector3.UnitY); if (texcoords) { builder.AddTextureCoord(new Vector2(0.0f, 1.0f)); builder.AddTextureCoord(new Vector2(1.0f, 1.0f)); builder.AddTextureCoord(new Vector2(1.0f, 0.0f)); builder.AddTextureCoord(new Vector2(0.0f, 0.0f)); } if (tangents) { builder.AddTangent(new Vector3(1.0f, 0.0f, 0.0f)); builder.AddTangent(new Vector3(1.0f, 0.0f, 0.0f)); builder.AddTangent(new Vector3(1.0f, 0.0f, 0.0f)); builder.AddTangent(new Vector3(1.0f, 0.0f, 0.0f)); } // Add indices builder.AddIndex(0); builder.AddIndex(1); builder.AddIndex(2); builder.AddIndex(2); builder.AddIndex(3); builder.AddIndex(0); // Build mesh return builder.Build(); }
public static Mesh BuildNormalDebugger(Mesh mesh) { if (mesh.Normals == null) return null; MeshBuilder builder = new MeshBuilder(); for (int i = 0; i < mesh.Normals.Length; i++) { builder.AddPosition(mesh.Positions[i]); builder.AddPosition(mesh.Positions[i] + mesh.Normals[i]); } return builder.Build(); }
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(); }
public static void BuildGrassPatch(int points, float range, out Mesh high, out Mesh medium, out Mesh low) { Random rnd = new Random(); MeshBuilder builder = new MeshBuilder(); builder.UseNormals = true; for (int i = 0; i < points; i++) { builder.AddPosition(new Vector3((float)rnd.NextDouble() * range, 0.0f, (float)rnd.NextDouble() * range)); builder.AddNormal(new Vector3((float)(rnd.NextDouble() * Math.PI * 2.0), (float)rnd.NextDouble(), (float)rnd.NextDouble())); } high = builder.Build(); builder.RemovePoints(points / 3); medium = builder.Build(); builder.RemovePoints(points / 3); low = builder.Build(); }
public static Mesh BuildFullscreenQuad() { // Create mesh builder MeshBuilder builder = new MeshBuilder(); builder.UseTexCoords = true; // Add vertices builder.AddPosition(new Vector3(-1.0f, -1.0f, 0.5f)); builder.AddPosition(new Vector3(1.0f, -1.0f, 0.5f)); builder.AddPosition(new Vector3(1.0f, 1.0f, 0.5f)); builder.AddPosition(new Vector3(-1.0f, 1.0f, 0.5f)); builder.AddTextureCoord(new Vector2(0.0f, 1.0f)); builder.AddTextureCoord(new Vector2(1.0f, 1.0f)); builder.AddTextureCoord(new Vector2(1.0f, 0.0f)); builder.AddTextureCoord(new Vector2(0.0f, 0.0f)); // Add indices builder.AddIndex(0); builder.AddIndex(1); builder.AddIndex(2); builder.AddIndex(2); builder.AddIndex(3); builder.AddIndex(0); // Build mesh return builder.Build(); }