private static int GetVertexGroups(SkeletonAsset skeleton, MeshLodSection section, int offset, ref Dictionary <string, List <VertexWeight> > VertexGroupDict) { int VertexCount = offset; for (int i = 0; i < section.vertices.Count; i++) { for (int x = 0; x < 4; x++) { float Weight = section.vertices[i].boneWeights[x]; // added condition to only add meaningful weights if (Weight != 0.0f) { int BoneIndex = section.vertices[i].boneIndices[x]; int SubObjectBoneIndex = section.boneIndices[BoneIndex]; string bn = skeleton.Bones[SubObjectBoneIndex].Name; if (!VertexGroupDict.ContainsKey(bn)) { VertexGroupDict.Add(bn, new List <VertexWeight>()); } VertexGroupDict[bn].Add(new VertexWeight(offset + i, Weight)); } } VertexCount++; } return(VertexCount); }
private FBXNode CreateFbxMesh(MeshLodSection section, FBXScene pScene) { FBXMesh fbxMesh = FBXMesh.Create(pScene, section.matName); FBXGeometryElementNormal lGeometryElementNormal = fbxMesh.CreateElementNormal(); lGeometryElementNormal.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementBinormal lGeometryElementBiNormal = fbxMesh.CreateElementBinormal(); lGeometryElementBiNormal.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementTangent lGeometryElementTangent = fbxMesh.CreateElementTangent(); lGeometryElementTangent.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); fbxMesh.InitControlPoints(section.vertices.Count); FBXGeometryElementMaterial lMaterialElement = fbxMesh.CreateElementMaterial(); lMaterialElement.SetMappingMode(FBXWrapper.MappingMode.eByPolygon); lMaterialElement.SetReferenceMode(FBXWrapper.ReferenceMode.eIndexToDirect); FBXGeometryElementUV lUVDiffuseElement = fbxMesh.CreateElementUV(section.matName); lUVDiffuseElement.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); lUVDiffuseElement.SetReferenceMode(FBXWrapper.ReferenceMode.eIndexToDirect); lUVDiffuseElement.SetIndexArrayCount(section.vertices.Count); for (int j = 0; j < section.vertices.Count; j++) { FBXVector4 position = new FBXVector4(section.vertices[j].position.members[0] * exportScale, section.vertices[j].position.members[1] * exportScale, section.vertices[j].position.members[2] * exportScale, 0); FBXVector4 normal = new FBXVector4(section.vertices[j].normals.members[0], section.vertices[j].normals.members[1], section.vertices[j].normals.members[2], section.vertices[j].normals.members[3]); FBXVector4 textCoords = new FBXVector4(section.vertices[j].texCoords.members[0], (-section.vertices[j].texCoords.members[1] + 1), 0, 0); FBXVector4 bitangent = new FBXVector4(section.vertices[j].biTangents.members[0], section.vertices[j].biTangents.members[1], section.vertices[j].biTangents.members[2], section.vertices[j].biTangents.members[3]); FBXVector4 tangent = new FBXVector4(section.vertices[j].tangents.members[0], section.vertices[j].tangents.members[1], section.vertices[j].tangents.members[2], section.vertices[j].tangents.members[3]); fbxMesh.SetControlPoint(j, position); lGeometryElementNormal.Add(normal); lGeometryElementBiNormal.Add(bitangent); lGeometryElementTangent.Add(tangent); lUVDiffuseElement.Add(textCoords); } for (int j = 0; j < section.indicies.Count; j++) { if (j % 3 == 0) { fbxMesh.EndPolygon(); fbxMesh.BeginPolygon(); } fbxMesh.AddPolygon(section.indicies[j]); } fbxMesh.EndPolygon(); FBXNode lMeshNode = FBXNode.Create(pScene, section.matName); lMeshNode.SetNodeAttribute(fbxMesh); lMeshNode.AddMaterial(pScene, section.matName); return(lMeshNode); }
private void CreateMeshSkinning(SkeletonAsset Skeleton, MeshLodSection section, FBXNode pFbxMesh, FBXNode pSkeletonRoot, FBXScene pScene) { Dictionary <string, List <VertexGroup.VertexWeight> > vg = VertexGroup.GetVertexGroups(Skeleton, section); CreateMeshSkinning(vg, pFbxMesh, pSkeletonRoot, pScene); }
private FBXNode CreateFbxMesh(MeshLOD lod, FBXScene pScene) { FBXMesh fbxMesh = FBXMesh.Create(pScene, lod.shortName); FBXNode lMeshNode = FBXNode.Create(pScene, lod.shortName); lMeshNode.SetNodeAttribute(fbxMesh); FBXGeometryElementNormal lGeometryElementNormal = fbxMesh.CreateElementNormal(); lGeometryElementNormal.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementBinormal lGeometryElementBiNormal = fbxMesh.CreateElementBinormal(); lGeometryElementBiNormal.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementTangent lGeometryElementTangent = fbxMesh.CreateElementTangent(); lGeometryElementTangent.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementMaterial lMaterialElement = fbxMesh.CreateElementMaterial(); lMaterialElement.SetMappingMode(FBXWrapper.MappingMode.eByPolygon); lMaterialElement.SetReferenceMode(FBXWrapper.ReferenceMode.eIndexToDirect); int verticesCount = lod.GetLODTotalVertCount(); fbxMesh.InitControlPoints(verticesCount); List <FBXGeometryElementUV[]> UVs = new List <FBXGeometryElementUV[]>(); for (int i = 0; i < lod.sections.Count; i++) { UVs.Add(new FBXGeometryElementUV[Vertex.UV_SLOTS]); } int VertexOffset = 0; for (int i = 0; i < lod.sections.Count; i++) { MeshLodSection section = lod.sections[i]; for (int j = 0; j < section.vertices.Count; j++) { FBXVector4 position = new FBXVector4(section.vertices[j].position.members[0] * exportScale, section.vertices[j].position.members[1] * exportScale, section.vertices[j].position.members[2] * exportScale, 0); FBXVector4 normal = new FBXVector4(section.vertices[j].normals.members[0], section.vertices[j].normals.members[1], section.vertices[j].normals.members[2], section.vertices[j].normals.members[3]); fbxMesh.SetControlPoint(VertexOffset + j, position); lGeometryElementNormal.Add(normal); // adding a check on bitangent and tangent as some meshes don't have them... if (section.vertices[j].biTangents.members.Length == 4) { FBXVector4 bitangent = new FBXVector4(section.vertices[j].biTangents.members[0], section.vertices[j].biTangents.members[1], section.vertices[j].biTangents.members[2], section.vertices[j].biTangents.members[3]); lGeometryElementBiNormal.Add(bitangent); } if (section.vertices[j].tangents.members.Length == 4) { FBXVector4 tangent = new FBXVector4(section.vertices[j].tangents.members[0], section.vertices[j].tangents.members[1], section.vertices[j].tangents.members[2], section.vertices[j].tangents.members[3]); lGeometryElementTangent.Add(tangent); } // multiple UVs management for (int uvInd = 0; uvInd < Vertex.UV_SLOTS; uvInd++) { if (section.vertices[j].texCoords[uvInd] != null) { FBXVector4 texCoords = new FBXVector4(section.vertices[j].texCoords[uvInd].members[0], (-section.vertices[j].texCoords[uvInd].members[1] + 1), 0, 0); if (UVs[i][uvInd] == null) { // if the UV layer does not already exist, we create it... UVs[i][uvInd] = fbxMesh.CreateElementUV(section.matName + "_" + uvInd); UVs[i][uvInd].SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); UVs[i][uvInd].SetReferenceMode(FBXWrapper.ReferenceMode.eDirect); // ... and fill it with empty vectors for all previous sections vertices. for (int p = 0; p < VertexOffset + j; p++) { UVs[i][uvInd].Add(new FBXVector4(0, 0, 0, 0)); } } // and now we can add the tex coord of the current vertex we're treating. UVs[i][uvInd].Add(texCoords); } } // since we use direct reference mode for UV, every vertices in the mesh must be present in every UV layer // so for every UV layer created for previous section, we had an empty vector for this vertex. UVs.Where((o, oi) => oi != i).ToList().ForEach(suv => { for (int subuv = 0; subuv < Vertex.UV_SLOTS; subuv++) { if (suv[subuv] != null) { suv[subuv].Add(new FBXVector4(0, 0, 0, 0)); } } } ); } for (int j = 0; j < section.indicies.Count; j++) { if (j % 3 == 0) { fbxMesh.EndPolygon(); fbxMesh.BeginPolygon(i); } fbxMesh.AddPolygon(VertexOffset + section.indicies[j]); } fbxMesh.EndPolygon(); VertexOffset = VertexOffset + section.vertices.Count; lMeshNode.AddMaterial(pScene, section.matName); } return(lMeshNode); }
public static Dictionary <string, List <VertexWeight> > GetVertexGroups(SkeletonAsset skeleton, MeshLodSection section) { var VertexGroups = new Dictionary <string, List <VertexWeight> >(); GetVertexGroups(skeleton, section, 0, ref VertexGroups); return(VertexGroups); }
// export given LOD to psk private byte[] ExportSkinnedMeshToPsk(SkeletonAsset skeleton, MeshLOD LOD, float OverrideScale = 1.0f) { PSKFile Psk = new PSKFile(); Psk.points = new List <PSKFile.PSKPoint>(); Psk.edges = new List <PSKFile.PSKEdge>(); Psk.materials = new List <PSKFile.PSKMaterial>(); Psk.bones = new List <PSKFile.PSKBone>(); Psk.faces = new List <PSKFile.PSKFace>(); Psk.weights = new List <PSKFile.PSKWeight>(); /* No skeleton defined still */ if (skeleton != null) { for (int i = 0; i < skeleton.Bones.Count; i++) { PSKFile.PSKBone Bone = new PSKFile.PSKBone(); Bone.name = skeleton.Bones[i].Name; Bone.childs = skeleton.Bones[i].Children.Count; Bone.parent = (skeleton.Bones[i].ParentIndex == -1) ? 0 : skeleton.Bones[i].ParentIndex; Bone.index = i; Bone.location = new PSKFile.PSKPoint(ConvertVector3ToPsk(skeleton.Bones[i].Location) * OverrideScale); Bone.rotation = new PSKFile.PSKQuad(0, 0, 0, 0); float[][] RotMatrix = new float[4][]; RotMatrix[0] = new float[4]; RotMatrix[1] = new float[4]; RotMatrix[2] = new float[4]; RotMatrix[3] = new float[4]; RotMatrix[0][0] = skeleton.Bones[i].Right.members[0]; RotMatrix[0][1] = skeleton.Bones[i].Right.members[1]; RotMatrix[0][2] = skeleton.Bones[i].Right.members[2]; RotMatrix[0][3] = 0.0f; RotMatrix[1][0] = skeleton.Bones[i].Up.members[0]; RotMatrix[1][1] = skeleton.Bones[i].Up.members[1]; RotMatrix[1][2] = skeleton.Bones[i].Up.members[2]; RotMatrix[1][3] = 0.0f; RotMatrix[2][0] = skeleton.Bones[i].Forward.members[0]; RotMatrix[2][1] = skeleton.Bones[i].Forward.members[1]; RotMatrix[2][2] = skeleton.Bones[i].Forward.members[2]; RotMatrix[2][3] = 0.0f; RotMatrix[3][0] = 0.0f; RotMatrix[3][1] = 0.0f; RotMatrix[3][2] = 0.0f; RotMatrix[3][3] = 1.0f; Vector Quat = new Vector(new float[4]); float tr = RotMatrix[0][0] + RotMatrix[1][1] + RotMatrix[2][2]; float s; if (tr > 0.0f) { float InvS = 1.0f / (float)Math.Sqrt(tr + 1.0f); Quat.members[3] = 0.5f * (1.0f / InvS); s = 0.5f * InvS; Quat.members[0] = (RotMatrix[1][2] - RotMatrix[2][1]) * s; Quat.members[1] = (RotMatrix[2][0] - RotMatrix[0][2]) * s; Quat.members[2] = (RotMatrix[0][1] - RotMatrix[1][0]) * s; } else { int m = 0; if (RotMatrix[1][1] > RotMatrix[0][0]) { m = 1; } if (RotMatrix[2][2] > RotMatrix[m][m]) { m = 2; } int[] nxt = new int[] { 1, 2, 0 }; int j = nxt[m]; int k = nxt[j]; s = RotMatrix[m][m] - RotMatrix[j][j] - RotMatrix[k][k] + 1.0f; float InvS = 1.0f / (float)Math.Sqrt(s); float[] qt = new float[4]; qt[m] = 0.5f * (1.0f / InvS); s = 0.5f * InvS; qt[3] = (RotMatrix[j][k] - RotMatrix[k][j]) * s; qt[j] = (RotMatrix[m][j] + RotMatrix[j][m]) * s; qt[k] = (RotMatrix[m][k] + RotMatrix[k][m]) * s; Quat.members[0] = qt[0]; Quat.members[1] = qt[1]; Quat.members[2] = qt[2]; Quat.members[3] = qt[3]; } Bone.rotation = new PSKFile.PSKQuad(ConvertVector4ToPsk(Quat)); Psk.bones.Add(Bone); } } int offset = 0; int matIdx = 0; for (int bufIdx = 0; bufIdx < LOD.sections.Count; bufIdx++) { MeshLodSection MeshBuffer = LOD.sections[bufIdx]; for (int i = 0; i < MeshBuffer.vertices.Count; i++) { if (MeshBuffer.vertices[i].position.members.Length != 3) { MeshBuffer.vertices[i].position.members = new float[3]; } if (MeshBuffer.vertices[i].texCoords.members.Length != 2) { MeshBuffer.vertices[i].texCoords.members = new float[2]; } Vector p = new Vector(MeshBuffer.vertices[i].position.members[0], MeshBuffer.vertices[i].position.members[1], MeshBuffer.vertices[i].position.members[2]); Psk.points.Add(new PSKFile.PSKPoint(ConvertVector3ToPsk(p))); Vector tc = new Vector(MeshBuffer.vertices[i].texCoords.members[0], MeshBuffer.vertices[i].texCoords.members[1]); Psk.edges.Add(new PSKFile.PSKEdge((ushort)(offset + i), ConvertVector2ToPsk(tc), (byte)matIdx)); if (MeshBuffer.vertices[i].boneWeights != null) { for (int x = 0; x < 4; x++) { float Weight = MeshBuffer.vertices[i].boneWeights[x]; // only add meaningful weights if (Weight != 0.0f) { int BoneIndex = MeshBuffer.vertices[i].boneIndices[x]; int SubObjectBoneIndex = MeshBuffer.boneIndices[BoneIndex]; Psk.weights.Add(new PSKFile.PSKWeight( Weight, (int)(offset + i), SubObjectBoneIndex )); } } } } // reverse indices order before building faces: necessary for correct normal building since all points have been mirrored along z-axis. // if this is not done, all normals are flipped inside. if (Reverse) { MeshBuffer.indicies.Reverse(); } for (int fi = 0; fi < MeshBuffer.indicies.Count; fi++) { if (fi % 3 == 0) { Psk.faces.Add(new PSKFile.PSKFace( (int)(offset + MeshBuffer.indicies[fi]), (int)(offset + MeshBuffer.indicies[fi + 1]), (int)(offset + MeshBuffer.indicies[fi + 2]), (byte)matIdx) ); } } Psk.materials.Add(new PSKFile.PSKMaterial(LOD.sections[bufIdx].matName, matIdx)); offset += (int)LOD.sections[bufIdx].vertCount; matIdx++; } return(Psk.SaveToMemory().ToArray()); }
// export given LOD to psk private byte[] ExportSkinnedMeshToPsk(SkeletonAsset skeleton, MeshLOD LOD, float OverrideScale = 1.0f) { PSKFile Psk = new PSKFile(); Psk.points = new List <PSKFile.PSKPoint>(); Psk.edges = new List <PSKFile.PSKEdge>(); Psk.materials = new List <PSKFile.PSKMaterial>(); Psk.bones = new List <PSKFile.PSKBone>(); Psk.faces = new List <PSKFile.PSKFace>(); Psk.weights = new List <PSKFile.PSKWeight>(); // create skeleton (only if mesh is skinned mesh) if (LOD.type == MeshType.MeshType_Skinned) { Psk.bones = CreatePskSkeleton(skeleton, OverrideScale); } // create mesh int offset = 0; int matIdx = 0; for (int bufIdx = 0; bufIdx < LOD.sections.Count; bufIdx++) { MeshLodSection MeshBuffer = LOD.sections[bufIdx]; for (int i = 0; i < MeshBuffer.vertices.Count; i++) { // vertex position if (MeshBuffer.vertices[i].position.members.Length != 3) { MeshBuffer.vertices[i].position.members = new float[3]; } Vector p = new Vector(MeshBuffer.vertices[i].position.members[0] * OverrideScale, MeshBuffer.vertices[i].position.members[1] * OverrideScale, MeshBuffer.vertices[i].position.members[2] * OverrideScale); Psk.points.Add(new PSKFile.PSKPoint(ConvertVector3ToPsk(p))); // vertex uv // supports only first uv for the time being // TODO support for multiple UVs if (MeshBuffer.vertices[i].texCoords[0] == null) { MeshBuffer.vertices[i].texCoords[0] = new Vector(new float[2]); } if (MeshBuffer.vertices[i].texCoords[0].members.Length != 2) { MeshBuffer.vertices[i].texCoords[0].members = new float[2]; } Vector tc = new Vector(MeshBuffer.vertices[i].texCoords[0].members[0], MeshBuffer.vertices[i].texCoords[0].members[1]); Psk.edges.Add(new PSKFile.PSKEdge((ushort)(offset + i), ConvertVector2ToPsk(tc), (byte)matIdx)); // bones weights if (MeshBuffer.vertices[i].boneWeights != null) { for (int x = 0; x < 4; x++) { float Weight = MeshBuffer.vertices[i].boneWeights[x]; // only add meaningful weights if (Weight != 0.0f) { int BoneIndex = MeshBuffer.vertices[i].boneIndices[x]; int SubObjectBoneIndex = MeshBuffer.boneIndices[BoneIndex]; Psk.weights.Add(new PSKFile.PSKWeight( Weight, (int)(offset + i), SubObjectBoneIndex )); } } } } // reverse indices order before building faces: necessary for correct normal building since all points have been mirrored along z-axis. // if this is not done, all normals are flipped inside. if (Reverse) { MeshBuffer.indicies.Reverse(); } for (int fi = 0; fi < MeshBuffer.indicies.Count; fi++) { if (fi % 3 == 0) { Psk.faces.Add(new PSKFile.PSKFace( (int)(offset + MeshBuffer.indicies[fi]), (int)(offset + MeshBuffer.indicies[fi + 1]), (int)(offset + MeshBuffer.indicies[fi + 2]), (byte)matIdx) ); } } Psk.materials.Add(new PSKFile.PSKMaterial(LOD.sections[bufIdx].matName, matIdx)); offset += (int)LOD.sections[bufIdx].vertCount; matIdx++; } return(Psk.SaveToMemory().ToArray()); }
private FBXNode CreateFbxMesh(MeshLOD lod, FBXScene pScene) { FBXMesh fbxMesh = FBXMesh.Create(pScene, lod.shortName); FBXNode lMeshNode = FBXNode.Create(pScene, lod.shortName); lMeshNode.SetNodeAttribute(fbxMesh); FBXGeometryElementNormal lGeometryElementNormal = fbxMesh.CreateElementNormal(); lGeometryElementNormal.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementBinormal lGeometryElementBiNormal = fbxMesh.CreateElementBinormal(); lGeometryElementBiNormal.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementTangent lGeometryElementTangent = fbxMesh.CreateElementTangent(); lGeometryElementTangent.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementMaterial lMaterialElement = fbxMesh.CreateElementMaterial(); lMaterialElement.SetMappingMode(FBXWrapper.MappingMode.eByPolygon); lMaterialElement.SetReferenceMode(FBXWrapper.ReferenceMode.eIndexToDirect); int verticesCount = lod.GetLODTotalVertCount(); fbxMesh.InitControlPoints(verticesCount); List <FBXGeometryElementUV> UVs = new List <FBXGeometryElementUV>(); for (int i = 0; i < lod.sections.Count; i++) { MeshLodSection section = lod.sections[i]; FBXGeometryElementUV lUVDiffuseElement = fbxMesh.CreateElementUV(section.matName); lUVDiffuseElement.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); lUVDiffuseElement.SetReferenceMode(FBXWrapper.ReferenceMode.eDirect); UVs.Add(lUVDiffuseElement); } int VertexOffset = 0; for (int i = 0; i < lod.sections.Count; i++) { MeshLodSection section = lod.sections[i]; for (int j = 0; j < section.vertices.Count; j++) { FBXVector4 position = new FBXVector4(section.vertices[j].position.members[0] * exportScale, section.vertices[j].position.members[1] * exportScale, section.vertices[j].position.members[2] * exportScale, 0); FBXVector4 normal = new FBXVector4(section.vertices[j].normals.members[0], section.vertices[j].normals.members[1], section.vertices[j].normals.members[2], section.vertices[j].normals.members[3]); FBXVector4 textCoords = new FBXVector4(section.vertices[j].texCoords.members[0], (-section.vertices[j].texCoords.members[1] + 1), 0, 0); FBXVector4 bitangent = new FBXVector4(section.vertices[j].biTangents.members[0], section.vertices[j].biTangents.members[1], section.vertices[j].biTangents.members[2], section.vertices[j].biTangents.members[3]); FBXVector4 tangent = new FBXVector4(section.vertices[j].tangents.members[0], section.vertices[j].tangents.members[1], section.vertices[j].tangents.members[2], section.vertices[j].tangents.members[3]); fbxMesh.SetControlPoint(VertexOffset + j, position); lGeometryElementNormal.Add(normal); lGeometryElementBiNormal.Add(bitangent); lGeometryElementTangent.Add(tangent); int uvI = 0; foreach (FBXGeometryElementUV uv in UVs) { if (uvI == i) { uv.Add(textCoords); } else { uv.Add(new FBXVector4(0, 0, 0, 0)); } uvI++; } } for (int j = 0; j < section.indicies.Count; j++) { if (j % 3 == 0) { fbxMesh.EndPolygon(); fbxMesh.BeginPolygon(i); } fbxMesh.AddPolygon(VertexOffset + section.indicies[j]); } fbxMesh.EndPolygon(); VertexOffset = VertexOffset + section.vertices.Count; lMeshNode.AddMaterial(pScene, section.matName); } return(lMeshNode); }