public VertexBuffer GetVertexBuffer(IMeshPart meshPart) { var e = getEntry(meshPart); if (e.VertexBuffer == null) { var geomData = meshPart.GetGeometryData(); var positions = geomData.GetSourceVector3(MeshPartGeometryData.Semantic.Position); var normals = geomData.GetSourceVector3(MeshPartGeometryData.Semantic.Normal); var texcoords = geomData.GetSourceVector2(MeshPartGeometryData.Semantic.Texcoord); // This might not work when no texcoords var vertices = new TangentVertex[positions.Length]; for (int j = 0; j < vertices.Length; j++) { vertices[j].pos = positions[j]; vertices[j].normal = normals[j]; if (texcoords != null) { vertices[j].uv = texcoords[j]; } //TODO: tangent } var vb = new VertexBuffer(game.GraphicsDevice, typeof(TangentVertex), vertices.Length, BufferUsage.None); vb.SetData(vertices); e.VertexBuffer = vb; } return(e.VertexBuffer); }
/// <summary> /// Creates a static mesh directly from vertices (triangles only) /// </summary> public static StaticMesh FromVertices(Vector3[] vertices) { TangentVertex[] verts = new TangentVertex[vertices.Length]; for (int i = 0; i < verts.Length; i++) { verts[i] = new TangentVertex( vertices[i], Vector2.Zero, new Vector3(0, 1, 0), Vector3.Zero, Vector3.Zero); } return(FromVertices(verts)); }
public static void CreatePlaneIndicesVertices(out TangentVertex[] vertices, out short[] indices) { vertices = new TangentVertex[4]; vertices[0] = new TangentVertex(new Vector3(-0.5f, 0, -0.5f), new Vector2(0, 0), Vector3.Up, Vector3.Zero); vertices[1] = new TangentVertex(new Vector3(0.5f, 0, -0.5f), new Vector2(1, 0), Vector3.Up, Vector3.Zero); vertices[2] = new TangentVertex(new Vector3(-0.5f, 0, 0.5f), new Vector2(0, 1), Vector3.Up, Vector3.Zero); vertices[3] = new TangentVertex(new Vector3(0.5f, 0, 0.5f), new Vector2(1, 1), Vector3.Up, Vector3.Zero); indices = new short[6]; indices[0] = 0; indices[1] = 1; indices[2] = 2; indices[3] = 2; indices[4] = 1; indices[5] = 3; }
private void drawConePrimitives(int segments) { Vector3 forward = Vector3.Forward; Vector3 targetPlaneX = Vector3.Right; Vector3 targetPlaneY = Vector3.Up; var vertices = new TangentVertex[segments + 1]; vertices[0] = new TangentVertex(Vector3.Zero, Vector2.Zero, -forward, Vector3.Zero); for (int i = 1; i < vertices.Length; i++) { float iAngle = MathHelper.TwoPi * (i - 1) / segments; var pos = forward + (float)Math.Cos(iAngle) * targetPlaneX + (float)Math.Sin(iAngle) * targetPlaneY; var normal = (float)-Math.Sin(iAngle) * targetPlaneX + (float)Math.Cos(iAngle) * targetPlaneY; vertices[i] = new TangentVertex(pos, Vector2.Zero, normal, Vector3.Zero); } int[] indices = new int[segments * 3 * 2]; for (int i = 0; i < segments; i++) { indices[i * 3 + 0] = 0; indices[i * 3 + 1] = i + 1; indices[i * 3 + 2] = (i + 1) % segments + 1; indices[segments * 3 + i * 3 + 0] = 1; indices[segments * 3 + i * 3 + 1] = (i + 1) % segments + 1; indices[segments * 3 + i * 3 + 2] = i + 1; } GraphicsDevice.VertexDeclaration = tangentVertexDeclaration; GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indices, 0, indices.Length / 3); }
/// <summary> /// Create track columns /// </summary> /// <param name="points">Points</param> /// <param name="landscape">Landscape for getting the ground height</param> public TrackColumns(List <TrackVertex> points, Landscape landscape) { if (landscape == null) { return; } #region Find out column positions float lastColumnsDistance = ColumnsDistance; List <Matrix> columnPointSpacesTop = new List <Matrix>(); List <Matrix> columnPointSpacesBottom = new List <Matrix>(); for (int num = 0; num < points.Count; num++) { // Distance of the current position to the next position float distance = Vector3.Distance( points[(num + 1) % points.Count].pos, points[num].pos); // Uniform calculation of the distance for the columns, // so it doesn't matter if there is a gap of 2 or 200 m // Have we reach or go over the ColumnsDistance? if (lastColumnsDistance - distance <= 0) { // Catmull interpolation, instead the linear interpolation, for a // better position calculation, especially in curves Vector3 p1 = points[num - 1 < 0 ? points.Count - 1 : num - 1].pos; Vector3 p2 = points[num].pos; Vector3 p3 = points[(num + 1) % points.Count].pos; Vector3 p4 = points[(num + 2) % points.Count].pos; Vector3 holderPoint = Vector3.CatmullRom(p1, p2, p3, p4, lastColumnsDistance / distance); // Just find out how much this point is pointing up float draft = Vector3.Dot(points[num].up, new Vector3(0, 0, 1)); // And don't add if height is too small! float columnHeight = holderPoint.Z - landscape.GetMapHeight(holderPoint.X, holderPoint.Y); // Store the position for this holder if (draft > 0.3f && //< 0 MaxColumnGenerationAngel && columnHeight > MinimumColumnHeight) { columnPositions.Add(holderPoint); // The unit vectors for our local point space Vector3 right = points[num].right; Vector3 dir = points[num].dir; Vector3 up = points[num].up; // Create the coordinate system for the current point by the 3 unit // vectors. Matrix pointSpace = Matrix.Identity; pointSpace.M11 = right.X; pointSpace.M12 = right.Y; pointSpace.M13 = right.Z; pointSpace.M21 = dir.X; pointSpace.M22 = dir.Y; pointSpace.M23 = dir.Z; pointSpace.M31 = up.X; pointSpace.M32 = up.Y; pointSpace.M33 = up.Z; // Remember point space columnPointSpacesTop.Add(pointSpace); // Same for bottom, but don't use up vector (let it stay default) pointSpace = Matrix.Identity; Vector3 upVector = new Vector3(0, 0, 1); // Rebuild right vector (to make it 90 degree to our up vector) Vector3 rightVector = Vector3.Cross(dir, upVector); pointSpace.M11 = rightVector.X; pointSpace.M12 = rightVector.Y; pointSpace.M13 = rightVector.Z; pointSpace.M21 = dir.X; pointSpace.M22 = dir.Y; pointSpace.M23 = dir.Z; columnPointSpacesBottom.Add(pointSpace); } // if (draft) // We have just set a pile, the next pile will be set after // reaching the next holder gap. lastColumnsDistance += ColumnsDistance; } // if (lastColumnsDistance) // The distance we have to cover until the next position. // We subtract our current distance from the remaining gap distance, // which will then be checked in the next loop. lastColumnsDistance -= distance; } // for (num) #endregion #region Generate vertex buffer columnVertices = new TangentVertex[ columnPositions.Count * BaseColumnVertices.Length * 2]; // Go through all columns for (int num = 0; num < columnPositions.Count; num++) { Vector3 pos = columnPositions[num]; // Find out the current landscape height here Vector3 bottomPos = new Vector3(pos.X, pos.Y, landscape.GetMapHeight(pos.X, pos.Y) + ColumnGroundHeight); Vector3 topPos = new Vector3(pos.X, pos.Y, pos.Z - TopColumnSubHeight); // Calculate top v tex coord for this column float topTexV = Vector3.Distance(topPos, bottomPos) / (MathHelper.Pi * 2); // Use the BaseColumnVertices twice, once for the bottom and then for the // top part of our generated column. for (int topBottom = 0; topBottom < 2; topBottom++) { // Go to all BaseColumnVertices for (int i = 0; i < BaseColumnVertices.Length; i++) { int vertIndex = num * BaseColumnVertices.Length * 2 + topBottom * BaseColumnVertices.Length + i; // For the top positions, modify them them to fit directly // on the bottom side of our road. Same for bottom, but don't // modify the z value Matrix transformMatrix = topBottom == 0 ? columnPointSpacesBottom[num] : columnPointSpacesTop[num]; // We don't have to transform the vertices much, just adjust // the z value and the v tex coord. columnVertices[vertIndex] = new TangentVertex( (topBottom == 0 ? bottomPos : topPos) + Vector3.Transform(BaseColumnVertices[i].pos, transformMatrix), BaseColumnVertices[i].U, topBottom == 0 ? 0 : topTexV, Vector3.Transform(BaseColumnVertices[i].normal, transformMatrix), Vector3.Transform(-BaseColumnVertices[i].tangent, transformMatrix)); } // for (int) } // for (topBottom) } // for (num) // Create the vertex buffer from our vertices. columnVb = new VertexBuffer( BaseGame.Device, typeof(TangentVertex), columnVertices.Length, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic); columnVb.SetData(columnVertices); #endregion #region GenerateIndexBuffer // Count of quads (polygons) we have for each column int quadPolysPerColumn = BaseColumnVertices.Length - 1; int[] indices = new int[(2 * 3 * quadPolysPerColumn) * columnPositions.Count]; // Current vertex index int vertexIndex = 0; // Helper variable, current index of the indices list int indicesIndex = 0; for (int num = 0; num < columnPositions.Count; num++) { // Set all quads of the column for (int j = 0; j < quadPolysPerColumn; j++) { indicesIndex = 3 * 2 * (num * quadPolysPerColumn + j); // 1. Polygon indices[indicesIndex] = vertexIndex + j; indices[indicesIndex + 1] = vertexIndex + 1 + BaseColumnVertices.Length + j; indices[indicesIndex + 2] = vertexIndex + 1 + j; // 2. Polygon indices[indicesIndex + 3] = indices[indicesIndex + 1]; indices[indicesIndex + 4] = indices[indicesIndex]; indices[indicesIndex + 5] = vertexIndex + BaseColumnVertices.Length + j; } // for (int) // Go to next column vertexIndex += BaseColumnVertices.Length * 2; } // for (num) // Create the index buffer from our indices. columnIb = new IndexBuffer( BaseGame.Device, typeof(int), indices.Length, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic); columnIb.SetData(indices); #endregion } // TrackColumns(points)
/// <summary> /// Add brake track /// </summary> /// <param name="position">Position</param> /// <param name="dir">Dir vector</param> /// <param name="right">Right vector</param> public void AddBrakeTrack(CarPhysics car) { Vector3 position = car.CarPosition + car.CarDirection * 1.25f; // Just skip if we setting to a similar location again. // This check is much faster and accurate for tracks on top of each // other than the foreach loop below, which is only useful to // put multiple tracks correctly behind each other! if (Vector3.DistanceSquared(position, lastAddedTrackPos) < 0.024f || // Limit number of tracks to keep rendering fast. brakeTracksVertices.Count > MaxBrakeTrackVertices) { return; } lastAddedTrackPos = position; const float width = 2.4f; // car is 2.6m width, we use 2.4m for tires const float length = 4.5f; // Length of break tracks float maxDist = (float)Math.Sqrt(width * width + length * length) / 2 - 0.35f; // Check if there is any track already set here or nearby? for (int num = 0; num < brakeTracksVertices.Count; num++) { if (Vector3.DistanceSquared(brakeTracksVertices[num].pos, position) < maxDist * maxDist) { // Then skip this brake track, don't put that much stuff on // top of each other. return; } } // Move position a little bit up (above the road) position += Vector3.Normalize(car.CarUpVector) * RaiseBreakTracksAmount; // Just add 6 new vertices to render (2 triangles) TangentVertex[] newVertices = new TangentVertex[] { // First triangle new TangentVertex( position - car.CarRight * width / 2 - car.CarDirection * length / 2, 0, 0, car.CarUpVector, car.CarRight), new TangentVertex( position - car.CarRight * width / 2 + car.CarDirection * length / 2, 0, 5, car.CarUpVector, car.CarRight), new TangentVertex( position + car.CarRight * width / 2 + car.CarDirection * length / 2, 1, 5, car.CarUpVector, car.CarRight), // Second triangle new TangentVertex( position - car.CarRight * width / 2 - car.CarDirection * length / 2, 0, 0, car.CarUpVector, car.CarRight), new TangentVertex( position + car.CarRight * width / 2 + car.CarDirection * length / 2, 1, 5, car.CarUpVector, car.CarRight), new TangentVertex( position + car.CarRight * width / 2 - car.CarDirection * length / 2, 1, 0, car.CarUpVector, car.CarRight), }; brakeTracksVertices.AddRange(newVertices); brakeTracksVerticesArray = brakeTracksVertices.ToArray(); }
public static void CreateUnitBoxVerticesAndIndices(out TangentVertex[] vertices, out short[] indices) { vertices = new TangentVertex[4 * 6]; int i; //Note: right handed axis // Front (topleft, topright, bottomleft, bottomright) i = 4 * 0; vertices[i].pos = new Vector3(0, 1, 1); i++; vertices[i].pos = new Vector3(1, 1, 1); i++; vertices[i].pos = new Vector3(0, 0, 1); i++; vertices[i].pos = new Vector3(1, 0, 1); i++; i -= 4; vertices[i].uv = new Vector2(0, 0); i++; vertices[i].uv = new Vector2(1, 0); i++; vertices[i].uv = new Vector2(0, 1); i++; vertices[i].uv = new Vector2(1, 1); i++; for (int j = i - 4; j < i; j++) { vertices[j].normal = Vector3.Backward; } // Back (topleft, topright, bottomleft, bottomright) i = 4 * 1; vertices[i].pos = new Vector3(1, 1, 0); i++; vertices[i].pos = new Vector3(0, 1, 0); i++; vertices[i].pos = new Vector3(1, 0, 0); i++; vertices[i].pos = new Vector3(0, 0, 0); i++; i -= 4; vertices[i].uv = new Vector2(0, 0); i++; vertices[i].uv = new Vector2(1, 0); i++; vertices[i].uv = new Vector2(0, 1); i++; vertices[i].uv = new Vector2(1, 1); i++; for (int j = i - 4; j < i; j++) { vertices[j].normal = Vector3.Forward; } // Left (topleft, topright, bottomleft, bottomright) i = 4 * 2; vertices[i].pos = new Vector3(0, 1, 0); i++; vertices[i].pos = new Vector3(0, 1, 1); i++; vertices[i].pos = new Vector3(0, 0, 0); i++; vertices[i].pos = new Vector3(0, 0, 1); i++; i -= 4; vertices[i].uv = new Vector2(0, 0); i++; vertices[i].uv = new Vector2(1, 0); i++; vertices[i].uv = new Vector2(0, 1); i++; vertices[i].uv = new Vector2(1, 1); i++; for (int j = i - 4; j < i; j++) { vertices[j].normal = Vector3.Left; } // Right (topleft, topright, bottomleft, bottomright) i = 4 * 3; vertices[i].pos = new Vector3(1, 1, 1); i++; vertices[i].pos = new Vector3(1, 1, 0); i++; vertices[i].pos = new Vector3(1, 0, 1); i++; vertices[i].pos = new Vector3(1, 0, 0); i++; i -= 4; vertices[i].uv = new Vector2(0, 0); i++; vertices[i].uv = new Vector2(1, 0); i++; vertices[i].uv = new Vector2(0, 1); i++; vertices[i].uv = new Vector2(1, 1); i++; for (int j = i - 4; j < i; j++) { vertices[j].normal = Vector3.Right; } // Top (topleft, topright, bottomleft, bottomright) i = 4 * 4; vertices[i].pos = new Vector3(0, 1, 0); i++; vertices[i].pos = new Vector3(1, 1, 0); i++; vertices[i].pos = new Vector3(0, 1, 1); i++; vertices[i].pos = new Vector3(1, 1, 1); i++; i -= 4; vertices[i].uv = new Vector2(0, 0); i++; vertices[i].uv = new Vector2(1, 0); i++; vertices[i].uv = new Vector2(0, 1); i++; vertices[i].uv = new Vector2(1, 1); i++; for (int j = i - 4; j < i; j++) { vertices[j].normal = Vector3.Up; } // Bottom (topleft, topright, bottomleft, bottomright) i = 4 * 5; vertices[i].pos = new Vector3(0, 0, 1); i++; vertices[i].pos = new Vector3(1, 0, 1); i++; vertices[i].pos = new Vector3(0, 0, 0); i++; vertices[i].pos = new Vector3(1, 0, 0); i++; i -= 4; vertices[i].uv = new Vector2(0, 1); i++; vertices[i].uv = new Vector2(1, 1); i++; vertices[i].uv = new Vector2(0, 0); i++; vertices[i].uv = new Vector2(1, 0); i++; for (int j = i - 4; j < i; j++) { vertices[j].normal = Vector3.Down; } indices = new short[6 * 6]; i = 0; for (short j = 0; j < 4 * 6; j += 4) { indices[i] = (short)(j + 0); i++; indices[i] = (short)(j + 1); i++; indices[i] = (short)(j + 2); i++; indices[i] = (short)(j + 1); i++; indices[i] = (short)(j + 3); i++; indices[i] = (short)(j + 2); i++; } }
public void AddSphere(int segments, float radius, MeshMaterial material) { if (!parts.ContainsKey(material)) { throw new InvalidOperationException("Material not created by the meshbuilder"); } TangentVertex[] vertices; short[] indices; // Source: http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/sphere_cylinder/ // Maak ringen van vertices van onder naar boven int i = 0; float phi, theta; float phiStep, thetaStep; float phiStart, phiEnd, thetaStart, thetaEnd; phiStep = MathHelper.TwoPi / segments; thetaStep = MathHelper.Pi / segments; phiStart = 0; phiEnd = MathHelper.TwoPi; thetaStart = -MathHelper.PiOver2 + thetaStep; thetaEnd = MathHelper.PiOver2; int numRings = (int)Math.Round((thetaEnd - thetaStart) / thetaStep); int numVertsOnRing = (int)Math.Round((phiEnd - phiStart) / phiStep); int numVertices = 1 + numRings * numVertsOnRing + 1; vertices = new TangentVertex[numVertices]; // Bottom vertex: (0,-1,0) vertices[i].pos = new Microsoft.Xna.Framework.Vector3(0, -1, 0); i++; theta = thetaStart; for (int iRing = 0; iRing < numRings; iRing++, theta += thetaStep) { phi = 0; for (int iVert = 0; iVert < numVertsOnRing; iVert++, phi += phiStep) { vertices[i].pos = new Microsoft.Xna.Framework.Vector3( (float)Math.Cos(theta) * (float)Math.Cos(phi), (float)Math.Sin(theta), -(float)Math.Cos(theta) * (float)Math.Sin(phi)); i++; } } // Top vertex: (0,1,0) vertices[i].pos = new Microsoft.Xna.Framework.Vector3(0, 1, 0); i++; // Generate normals for (int j = 0; j < vertices.Length; j++) { vertices[j].normal = Microsoft.Xna.Framework.Vector3.Normalize(vertices[j].pos); } int numIndices = (numVertsOnRing * 2 * 3) * numRings; indices = new short[numIndices]; i = 0; // Triangle fan at bottom and top, elsewhere strips between the rings // Top and bottom fan for (int iVert = 0; iVert < numVertsOnRing - 1; iVert++) { // Bottom fan indices[i] = (short)(0); i++; indices[i] = (short)(1 + iVert); i++; indices[i] = (short)(1 + (iVert + 1)); i++; // Top fan indices[i] = (short)(numVertices - 1); i++; indices[i] = (short)(1 + (numRings - 1) * numVertsOnRing + (iVert + 1)); i++; indices[i] = (short)(1 + (numRings - 1) * numVertsOnRing + iVert); i++; } // Top and bottom final fan indices[i] = (short)(0); i++; indices[i] = (short)(1 + numVertsOnRing - 1); i++; indices[i] = (short)(1 + 0); i++; indices[i] = (short)(numVertices - 1); i++; indices[i] = (short)(1 + (numRings - 1) * numVertsOnRing + 0); i++; indices[i] = (short)(1 + (numRings - 1) * numVertsOnRing + numVertsOnRing - 1); i++; // Strips for (int iRing = 0; iRing < numRings - 1; iRing++) { for (int iVert = 0; iVert < numVertsOnRing - 1; iVert++) { indices[i] = (short)(1 + numVertsOnRing * iRing + iVert); i++; indices[i] = (short)(1 + numVertsOnRing * (iRing + 1) + iVert); i++; indices[i] = (short)(1 + numVertsOnRing * iRing + (iVert + 1)); i++; indices[i] = (short)(1 + numVertsOnRing * iRing + (iVert + 1)); i++; indices[i] = (short)(1 + numVertsOnRing * (iRing + 1) + iVert); i++; indices[i] = (short)(1 + numVertsOnRing * (iRing + 1) + (iVert + 1)); i++; } // Final gap: indices[i] = (short)(1 + numVertsOnRing * iRing + (numVertsOnRing - 1)); i++; indices[i] = (short)(1 + numVertsOnRing * (iRing + 1) + (numVertsOnRing - 1)); i++; indices[i] = (short)(1 + numVertsOnRing * iRing + (0)); i++; indices[i] = (short)(1 + numVertsOnRing * iRing + (0)); i++; indices[i] = (short)(1 + numVertsOnRing * (iRing + 1) + (numVertsOnRing - 1)); i++; indices[i] = (short)(1 + numVertsOnRing * (iRing + 1) + (0)); i++; } var mapping = new SphericalMapping(); var data = parts[material]; foreach (var index in indices) { data.Positions.Add(vertices[index].pos * radius); data.Normals.Add(vertices[index].normal); data.Texcoords.Add(mapping.Map(data.Positions[data.Positions.Count - 1].ToSlimDX()).xna() * 3); } }
private static void LoadMesh(AssetImporterGltfMeshContext context, int meshIndex, Matrix worldMatrix) { Mesh mesh = context.Model.Meshes[meshIndex]; for (int p = 0; p < mesh.Primitives.Length; p++) { var prim = mesh.Primitives[p]; if (prim.Mode != MeshPrimitive.ModeEnum.TRIANGLES) { throw new NotImplementedException("Modes other than TRIANGLES are not implemented (yet)"); } Accessor positionAccessor = GetAccessorByType("POSITION", context.Model, prim); if (positionAccessor.Type != Accessor.TypeEnum.VEC3) { throw new InvalidDataException("POSITION accessor must have type VEC3"); } Accessor normalAccessor = GetAccessorByType("NORMAL", context.Model, prim); if (normalAccessor != null && normalAccessor.Type != Accessor.TypeEnum.VEC3) { throw new InvalidDataException("NORMAL accessor must have type VEC3"); } Accessor texcoordAccessor = GetAccessorByType("TEXCOORD_0", context.Model, prim); if (texcoordAccessor != null && texcoordAccessor.Type != Accessor.TypeEnum.VEC2) { throw new InvalidDataException("TEXCOORD accessor must have type VEC2"); } Accessor tangentAccessor = GetAccessorByType("TANGENT", context.Model, prim); if (tangentAccessor != null && tangentAccessor.Type != Accessor.TypeEnum.VEC4) { throw new InvalidDataException("TANGENT accessor must have type VEC4"); } TangentVertex[] vertices = new TangentVertex[positionAccessor.Count]; BufferView positionBufferView = context.Model.BufferViews[positionAccessor.BufferView.Value]; BufferView normalsBufferView = null; if (normalAccessor != null) { normalsBufferView = context.Model.BufferViews[normalAccessor.BufferView.Value]; } BufferView texCoordBufferView = null; if (texcoordAccessor != null) { texCoordBufferView = context.Model.BufferViews[texcoordAccessor.BufferView.Value]; } BufferView tangentBufferView = null; if (tangentAccessor != null) { tangentBufferView = context.Model.BufferViews[tangentAccessor.BufferView.Value]; } ReadOnlySpan <Vector3> positionSpan = MemoryMarshal.Cast <byte, Vector3>( new ReadOnlySpan <byte>(context.RawBuffers[positionBufferView.Buffer], positionBufferView.ByteOffset + positionAccessor.ByteOffset, positionAccessor.Count * 12)); ReadOnlySpan <Vector3> normalsSpan = null; if (normalsBufferView != null) { normalsSpan = MemoryMarshal.Cast <byte, Vector3>( new ReadOnlySpan <byte>(context.RawBuffers[normalsBufferView.Buffer], normalsBufferView.ByteOffset + normalAccessor.ByteOffset, normalAccessor.Count * 12)); } ReadOnlySpan <Vector2> texCoordSpan = null; if (texCoordBufferView != null) { texCoordSpan = MemoryMarshal.Cast <byte, Vector2>( new ReadOnlySpan <byte>(context.RawBuffers[texCoordBufferView.Buffer], texCoordBufferView.ByteOffset + texcoordAccessor.ByteOffset, texcoordAccessor.Count * 8)); } ReadOnlySpan <Vector4> tangentSpan = null; if (tangentBufferView != null) { tangentSpan = MemoryMarshal.Cast <byte, Vector4>( new ReadOnlySpan <byte>(context.RawBuffers[tangentBufferView.Buffer], tangentBufferView.ByteOffset + tangentAccessor.ByteOffset, tangentAccessor.Count * 16)); } for (int v = 0; v < vertices.Length; v++) { vertices[v].Position = positionSpan[v]; if (normalsSpan != null) { vertices[v].Normal = normalsSpan[v]; } if (texCoordSpan != null) { vertices[v].TexCoord = texCoordSpan[v]; } if (tangentSpan != null) { vertices[v].Tangent = new Vector3(tangentSpan[v].X, tangentSpan[v].Y, tangentSpan[v].Z); if (normalsSpan != null) { vertices[v].BiTangent = Vector3.Cross(normalsSpan[v], vertices[v].Tangent) * tangentSpan[v].W; } } } StaticMesh staticMesh = null; if (prim.Indices == null) { staticMesh = StaticMesh.FromVertices(vertices); } else { int primIndex = prim.Indices.Value; Accessor indexAccessor = GetAccessorByIndex(primIndex, context.Model); if (indexAccessor != null) { if (indexAccessor.Type != Accessor.TypeEnum.SCALAR) { throw new InvalidDataException("Index accessor must have type SCALAR"); } uint[] indices = new uint[indexAccessor.Count]; BufferView indexBufferView = context.Model.BufferViews[indexAccessor.BufferView.Value]; switch (indexAccessor.ComponentType) { case Accessor.ComponentTypeEnum.UNSIGNED_BYTE: { ReadOnlySpan <byte> indexSpan = new ReadOnlySpan <byte>(context.RawBuffers[indexBufferView.Buffer], indexBufferView.ByteOffset + indexAccessor.ByteOffset, indexAccessor.Count); for (int idx = 0; idx < indices.Length; idx++) { indices[idx] = (uint)indexSpan[idx]; } } break; case Accessor.ComponentTypeEnum.UNSIGNED_SHORT: { ReadOnlySpan <ushort> indexSpan = MemoryMarshal.Cast <byte, ushort>( new ReadOnlySpan <byte>(context.RawBuffers[indexBufferView.Buffer], indexBufferView.ByteOffset + indexAccessor.ByteOffset, indexAccessor.Count * 2)); for (int idx = 0; idx < indices.Length; idx++) { indices[idx] = (uint)indexSpan[idx]; } } break; case Accessor.ComponentTypeEnum.UNSIGNED_INT: { ReadOnlySpan <uint> indexSpan = MemoryMarshal.Cast <byte, uint>( new ReadOnlySpan <byte>(context.RawBuffers[indexBufferView.Buffer], indexBufferView.ByteOffset + indexAccessor.ByteOffset, indexAccessor.Count * 4)); indices = indexSpan.ToArray(); } break; default: throw new NotImplementedException("ComponentType " + indexAccessor.ComponentType + " not implemented."); } staticMesh = StaticMesh.FromVertices(vertices, indices); } } staticMesh.Name = mesh.Name + "_" + p + ".staticMesh"; context.PackageToSaveIn.StoreAsset(staticMesh); Materials.Material material = CreateMaterialForMesh(prim, context.Model); staticMesh.Material = material; context.ImportedAssets.Add(staticMesh); } }
public void TestRenderDefaultModelShader() { var shaders = new List <DefaultModelShader>(); DefaultModelShader shader = null; VertexBuffer vb = null; VertexDeclaration decl = null; XNAGame game = new XNAGame(); game.InitializeEvent += delegate { decl = TangentVertexExtensions.CreateVertexDeclaration(game); TangentVertex[] vertices = new TangentVertex[4]; vertices[0] = new TangentVertex(Vector3.Zero, Vector2.Zero, Vector3.Up, Vector3.Zero); vertices[1] = new TangentVertex(Vector3.Forward, Vector2.UnitX, Vector3.Up, Vector3.Zero); vertices[2] = new TangentVertex(Vector3.Forward + Vector3.Right, Vector2.UnitX + Vector2.UnitY, Vector3.Up, Vector3.Zero); vertices[3] = new TangentVertex(Vector3.Right, Vector2.UnitY, Vector3.Up, Vector3.Zero); vb = new VertexBuffer(game.GraphicsDevice, typeof(TangentVertex), vertices.Length, BufferUsage.None); vb.SetData(vertices); shader = new DefaultModelShader(game, new EffectPool()); DefaultModelShader s; Texture2D tex = Texture2D.FromFile(game.GraphicsDevice, File.OpenRead(TestFiles.WoodPlanksBareJPG)); s = shader.Clone(); s.DiffuseColor = Color.Red.ToVector4(); s.Technique = DefaultModelShader.TechniqueType.Colored; shaders.Add(s); s = shader.Clone(); s.DiffuseTexture = tex; s.Technique = DefaultModelShader.TechniqueType.Textured; shaders.Add(s); }; game.DrawEvent += delegate { game.GraphicsDevice.RenderState.CullMode = CullMode.None; game.GraphicsDevice.VertexDeclaration = decl; shader.ViewProjection = game.Camera.ViewProjection; for (int i = 0; i < shaders.Count; i++) { //shaders[i].ViewProjection = game.Camera.ViewProjection; shaders[i].World = Matrix.CreateTranslation(Vector3.Right * i * 3) * Matrix.CreateScale(10); shaders[i].DrawPrimitives(delegate() { game.GraphicsDevice.Vertices[0].SetSource(vb, 0, TangentVertex.SizeInBytes); game.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleFan, 0, 2); } ); } }; game.Run(); }
/// <summary> /// Loads the static mesh from the compiled binary mesh /// </summary> public override void Deserialize(BinaryReader reader) { base.Deserialize(reader); // Read mesh data int NumTriangles = reader.ReadInt32(); int vertLen = reader.ReadInt32(); objectVertices = new TangentVertex[vertLen]; for (int i = 0; i < objectVertices.Length; i++) { objectVertices[i] = new TangentVertex( new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()), new Vector2(reader.ReadSingle(), reader.ReadSingle()), new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()), new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()), new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle())); } int indexLen = reader.ReadInt32(); objectIndices = new uint[indexLen]; for (int i = 0; i < objectIndices.Length; i++) { objectIndices[i] = reader.ReadUInt32(); } // Read BoundingSphere BoundingSphere = new BoundingSphere( new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()), reader.ReadSingle()); // Read MeshCameras int meshCameraCount = reader.ReadInt32(); if (meshCameraCount == 0) { MeshCameras = null; } else { MeshCameras = new MeshCamera[meshCameraCount]; for (int i = 0; i < meshCameraCount; i++) { MeshCameras[i] = new MeshCamera(); MeshCameras[i].Translation = new Vector3( reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); MeshCameras[i].CameraType = (MeshCameraType)reader.ReadInt32(); } } // Create XNA buffers and fill them try { VertexBuffer newVertexBuffer = new VertexBuffer(AlkaronCoreGame.Core.GraphicsDevice, TangentVertex.VertexDecl, TangentVertex.SizeInBytes * objectVertices.Length, BufferUsage.WriteOnly); IndexBuffer newIndexBuffer = new IndexBuffer(AlkaronCoreGame.Core.GraphicsDevice, IndexElementSize.ThirtyTwoBits, objectIndices.Length, BufferUsage.WriteOnly); if (newVertexBuffer != null) { if (vertexBuffer != null) { vertexBuffer.Dispose(); vertexBuffer = null; } vertexBuffer = newVertexBuffer; } if (newIndexBuffer != null) { if (indexBuffer != null) { indexBuffer.Dispose(); indexBuffer = null; } indexBuffer = newIndexBuffer; } } catch { return; } vertexBuffer.SetData <TangentVertex>(objectVertices); indexBuffer.SetData <uint>(objectIndices); CreateBoundingSphere(); }
/// <summary> /// This code is also in Meshbuilder... /// </summary> /// <param name="segments"></param> /// <param name="vertices"></param> /// <param name="indices"></param> public static void CreateUnitSphereVerticesAndIndices(int segments, out TangentVertex[] vertices, out short[] indices) { // Source: http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/sphere_cylinder/ // Maak ringen van vertices van onder naar boven int i = 0; float phi, theta; float phiStep, thetaStep; float phiStart, phiEnd, thetaStart, thetaEnd; phiStep = MathHelper.TwoPi / segments; thetaStep = MathHelper.Pi / segments; phiStart = 0; phiEnd = MathHelper.TwoPi; thetaStart = -MathHelper.PiOver2 + thetaStep; thetaEnd = MathHelper.PiOver2; int numRings = (int)Math.Round((thetaEnd - thetaStart) / thetaStep); int numVertsOnRing = (int)Math.Round((phiEnd - phiStart) / phiStep); int numVertices = 1 + numRings * numVertsOnRing + 1; vertices = new TangentVertex[numVertices]; // Bottom vertex: (0,-1,0) vertices[i].pos = new Vector3(0, -1, 0); i++; theta = thetaStart; for (int iRing = 0; iRing < numRings; iRing++, theta += thetaStep) { phi = 0; for (int iVert = 0; iVert < numVertsOnRing; iVert++, phi += phiStep) { vertices[i].pos = new Vector3( (float)Math.Cos(theta) * (float)Math.Cos(phi), (float)Math.Sin(theta), -(float)Math.Cos(theta) * (float)Math.Sin(phi)); //TODO: normals i++; } } // Top vertex: (0,1,0) vertices[i].pos = new Vector3(0, 1, 0); i++; // Generate normals for (int j = 0; j < vertices.Length; j++) { vertices[j].normal = Vector3.Normalize(vertices[j].pos); } int numIndices = (numVertsOnRing * 2 * 3) * numRings; indices = new short[numIndices]; i = 0; // Triangle fan at bottom and top, elsewhere strips between the rings // Top and bottom fan for (int iVert = 0; iVert < numVertsOnRing - 1; iVert++) { // Bottom fan indices[i] = (short)(0); i++; indices[i] = (short)(1 + iVert); i++; indices[i] = (short)(1 + (iVert + 1)); i++; // Top fan indices[i] = (short)(numVertices - 1); i++; indices[i] = (short)(1 + (numRings - 1) * numVertsOnRing + (iVert + 1)); i++; indices[i] = (short)(1 + (numRings - 1) * numVertsOnRing + iVert); i++; } // Top and bottom final fan indices[i] = (short)(0); i++; indices[i] = (short)(1 + numVertsOnRing - 1); i++; indices[i] = (short)(1 + 0); i++; indices[i] = (short)(numVertices - 1); i++; indices[i] = (short)(1 + (numRings - 1) * numVertsOnRing + 0); i++; indices[i] = (short)(1 + (numRings - 1) * numVertsOnRing + numVertsOnRing - 1); i++; // Strips for (int iRing = 0; iRing < numRings - 1; iRing++) { for (int iVert = 0; iVert < numVertsOnRing - 1; iVert++) { indices[i] = (short)(1 + numVertsOnRing * iRing + iVert); i++; indices[i] = (short)(1 + numVertsOnRing * (iRing + 1) + iVert); i++; indices[i] = (short)(1 + numVertsOnRing * iRing + (iVert + 1)); i++; indices[i] = (short)(1 + numVertsOnRing * iRing + (iVert + 1)); i++; indices[i] = (short)(1 + numVertsOnRing * (iRing + 1) + iVert); i++; indices[i] = (short)(1 + numVertsOnRing * (iRing + 1) + (iVert + 1)); i++; } // Final gap: indices[i] = (short)(1 + numVertsOnRing * iRing + (numVertsOnRing - 1)); i++; indices[i] = (short)(1 + numVertsOnRing * (iRing + 1) + (numVertsOnRing - 1)); i++; indices[i] = (short)(1 + numVertsOnRing * iRing + (0)); i++; indices[i] = (short)(1 + numVertsOnRing * iRing + (0)); i++; indices[i] = (short)(1 + numVertsOnRing * (iRing + 1) + (numVertsOnRing - 1)); i++; indices[i] = (short)(1 + numVertsOnRing * (iRing + 1) + (0)); i++; } }