// Convert BoneWeightCollection to Byte4 (bone indices) and Vector4 (bone weights). private void ConvertBoneWeights(BoneWeightCollection boneWeightCollection, Byte4[] boneIndices, Vector4[] boneWeights, int vertexIndex, GeometryContent geometry) { // Normalize weights. (Number of weights should be MaxBonesPerVertex. Sum should be 1.) boneWeightCollection.NormalizeWeights(MaxBonesPerVertex); // Convert BoneWeights object to bone indices and bone weights. for (int i = 0; i < boneWeightCollection.Count; i++) { BoneWeight boneWeight = boneWeightCollection[i]; int boneIndex = _skeleton.GetIndex(boneWeight.BoneName); if (boneIndex == -1) { string message = String.Format( CultureInfo.InvariantCulture, "Vertex references unknown bone name \"{0}\".", boneWeight.BoneName); throw new InvalidContentException(message, geometry.Parent.Identity); } _tempIndices[i] = boneIndex; _tempWeights[i] = boneWeight.Weight; } // Clear unused indices/weights. for (int i = boneWeightCollection.Count; i < MaxBonesPerVertex; i++) { _tempIndices[i] = 0; _tempWeights[i] = 0f; } boneIndices[vertexIndex] = new Byte4(_tempIndices[0], _tempIndices[1], _tempIndices[2], _tempIndices[3]); boneWeights[vertexIndex] = new Vector4(_tempWeights[0], _tempWeights[1], _tempWeights[2], _tempWeights[3]); }
static void ConvertWeights(BoneWeightCollection inputWeights, Dictionary <string, int> boneIndices, Vector4[] outIndices, Vector4[] outWeights, int vertexIndex, GeometryContent geometry) { // we only handle 4 weights per bone const int maxWeights = 4; // create some temp arrays to hold our values int[] tempIndices = new int[maxWeights]; float[] tempWeights = new float[maxWeights]; // cull out any extra bones inputWeights.NormalizeWeights(maxWeights); // get our indices and weights for (int i = 0; i < inputWeights.Count; i++) { BoneWeight weight = inputWeights[i]; tempIndices[i] = boneIndices[weight.BoneName]; tempWeights[i] = weight.Weight; } // zero out any remaining spaces for (int i = inputWeights.Count; i < maxWeights; i++) { tempIndices[i] = 0; tempWeights[i] = 0; } // output the values outIndices[vertexIndex] = new Vector4(tempIndices[0], tempIndices[1], tempIndices[2], tempIndices[3]); outWeights[vertexIndex] = new Vector4(tempWeights[0], tempWeights[1], tempWeights[2], tempWeights[3]); }
private static void AddTriangleVertex(MeshBuilder builder, XmlMesh xmlMesh, XmlSubMesh xmlSubMesh, XmlSkeleton skeleton, int vertexIndex, int normalChannel, int uvChannel, int weightsChannel) { var geometry = xmlSubMesh.Geometry; if (xmlSubMesh.UseSharedGeometry) { geometry = xmlMesh.SharedGeometry; } var vertex = geometry.VertexBuffers[0].Vertices[vertexIndex]; var uv = geometry.VertexBuffers[1].Vertices[vertexIndex]; var boneAssignments = xmlSubMesh.BoneAssignments.Where(x => x.VertexIndex == vertexIndex); if (xmlSubMesh.UseSharedGeometry) { boneAssignments = xmlMesh.SharedBoneAssignments.Where(x => x.VertexIndex == vertexIndex); } builder.SetVertexChannelData(normalChannel, vertex.Normal.AsVector3()); builder.SetVertexChannelData(uvChannel, new Vector2(uv.TextureCoordinate.U, uv.TextureCoordinate.V)); var weights = new BoneWeightCollection(); foreach (var boneAssignment in boneAssignments) { weights.Add(new BoneWeight(skeleton.Bones[boneAssignment.BoneIndex].Name, boneAssignment.Weight)); } builder.SetVertexChannelData(weightsChannel, weights); builder.AddTriangleVertex(vertexIndex); }
private static void ProcessWeightsChannel(ContentProcessorContext context, string asset, GeometryContent geometry, int vertexChannelIndex, Dictionary <string, int> boneIndices, Dictionary <int, int> boneRemap) { if (boneIndices == null) { throw new InvalidContentException("Mesh has bone weights with no skeleton"); } VertexChannelCollection channels = geometry.Vertices.Channels; VertexChannel channel2 = channels[vertexChannelIndex]; VertexChannel <BoneWeightCollection> channel = channel2 as VertexChannel <BoneWeightCollection>; Byte4[] outputIndices = new Byte4[channel.Count]; Vector4[] outputWeights = new Vector4[channel.Count]; for (int i = 0; i < channel.Count; i++) { BoneWeightCollection inputWeights = channel[i]; ConvertVertexWeights(context, asset, inputWeights, boneIndices, outputIndices, outputWeights, i, geometry, boneRemap); } int usageIndex = VertexChannelNames.DecodeUsageIndex(channel.Name); string name = VertexChannelNames.EncodeName(VertexElementUsage.BlendIndices, usageIndex); string str = VertexChannelNames.EncodeName(VertexElementUsage.BlendWeight, usageIndex); channels.Insert <Byte4>(vertexChannelIndex + 1, name, outputIndices); channels.Insert <Vector4>(vertexChannelIndex + 2, str, outputWeights); channels.RemoveAt(vertexChannelIndex); }
// From the XNA CPU Skinning Sample under Ms-PL, (c) Microsoft Corporation private static void ConvertWeights( BoneWeightCollection weights, Dictionary <string, byte> boneIndices, Byte4[] outIndices, Vector4[] outWeights, int vertexIndex) { // we only handle 4 weights per bone const int maxWeights = 4; // create some tmp spans to hold our values Span <byte> tmpIndices = stackalloc byte[maxWeights]; Span <float> tmpWeights = stackalloc float[maxWeights]; // cull out any extra bones weights.NormalizeWeights(maxWeights); // get our indices and weights for (var i = 0; i < weights.Count; i++) { var weight = weights[i]; if (!boneIndices.ContainsKey(weight.BoneName)) { throw new Exception(string.Format( "Bone '{0}' was not found in the skeleton! Skeleton bones are: '{1}'.", weight.BoneName, string.Join("', '", boneIndices.Keys))); } tmpIndices[i] = boneIndices[weight.BoneName]; tmpWeights[i] = weight.Weight; } // zero out any remaining spaces for (int i = weights.Count; i < maxWeights; i++) { tmpIndices[i] = 0; tmpWeights[i] = 0; } // output the values outIndices[vertexIndex] = new Byte4(tmpIndices[0], tmpIndices[1], tmpIndices[2], tmpIndices[3]); outWeights[vertexIndex] = new Vector4(tmpWeights[0], tmpWeights[1], tmpWeights[2], tmpWeights[3]); }
public override void SetData(int index) { int i = _indicesChannel.Indices[index] * _vertexSize + _indicesOffset; int j = _weightChannel.Indices[index] * _vertexSize + _weightOffset; // Both channels use the same source data float[] data = _indicesChannel.Source.Data; float[] blendIndices = new float[] { data[i + 0], data[i + 1], data[i + 2], data[i + 3] }; float[] blendWeights = new float[] { data[j + 0], data[j + 1], data[j + 2], 0 }; // Fourth blend weight is stored implicitly blendWeights[3] = 1 - blendWeights[0] - blendWeights[1] - blendWeights[2]; if (blendWeights[3] == 1) { blendWeights[3] = 0; } BoneWeightCollection weights = new BoneWeightCollection(); for (int k = 0; k < blendIndices.Length; k++) { int jointIndex = (int)blendIndices[k]; float jointWeight = blendWeights[k]; if (jointWeight <= 0) { continue; } String jointName = GetJointKey(_joints[jointIndex]); weights.Add(new BoneWeight(jointName, jointWeight)); } if (weights.Count > 0) { _meshBuilder.SetVertexChannelData(_channelIndex, weights); } }
private static void ConvertVertexWeights(ContentProcessorContext context, string asset, BoneWeightCollection inputWeights, Dictionary <string, int> boneIndices, Byte4[] outputIndices, Vector4[] outputWeights, int vertexIndex, GeometryContent geometry, Dictionary <int, int> boneRemap) { inputWeights.NormalizeWeights(4); for (int i = 0; i < inputWeights.Count; i++) { BoneWeight weight = inputWeights[i]; if (!boneIndices.TryGetValue(weight.BoneName, out tempIndices[i])) { string boneName = weight.BoneName.Replace("__Skeleton", ""); if (!boneIndices.TryGetValue(boneName, out tempIndices[i])) { context.Logger.LogWarning(null, new ContentIdentity(asset), "Unknown bone name: " + weight.BoneName); //throw new InvalidContentException("Unknown bone name: " + weight.BoneName); continue; } } tempWeights[i] = weight.Weight; if (boneRemap != null) { tempIndices[i] = boneRemap[tempIndices[i]]; } } for (int j = inputWeights.Count; j < 4; j++) { tempIndices[j] = 0; tempWeights[j] = 0f; } outputIndices[vertexIndex] = new Byte4((float)tempIndices[0], (float)tempIndices[1], (float)tempIndices[2], (float)tempIndices[3]); outputWeights[vertexIndex] = new Vector4(tempWeights[0], tempWeights[1], tempWeights[2], tempWeights[3]); }
private static void VertexWeightsInUse(ContentProcessorContext context, string asset, BoneWeightCollection inputWeights, Dictionary <string, int> boneIndices, SortedDictionary <int, bool> indicesInUse) { if (boneIndices == null) { throw new InvalidContentException("Mesh has bone weights with no skeleton"); } int index; for (int i = 0; i < inputWeights.Count; i++) { BoneWeight weight = inputWeights[i]; if (!boneIndices.TryGetValue(weight.BoneName, out index)) { context.Logger.LogWarning(null, new ContentIdentity(asset), "Unknown bone name: " + weight.BoneName); //throw new InvalidContentException("Unknown bone name: " + weight.BoneName); continue; } if (indicesInUse.ContainsKey(index) == false) { indicesInUse.Add(index, true); } } }
private GeometryContent CreateGeometry(MeshContent mesh, Mesh aiMesh) { var geom = new GeometryContent { Material = _materials[aiMesh.MaterialIndex] }; // Vertices var baseVertex = mesh.Positions.Count; foreach (var vert in aiMesh.Vertices) { mesh.Positions.Add(ToXna(vert)); } geom.Vertices.AddRange(Enumerable.Range(baseVertex, aiMesh.VertexCount)); geom.Indices.AddRange(aiMesh.GetIndices()); if (aiMesh.HasBones) { var xnaWeights = new List <BoneWeightCollection>(); for (var i = 0; i < geom.Indices.Count; i++) { var list = new BoneWeightCollection(); for (var boneIndex = 0; boneIndex < aiMesh.BoneCount; boneIndex++) { var bone = aiMesh.Bones[boneIndex]; foreach (var weight in bone.VertexWeights) { if (weight.VertexID != i) { continue; } list.Add(new BoneWeight(bone.Name, weight.Weight)); } } if (list.Count > 0) { xnaWeights.Add(list); } } geom.Vertices.Channels.Add(VertexChannelNames.Weights(0), xnaWeights); } // Individual channels go here if (aiMesh.HasNormals) { geom.Vertices.Channels.Add(VertexChannelNames.Normal(), ToXna(aiMesh.Normals)); } for (var i = 0; i < aiMesh.TextureCoordinateChannelCount; i++) { geom.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(i), ToXnaTexCoord(aiMesh.TextureCoordinateChannels[i])); } for (var i = 0; i < aiMesh.VertexColorChannelCount; i++) { geom.Vertices.Channels.Add(VertexChannelNames.Color(i), ToXnaColors(aiMesh.VertexColorChannels[i])); } return(geom); }
public override NodeContent Import(string filename, ContentImporterContext context) { context.Logger.LogMessage("Importing H3D file: {0}", filename); _identity = new ContentIdentity(filename, GetType().Name); _rootNode = new NodeContent() { Identity = _identity, Name = "RootNode" }; var scene = FormatIdentifier.IdentifyAndOpen(filename); var model = scene.Models[0]; if (!scene.Textures.Any()) { var path = Path.Combine(Path.GetDirectoryName(filename), $"{Path.GetFileNameWithoutExtension(filename)}@Textures{Path.GetExtension(filename)}"); if (File.Exists(path)) { context.Logger.LogMessage($"Found texture file {path}. Loading data..."); scene.Merge(FormatIdentifier.IdentifyAndOpen(path, model.Skeleton)); } else { context.Logger.LogMessage($"Couldn't find texture file {path}!"); } } // Textures var textures = new Dictionary <string, Texture2DContent>(); foreach (var texture in scene.Textures) { var bitmapContent = new PixelBitmapContent <Color>(texture.Width, texture.Height) { Identity = _identity, Name = texture.Name }; bitmapContent.SetPixelData(texture.ToRGBA()); var textureContent = new Texture2DContent() { Identity = _identity, Name = texture.Name }; textureContent.Faces[0].Add(bitmapContent); textures.Add(textureContent.Name, textureContent); } // Materials var materials = new Dictionary <string, H3DMaterialContent>(); foreach (var material in model.Materials) { #if DEBUG var hlslCode = new HLSLShaderGenerator(material.MaterialParams) { BoneCount = model.Skeleton.Count }.GetShader(); var glslCode = new GLSLFragmentShaderGenerator(material.MaterialParams).GetFragShader(); #endif var materialContent = new H3DMaterialContent() { Identity = _identity, Name = material.Name, Effect = new EffectContent { Identity = _identity, Name = "H3DEffect", EffectCode = new HLSLShaderGenerator(material.MaterialParams) { BoneCount = model.Skeleton.Count }.GetShader() }, Material = material.Name, FaceCulling = (H3DFaceCulling?)material.MaterialParams.FaceCulling, EmissionColor = material.MaterialParams.EmissionColor.ToXNA(), AmbientColor = material.MaterialParams.AmbientColor.ToXNA(), DiffuseColor = material.MaterialParams.DiffuseColor.ToXNA(), Specular0Color = material.MaterialParams.Specular0Color.ToXNA(), Specular1Color = material.MaterialParams.Specular1Color.ToXNA(), Constant0Color = material.MaterialParams.Constant0Color.ToXNA(), Constant1Color = material.MaterialParams.Constant1Color.ToXNA(), Constant2Color = material.MaterialParams.Constant2Color.ToXNA(), Constant3Color = material.MaterialParams.Constant3Color.ToXNA(), Constant4Color = material.MaterialParams.Constant4Color.ToXNA(), Constant5Color = material.MaterialParams.Constant5Color.ToXNA(), BlendColor = material.MaterialParams.BlendColor.ToXNA(), DepthBufferRead = material.MaterialParams.DepthBufferRead, DepthBufferWrite = material.MaterialParams.DepthBufferWrite, StencilBufferRead = material.MaterialParams.StencilBufferRead, StencilBufferWrite = material.MaterialParams.StencilBufferWrite, }; var texCount = 0; if (material.EnabledTextures[0]) { texCount++; } if (material.EnabledTextures[1]) { texCount++; } if (material.EnabledTextures[2]) { texCount++; } materialContent.TextureList = new Texture2DContent[texCount]; if (material.EnabledTextures[0]) { materialContent.TextureList[0] = textures[material.Texture0Name]; } if (material.EnabledTextures[1]) { materialContent.TextureList[1] = textures[material.Texture1Name]; } if (material.EnabledTextures[2]) { materialContent.TextureList[2] = textures[material.Texture2Name]; } materialContent.TextureSamplerSettings = material.TextureMappers.Select(tm => new TextureSamplerSettings() { WrapU = tm.WrapU.ToXNAWrap(), WrapV = tm.WrapV.ToXNAWrap(), MagFilter = (TextureSamplerSettings.TextureMagFilter)tm.MagFilter, MinFilter = (TextureSamplerSettings.TextureMinFilter)tm.MinFilter }).ToArray(); materials.Add(material.Name, materialContent); } // Geometry var meshes = new List <MeshContent>(); for (var i = 0; i < model.Meshes.Count; i++) { var modelMesh = model.Meshes[i]; if (modelMesh.Type == H3DMeshType.Silhouette) { continue; } var mesh = new MeshContent() { Identity = _identity, Name = $"{model.Materials[modelMesh.MaterialIndex].Name}_node{i}", }; var geometry = new GeometryContent { Identity = _identity, Material = materials[model.Materials[modelMesh.MaterialIndex].Name] }; var vertices = GetWorldSpaceVertices(model.Skeleton, modelMesh); var baseVertex = mesh.Positions.Count; foreach (var vertex in vertices) { mesh.Positions.Add(vertex.Position.ToVector3()); } geometry.Vertices.AddRange(Enumerable.Range(baseVertex, vertices.Length)); foreach (var attribute in modelMesh.Attributes) { if (attribute.Name >= PICAAttributeName.BoneIndex) { continue; } switch (attribute.Name) { case PICAAttributeName.Position: break; // Already added case PICAAttributeName.Normal: geometry.Vertices.Channels.Add(VertexChannelNames.Normal(0), vertices.Select(vertex => vertex.Normal.ToVector3())); break; case PICAAttributeName.Tangent: geometry.Vertices.Channels.Add(VertexChannelNames.Tangent(0), vertices.Select(vertex => vertex.Tangent.ToVector3())); break; case PICAAttributeName.Color: geometry.Vertices.Channels.Add(VertexChannelNames.Color(0), vertices.Select(vertex => vertex.Color.ToColor())); break; case PICAAttributeName.TexCoord0: geometry.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(0), vertices.Select(vertex => vertex.TexCoord0.ToVector2().ToUV())); break; case PICAAttributeName.TexCoord1: geometry.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(1), vertices.Select(vertex => vertex.TexCoord1.ToVector2().ToUV())); break; case PICAAttributeName.TexCoord2: geometry.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(2), vertices.Select(vertex => vertex.TexCoord2.ToVector2().ToUV())); break; } } var vertexOffset = 0; var xnaWeights = new List <BoneWeightCollection>(); foreach (var modelSubMesh in modelMesh.SubMeshes) { geometry.Indices.AddRange(modelSubMesh.Indices.Select(index => (int)index)); var vertexCount = modelSubMesh.MaxIndex + 1 - vertexOffset; var subMeshVertices = vertices.Skip(vertexOffset).Take(vertexCount).ToList(); if (modelSubMesh.Skinning == H3DSubMeshSkinning.Smooth) { foreach (var vertex in subMeshVertices) { var list = new BoneWeightCollection(); for (var index = 0; index < 4; index++) { var bIndex = vertex.Indices[index]; var weight = vertex.Weights[index]; if (weight == 0) { break; } if (bIndex < modelSubMesh.BoneIndicesCount && bIndex > -1) { bIndex = modelSubMesh.BoneIndices[bIndex]; } else { bIndex = 0; } list.Add(new BoneWeight(model.Skeleton[bIndex].Name, weight)); } xnaWeights.Add(list); } } else { foreach (var vertex in vertices) { var bIndex = vertex.Indices[0]; if (bIndex < modelSubMesh.BoneIndices.Length && bIndex > -1) { bIndex = modelSubMesh.BoneIndices[bIndex]; } else { bIndex = 0; } xnaWeights.Add(new BoneWeightCollection() { new BoneWeight(model.Skeleton[bIndex].Name, 0) }); } } vertexOffset += vertexCount; } geometry.Vertices.Channels.Add(VertexChannelNames.Weights(0), xnaWeights); mesh.Geometry.Add(geometry); meshes.Add(mesh); } foreach (var mesh in meshes) { _rootNode.Children.Add(mesh); } var rootBone = ImportBones(model); _rootNode.Children.Add(rootBone); if (!scene.SkeletalAnimations.Any()) { var path = Path.Combine(Path.GetDirectoryName(filename), $"{Path.GetFileNameWithoutExtension(filename)}@Animations{Path.GetExtension(filename)}"); if (File.Exists(path)) { context.Logger.LogMessage($"Found animation file {path}. Loading data..."); scene.Merge(FormatIdentifier.IdentifyAndOpen(path, model.Skeleton)); } else { context.Logger.LogMessage($"Couldn't find animation file {path}!"); } } foreach (var animation in ImportSkeletalAnimations(scene)) { rootBone.Animations.Add(animation.Name, animation); } foreach (var animation in ImportMaterialAnimations(scene)) { _rootNode.Children.Add(animation); } return(_rootNode); }
/// <summary> /// Go through the vertex channels in the geometry and replace the /// BoneWeightCollection objects with weight and index channels. /// </summary> /// <param name="geometry">The geometry to process.</param> /// <param name="vertexChannelIndex">The index of the vertex channel to process.</param> /// <param name="context">The processor context.</param> protected override void ProcessVertexChannel(GeometryContent geometry, int vertexChannelIndex, ContentProcessorContext context) { bool boneCollectionsWithZeroWeights = false; if (geometry.Vertices.Channels[vertexChannelIndex].Name == VertexChannelNames.Weights()) { int meshIndex = (int)geometry.Parent.OpaqueData["MeshIndex"]; BoneIndexer indexer = indexers[meshIndex]; // Skin channels are passed in from importers as BoneWeightCollection objects VertexChannel <BoneWeightCollection> vc = (VertexChannel <BoneWeightCollection>) geometry.Vertices.Channels[vertexChannelIndex]; int maxBonesPerVertex = 0; for (int i = 0; i < vc.Count; i++) { int count = vc[i].Count; if (count > maxBonesPerVertex) { maxBonesPerVertex = count; } } // Add weights as colors (Converts well to 4 floats) // and indices as packed 4byte vectors. Color[] weightsToAdd = new Color[vc.Count]; Byte4[] indicesToAdd = new Byte4[vc.Count]; // Go through the BoneWeightCollections and create a new // weightsToAdd and indicesToAdd array for each BoneWeightCollection. for (int i = 0; i < vc.Count; i++) { BoneWeightCollection bwc = vc[i]; if (bwc.Count == 0) { boneCollectionsWithZeroWeights = true; continue; } bwc.NormalizeWeights(4); int count = bwc.Count; if (count > maxBonesPerVertex) { maxBonesPerVertex = count; } // Add the appropriate bone indices based on the bone names in the // BoneWeightCollection Vector4 bi = new Vector4(); bi.X = count > 0 ? indexer.GetBoneIndex(bwc[0].BoneName) : (byte)0; bi.Y = count > 1 ? indexer.GetBoneIndex(bwc[1].BoneName) : (byte)0; bi.Z = count > 2 ? indexer.GetBoneIndex(bwc[2].BoneName) : (byte)0; bi.W = count > 3 ? indexer.GetBoneIndex(bwc[3].BoneName) : (byte)0; indicesToAdd[i] = new Byte4(bi); Vector4 bw = new Vector4(); bw.X = count > 0 ? bwc[0].Weight : 0; bw.Y = count > 1 ? bwc[1].Weight : 0; bw.Z = count > 2 ? bwc[2].Weight : 0; bw.W = count > 3 ? bwc[3].Weight : 0; weightsToAdd[i] = new Color(bw); } // Remove the old BoneWeightCollection channel geometry.Vertices.Channels.Remove(vc); // Add the new channels geometry.Vertices.Channels.Add <Byte4>(VertexElementUsage.BlendIndices.ToString(), indicesToAdd); geometry.Vertices.Channels.Add <Color>(VertexElementUsage.BlendWeight.ToString(), weightsToAdd); } else { // No skinning info, so we let the base class process the channel base.ProcessVertexChannel(geometry, vertexChannelIndex, context); } if (boneCollectionsWithZeroWeights) { context.Logger.LogWarning("", geometry.Identity, "BonesWeightCollections with zero weights found in geometry."); } }
private MeshContent ExtractMesh(aiMesh aiMesh) { if (!String.IsNullOrEmpty(aiMesh.mName.Data)) { log("modelname " + aiMesh.mName.Data); meshBuilder = MeshBuilder.StartMesh(aiMesh.mName.Data); } else { meshBuilder = MeshBuilder.StartMesh(Path.GetFileNameWithoutExtension(filename)); } if (!aiMesh.HasPositions()) { throw new Exception("MOdel does not have Position"); } // Add additional vertex channels for texture coordinates and normals if (aiMesh.HasTextureCoords(0)) { textureCoordinateDataIndex = meshBuilder.CreateVertexChannel <Vector2>(VertexChannelNames.TextureCoordinate(0)); } else if (aiMesh.HasVertexColors(0)) { colorCoordinateDataIndex = meshBuilder.CreateVertexChannel <Vector4>(VertexChannelNames.Color(0)); } if (aiMesh.HasNormals()) { normalDataIndex = meshBuilder.CreateVertexChannel <Vector3>(VertexChannelNames.Normal()); } if (aiMesh.HasTangentsAndBitangents()) { tangentDataIndex = meshBuilder.CreateVertexChannel <Vector3>(VertexChannelNames.Tangent(0)); binormalDataIndex = meshBuilder.CreateVertexChannel <Vector3>(VertexChannelNames.Binormal(0)); } if (aiMesh.HasBones()) { boneDataIndex = meshBuilder.CreateVertexChannel <BoneWeightCollection>(VertexChannelNames.Weights(0)); } var numFaces = (int)aiMesh.mNumFaces; var numVertices = (int)aiMesh.mNumVertices; var aiPositions = aiMesh.mVertices; var aiNormals = aiMesh.mNormals; var aiTextureCoordsAll = aiMesh.mTextureCoords; var aiTextureCoords = (aiTextureCoordsAll != null) ? aiTextureCoordsAll[0] : null; for (int j = 0; j < aiMesh.mNumVertices; j++) { meshBuilder.CreatePosition(aiMesh.mVertices[j].x, aiMesh.mVertices[j].y, aiMesh.mVertices[j].z); } meshBuilder.SetMaterial(GetMaterial(aiMesh)); var aiFaces = aiMesh.mFaces; var dxIndices = new uint[numFaces * 3]; for (int k = 0; k < numFaces; ++k) { var aiFace = aiFaces[k]; var aiIndices = aiFace.mIndices; for (int j = 0; j < 3; ++j) { int index = (int)aiIndices[j]; if (aiMesh.HasTextureCoords(0)) { meshBuilder.SetVertexChannelData(textureCoordinateDataIndex, new Vector2(aiMesh.mTextureCoords[0][index].x, aiMesh.mTextureCoords[0][index].y)); } else if (aiMesh.HasVertexColors(0)) { meshBuilder.SetVertexChannelData(colorCoordinateDataIndex, new Vector4(aiMesh.mColors[0][index].r, aiMesh.mColors[0][index].g, aiMesh.mColors[0][index].b, aiMesh.mColors[0][index].a)); } if (aiMesh.HasNormals()) { meshBuilder.SetVertexChannelData(normalDataIndex, new Vector3(aiMesh.mNormals[index].x, aiMesh.mNormals[index].y, aiMesh.mNormals[index].z)); } if (aiMesh.HasTangentsAndBitangents()) { meshBuilder.SetVertexChannelData(tangentDataIndex, new Vector3(aiMesh.mTangents[index].x, aiMesh.mTangents[index].y, aiMesh.mTangents[index].z)); meshBuilder.SetVertexChannelData(binormalDataIndex, new Vector3(aiMesh.mBitangents[index].x, aiMesh.mBitangents[index].y, aiMesh.mBitangents[index].z)); } if (aiMesh.HasBones()) { BoneWeightCollection BoneWeightCollection = new BoneWeightCollection(); if (wbone.ContainsKey(index)) { foreach (var item in wbone[index]) { BoneWeightCollection.Add(new BoneWeight(item.Key, item.Value)); } } meshBuilder.SetVertexChannelData(boneDataIndex, BoneWeightCollection); } meshBuilder.AddTriangleVertex(index); } } MeshContent meshContent = meshBuilder.FinishMesh(); return(meshContent); }
public void DefaultEffectTest() { NodeContent input; { input = new NodeContent(); var mesh = new MeshContent() { Name = "Mesh1" }; mesh.Positions.Add(new Vector3(0, 0, 0)); mesh.Positions.Add(new Vector3(1, 0, 0)); mesh.Positions.Add(new Vector3(1, 1, 1)); var geom = new GeometryContent(); geom.Vertices.Add(0); geom.Vertices.Add(1); geom.Vertices.Add(2); geom.Indices.Add(0); geom.Indices.Add(1); geom.Indices.Add(2); geom.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(0), new[] { new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), }); var wieghts = new BoneWeightCollection(); wieghts.Add(new BoneWeight("bone1", 0.5f)); geom.Vertices.Channels.Add(VertexChannelNames.Weights(0), new[] { wieghts, wieghts, wieghts }); mesh.Geometry.Add(geom); input.Children.Add(mesh); var bone1 = new BoneContent { Name = "bone1", Transform = Matrix.CreateTranslation(0, 1, 0) }; input.Children.Add(bone1); var anim = new AnimationContent() { Name = "anim1", Duration = TimeSpan.Zero }; input.Animations.Add(anim.Name, anim); } var processorContext = new ProcessorContext(TargetPlatform.Windows, "dummy.xnb"); var processor = new ModelProcessor { DefaultEffect = MaterialProcessorDefaultEffect.SkinnedEffect, }; var output = processor.Process(input, processorContext); // TODO: Not sure why, but XNA always returns a BasicMaterialContent // even when we specify SkinnedEffect as the default. We need to fix // the test first before we can enable the assert here. //Assert.IsInstanceOf(typeof(SkinnedMaterialContent), output.Meshes[0].MeshParts[0].Material); }
public override NodeContent Import(string filename, ContentImporterContext context) { ContentIdentity identity = new ContentIdentity(filename, GetType().Name); const int MAX_BONE_WEIGHTS = 4; VertexBoneWeightLimitConfig boneConfig = new VertexBoneWeightLimitConfig(MAX_BONE_WEIGHTS); AssimpImporter importer = new AssimpImporter(); importer.SetConfig(boneConfig); importer.AttachLogStream(new LogStream((msg, userData) => context.Logger.LogMessage(msg))); Scene scene = importer.ImportFile(filename, PostProcessSteps.FlipUVs | PostProcessSteps.JoinIdenticalVertices | PostProcessSteps.Triangulate | PostProcessSteps.SortByPrimitiveType | PostProcessSteps.FindInvalidData | PostProcessSteps.LimitBoneWeights | PostProcessSteps.FixInFacingNormals); // Root node NodeContent rootNode = new NodeContent { Name = scene.RootNode.Name, Identity = identity, Transform = Matrix.Transpose(ToXna(scene.RootNode.Transform)) }; // Materials MaterialContent[] materials = new MaterialContent[scene.MaterialCount]; for (int m = 0; m < scene.MaterialCount; m++) { materials[m] = new BasicMaterialContent(); materials[m].Identity = identity; // For some reason, there is all kinds of nasty junk in this string: materials[m].Name = CleanInput(scene.Materials[m].Name); for (int t = 0; t < scene.Materials[m].GetTextureCount(TextureType.Diffuse); t++) { TextureSlot diffuseMap = scene.Materials[m].GetTexture(TextureType.Diffuse, t); if (!String.IsNullOrEmpty(diffuseMap.FilePath)) { materials[m].Textures.Add("Texture" + (t > 0 ? t.ToString() : ""), new ExternalReference <TextureContent>(diffuseMap.FilePath, identity)); } } } // Bones // We find 'mesh container' nodes with the best names for those meshes while looking for the bones, // and will need them later when we create the MeshContents. I have a feeling that this won't work // in general, and may need to be made more robust. Dictionary <Mesh, string> meshNames = new Dictionary <Mesh, string>(); Dictionary <Node, BoneContent> nodeToBoneMap = new Dictionary <Node, BoneContent>(); BoneContent skeleton = null; // The root bone for the model. List <Node> hierarchyNodes = scene.RootNode.Children.SelectDeep(n => n.Children).ToList(); foreach (Node node in hierarchyNodes) { BoneContent bone = new BoneContent { Name = node.Name, Transform = Matrix.Transpose(ToXna(node.Transform)) }; if (node.MeshIndices != null) { // This node is a 'mesh container' instead of a bone, so we only care about extracting the name of the mesh. foreach (int meshIndex in node.MeshIndices) { if (!meshNames.ContainsKey(scene.Meshes[meshIndex])) { meshNames.Add(scene.Meshes[meshIndex], node.Name); } } } else if (node.Parent == scene.RootNode) { if (skeleton == null) { // This will be our skeleton so put the animations here: if (scene.HasAnimations) { foreach (Animation assimpAnim in scene.Animations) { if (assimpAnim.HasNodeAnimations) { AnimationContent newAnim = new AnimationContent(); newAnim.Identity = identity; newAnim.Duration = TimeSpan.FromSeconds(assimpAnim.DurationInTicks / assimpAnim.TicksPerSecond); newAnim.Name = assimpAnim.Name; foreach (NodeAnimationChannel nac in assimpAnim.NodeAnimationChannels) { Node animatedNode = hierarchyNodes.Find(n => n.Name == nac.NodeName); AnimationChannel newChan = BuildAnimtionChannel(animatedNode, nac); newAnim.Channels.Add(nac.NodeName, newChan); } if (String.IsNullOrEmpty(assimpAnim.Name)) { bone.Animations.Add("SkelematorNoAnimationName", newAnim); } else { bone.Animations.Add(assimpAnim.Name, newAnim); } } } } rootNode.Children.Add(bone); skeleton = bone; } else { context.Logger.LogWarning(null, identity, "Found multiple skeletons in the model, throwing extras away..."); } } else { BoneContent parent = nodeToBoneMap[node.Parent]; parent.Children.Add(bone); } nodeToBoneMap.Add(node, bone); } // Meshes Dictionary <Mesh, MeshContent> meshes = new Dictionary <Mesh, MeshContent>(); foreach (Mesh sceneMesh in scene.Meshes) { // See comment about meshNames at the beginning of the bone section. MeshBuilder mb = MeshBuilder.StartMesh(meshNames[sceneMesh]); mb.SwapWindingOrder = true; // Appears to require this... int positionIndex = -1; for (int v = 0; v < sceneMesh.VertexCount; v++) { Vector3D vert = sceneMesh.Vertices[v]; // CreatePosition should just return a 0-based index of the newly added vertex. positionIndex = mb.CreatePosition(new Vector3(vert.X, vert.Y, vert.Z)); if (positionIndex != v) { throw new InvalidContentException("Something unexpected happened while building a MeshContent from the Assimp scene mesh's vertices. The scene mesh may contains duplicate vertices."); } } if (positionIndex + 1 < 3) { throw new InvalidContentException("There were not enough vertices in the Assimp scene mesh."); } // Create vertex channels int normalVertexChannelIndex = mb.CreateVertexChannel <Vector3>(VertexChannelNames.Normal()); int[] texCoordVertexChannelIndex = new int[sceneMesh.TextureCoordsChannelCount]; for (int x = 0; x < sceneMesh.TextureCoordsChannelCount; x++) { texCoordVertexChannelIndex[x] = mb.CreateVertexChannel <Vector2>(VertexChannelNames.TextureCoordinate(x)); } int boneWeightVertexChannelIndex = -1; if (sceneMesh.HasBones) { boneWeightVertexChannelIndex = mb.CreateVertexChannel <BoneWeightCollection>(VertexChannelNames.Weights()); } // Prepare vertex channel data BoneWeightCollection[] boneWeightData = null; if (sceneMesh.HasBones) { boneWeightData = new BoneWeightCollection[sceneMesh.VertexCount]; for (int v = 0; v < sceneMesh.VertexCount; v++) { boneWeightData[v] = new BoneWeightCollection(); } foreach (Bone sceneMeshBone in sceneMesh.Bones) { // We have to assume that the bone's name matches up with a node, and therefore one of our BoneContents. foreach (VertexWeight sceneMeshBoneWeight in sceneMeshBone.VertexWeights) { boneWeightData[sceneMeshBoneWeight.VertexID].Add(new BoneWeight(sceneMeshBone.Name, sceneMeshBoneWeight.Weight)); } } for (int v = 0; v < sceneMesh.VertexCount; v++) { if (boneWeightData[v].Count <= 0) { throw new InvalidContentException("Encountered vertices without bone weights."); } boneWeightData[v].NormalizeWeights(); } } // Set the per-geometry data mb.SetMaterial(materials[sceneMesh.MaterialIndex]); mb.SetOpaqueData(new OpaqueDataDictionary()); // Add each vertex for (int f = 0; f < sceneMesh.FaceCount; f++) { if (sceneMesh.Faces[f].IndexCount != 3) { throw new InvalidContentException("Only triangular faces allowed."); } for (int t = 0; t < 3; t++) { mb.SetVertexChannelData(normalVertexChannelIndex, ToXna(sceneMesh.Normals[sceneMesh.Faces[f].Indices[t]])); for (int x = 0; x < sceneMesh.TextureCoordsChannelCount; x++) { mb.SetVertexChannelData(texCoordVertexChannelIndex[x], ToXnaVector2((sceneMesh.GetTextureCoords(x))[sceneMesh.Faces[f].Indices[t]])); } if (sceneMesh.HasBones) { mb.SetVertexChannelData(boneWeightVertexChannelIndex, boneWeightData[sceneMesh.Faces[f].Indices[t]]); } mb.AddTriangleVertex((int)(sceneMesh.Faces[f].Indices[t])); } } MeshContent mesh = mb.FinishMesh(); rootNode.Children.Add(mesh); meshes.Add(sceneMesh, mesh); } return(rootNode); }
public MeshContent Process() { newMesh = new MeshContent(); newMesh.Name = splitter.mesh.Name + splitter.currentIndex.ToString(); SortedDictionary <string, object> faceBones = new SortedDictionary <string, object>(); GeometryContent newGeom = new GeometryContent(); while (index < geom.Indices.Count - 1) { int[] faceIndices = new int[] { geom.Indices[index], geom.Indices[index + 1], geom.Indices[index + 2] }; for (int i = 0; i < 3; i++) { BoneWeightCollection weightCollection = weightChannel[ geom.Indices[index + i]]; foreach (BoneWeight weight in weightCollection) { if (!meshBones.ContainsKey(weight.BoneName) && !faceBones.ContainsKey(weight.BoneName)) { faceBones.Add(weight.BoneName, null); } } } if (meshBones.Count + faceBones.Count > splitter.maxBones) { faceBones.Clear(); vertexEndIndex = index; break; } foreach (string s in faceBones.Keys) { meshBones.Add(s, null); } faceBones.Clear(); for (int i = 0; i < 3; i++) { if (oldToNewDict.ContainsKey(faceIndices[i])) { } else { int newIndex = newMesh.Positions.Count; newMesh.Positions.Add(geom.Vertices.Positions[faceIndices[i]]); oldToNewDict.Add(faceIndices[i], newIndex); newGeom.Vertices.Add(newIndex); } newGeom.Indices.Add(oldToNewDict[faceIndices[i]]); } index += 3; vertexEndIndex = index; } newMesh.Geometry.Add(newGeom); Finish(); return(newMesh); }
//-------------------------------------------------------------- //-------------------------------------------------------------- //-------------------------------------------------------------- //-------------------------------------------------------------- /* /// <summary> /// Gets or sets a value indicating whether alpha premultiply of vertex color is enabled. /// </summary> /// <value> /// <see langword="true"/> if alpha premultiply of vertex colors is enabled; otherwise, <see langword="false"/>. /// </value> [DefaultValue(true)] [DisplayName("Premultiply Vertex Colors")] [Description("If enabled, vertex color channels are converted to premultiplied alpha format.")] public virtual bool PremultiplyVertexColors { get { return _premultiplyVertexColors; } set { _premultiplyVertexColors = value; } } private bool _premultiplyVertexColors = true; */ //-------------------------------------------------------------- #endregion Other #if ANIMATION // Convert BoneWeightCollection to Byte4 (bone indices) and Vector4 (bone weights). private void ConvertBoneWeights(BoneWeightCollection boneWeightCollection, Byte4[] boneIndices, Vector4[] boneWeights, int vertexIndex, GeometryContent geometry) { // Normalize weights. (Number of weights should be MaxBonesPerVertex. Sum should be 1.) boneWeightCollection.NormalizeWeights(MaxBonesPerVertex); // Convert BoneWeights object to bone indices and bone weights. for (int i = 0; i < boneWeightCollection.Count; i++) { BoneWeight boneWeight = boneWeightCollection[i]; int boneIndex = _skeleton.GetIndex(boneWeight.BoneName); if (boneIndex == -1) { string message = String.Format( CultureInfo.InvariantCulture, "Vertex references unknown bone name \"{0}\".", boneWeight.BoneName); throw new InvalidContentException(message, geometry.Parent.Identity); } _tempIndices[i] = boneIndex; _tempWeights[i] = boneWeight.Weight; } // Clear unused indices/weights. for (int i = boneWeightCollection.Count; i < MaxBonesPerVertex; i++) { _tempIndices[i] = 0; _tempWeights[i] = 0f; } boneIndices[vertexIndex] = new Byte4(_tempIndices[0], _tempIndices[1], _tempIndices[2], _tempIndices[3]); boneWeights[vertexIndex] = new Vector4(_tempWeights[0], _tempWeights[1], _tempWeights[2], _tempWeights[3]); }
public void DefaultEffectTest() { NodeContent input; { input = new NodeContent(); var mesh = new MeshContent() { Name = "Mesh1" }; mesh.Positions.Add(new Vector3(0, 0, 0)); mesh.Positions.Add(new Vector3(1, 0, 0)); mesh.Positions.Add(new Vector3(1, 1, 1)); var geom = new GeometryContent(); geom.Vertices.Add(0); geom.Vertices.Add(1); geom.Vertices.Add(2); geom.Indices.Add(0); geom.Indices.Add(1); geom.Indices.Add(2); geom.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(0), new[] { new Vector2(0,0), new Vector2(1,0), new Vector2(1,1), }); var wieghts = new BoneWeightCollection(); wieghts.Add(new BoneWeight("bone1", 0.5f)); geom.Vertices.Channels.Add(VertexChannelNames.Weights(0), new[] { wieghts, wieghts, wieghts }); mesh.Geometry.Add(geom); input.Children.Add(mesh); var bone1 = new BoneContent { Name = "bone1", Transform = Matrix.CreateTranslation(0,1,0) }; input.Children.Add(bone1); var anim = new AnimationContent() { Name = "anim1", Duration = TimeSpan.Zero }; input.Animations.Add(anim.Name, anim); } var processorContext = new TestProcessorContext(TargetPlatform.Windows, "dummy.xnb"); var processor = new ModelProcessor { DefaultEffect = MaterialProcessorDefaultEffect.SkinnedEffect, }; var output = processor.Process(input, processorContext); // TODO: Not sure why, but XNA always returns a BasicMaterialContent // even when we specify SkinnedEffect as the default. We need to fix // the test first before we can enable the assert here. //Assert.IsInstanceOf(typeof(SkinnedMaterialContent), output.Meshes[0].MeshParts[0].Material); }
private MeshContent CreateMesh(Mesh sceneMesh) { var mesh = new MeshContent { Name = sceneMesh.Name }; // Position vertices are shared at the mesh level foreach (var vert in sceneMesh.Vertices) { mesh.Positions.Add(new Vector3(vert.X, vert.Y, vert.Z)); } var geom = new GeometryContent { Material = _materials[sceneMesh.MaterialIndex] }; // Geometry vertices reference 1:1 with the MeshContent parent, // no indirection is necessary. //geom.Vertices.Positions.AddRange(mesh.Positions); geom.Vertices.AddRange(Enumerable.Range(0, sceneMesh.VertexCount)); geom.Indices.AddRange(sceneMesh.GetIndices()); if (sceneMesh.HasBones) { var xnaWeights = new List <BoneWeightCollection>(); for (var i = 0; i < geom.Indices.Count; i++) { var list = new BoneWeightCollection(); for (var boneIndex = 0; boneIndex < sceneMesh.BoneCount; boneIndex++) { var bone = sceneMesh.Bones[boneIndex]; foreach (var weight in bone.VertexWeights) { if (weight.VertexID != i) { continue; } list.Add(new BoneWeight(bone.Name, weight.Weight)); } } if (list.Count > 0) { xnaWeights.Add(list); } } geom.Vertices.Channels.Add(VertexChannelNames.Weights(0), xnaWeights); } // Individual channels go here if (sceneMesh.HasNormals) { geom.Vertices.Channels.Add(VertexChannelNames.Normal(), ToXna(sceneMesh.Normals)); } for (var i = 0; i < sceneMesh.TextureCoordinateChannelCount; i++) { geom.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(i), ToXnaTexCoord(sceneMesh.TextureCoordinateChannels[i])); } mesh.Geometry.Add(geom); return(mesh); }
public static MeshContent BuildMesh(MMDModel1 model, string filename) { //メッシュ作成 MeshContent buildingMesh = new MeshContent(); //まずは頂点を登録。 //ひげねこ氏によるとモデルごとのローカル座標である必要があるようだが //pmdはモデル一つ=変換必要なし foreach (var vec in model.Vertexes) buildingMesh.Positions.Add(MMDXMath.ToVector3(vec.Pos)); //ジオメトリとマテリアルの作成 //メモ:頂点が3つ合わさって面、面が幾つか集まってジオメトリ。ジオメトリにマテリアルが付随。ジオメトリの集合がメッシュ long FaceIndex = 0; Dictionary<ushort, int> vertMap = new Dictionary<ushort, int>(); //ジオメトリとマテリアルの生成 for (int i = 0; i < model.Materials.Length; i++) { GeometryContent geometry = new GeometryContent(); BasicMaterialContent material = new BasicMaterialContent(); geometry.Material = material; //マテリアル設定 material.VertexColorEnabled = false;//頂点カラー無し material.Alpha = model.Materials[i].Alpha; material.DiffuseColor = MMDXMath.ToVector3(model.Materials[i].DiffuseColor); material.EmissiveColor = MMDXMath.ToVector3(model.Materials[i].MirrorColor); material.SpecularColor = MMDXMath.ToVector3(model.Materials[i].SpecularColor); material.SpecularPower = model.Materials[i].Specularity; if (!string.IsNullOrEmpty(model.Materials[i].TextureFileName)) material.Texture = new ExternalReference<TextureContent>(NormalizeFilepath(model.Materials[i].TextureFileName, filename)); if (!string.IsNullOrEmpty(model.Materials[i].SphereTextureFileName)) { if (Path.GetExtension(model.Materials[i].SphereTextureFileName).ToLower() == ".sph") { material.OpaqueData.Add("UseSphere", 1); } else if (Path.GetExtension(model.Materials[i].SphereTextureFileName).ToLower() == ".spa") { material.OpaqueData.Add("UseSphere", 2); } else throw new InvalidContentException("スフィアマップは*.sph, *.spaのみ指定可能です: " + model.Materials[i].SphereTextureFileName); material.Textures.Add("Sphere", new ExternalReference<TextureContent>(ProcessSphere(NormalizeFilepath(model.Materials[i].SphereTextureFileName, filename)))); } else { material.OpaqueData.Add("UseSphere", 0); } //トゥーンのテクスチャを入れる string toonTexPath = ToonTexManager.Instance.GetToonTexPath(model.Materials[i].ToonIndex, model.ToonFileNames, filename); if (!string.IsNullOrEmpty(toonTexPath)) { material.Textures.Add("ToonTex", new ExternalReference<TextureContent>(toonTexPath)); material.OpaqueData.Add("UseToon", true); } else material.OpaqueData.Add("UseToon", false); //一応エッジ情報突っ込んでおく material.OpaqueData.Add("Edge", (model.Materials[i].EdgeFlag != 0)); //ジオメトリのチャンネル設定 //法線 geometry.Vertices.Channels.Add(VertexChannelNames.Normal(0), typeof(Vector3), null); //テクスチャ if (!string.IsNullOrEmpty(model.Materials[i].TextureFileName)) geometry.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(0), typeof(Vector2), null); //ボーンウェイト geometry.Vertices.Channels.Add(VertexChannelNames.Weights(0), typeof(BoneWeightCollection), null); //面と頂点をジオメトリに登録 //このマテリアルに対応する面は今までのマテリアルの面数の合計からこのマテリアルの面数個分 vertMap.Clear(); //マテリアルに付随する面を取得 for (long j = FaceIndex; j < FaceIndex + model.Materials[i].FaceVertCount; j++) { //面から頂点番号取得 ushort VertIndex = model.FaceVertexes[j]; //ジオメトリに登録済みかどうか? int geoVertIndex; if (!vertMap.TryGetValue(VertIndex, out geoVertIndex)) { //未登録なので、ジオメトリに登録し、ジオメトリ頂点番号取得 geoVertIndex = geometry.Vertices.Add(VertIndex); //頂点マップに登録 vertMap.Add(VertIndex, geoVertIndex); //チャンネル情報の登録 int channelIndex = 0; //法線登録 geometry.Vertices.Channels.Get<Vector3>(channelIndex++)[geoVertIndex] = MMDXMath.ToVector3(model.Vertexes[VertIndex].NormalVector); //テクスチャ座標 if (!string.IsNullOrEmpty(model.Materials[i].TextureFileName)) geometry.Vertices.Channels.Get<Vector2>(channelIndex++)[geoVertIndex] = MMDXMath.ToVector2(model.Vertexes[VertIndex].UV); //ボーンウェイト BoneWeightCollection boneWeight = new BoneWeightCollection(); int boneNum = model.Vertexes[VertIndex].BoneNum[0]; if (boneNum >= 0 && boneNum < model.Bones.Length) boneWeight.Add(new BoneWeight(model.Bones[boneNum].BoneName, model.Vertexes[VertIndex].BoneWeight / 100f)); boneNum = model.Vertexes[VertIndex].BoneNum[1]; if (boneNum >= 0 && boneNum < model.Bones.Length) boneWeight.Add(new BoneWeight(model.Bones[boneNum].BoneName, 1.0f - model.Vertexes[VertIndex].BoneWeight / 100f)); geometry.Vertices.Channels.Get<BoneWeightCollection>(channelIndex++)[geoVertIndex] = boneWeight; } //インデックスに登録 geometry.Indices.Add(geoVertIndex); } //ジオメトリをモデルに追加 buildingMesh.Geometry.Add(geometry); //面頂点カウント進める FaceIndex += model.Materials[i].FaceVertCount; } //重複頂点データのマージ //MeshHelper.MergeDuplicatePositions(buildingMesh, 0); //MeshHelper.MergeDuplicateVertices(buildingMesh); //メッシュ出来たので返却 return buildingMesh; }