public Boolean ProcessAssetContext(H1StaticLODModel staticLODModel, H1MeshContext[] meshContexts, H1SkeletalContext skeletalContext) { if (m_Skeleton == null) { return(false); } // 1. process skeletalContext (H1SkeletalContext) H1SkeletalContext.JointNode rootNode = skeletalContext.Root; H1ReferenceSkeleton refSkeleton = m_Skeleton.RefSkeleton; #region Disabled // process recursively from root node //Dictionary<String, H1SkeletalContext.JointNode> mapNodeNameToJointNode = new Dictionary<string, H1SkeletalContext.JointNode>(); //if (!ProcessAssetContextRecursive(rootNode, ref refSkeleton, ref mapNodeNameToJointNode)) // return false; // failed to process nodes from root nodes #endregion // 2. process meshContexts (H1MeshContext) // collect all vertices for all different mesh contexts Int32[] meshContextOffsetsList = new Int32[meshContexts.Count()]; List <Vector3> positionsList = new List <Vector3>(); List <Vector3> tangentXList = new List <Vector3>(); List <Vector3> tangentYList = new List <Vector3>(); List <Vector3> tangentZList = new List <Vector3>(); List <Vector2> texcoordsList = new List <Vector2>(); Int32 currMeshContextIndex = 0; foreach (H1MeshContext meshContext in meshContexts) { meshContextOffsetsList[currMeshContextIndex] = positionsList.Count; positionsList.AddRange(meshContext.Positions); tangentXList.AddRange(meshContext.Tangents); tangentYList.AddRange(meshContext.Normals); tangentZList.AddRange(meshContext.BiTangents); texcoordsList.AddRange(meshContext.UVBuffers[0].Buffer); currMeshContextIndex++; } Vector3[] positions = positionsList.ToArray(); Vector3[] tangentX = tangentXList.ToArray(); Vector3[] tangentY = tangentYList.ToArray(); Vector3[] tangentZ = tangentZList.ToArray(); Vector2[] texcoords = texcoordsList.ToArray(); Int32 numPositions = positions.Count(); if (numPositions != texcoords.Count()) { return(false); } // create the list of vertex info List <VertexInfo> vertexInfoList = new List <VertexInfo>(); #if DEBUG List <Boolean> taggedVertexInfoList = new List <Boolean>(); #endif for (Int32 i = 0; i < numPositions; ++i) { vertexInfoList.Add(new VertexInfo()); vertexInfoList[i].VertexIndex = i; #if DEBUG taggedVertexInfoList.Add(false); #endif } // set the triangle index // create collection of index for all mesh contexts List <UInt32> indexList = new List <UInt32>(); Int32 meshContextIndex = 0; foreach (H1MeshContext meshContext in meshContexts) { // using meshContextOffsetsList information, remap indices correctly foreach (UInt32 vertexIndex in meshContext.Indices) { indexList.Add(Convert.ToUInt32(meshContextOffsetsList[meshContextIndex]) + vertexIndex); } meshContextIndex++; } UInt32[] indices = indexList.ToArray(); #if DEBUG Boolean[] taggedIndices = new Boolean[indexList.Count]; #endif // looping index, set triangle index for each vertexInfoList Int32 indexOfIndex = 0; foreach (UInt32 index in indices) { Int32 vertexIndex = Convert.ToInt32(index); Int32 triangleIndex = indexOfIndex / 3; // set the triangle index vertexInfoList[vertexIndex].TriangleIndices.Add(triangleIndex); #if DEBUG taggedIndices[indexOfIndex] = false; #endif indexOfIndex++; } // process vertex weights and bone index in advance by looping all H1MeshBoneInfo Int32 meshBoneInfoIndex = 0; foreach (H1MeshBoneInfo meshBoneInfo in refSkeleton.RefBoneInfoList) { Int32 jointNodeIndex = skeletalContext.JointNodes.FindIndex(x => x.JointName == meshBoneInfo.Name); H1SkeletalContext.JointNode node = skeletalContext.JointNodes[jointNodeIndex]; foreach (H1SkeletalContext.Joint nodeData in node.JointDataList) { // looping weighted vertices Int32 vertexIndexOffset = nodeData.MeshContextIndex == -1 ? 0 : meshContextOffsetsList[nodeData.MeshContextIndex]; // process vertex weights and bone index foreach (H1SkeletalContext.WeightedVertex weightedVertex in nodeData.WeightedVertices) { VertexInfo.InfluenceBoneData influencedBoneData = new VertexInfo.InfluenceBoneData(); influencedBoneData.BoneIndex = meshBoneInfoIndex; influencedBoneData.BoneWeight = weightedVertex.Weight; vertexInfoList[vertexIndexOffset + weightedVertex.VertexIndex].InfluencedBones.Add(influencedBoneData); } } meshBoneInfoIndex++; } #if DEBUG // verification code for vertex weights List <float> taggedVertexWeights = new List <float>(); foreach (VertexInfo vertexInfo in vertexInfoList) { float totalWeight = 0.0f; foreach (VertexInfo.InfluenceBoneData influencedBoneData in vertexInfo.InfluencedBones) { totalWeight += influencedBoneData.BoneWeight; } taggedVertexWeights.Add(totalWeight); } List <Int32> invalidVertexIndices = new List <Int32>(); Int32 currVertexIndex = 0; foreach (float totalWeight in taggedVertexWeights) { if (totalWeight < 0.99f) { invalidVertexIndices.Add(currVertexIndex); } currVertexIndex++; } if (invalidVertexIndices.Count > 0) { return(false); } #endif // looping meshBoneInfo, set bone index and bone weight foreach (H1MeshBoneInfo meshBoneInfo in refSkeleton.RefBoneInfoList) { Int32 jointNodeIndex = skeletalContext.JointNodes.FindIndex(x => x.JointName == meshBoneInfo.Name); H1SkeletalContext.JointNode node = skeletalContext.JointNodes[jointNodeIndex]; List <UInt32> ChunkVertexIndices = new List <UInt32>(); // vertex indices for this chunk (bone node) foreach (H1SkeletalContext.Joint nodeData in node.JointDataList) { // looping weighted vertices Int32 vertexIndexOffset = nodeData.MeshContextIndex == -1 ? 0 : meshContextOffsetsList[nodeData.MeshContextIndex]; // add chunk vertex indices foreach (H1SkeletalContext.WeightedVertex weightedVertex in nodeData.WeightedVertices) { ChunkVertexIndices.Add(Convert.ToUInt32(vertexIndexOffset + weightedVertex.VertexIndex)); } } // exceptional handling for MeshBoneInfo which doesn't contain any mesh data, no need to generate chunk for this BasePose if (ChunkVertexIndices.Count == 0) { continue; } // process skeletal mesh chunk H1SkelMeshChunk skelMeshChunk = new H1SkelMeshChunk(); // calculate triangles for this mesh chunk List <UInt32> triangles = new List <UInt32>(); foreach (Int32 vertexIndex in ChunkVertexIndices) { VertexInfo vertexInfo = vertexInfoList[vertexIndex]; H1SoftSkinVertex newSoftSkinVertex = new H1SoftSkinVertex(); newSoftSkinVertex.Position = positions[vertexInfo.VertexIndex]; newSoftSkinVertex.TangentX = tangentX[vertexInfo.VertexIndex]; newSoftSkinVertex.TangentY = tangentY[vertexInfo.VertexIndex]; newSoftSkinVertex.TangentZ = tangentZ[vertexInfo.VertexIndex]; // @TODO - in the future, it could increase texcoords (ex. light map texcoord) newSoftSkinVertex.UVs[0] = texcoords[vertexInfo.VertexIndex]; for (Int32 i = 0; i < H1ObjectGlobalDefinitions.MAX_TOTAL_INFLUENCES; ++i) { if (vertexInfo.InfluencedBones.Count <= i) { // insert the default value newSoftSkinVertex.InfluenceWeights[i] = 0; newSoftSkinVertex.InfluenceBones[i] = 0; continue; } VertexInfo.InfluenceBoneData boneData = vertexInfo.InfluencedBones[i]; newSoftSkinVertex.InfluenceWeights[i] = Convert.ToByte(boneData.BoneWeight * 255.0f); // @TODO - for this bone index, we can replace with 'm_BoneMap' newSoftSkinVertex.InfluenceBones[i] = Convert.ToByte(boneData.BoneIndex); } skelMeshChunk.SoftVertices.Add(newSoftSkinVertex); // process triangle indices foreach (Int32 triangleIndex in vertexInfo.TriangleIndices) { UInt32 triangleIndexUInt32 = Convert.ToUInt32(triangleIndex); if (!triangles.Exists(x => { return(x == triangleIndexUInt32); })) { triangles.Add(triangleIndexUInt32); } } } // build vertex buffers List <Vector4> chunkPositions = new List <Vector4>(); List <Vector4> chunkTangentZs = new List <Vector4>(); List <Vector4> chunkTangentXs = new List <Vector4>(); List <Vector2> chunkTexcoords = new List <Vector2>(); List <Int4> chunkBoneIndices = new List <Int4>(); List <Vector4> chunkBoneWeights = new List <Vector4>(); List <Vector4> chunkColors = new List <Vector4>(); Dictionary <Int32, Int32> vertexToChunkVertexMap = new Dictionary <Int32, Int32>(); foreach (Int32 triangleIndex in triangles) { for (Int32 faceIndex = 0; faceIndex < 3; ++faceIndex) { Int32 vertexIndex = Convert.ToInt32(indices[triangleIndex * 3 + faceIndex]); #if DEBUG taggedVertexInfoList[vertexIndex] = true; #endif // determine if the same vertex exists based on chunkPositions //if (chunkPositions.Contains(new Vector4(positions[vertexIndex], 1.0f))) if (vertexToChunkVertexMap.ContainsKey(vertexIndex)) { continue; } // position index is base-index Int32 newIndex = chunkPositions.Count; vertexToChunkVertexMap.Add(vertexIndex, newIndex); chunkPositions.Add(new Vector4(positions[vertexIndex], 1.0f)); chunkTangentZs.Add(new Vector4(tangentZ[vertexIndex], 1.0f)); chunkTangentXs.Add(new Vector4(tangentX[vertexIndex], 1.0f)); chunkTexcoords.Add(new Vector2(texcoords[vertexIndex].X, texcoords[vertexIndex].Y)); VertexInfo vertexInfo = vertexInfoList[vertexIndex]; Int4 influencedBones = new Int4(0); Vector4 influencedWeights = new Vector4(0.0f); Int32 insertedIndex = 0; foreach (VertexInfo.InfluenceBoneData boneData in vertexInfo.InfluencedBones) { influencedBones[insertedIndex] = boneData.BoneIndex; influencedWeights[insertedIndex] = boneData.BoneWeight; insertedIndex++; } chunkBoneIndices.Add(influencedBones); chunkBoneWeights.Add(influencedWeights); //@TODO - temporary set it as 'RED' chunkColors.Add(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); } } // create skeletal mesh vertex data // 1. position H1SkeletalMeshVertexData <Vector4> positionVertexData = new H1SkeletalMeshVertexData <Vector4>(); positionVertexData.SetVertexData(chunkPositions.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.Position, false); // 2. tangentZ H1SkeletalMeshVertexData <Vector4> tangentZVertexData = new H1SkeletalMeshVertexData <Vector4>(); tangentZVertexData.SetVertexData(chunkTangentZs.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.TangentZ, false); // 3. tangentX H1SkeletalMeshVertexData <Vector4> tangentXVertexData = new H1SkeletalMeshVertexData <Vector4>(); tangentXVertexData.SetVertexData(chunkTangentXs.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.TangentX, false); // 4. bone indices H1SkeletalMeshVertexData <Int4> boneIndicesVertexData = new H1SkeletalMeshVertexData <Int4>(); boneIndicesVertexData.SetVertexData(chunkBoneIndices.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.InfluencedBones, false); // 5. bone weights H1SkeletalMeshVertexData <Vector4> boneWeightsVertexData = new H1SkeletalMeshVertexData <Vector4>(); boneWeightsVertexData.SetVertexData(chunkBoneWeights.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.InfluencedWeights, false); // 6. texcoord H1SkeletalMeshVertexData <Vector2> texcoordVertexData = new H1SkeletalMeshVertexData <Vector2>(); texcoordVertexData.SetVertexData(chunkTexcoords.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.Texcoord, false); // 7. colors H1SkeletalMeshVertexData <Vector4> colorVertexData = new H1SkeletalMeshVertexData <Vector4>(); colorVertexData.SetVertexData(chunkColors.ToArray(), H1SkeletalMeshVertexDataInterface.VertexDataType.Color); Int32 newSkelMeshChunkIndex = staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers.Count; staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers.Add(new H1SkeletalMeshVertexBuffers(newSkelMeshChunkIndex)); staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(positionVertexData); staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(tangentZVertexData); staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(tangentXVertexData); staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(boneIndicesVertexData); staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(boneWeightsVertexData); staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(texcoordVertexData); staticLODModel.VertexBufferGPUSkin.SkeletalMeshVertexBuffers[newSkelMeshChunkIndex].AddSkeletalMeshVertexData(colorVertexData); // build index buffer List <UInt32> chunkIndices = new List <UInt32>(); foreach (Int32 triangleIndex in triangles) { for (Int32 faceIndex = 0; faceIndex < 3; ++faceIndex) { #if DEBUG taggedIndices[triangleIndex * 3 + faceIndex] = true; #endif Int32 vertexIndex = Convert.ToInt32(indices[triangleIndex * 3 + faceIndex]); chunkIndices.Add(Convert.ToUInt32(vertexToChunkVertexMap[vertexIndex])); } } staticLODModel.MultiSizeIndexContainer.Indices.AddRange(chunkIndices.ToArray()); // add new chunk Int32 newChunkIndex = staticLODModel.Chunks.Count; staticLODModel.Chunks.Add(skelMeshChunk); // process skeletal mesh section H1SkelMeshSection skelMeshSection = new H1SkelMeshSection(); skelMeshSection.ChunkIndex = Convert.ToUInt16(newChunkIndex); // @TODO - fix this num triangle inconsistency //skelMeshSection.NumTriangles = Convert.ToUInt16(triangles.Count); skelMeshSection.NumTriangles = Convert.ToUInt16(chunkIndices.Count / 3); //@TODO - add material index // add skeletal sections staticLODModel.Sections.Add(skelMeshSection); } #if DEBUG // debugging code for detecting missing vertex to draw meshes List <Int32> notTaggedVertexIndex = new List <Int32>(); Int32 currTaggedVertexIndex = 0; foreach (Boolean isTaggedVertex in taggedVertexInfoList) { if (isTaggedVertex == false) { notTaggedVertexIndex.Add(currTaggedVertexIndex); } currTaggedVertexIndex++; } if (notTaggedVertexIndex.Count > 0) { return(false); } // debugging code for detecting missing index to draw meshes List <Int32> notTaggedIndex = new List <Int32>(); Int32 currIndexOfIndex = 0; foreach (Boolean isTaggedIndex in taggedIndices) { if (isTaggedIndex == false) { notTaggedIndex.Add(currIndexOfIndex); } currIndexOfIndex++; } if (notTaggedIndex.Count > 0) { return(false); } #endif return(true); }
public Boolean GenerateSkeleltalMeshObjectGpuSkin() { // allocate new instance of SkeletalMeshGpuSkin m_SkeletalMeshObject = new H1SkeletalMeshObjectGPUSkin(m_SkeletalMesh.SkeletalMeshResource); H1SkeletalMeshObjectGPUSkin refSkeletalMeshObject = m_SkeletalMeshObject as H1SkeletalMeshObjectGPUSkin; // process soft vertices for each chunk to separate vertex buffers // @TODO - handle LOD variation List <H1SkelMeshChunk> skelChunks = SkeletalMesh.SkeletalMeshResource.GetLODModel(0).Chunks; // @TODO - temporary add LOD_0 H1SkeletalMeshObjectGPUSkin.H1SkeletalMeshObjectLOD skeletalMeshObjectLOD_0 = refSkeletalMeshObject.AddSkeletalMeshObjectLOD(); Int32 skelChunkIndex = 0; foreach (H1SkelMeshChunk skelChunk in skelChunks) { H1SkeletalMeshVertexBuffers skeletalMeshVBsRef = skeletalMeshObjectLOD_0.SkelMeshResourceRef.GetLODModel(0).VertexBufferGPUSkin.SkeletalMeshVertexBuffers[skelChunkIndex]; // add GPUSkinFactory skeletalMeshObjectLOD_0.GPUSkinVertexFactories.VertexFactories.Add(new H1GpuSkinVertexFactory()); H1GpuSkinVertexFactory newGpuSkinVertexFactoryRef = skeletalMeshObjectLOD_0.GPUSkinVertexFactories.VertexFactories.Last(); // offset tracking Int32 currOffset = 0; Int32 skelMeshVBsCount = skeletalMeshVBsRef.GetSkeletalMeshVertexDataCount(); for (Int32 skelMeshVBIndex = 0; skelMeshVBIndex < skelMeshVBsCount; ++skelMeshVBIndex) { H1SkeletalMeshVertexDataInterface skeletalMeshVertexData = skeletalMeshVBsRef.GetSkeletalMeshVertexData(skelMeshVBIndex); switch (skeletalMeshVertexData.DataType) { case H1SkeletalMeshVertexDataInterface.VertexDataType.Position: { H1SkeletalMeshVertexData <Vector4> positionVertexData = skeletalMeshVertexData as H1SkeletalMeshVertexData <Vector4>; newGpuSkinVertexFactoryRef.ShaderData.PositionBuffer = H1VertexBuffer.ProcessVertexBuffer(positionVertexData.VertexBuffer); newGpuSkinVertexFactoryRef.PositionStreamComponent = new H1VertexStreamComponent(H1VertexStreamSematicType.Position, H1VertexElementType.Float4, currOffset++); break; } case H1SkeletalMeshVertexDataInterface.VertexDataType.TangentZ: { H1SkeletalMeshVertexData <Vector4> tangentZVertexData = skeletalMeshVertexData as H1SkeletalMeshVertexData <Vector4>; newGpuSkinVertexFactoryRef.ShaderData.TangentZBuffer = H1VertexBuffer.ProcessVertexBuffer(tangentZVertexData.VertexBuffer); newGpuSkinVertexFactoryRef.TangentZStreamComponent = new H1VertexStreamComponent(H1VertexStreamSematicType.TangentZ, H1VertexElementType.Float4, currOffset++); break; } case H1SkeletalMeshVertexDataInterface.VertexDataType.TangentX: { H1SkeletalMeshVertexData <Vector4> tangentXVertexData = skeletalMeshVertexData as H1SkeletalMeshVertexData <Vector4>; newGpuSkinVertexFactoryRef.ShaderData.TangentXBuffer = H1VertexBuffer.ProcessVertexBuffer(tangentXVertexData.VertexBuffer); newGpuSkinVertexFactoryRef.TangentXStreamComponent = new H1VertexStreamComponent(H1VertexStreamSematicType.TangentX, H1VertexElementType.Float4, currOffset++); break; } case H1SkeletalMeshVertexDataInterface.VertexDataType.InfluencedBones: { H1SkeletalMeshVertexData <Int4> boneIndicesVertexData = skeletalMeshVertexData as H1SkeletalMeshVertexData <Int4>; newGpuSkinVertexFactoryRef.ShaderData.BoneIndices = H1VertexBuffer.ProcessVertexBuffer(boneIndicesVertexData.VertexBuffer); newGpuSkinVertexFactoryRef.BoneIndicesStreamComponent = new H1VertexStreamComponent(H1VertexStreamSematicType.BoneIndices, H1VertexElementType.Int4, currOffset++); break; } case H1SkeletalMeshVertexDataInterface.VertexDataType.InfluencedWeights: { H1SkeletalMeshVertexData <Vector4> blendWeightsVertexData = skeletalMeshVertexData as H1SkeletalMeshVertexData <Vector4>; newGpuSkinVertexFactoryRef.ShaderData.BoneWeights = H1VertexBuffer.ProcessVertexBuffer(blendWeightsVertexData.VertexBuffer); newGpuSkinVertexFactoryRef.BoneWeightsStreamComponent = new H1VertexStreamComponent(H1VertexStreamSematicType.BoneWeights, H1VertexElementType.Float4, currOffset++); break; } // @TODO - support multiple texcoords case H1SkeletalMeshVertexDataInterface.VertexDataType.Texcoord: { H1SkeletalMeshVertexData <Vector2> texcoordVertexData = skeletalMeshVertexData as H1SkeletalMeshVertexData <Vector2>; newGpuSkinVertexFactoryRef.ShaderData.TexcoordBuffers.Add(H1VertexBuffer.ProcessVertexBuffer(texcoordVertexData.VertexBuffer)); newGpuSkinVertexFactoryRef.TexcoordStreamComponents.Add(new H1VertexStreamComponent(H1VertexStreamSematicType.Texcoord, H1VertexElementType.Float2, currOffset++)); break; } case H1SkeletalMeshVertexDataInterface.VertexDataType.Color: { H1SkeletalMeshVertexData <Vector4> colorVertexData = skeletalMeshVertexData as H1SkeletalMeshVertexData <Vector4>; newGpuSkinVertexFactoryRef.ShaderData.ColorBuffer = H1VertexBuffer.ProcessVertexBuffer(colorVertexData.VertexBuffer); newGpuSkinVertexFactoryRef.ColorStreamComponent = new H1VertexStreamComponent(H1VertexStreamSematicType.Color, H1VertexElementType.Float4, currOffset++); break; } } } // generate RHIVertexFormat Declaration newGpuSkinVertexFactoryRef.GenerateVertexDeclaration(); skelChunkIndex++; } // add index buffer (containing multiple skeletal mesh chunks's indices) List <UInt32> indices = SkeletalMesh.SkeletalMeshResource.GetLODModel(0).MultiSizeIndexContainer.Indices; UInt32 bufferSize = Convert.ToUInt32(Utilities.SizeOf <UInt32>() * indices.Count); skeletalMeshObjectLOD_0.IndexBuffer = H1Global <H1ManagedRenderer> .Instance.CreateIndexBuffer(bufferSize); // write indices data skeletalMeshObjectLOD_0.IndexBuffer.WriteData(indices.ToArray()); return(true); }