JsonMesh makeJsonMesh(MeshStorageKey meshKey, ResId id) { var result = new JsonMesh(meshKey, id, this); if (!meshKey.skeletonRoot || !meshKey.prefab) { return(result); } if (!isSkeletalMesh(meshKey.mesh)) { return(result); } /* * Doing this in steps, as it is possible to have root transform issue and then somehow no bindpose issues. * I mean, miracles can happen, right? */ result = fixSkinMeshRootBoneTransform(meshKey, result); //Currently disabled //result = fixSkinMeshPosedBones(meshKey, result); return(result); }
public void rebuildMesh() { if (!skinMeshRend) { return; } var resMap = new ResourceMapper(); //jsonMesh = new JsonMesh(new Mesh) var prefabRoot = ExportUtility.getLinkedRootPrefabAsset(skinMeshRend.gameObject); var assetSkeletonRoot = JsonSkeletonBuilder.findSkeletonRoot(skinMeshRend); var mesh = skinMeshRend.sharedMesh; jsonMesh = new JsonMesh(new MeshStorageKey(mesh, prefabRoot, assetSkeletonRoot), 0, resMap); var boneNames = skinMeshRend.bones.Select((arg) => arg.name).ToList(); origTransforms = skinMeshRend.bones.ToList(); if (skeletonRoot) { debugTransforms = Utility.findNamedTransforms(boneNames, skeletonRoot); } else { debugTransforms = null; } //var foundTransforms = boneNames.Select((arg) => ; }
public JsonMesh(JsonMesh other){ if (other == null) throw new System.ArgumentNullException(); id = other.id; name = other.name; uniqueName = other.uniqueName; usageFlags = other.usageFlags; convexCollider = other.convexCollider; triangleCollider = other.triangleCollider; path = other.path; materials = other.materials.ToList(); readable = other.readable; vertexCount = other.vertexCount; colors = other.colors.copyArray(); verts = other.verts.copyArray(); tangents = other.tangents.copyArray(); uv0 = other.uv0.copyArray(); uv1 = other.uv1.copyArray(); uv2 = other.uv2.copyArray(); uv3 = other.uv3.copyArray(); uv4 = other.uv4.copyArray(); uv5 = other.uv5.copyArray(); uv6 = other.uv6.copyArray(); uv7 = other.uv7.copyArray(); boneWeights = other.boneWeights.ToList(); boneIndexes = other.boneIndexes.ToList(); defaultSkeletonId = other.defaultSkeletonId; defaultBoneNames = other.defaultBoneNames.ToList(); defaultMeshNodeName = other.defaultMeshNodeName; defaultMeshNodePath = other.defaultMeshNodePath; defaultMeshNodeMatrix = other.defaultMeshNodeMatrix; blendShapeCount = other.blendShapeCount; blendShapes = other.blendShapes.Select((arg) => new JsonBlendShape(arg)).ToList(); bindPoses = other.bindPoses.ToList(); subMeshes = other.subMeshes.Select((arg) => new SubMesh(arg)).ToList(); subMeshCount = other.subMeshCount; }
//Looks like I can't move this out of here for now... JsonMesh fixSkinMeshRootBoneTransform(MeshStorageKey meshKey, JsonMesh srcMesh) { //return srcMesh; //let's check if we even NEED transformation. //Root bool largeRootTransformFound = false; { var desired = Matrix4x4.identity; var current = meshKey.skeletonRoot.localToWorldMatrix; var maxRootDiff = SkeletalMeshTools.getMaxDifference(desired, current); if (maxRootDiff > SkeletalMeshTools.matrixEpsilon) { Debug.LogFormat( string.Format("Large root matrix transform difference foune on mesh {0}, mesh will be transformed to accomodate." + "\ncurrent:\n{1}\ndesired:\n{2}\n", meshKey.mesh.name, current, desired)); largeRootTransformFound = true; } } if (!largeRootTransformFound) { return(srcMesh); } /* * We're now bringing skleletal mesh into rootSpace. */ var srcRootTransform = meshKey.prefab.transform.localToWorldMatrix; var srcRootInvTransform = meshKey.prefab.transform.worldToLocalMatrix; /* * Aw, damn it. Sksleton root is not going to cut it. We need mesh node itself. * * So, in unity it is, by default: (Right to left notation) * ResultTransform = targetBoneTransform * bindPose * meshTransform. */ var skelData = skelRegistry.getDefaultSkeletonData(meshKey); if (skelData == null) { throw new System.ArgumentException( string.Format("Coudl not locate default skeleton data for {0}", meshKey)); } if (!skelData.meshNodeTransform) { throw new System.ArgumentException( string.Format("mesh node transform is not set for {0}", meshKey) ); } var nodeMatrix = skelData.meshNodeTransform.localToWorldMatrix; var nodeInvMatrix = skelData.meshNodeTransform.worldToLocalMatrix; //var relativeMatrix = Utility.getRelativeMatrix(skelData.meshNodeTransform, meshKey.prefab.transform); var transformMatrix = srcRootInvTransform * nodeMatrix; var newMesh = new JsonMesh(srcMesh); newMesh.transformMeshWith(transformMatrix); var meshMatrix = Utility.getRelativeMatrix(skelData.meshNodeTransform, meshKey.prefab.transform); var meshInvMatrix = Utility.getRelativeInverseMatrix(skelData.meshNodeTransform, meshKey.prefab.transform); newMesh.processBindPoses((bindPose, index) => { /* * Givent that i'm getting error that's squarely factor of 10 while bones themselves have scale factor of 100 * (thanks, fbx exporter), it means I failed to accomodate for removal of mesh transform. Let's see... */ var newTransform = meshInvMatrix * bindPose; Debug.LogFormat("Converting bindpose {0}:\noriginal:\n{1}\nnew:\n{2}\nmesh:\n{3}\nmeshInv:\n{4}\nroot:\n{5}\nrootInv:\n{6}", index, bindPose, newTransform, meshMatrix, meshInvMatrix, srcRootTransform, srcRootInvTransform); return(newTransform); }); return(newMesh); }
public static readonly float matrixEpsilon = 0.00001f; //I'll consider matrices equivalent if this is below this threshold public static JsonMesh fixSkinMeshPosedBones(MeshStorageKey meshKey, JsonMesh srcMesh) { var result = srcMesh; var boneTransforms = Utility.findNamedTransforms(result.defaultBoneNames, meshKey.skeletonRoot); for (int i = 0; i < boneTransforms.Count; i++) { if (!boneTransforms[i]) { Debug.LogWarningFormat( string.Format("Could not locate bone {0}({1}) on mesh {2}", result.defaultBoneNames[i], i, meshKey.mesh) ); } } var rootNode = meshKey.prefab.transform; bool largeBoneTransformFound = false; { var srcRootTransform = meshKey.skeletonRoot.localToWorldMatrix; //var srcRootInvTransform = meshKey.skeletonRoot.worldToLocalMatrix; for (int boneIndex = 0; boneIndex < boneTransforms.Count; boneIndex++) { var curBone = boneTransforms[boneIndex]; var curBoneMatrix = Utility.getRelativeMatrix(curBone, rootNode); var curBoneInvMatrix = Utility.getRelativeInverseMatrix(curBone, rootNode); var bindPose = srcMesh.bindPoses[boneIndex]; Debug.LogFormat("curBone: {0}({1})\nmatrix:\n{2}\ninvMatrix:\n{3}\nbindPose:\n{4}\ninvBindPose:\n{5}\nroot:\n{6}\ninvRoot:\n{7}\n", boneIndex, curBone.name, curBoneMatrix, curBoneInvMatrix, bindPose, bindPose.inverse, srcRootTransform, srcRootTransform.inverse); /* * var curBone = Utility.getRelativeMatrix(boneTransforms[boneIndex], ; * var inverseMatrix = curBone.worldToLocalMatrix * srcRootTransform; * var bindPose = srcMesh.bindPoses[boneIndex];//meshKey.mesh.bindposes[i]; ///NOPE. We're done tweaking the mesh at this point. * var diff = getMaxDifference(inverseMatrix, bindPose); * Debug.LogFormat("index:{0}({1})\ninverseMatrix:\n{2}\nbindPose:\n{3}\nboneMatrix:\n{4}\nsrcRoot:\n{5}\ndiff: {6}\nepsilon: {7}", * boneIndex, curBone.name, inverseMatrix, bindPose, curBone.worldToLocalMatrix, srcRootTransform, diff, matrixEpsilon); */ var curPose = bindPose; var desiredPose = curBoneInvMatrix; var diff = getMaxDifference(curPose, desiredPose); Debug.LogFormat("bindPose:\n{0}\ndesiredPose:\n{1}\ndiff: {2}; epsilon: {3}\n", curPose, desiredPose, diff, matrixEpsilon); if (diff > matrixEpsilon) { largeBoneTransformFound = true; Debug.LogFormat("Large transform found"); //break; } } } if (!largeBoneTransformFound) { return(result); } else { Debug.LogFormat( string.Format("Large transform difference found on mesh {0}, mesh will be transformed to accomodate", meshKey.mesh.name)); } return(result); //disable it for now. //Oooh boy. Here it comes. The transformation. /* * The fact the mesh has both prefab and skeleton root specified indicats that it is skeletal. * * To accomodate for unreal approach to skinning, we now need to transform it into root space of our prefab. */ var transformed = new JsonMesh(result); var transformMatrices = new List <Matrix4x4>(); var rootTransform = meshKey.skeletonRoot.transform.localToWorldMatrix; var invRootTransform = meshKey.skeletonRoot.transform.worldToLocalMatrix; var oldBindPoses = meshKey.mesh.bindposes; var rootParentTransform = Matrix4x4.identity; var rootParentInvTransform = Matrix4x4.identity; if (meshKey.skeletonRoot.parent) { var rootParent = meshKey.skeletonRoot.parent; rootParentTransform = rootParent.localToWorldMatrix; rootParentInvTransform = rootParent.worldToLocalMatrix; } for (int boneIndex = 0; boneIndex < transformed.bindPoses.Count; boneIndex++) { var newTransformMatrix = Matrix4x4.identity; var curBone = boneTransforms[boneIndex]; if (curBone) { newTransformMatrix = rootParentInvTransform * curBone.localToWorldMatrix * srcMesh.bindPoses[boneIndex]; //meshKey.mesh.bindposes[boneIndex]; //invRootTransform * curBone.localToWorldMatrix * meshKey.mesh.bindposes[boneIndex]; } transformMatrices.Add(newTransformMatrix); } transformed.transformSkeletalMesh(transformMatrices); transformed.setBindPosesFromTransforms(boneTransforms, meshKey.skeletonRoot); // return(transformed); }