public Capsule(Vector3 p0, Vector3 p1, Single radius) { ModelMeshPart mesh = new ModelMeshPart(); int segments = 10; // Higher numbers improve quality radius = 3; // The radius (width) of the cylinder int height = 10; // The height of the cylinder var vertices = new List<Vector3>(); for (double y = 0; y < 2; y++) { for (double x = 0; x < segments; x++) { double theta = (x / (segments - 1)) * 2 * Math.PI; vertices.Add(new Vector3() { X = (float)(radius * Math.Cos(theta)), Y = (float)(height * y), Z = (float)(radius * Math.Sin(theta)), }); } } var indices = new List<int>(); for (int x = 0; x < segments - 1; x++) { indices.Add(x); indices.Add(x + segments); indices.Add(x + segments + 1); indices.Add(x + segments + 1); indices.Add(x + 1); indices.Add(x); } }
public Sphere(Single radius, int stacks = 15, int slices = 15) { ModelMeshPart meshpart = new ModelMeshPart(); // TODO: Correctly assign normals and UVs for (int t = 0; t < stacks; t++) { Single theta1 = ((Single)(t) / stacks) * (Single)Math.PI; Single theta2 = ((Single)(t + 1) / stacks) * (Single)Math.PI; for (int p = 0; p < slices; p++) { Single phi1 = ((Single)(p) / slices) * 2 * (Single)Math.PI; Single phi2 = ((Single)(p + 1) / slices) * 2 * (Single)Math.PI; var n1 = new Vector3( (Single)(Math.Sin(theta1) * Math.Cos(phi1)), (Single)(Math.Cos(theta1)), (Single)(Math.Sin(theta1) * Math.Sin(phi1)) ); var n2 = new Vector3( (Single)(Math.Sin(theta1) * Math.Cos(phi2)), (Single)(Math.Cos(theta1)), (Single)(Math.Sin(theta1) * Math.Sin(phi2)) ); var n3 = new Vector3( (Single)(Math.Sin(theta2) * Math.Cos(phi2)), (Single)(Math.Cos(theta2)), (Single)(Math.Sin(theta2) * Math.Sin(phi2)) ); var n4 = new Vector3( (Single)(Math.Sin(theta2) * Math.Cos(phi1)), (Single)(Math.Cos(theta2)), (Single)(Math.Sin(theta2) * Math.Sin(phi1)) ); var p1 = n1 * radius; var p2 = n2 * radius; var p3 = n3 * radius; var p4 = n4 * radius; var uv1 = new Vector2( 0.5f + (Single)Math.Atan2(-p1.Z, p1.X) / MathHelper.TwoPi, 0.5f - (Single)Math.Asin(p1.Y) / MathHelper.Pi ); var uv2 = new Vector2( 0.5f + (Single)Math.Atan2(-p2.Z, p2.X) / MathHelper.TwoPi, 0.5f - (Single)Math.Asin(p2.Y) / MathHelper.Pi ); var uv3 = new Vector2( 0.5f + (Single)Math.Atan2(-p3.Z, p3.X) / MathHelper.TwoPi, 0.5f - (Single)Math.Asin(p3.Y) / MathHelper.Pi ); var uv4 = new Vector2( 0.5f + (Single)Math.Atan2(-p4.Z, p4.X) / MathHelper.TwoPi, 0.5f - (Single)Math.Asin(p4.Y) / MathHelper.Pi ); if (t == 0) { meshpart.AddFace( new Vector3[] { p1, p3, p4 }, new Vector3[] { n1, n3, n4 }, new Vector2[] { uv1, uv3, uv4 } ); } else if (t + 1 == stacks) { meshpart.AddFace( new Vector3[] { p3, p1, p2 }, new Vector3[] { n3, n1, n2 }, new Vector2[] { uv3, uv1, uv2 } ); } else { meshpart.AddFace( new Vector3[] { p1, p2, p4 }, new Vector3[] { n1, n2, n4 }, new Vector2[] { uv1, uv2, uv4 } ); meshpart.AddFace( new Vector3[] { p2, p3, p4 }, new Vector3[] { n2, n3, n4 }, new Vector2[] { uv2, uv3, uv4 } ); } } } //Material material = new Material { Name = "sky", Texture = new Texture() }; //SceneManager.Current.Add(material); //meshpart.Material = material; this.AddModelMeshPart(meshpart); }
public void AddModelMeshPart(ModelMeshPart meshpart, bool bFinalise = true) { if (bFinalise) { meshpart.Finalise(); } meshParts.Add(meshpart); }
public static void PreProcess(Model model, PreProcessOptions options) { if (options.HasFlag(PreProcessOptions.SplitMeshPart)) { // Specific to C:R, I'll abstract this out as and when necessary foreach (ModelMesh mesh in model.Meshes) { int partCount = mesh.MeshParts.Count; for (int i = partCount - 1; i >= 0; i--) { ModelMeshPart part = mesh.MeshParts[i]; if (part.VertexBuffer.Data.Count > 16383) { while (part.IndexBuffer.Data.Count > 0) { var buffer = part.IndexBuffer.Data; HashSet<int> usedVerts = new HashSet<int>(); int total = buffer.Count; for (int j = 0; j < buffer.Count; j += 3) { usedVerts.Add(buffer[j + 0]); usedVerts.Add(buffer[j + 1]); usedVerts.Add(buffer[j + 2]); int chunkSize = Math.Min(buffer.Count, 16383); if (j + 3 == buffer.Count || usedVerts.Count >= chunkSize) { if (usedVerts.Count == chunkSize) { j += 3; } Dictionary<int, int> indexLUT = new Dictionary<int, int>(); var newPart = new ModelMeshPart(); newPart.Material = part.Material; for (int k = 0; k < j; k++) { if (!indexLUT.ContainsKey(buffer[k])) { indexLUT.Add(buffer[k], newPart.VertexBuffer.AddVertex(part.VertexBuffer.Data[buffer[k]])); } newPart.IndexBuffer.AddIndex(indexLUT[buffer[k]]); } buffer.RemoveRange(0, j); mesh.AddModelMeshPart(newPart); SceneManager.Current.UpdateProgress(string.Format("Allocated {0:n0} of {1:n0}", j * chunkSize, total)); break; } } } mesh.MeshParts.RemoveAt(i); } } } } if (options.HasFlag(PreProcessOptions.Dedupe)) { foreach (ModelMesh mesh in model.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { part.Optimise(); } } } if (options.HasFlag(PreProcessOptions.ResolveNonManifold)) { foreach (ModelMesh mesh in model.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { Dictionary<int, int> edgeCounts = new Dictionary<int, int>(); List<int> buffer = part.IndexBuffer.Data; bool bFixedNonManifoldMesh = false; for (int i = 0; i < buffer.Count; i += 3) { int[] edges = new int[3]; for (int j = 0; j < 3; j++) { int oppositeIndex = (j + 1 < 3 ? j + 1 : 0); edges[j] = Math.Max(buffer[i + j], buffer[i + oppositeIndex]) << 24 + Math.Min(buffer[i + j], buffer[i + oppositeIndex]); if (edgeCounts.ContainsKey(edges[j])) { if (edgeCounts[edges[j]] == 2) { buffer[i + j] = part.VertexBuffer.AddVertex(part.VertexBuffer.Data[buffer[i + j]].Clone()); buffer[i + oppositeIndex] = part.VertexBuffer.AddVertex(part.VertexBuffer.Data[buffer[i + oppositeIndex]].Clone()); j--; bFixedNonManifoldMesh = true; } else { edgeCounts[edges[j]]++; } } else { edgeCounts.Add(edges[j], 1); } } } if (bFixedNonManifoldMesh) { part.IndexBuffer.Initialise(); part.VertexBuffer.Initialise(); } } } } }
public static void Normalise(ModelMeshPart model) { List<Vector3> faceNormals = new List<Vector3>(); for (int i = 0; i < model.IndexBuffer.Length; i += 3) { Vector3 v0 = model.VertexBuffer.Data[model.IndexBuffer.Data[i + 0]].Position; Vector3 v1 = model.VertexBuffer.Data[model.IndexBuffer.Data[i + 1]].Position; Vector3 v2 = model.VertexBuffer.Data[model.IndexBuffer.Data[i + 2]].Position; Vector3 u = v0 - v1; Vector3 v = v0 - v2; faceNormals.Add(Vector3.Cross(u, v).Normalized()); } for (int i = 0; i < model.VertexBuffer.Data.Count; i++) { for (int j = 0; j < model.IndexBuffer.Length; j += 3) { if (model.IndexBuffer.Data[j + 0] == i) { model.VertexBuffer.ModifyVertexNormal(i, model.VertexBuffer.Data[i].Normal + faceNormals[j / 3]); } if (model.IndexBuffer.Data[j + 1] == i) { model.VertexBuffer.ModifyVertexNormal(i, model.VertexBuffer.Data[i].Normal + faceNormals[j / 3]); } if (model.IndexBuffer.Data[j + 2] == i) { model.VertexBuffer.ModifyVertexNormal(i, model.VertexBuffer.Data[i].Normal + faceNormals[j / 3]); } } } for (int i = 0; i < model.VertexBuffer.Data.Count; i++) { model.VertexBuffer.ModifyVertexNormal(i, model.VertexBuffer.Data[i].Normal.Normalized()); } }
public void Draw() { if (Linked) { var parentTransform = ((ModelBone)link).CombinedTransform; if (linkType == LinkType.All) { transform = parentTransform; } else { transform = Matrix4.Identity; var v = parentTransform.ExtractTranslation(); parentTransform.Normalize(); parentTransform.M41 = v.X; parentTransform.M42 = v.Y; parentTransform.M43 = v.Z; if ((linkType & LinkType.Rotation) == LinkType.Rotation) { transform *= Matrix4.CreateFromQuaternion(parentTransform.ExtractRotation()); } if ((linkType & LinkType.Scale) == LinkType.Scale) { transform *= Matrix4.CreateScale(parentTransform.ExtractScale()); } if ((linkType & LinkType.Position) == LinkType.Position) { transform *= Matrix4.CreateTranslation(parentTransform.ExtractTranslation()); } } } var mS = SceneManager.Current.Transform; var mT = transform; switch (assetType) { case AssetType.Model: var model = asset as Model; if (model != null) { GL.PushMatrix(); GL.MultMatrix(ref mS); GL.MultMatrix(ref mT); model.Draw(); GL.PopMatrix(); } break; case AssetType.Sprite: if (asset == null) { var sprite = new ModelMeshPart(); sprite.AddVertex(new Vector3(-0.25f, -0.25f, 0.0f), Vector3.UnitY, new Vector2(0, 1)); sprite.AddVertex(new Vector3(-0.25f, 0.25f, 0.0f), Vector3.UnitY, new Vector2(0, 0)); sprite.AddVertex(new Vector3( 0.25f, 0.25f, 0.0f), Vector3.UnitY, new Vector2(1, 0)); sprite.AddVertex(new Vector3( 0.25f, -0.25f, 0.0f), Vector3.UnitY, new Vector2(1, 1)); sprite.AddVertex(new Vector3( 0.25f, -0.25f, 0.0f), Vector3.UnitY, new Vector2(0, 1)); sprite.AddVertex(new Vector3( 0.25f, 0.25f, 0.0f), Vector3.UnitY, new Vector2(0, 0)); sprite.AddVertex(new Vector3(-0.25f, 0.25f, 0.0f), Vector3.UnitY, new Vector2(1, 0)); sprite.AddVertex(new Vector3(-0.25f, -0.25f, 0.0f), Vector3.UnitY, new Vector2(1, 1)); sprite.IndexBuffer.Initialise(); sprite.VertexBuffer.Initialise(); sprite.Material = new Material { Name = "Entity.Asset", Texture = SceneManager.Current.Content.Load<Texture, PNGImporter>("entity_" + entityType.ToString().ToLower(), Path.GetDirectoryName(Application.ExecutablePath) + @"\data\icons\") }; sprite.PrimitiveType = PrimitiveType.Quads; var spritemesh = new ModelMesh(); spritemesh.AddModelMeshPart(sprite); var spritemodel = new Model(); spritemodel.AddMesh(spritemesh); asset = spritemodel; } GL.PushMatrix(); var position = Matrix4.CreateTranslation(mT.ExtractTranslation()); GL.MultMatrix(ref mS); GL.MultMatrix(ref position); GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); ((Model)asset).Draw(); GL.Disable(EnableCap.Blend); GL.PopMatrix(); break; } }