public Terrain(ContentManager content, GraphicsDevice device, string heightMapPath, string texturePath) { mContent = content; mGraphics = device; mHeightMapPath = heightMapPath; mTexturePath = texturePath; var meshData = new MeshData(); var heightMapStream = new FileStream(heightMapPath, FileMode.Open, FileAccess.Read); var heightmap = Texture2D.FromStream(device, heightMapStream); heightMapStream.Close(); mWidth = heightmap.Width; mHeight = heightmap.Height; meshData.mVertices = new VertexPositionTexture[mWidth * mHeight]; meshData.mIndices = new int[(mWidth * 2 + 2) * (mHeight - 1)]; var subData = new MeshData.SubData(); var material = new Material(); var textureStream = new FileStream(texturePath, FileMode.Open, FileAccess.Read); material.mDiffuseMap = Texture2D.FromStream(device, textureStream); material.DiffuseMapStream = textureStream; material.mGraphicsDevice = device; textureStream.Close(); material.mDiffuseColor = new Vector3(1.0f); subData.mIndicesOffset = 0; subData.mMaterialIndex = 0; subData.mNumPrimitives = (heightmap.Width * 2 + 2) * (heightmap.Height - 1); meshData.mMaterials.Add(material); meshData.mSubDatas.Add(subData); meshData.mPrimitiveType = PrimitiveType.TriangleStrip; meshData.mTotalNumPrimitives = (heightmap.Width * 2 + 2) * (heightmap.Height - 1); meshData.mBoundingSphere.Radius = (float)Math.Sqrt(Math.Pow(heightmap.Width / 2.0f, 2) + Math.Pow(heightmap.Height / 2.0f, 2)); meshData.mIsTerrain = true; Actor = new Actor(new Mesh.Mesh(mGraphics, meshData), null) { mCastShadow = false }; Size = mWidth; LoadVertices(heightmap); LoadIndices(); Actor.mMesh.UpdateData(); mGrass = new Grass(this); mGrass.Generate(); }
/// <summary> /// Loads a mesh from a file /// </summary> /// <param name="filename">The name of the file</param> /// <returns>A mesh which contains the data of the file</returns> public Mesh.Mesh LoadMesh(string filename) { var vertexCount = 0; var indexCount = 0; var bonesCount = 0; var directory = Path.GetDirectoryName(filename); directory += "/"; var meshData = new MeshData(); var importer = new AssimpContext(); var boneConfig = new MaxBoneCountConfig(4); importer.SetConfig(boneConfig); var scene = importer.ImportFile(filename, PostProcessSteps.ImproveCacheLocality | PostProcessSteps.JoinIdenticalVertices | PostProcessSteps.LimitBoneWeights | PostProcessSteps.Triangulate | PostProcessSteps.OptimizeMeshes | PostProcessSteps.RemoveRedundantMaterials | PostProcessSteps.MakeLeftHanded | PostProcessSteps.OptimizeGraph); // We want to sort all the meshes to their corresponding materials var meshSorted = new List <Assimp.Mesh> [scene.MaterialCount]; for (var i = 0; i < scene.MaterialCount; i++) { meshSorted[i] = new List <Assimp.Mesh>(); } foreach (var mesh in scene.Meshes) { var index = mesh.MaterialIndex; meshSorted[index].Add(mesh); vertexCount += mesh.VertexCount; indexCount += mesh.FaceCount * 3; bonesCount += mesh.BoneCount; } // Load bones and animations if (scene.HasAnimations || bonesCount > 0) { meshData.mIsSkinned = true; meshData.mBones = CreateBoneHierarchy(scene); foreach (var animation in scene.Animations) { meshData.mAnimations.Add(new Animation.Animation(animation, meshData.mBones)); } meshData.mVerticesExt = new VertexPositionTextureSkinned[vertexCount]; // Set the skinning informatio to 0 for (var i = 0; i < meshData.mVerticesExt.Length; i++) { meshData.mVerticesExt[i].BoneWeights.X = 0.0f; meshData.mVerticesExt[i].BoneWeights.Y = 0.0f; meshData.mVerticesExt[i].BoneWeights.Z = 0.0f; meshData.mVerticesExt[i].BoneWeights.W = 0.0f; meshData.mVerticesExt[i].BoneIndex = new Byte4(0.0f, 0.0f, 0.0f, 0.0f); } } else { meshData.mVertices = new VertexPositionTexture[vertexCount]; } meshData.mIndices = new int[indexCount]; var usedFaces = 0; var usedVertices = 0; var loadedVertices = 0; for (var i = 0; i < scene.MaterialCount; i++) { var material = LoadMaterial(scene.Materials[i], directory); var subData = new MeshData.SubData { mIndicesOffset = usedFaces * 3, mMaterialIndex = i }; foreach (var mesh in meshSorted[i]) { for (var j = 0; j < mesh.BoneCount; j++) { var boneIndex = Array.FindIndex(meshData.mBones, ele => ele.mName == mesh.Bones[j].Name); var bone = meshData.mBones[boneIndex]; bone.mOffset = AssimpToXna(mesh.Bones[j].OffsetMatrix); var bonePosition = new Vector4(0.0f); for (var k = 0; k < mesh.Bones[j].VertexWeightCount; k++) { var weight = mesh.Bones[j].VertexWeights[k]; bonePosition += new Vector4(mesh.Vertices[weight.VertexID].X * weight.Weight, mesh.Vertices[weight.VertexID].Y * weight.Weight, mesh.Vertices[weight.VertexID].Z * weight.Weight, weight.Weight); var indices = meshData.mVerticesExt[usedVertices + weight.VertexID].BoneIndex.ToVector4(); if (!(meshData.mVerticesExt[usedVertices + weight.VertexID].BoneWeights.X > 0.0f)) { meshData.mVerticesExt[usedVertices + weight.VertexID].BoneWeights.X = weight.Weight; indices.X = boneIndex; } else if (!(meshData.mVerticesExt[usedVertices + weight.VertexID].BoneWeights.Y > 0.0f)) { meshData.mVerticesExt[usedVertices + weight.VertexID].BoneWeights.Y = weight.Weight; indices.Y = boneIndex; } else if (!(meshData.mVerticesExt[usedVertices + weight.VertexID].BoneWeights.Z > 0.0f)) { meshData.mVerticesExt[usedVertices + weight.VertexID].BoneWeights.Z = weight.Weight; indices.Z = boneIndex; } else if (!(meshData.mVerticesExt[usedVertices + weight.VertexID].BoneWeights.W > 0.0f)) { meshData.mVerticesExt[usedVertices + weight.VertexID].BoneWeights.W = weight.Weight; indices.W = boneIndex; } meshData.mVerticesExt[usedVertices + weight.VertexID].BoneIndex = new Byte4(indices); } bonePosition /= bonePosition.W; bone.mPosition = new Vector3(bonePosition.X, bonePosition.Y, bonePosition.Z); } // Copy the vertices for (var j = 0; j < mesh.VertexCount; j++) { float radius; if (meshData.mVertices != null) { meshData.mVertices[usedVertices].Position.X = mesh.Vertices[j].X; meshData.mVertices[usedVertices].Position.Y = mesh.Vertices[j].Y; meshData.mVertices[usedVertices].Position.Z = mesh.Vertices[j].Z; radius = meshData.mVertices[usedVertices].Position.Length(); } else { meshData.mVerticesExt[usedVertices].Position.X = mesh.Vertices[j].X; meshData.mVerticesExt[usedVertices].Position.Y = mesh.Vertices[j].Y; meshData.mVerticesExt[usedVertices].Position.Z = mesh.Vertices[j].Z; radius = meshData.mVerticesExt[usedVertices].Position.Length(); } var vertex = meshData.mVertices?[usedVertices].Position ?? meshData.mVerticesExt[usedVertices].Position; meshData.mBoundingSphere.Radius = Math.Max(radius, meshData.mBoundingSphere.Radius); if (mesh.UVComponentCount[0] != 0) { if (meshData.mVertices != null) { meshData.mVertices[usedVertices].TextureCoordinate.X = mesh.TextureCoordinateChannels[0][j].X; meshData.mVertices[usedVertices].TextureCoordinate.Y = mesh.TextureCoordinateChannels[0][j].Y; } else { meshData.mVerticesExt[usedVertices].TextureCoordinate.X = mesh.TextureCoordinateChannels[0][j].X; meshData.mVerticesExt[usedVertices].TextureCoordinate.Y = mesh.TextureCoordinateChannels[0][j].Y; } } usedVertices++; } // Copy the indices for (var j = 0; j < mesh.FaceCount; j++) { for (var k = 0; k < 3; k++) { meshData.mIndices[usedFaces * 3 + k] = mesh.Faces[j].Indices[k] + loadedVertices; } usedFaces++; } loadedVertices = usedVertices; } subData.mNumPrimitives = usedFaces - subData.mIndicesOffset / 3; meshData.mSubDatas.Add(subData); meshData.mMaterials.Add(material); } if (meshData.mIsSkinned) { for (var i = 0; i < meshData.mVerticesExt.Length; i++) { var vertex = meshData.mVerticesExt[i].BoneWeights; // Should fix bone weights which are zero if (vertex.X + vertex.Y + vertex.Z + vertex.W == 10000.0f) { //meshData.mVerticesExt[i].BoneWeights = meshData.mVerticesExt[i - 1].BoneWeights; //meshData.mVerticesExt[i].BoneIndex = meshData.mVerticesExt[i - 1].BoneIndex; } else { meshData.mVerticesExt[i].BoneWeights *= 1.0f / (vertex.X + vertex.Y + vertex.Z + vertex.W); } } } meshData.mTotalNumPrimitives = usedFaces; meshData.mRootTransformation = AssimpToXna(scene.RootNode.Transform); meshData.mBoundingRectangle = CalculateBoundingRectangle(meshData); return(new Mesh.Mesh(mGraphicsDevice, meshData)); }