/// <summary> /// Creates the cornell box. /// </summary> /// <param name="roomSize">Size of the room.</param> /// <param name="sphereRadius">The sphere radius.</param> /// <param name="cubeSize">Size of the cube.</param> /// <returns></returns> public static DefaultMesh CreateCornellBox(float roomSize = 2, float sphereRadius = 0.3f, float cubeSize = 0.6f) { var mesh = new DefaultMesh(); //off-center plane var plane = CreatePlane(roomSize, roomSize, 2, 2).Transform(Transformation.Translation(0, -roomSize / 2, 0)); plane.SetConstantUV(new Vector2(0, 0)); mesh.Add(plane); //bottom //rotate plane repeatedly to create box mesh.Add(plane.Transform(Transformation.Rotation(90f, Axis.X))); //front mesh.Add(plane.Transform(Transformation.Rotation(-90f, Axis.X))); //back plane.SetConstantUV(new Vector2(1, 0)); mesh.Add(plane.Transform(Transformation.Rotation(90f, Axis.Z))); //right plane.SetConstantUV(new Vector2(2, 0)); mesh.Add(plane.Transform(Transformation.Rotation(270f, Axis.Z))); //left plane.SetConstantUV(new Vector2(0, 0)); mesh.Add(plane.Transform(Transformation.Rotation(180f, Axis.Z))); //top var sphere = CreateSphere(sphereRadius, 4); sphere.SetConstantUV(new Vector2(3, 0)); mesh.Add(sphere.Transform(Transformation.Translation(0.4f, -1 + sphereRadius, -0.2f))); var cube = CreateCubeWithNormals(cubeSize); var translateAndRotY = Transformation.Combine(Transformation.Rotation(35f, Axis.Y), Transformation.Translation(-0.5f, -1 + 0.5f * cubeSize, 0.1f)); cube.SetConstantUV(new Vector2(3, 0)); mesh.Add(cube.Transform(translateAndRotY)); return(mesh); }
/// <summary> /// Adds the specified b. /// </summary> /// <param name="a">a.</param> /// <param name="b">The b.</param> /// <exception cref="ArgumentException">Original mesh has no normals, but added mesh has normals /// or /// Original mesh has no uvs, but added mesh has uvs</exception> public static void Add(this DefaultMesh a, DefaultMesh b) { var count = (uint)a.Position.Count; a.Position.AddRange(b.Position); if (b.Normal.Count > 0) { if (a.Normal.Count != count) { throw new ArgumentException("Original mesh has no normals, but added mesh has normals"); } a.Normal.AddRange(b.Normal); } if (b.TexCoord.Count > 0) { if (a.TexCoord.Count != count) { throw new ArgumentException("Original mesh has no uvs, but added mesh has uvs"); } a.TexCoord.AddRange(b.TexCoord); } foreach (var id in b.IDs) { a.IDs.Add(id + count); } }
/// <summary> /// Creates a cube made up of pairs of triangles; stored as an indexed vertex array /// </summary> /// <param name="size">length of one side</param> /// <returns> /// Mesh with positions, ids, normals /// </returns> public static DefaultMesh CreateCubeWithNormals(float size = 1.0f) { var m = new DefaultMesh(); void createPosition(float x, float y, float z) => m.Position.Add(new Vector3(x, y, z)); void createID(uint index) => m.IDs.Add(index); void createNormal(float x, float y, float z) => m.Normal.Add(new Vector3(x, y, z)); ShapeBuilder.Cube(createPosition, createID, size, createNormal); return(m); }
/// <summary> /// creates a sphere made up of pairs of triangles; stored as an indexed vertex array /// </summary> /// <param name="radius">radius</param> /// <param name="subdivision">subdivision count, each subdivision creates 4 times more faces</param> /// <returns> /// Mesh with positions, ids, normals /// </returns> public static DefaultMesh CreateSphere(float radius = 1.0f, uint subdivision = 1) { var m = new DefaultMesh(); //var pos = m.AddAttribute<Vector3>(Mesh.PositionName); //var normal = m.AddAttribute<Vector3>(Mesh.NormalName); void createPosition(float x, float y, float z) => m.Position.Add(new Vector3(x, y, z)); void createID(uint id) => m.IDs.Add(id); void createNormal(float x, float y, float z) => m.Normal.Add(new Vector3(x, y, z)); ShapeBuilder.Sphere(createPosition, createID, radius, subdivision, createNormal); return(m); }
/// <summary> /// Flips the normals. /// </summary> /// <param name="m">The m.</param> /// <returns></returns> public static DefaultMesh FlipNormals(this DefaultMesh m) { var mesh = new DefaultMesh(); mesh.Position.AddRange(m.Position); mesh.TexCoord.AddRange(m.TexCoord); mesh.IDs.AddRange(m.IDs); foreach (var n in m.Normal) { var newN = -n; mesh.Normal.Add(newN); } return(mesh); }
/// <summary> /// Switches the triangle mesh winding. /// </summary> /// <param name="m">The m.</param> /// <returns></returns> public static DefaultMesh SwitchTriangleMeshWinding(this DefaultMesh m) { var mesh = new DefaultMesh(); mesh.Position.AddRange(m.Position); mesh.Normal.AddRange(m.Normal); mesh.TexCoord.AddRange(m.TexCoord); for (int i = 0; i < m.IDs.Count; i += 3) { mesh.IDs.Add(m.IDs[i]); mesh.IDs.Add(m.IDs[i + 2]); mesh.IDs.Add(m.IDs[i + 1]); } return(mesh); }
/// <summary> /// Creates a plane made up of pairs of triangles; stored as an indexed vertex array. /// </summary> /// <param name="sizeX">extent of the grid in the x-coordinate axis</param> /// <param name="sizeZ">extent of the grid in the z-coordinate axis</param> /// <param name="segmentsX">number of grid segments in the x-coordinate axis</param> /// <param name="segmentsZ">number of grid segments in the z-coordinate axis</param> /// <returns> /// Mesh with positions, ids, normals, and uvs /// </returns> public static DefaultMesh CreatePlane(float sizeX, float sizeZ, uint segmentsX, uint segmentsZ) { var m = new DefaultMesh(); void CreateVertex(float x, float z) => m.Position.Add(new Vector3(x, 0.0f, z)); void CreateID(uint id) => m.IDs.Add(id); void CreateNormal() => m.Normal.Add(Vector3.UnitY); void CreateUV(float u, float v) => m.TexCoord.Add(new Vector2(u, v)); var startX = -sizeX / 2f; var startZ = -sizeZ / 2f; ShapeBuilder.Grid(startX, sizeX, startZ, sizeZ, segmentsX, segmentsZ, CreateVertex, CreateID , CreateNormal, CreateUV); return(m); }
/// <summary> /// Sets the constant uv. /// </summary> /// <param name="mesh">The mesh.</param> /// <param name="uv">The uv.</param> public static void SetConstantUV(this DefaultMesh mesh, Vector2 uv) { var uvs = mesh.TexCoord; var pos = mesh.Position; uvs.Capacity = pos.Count; //overwrite existing for (int i = 0; i < uvs.Count; ++i) { uvs[i] = uv; } //add for (int i = uvs.Count; i < pos.Count; ++i) { uvs.Add(uv); } }
/// <summary> /// Transforms the mesh by the specified transform. /// </summary> /// <param name="mesh">The mesh to transform.</param> /// <param name="transformation">The transformation.</param> /// <returns></returns> public static DefaultMesh Transform(this DefaultMesh mesh, Transformation transformation) { var newMesh = new DefaultMesh(); newMesh.TexCoord.AddRange(mesh.TexCoord); newMesh.IDs.AddRange(mesh.IDs); foreach (var pos in mesh.Position) { var newPos = transformation.Transform(pos); newMesh.Position.Add(newPos); } foreach (var n in mesh.Normal) { var newN = Vector3.Normalize(Vector3.TransformNormal(n, transformation.Matrix)); newMesh.Normal.Add(newN); } return(newMesh); }
/// <summary> /// Transforms the specified transform. /// </summary> /// <param name="m">The m.</param> /// <param name="transform">The transform.</param> /// <returns></returns> public static DefaultMesh Transform(this DefaultMesh m, Matrix4x4 transform) { var mesh = new DefaultMesh(); mesh.TexCoord.AddRange(m.TexCoord); mesh.IDs.AddRange(m.IDs); foreach (var pos in m.Position) { var newPos = Vector3.Transform(pos, transform); mesh.Position.Add(newPos); } foreach (var n in m.Normal) { var newN = Vector3.Normalize(Vector3.TransformNormal(n, transform)); mesh.Normal.Add(newN); } return(mesh); }
/// <summary> /// Switches the handedness. /// </summary> /// <param name="m">The m.</param> /// <returns></returns> public static DefaultMesh SwitchHandedness(this DefaultMesh m) { var mesh = new DefaultMesh(); mesh.TexCoord.AddRange(m.TexCoord); mesh.IDs.AddRange(m.IDs); foreach (var pos in m.Position) { var newPos = pos; newPos.Z = -newPos.Z; mesh.Position.Add(newPos); } foreach (var n in m.Normal) { var newN = n; newN.Z = -newN.Z; mesh.Normal.Add(newN); } return(mesh); }
/// <summary> /// Creates a <see cref="DefaultMesh"/>from a byte array. /// </summary> /// <param name="objByteData">The byte data.</param> /// <returns></returns> public static DefaultMesh FromObj(byte[] objByteData) { var parser = new ObjParser(new MemoryStream(objByteData)); var uniqueVertexIDs = new Dictionary <ObjParser.Vertex, uint>(new VertexComparer()); var mesh = new DefaultMesh(); foreach (var face in parser.faces) { //only accept triangles if (3 != face.Count) { continue; } foreach (var vertex in face) { if (uniqueVertexIDs.TryGetValue(vertex, out uint index)) { mesh.IDs.Add(index); } else { uint id = (uint)mesh.Position.Count; //add vertex data to mesh mesh.Position.Add(parser.position[vertex.idPos]); if (-1 != vertex.idNormal) { mesh.Normal.Add(parser.normals[vertex.idNormal]); } if (-1 != vertex.idTexCoord) { mesh.TexCoord.Add(parser.texCoords[vertex.idTexCoord]); } mesh.IDs.Add(id); //new id uniqueVertexIDs[vertex] = id; } } } return(mesh); }
/// <summary> /// Creates the cornell box. /// </summary> /// <param name="roomSize">Size of the room.</param> /// <param name="sphereRadius">The sphere radius.</param> /// <param name="cubeSize">Size of the cube.</param> /// <returns></returns> public static DefaultMesh CreateCornellBox(float roomSize = 2, float sphereRadius = 0.3f, float cubeSize = 0.6f) { var mesh = new DefaultMesh(); var plane = CreatePlane(roomSize, roomSize, 2, 2); var xform = new Transformation(); xform.TranslateGlobal(0, -roomSize / 2, 0); plane.SetConstantUV(new Vector2(3, 0)); mesh.Add(plane.Transform(xform)); xform.RotateZGlobal(90f); plane.SetConstantUV(new Vector2(1, 0)); mesh.Add(plane.Transform(xform)); xform.RotateZGlobal(90f); plane.SetConstantUV(new Vector2(0, 0)); mesh.Add(plane.Transform(xform)); xform.RotateZGlobal(90f); plane.SetConstantUV(new Vector2(2, 0)); mesh.Add(plane.Transform(xform)); xform.RotateYGlobal(270f); plane.SetConstantUV(new Vector2(0, 0)); mesh.Add(plane.Transform(xform)); var sphere = Meshes.CreateSphere(sphereRadius, 4); sphere.SetConstantUV(new Vector2(3, 0)); xform.Reset(); xform.TranslateGlobal(0.4f, -1 + sphereRadius, -0.2f); mesh.Add(sphere.Transform(xform)); var cube = Meshes.CreateCubeWithNormals(cubeSize); cube.SetConstantUV(new Vector2(3, 0)); xform.Reset(); xform.RotateYGlobal(35f); xform.TranslateGlobal(-0.5f, -1 + 0.5f * cubeSize, 0.1f); mesh.Add(cube.Transform(xform)); return(mesh); }
/// <summary> /// Transforms the mesh by the specified transform. /// </summary> /// <param name="mesh">The mesh to transform.</param> /// <param name="transform">The transformation.</param> /// <returns></returns> public static DefaultMesh Transform(this DefaultMesh mesh, Transformation3D transform) { if (transform is null) { throw new ArgumentNullException(nameof(transform)); } var matrix = transform.CalcLocalToWorldRowMajorMatrix(); var newMesh = new DefaultMesh(); newMesh.TexCoord.AddRange(mesh.TexCoord); newMesh.IDs.AddRange(mesh.IDs); foreach (var pos in mesh.Position) { var newPos = Vector3.Transform(pos, matrix); newMesh.Position.Add(newPos); } foreach (var n in mesh.Normal) { var newN = Vector3.Normalize(Vector3.TransformNormal(n, matrix)); newMesh.Normal.Add(newN); } return(newMesh); }
/// <summary> /// Sets the constant uv. /// </summary> /// <param name="mesh">The mesh.</param> /// <param name="uv">The uv.</param> public static void SetConstantUV(this DefaultMesh mesh, in Vector2 uv)