public void Load(Stream source_stream) { NiHeader header = GetHeader(source_stream); header.Dump(); int bt_NiTriShapeData = header.GetBlockTypeIdxByName("NiTriShapeData"); int bt_BSLightingShaderProperty = header.GetBlockTypeIdxByName("BSLightingShaderProperty"); int bt_BSShaderTextureSet = header.GetBlockTypeIdxByName("BSShaderTextureSet"); int bt_NiSkinInstance = header.GetBlockTypeIdxByName("NiSkinInstance"); int bt_NiSkinPartition = header.GetBlockTypeIdxByName("NiSkinPartition"); int num_blocks = header.blocks.Length; for (int i = 0; i < num_blocks; i++) { if (header.blocks[i].type == bt_NiTriShapeData) { NiTriShapeData triShapeData = GetObject <NiTriShapeData>(header, i); triShapeData.Dump(); } if (header.blocks[i].type == bt_BSLightingShaderProperty) { BSLightingShaderProperty lightingShaderProperty = GetObject <BSLightingShaderProperty>(header, i); lightingShaderProperty.Dump(); } if (header.blocks[i].type == bt_BSShaderTextureSet) { BSShaderTextureSet shaderTextureSet = GetObject <BSShaderTextureSet>(header, i); shaderTextureSet.Dump(); } if (header.blocks[i].type == bt_NiSkinInstance) { NiSkinInstance skinInstance = GetObject <NiSkinInstance>(header, i); skinInstance.Dump(); foreach (ObjectRef boneref in skinInstance.bones) { NiNode node = GetObject <NiNode>(header, boneref); System.Console.WriteLine(header.strings[node.name]); } } if (header.blocks[i].type == bt_NiSkinPartition) { NiSkinPartition skinPartition = GetObject <NiSkinPartition>(header, i); skinPartition.Dump(); } } }
private void BuildRig(NiSkinInstance skinInstance, GameObject holder) { var mesh = holder.GetComponent <MeshFilter>().sharedMesh; var partitions = skinInstance.SkinPartition.Object; var oldRenderer = holder.GetComponent <MeshRenderer>(); var mat = oldRenderer.sharedMaterial; Object.DestroyImmediate(oldRenderer); var renderer = holder.AddComponent <SkinnedMeshRenderer>(); renderer.sharedMaterial = mat; renderer.sharedMesh = mesh; renderer.rootBone = _unityObjects[skinInstance.Root.Object].transform; var boneWeights = new BoneWeight[mesh.vertices.Length]; // // Loop through all the skin partitions to build the final rig. // Currently there are skinned meshes where weird parts are stuck to root create awful rigs. // foreach (var partition in partitions.SkinPartitions) { for (var i = 0; i < partition.VertexMap.Length; i++) { var index = partition.VertexMap[i]; var weight = new BoneWeight(); for (var j = 0; j < partition.WeightsPerVertex; j++) { var value = partition.BoneIndices[i, j]; switch (j) { case 0: weight.boneIndex0 = value; break; case 1: weight.boneIndex1 = value; break; case 2: weight.boneIndex2 = value; break; case 3: weight.boneIndex3 = value; break; default: throw new ArgumentOutOfRangeException( $"{_assetPath} has a skinned mesh with more than 4 weights/vertex. This is not supported."); } var vertexWeight = partition.VertexWeights[i, j]; switch (j) { case 0: weight.weight0 = vertexWeight; break; case 1: weight.weight1 = vertexWeight; break; case 2: weight.weight2 = vertexWeight; break; case 3: weight.weight3 = vertexWeight; break; default: throw new ArgumentOutOfRangeException( $"{_assetPath} has a skinned mesh with more than 4 weights/vertex. This is not supported."); } } boneWeights[index] = weight; } } mesh.boneWeights = boneWeights; var bones = new Transform[skinInstance.BonesCount]; var poses = new Matrix4x4[skinInstance.BonesCount]; for (var index = 0; index < skinInstance.BonesCount; index++) { var bone = skinInstance.SkinningData.Object.BoneList[index].Transform; var boneData = skinInstance.Bones[index]; var unityObject = _unityObjects[boneData].transform; bones[index] = unityObject; // // I have no clue how to properly bind the skin to the bones. // bone.Position & bone.Rotation is suppose to be offsets with the description of: // "Offset of the skin from this bone in bind position." // But I'm having a hard type parsing that. // var transform = unityObject; var pos = transform.position; var rot = transform.eulerAngles; Debug.Log($"{(Vector3) bone.Position} | {MatrixToEulerAngles(bone.Rotation)} | {bone.Scale} | {unityObject.name}"); //transform.position = bone.Position; //transform.eulerAngles = renderer.rootBone.eulerAngles + MatrixToEulerAngles(bone.Rotation); poses[index] = unityObject.worldToLocalMatrix * renderer.rootBone.localToWorldMatrix; //transform.position = pos; //transform.eulerAngles = rot; } mesh.bindposes = poses; renderer.bones = bones; }