void FbxLoader::ComputeNodeMatrix(FbxNode* node, Node& meshNode, bool local) { if(!node) return; FbxAnimEvaluator* evaluator = scene->GetAnimationEvaluator(); FbxAMatrix global; global.SetIdentity(); FbxTime time; time.SetSecondDouble(0.0); if(node != scene->GetRootNode()) { if(local) { global = evaluator->GetNodeLocalTransform(node, time); } else { global = evaluator->GetNodeGlobalTransform(node, time); } } auto T = global.GetT() * factor; if(axismode == eLeftHanded) { auto R = global.GetR(); R[1] *= -1; R[2] *= -1; T[0] *= -1; global.SetR(R); } global.SetT(T); meshNode.matrix = Matrix( (float)global[0][0], (float)global[0][1], (float)global[0][2], (float)global[0][3], (float)global[1][0], (float)global[1][1], (float)global[1][2], (float)global[1][3], (float)global[2][0], (float)global[2][1], (float)global[2][2], (float)global[2][3], (float)global[3][0], (float)global[3][1], (float)global[3][2], (float)global[3][3]); }
FbxAMatrix LoaderFbxMesh::parseTransformMatrixOther(FbxCluster* cluster, FbxMesh* mesh, FbxPose* fbxPose, FbxAMatrix globalPosition) { FbxAMatrix referenceGeometry; FbxAMatrix referenceGlobalInitPosition; FbxAMatrix referenceGlobalCurrentPosition; FbxAMatrix clusterGeometry; FbxAMatrix clusterGlobalInitPosition; FbxAMatrix clusterGlobalCurrentPosition; FbxAMatrix clusterRelativeInitPosition; FbxAMatrix clusterRelativeCurrentPositionInverse; FbxTime time(0); FbxAMatrix fbxMatrixIdentity; fbxMatrixIdentity.SetIdentity(); cluster->GetTransformMatrix(referenceGlobalInitPosition); referenceGlobalCurrentPosition = globalPosition; referenceGeometry = getGeometry(mesh->GetNode()); referenceGlobalInitPosition *= referenceGeometry; cluster->GetTransformLinkMatrix(clusterGlobalInitPosition); clusterGlobalCurrentPosition = getGlobalPosition(cluster->GetLink(), time, fbxPose, nullptr); clusterRelativeInitPosition = clusterGlobalInitPosition.Inverse() * referenceGlobalInitPosition; clusterRelativeCurrentPositionInverse = referenceGlobalCurrentPosition.Inverse() * clusterGlobalCurrentPosition; FbxAMatrix offsetMatrix; offsetMatrix = clusterRelativeCurrentPositionInverse * clusterRelativeInitPosition; return offsetMatrix; }
FbxMatrix FBXScene::GetGeometricOffset2(FbxNode* pNode) { if( !pNode ) { FbxAMatrix mat; mat.SetIdentity(); return mat; } // CheckMe: E Source Set = E Source Pivot? FbxVector4 T = pNode->GetGeometricTranslation(FbxNode::eSourcePivot); FbxVector4 R = pNode->GetGeometricRotation(FbxNode::eSourcePivot); FbxVector4 S = pNode->GetGeometricScaling(FbxNode::eSourcePivot); FbxAMatrix matFBXGeometryOffset; matFBXGeometryOffset.SetIdentity(); matFBXGeometryOffset.SetTRS(T,R,S); return matFBXGeometryOffset; }
MeshData* FBXImporter::GetMeshInfo() { mMeshData = new MeshData(); int indicesIndexOffset = 0; // 记录当前mesh在整个ib中的索引位移。 int verticesIndexOffset = 0; // 记录当前mesh在整个vb中的顶点位移。 for (int meshIndex = 0; meshIndex < mFBXMeshDatas.size(); meshIndex++) { FbxMesh* mesh = mFBXMeshDatas[meshIndex]->mMesh; FBXMeshData* fbxMeshData = mFBXMeshDatas[meshIndex]; fbxMeshData->mVerticesCount = mesh->GetControlPointsCount(); fbxMeshData->mIndicesCount = mesh->GetPolygonVertexCount(); fbxMeshData->mTrianglesCount = mesh->GetPolygonCount(); // 获取3dsmax中的全局变换矩阵,稍后可以在DX中还原。 FbxMatrix gloableTransform = mesh->GetNode()->EvaluateGlobalTransform(); FbxAMatrix matrixGeo; matrixGeo.SetIdentity(); const FbxVector4 lT = mesh->GetNode()->GetGeometricTranslation(FbxNode::eSourcePivot); const FbxVector4 lR = mesh->GetNode()->GetGeometricRotation(FbxNode::eSourcePivot); const FbxVector4 lS = mesh->GetNode()->GetGeometricScaling(FbxNode::eSourcePivot); matrixGeo.SetT(lT); matrixGeo.SetR(lR); matrixGeo.SetS(lS); FbxAMatrix matrixL2W; matrixL2W.SetIdentity(); matrixL2W = mesh->GetNode()->EvaluateGlobalTransform(); matrixL2W *= matrixGeo; XMMATRIX globalTransform = XMLoadFloat4x4(&fbxMeshData->globalTransform); FbxMatrixToXMMATRIX(globalTransform, matrixL2W); XMStoreFloat4x4(&fbxMeshData->globalTransform, globalTransform); // 读取顶点。 ReadVertices(fbxMeshData); // 读取索引。 ReadIndices(fbxMeshData); // 先读取网格对应的材质索引信息,以便优化稍后纹理读取。 // 一个网格可能只对应一个materialId,也可能对应多个materialId(3dsmax里的Multi/Sub-Object材质)。 // 如果只对应一个材质,简单的读取就行,不过普遍情况可能是为了优化渲染合并mesh从而拥有多材质。 // 这个函数调用完毕我们会得到materialId和拥有这个materialId的三角形列表(三角形编号列表),保存在vector<MaterialIdOffset>的容器中。 //struct Material //{ // Material() {} // Material(int id, string diffuse, string normalMap) // : materialId(id), // diffuseTextureFile(diffuse), // normalMapTextureFile(normalMap) // {} // // int materialId; // string diffuseTextureFile; // string normalMapTextureFile; //}; // struct MaterialIdOffset //{ // MaterialIdOffset() // : polygonCount(0) // {} // int polygonCount; // Material material; //}; ConnectMaterialsToMesh(mesh, fbxMeshData->mTrianglesCount); // 根据ConnectMaterialsToMesh得到的信息读取材质纹理信息,同样存入vector<MaterialIdOffset>容器。 LoadMaterials(fbxMeshData); int triangleCount = mesh->GetPolygonCount(); int controlPointIndex = 0; int normalIndex = 0; fbxMeshData->mUVs.resize(fbxMeshData->mIndicesCount, XMFLOAT2(-1.0f, -1.0f)); // Extract normals and uvs from FbxMesh. for (int i = 0; i < triangleCount; i++) { int polygonSize = mesh->GetPolygonSize(i); for (int j = 0; j < polygonSize; j++) { controlPointIndex = mesh->GetPolygonVertex(i, j); ReadNormals(fbxMeshData, controlPointIndex, normalIndex); // 有纹理我们才读取uv,tangent以及binormal。 if (fbxMeshData->hasDiffuseTexture()) { ReadUVs(fbxMeshData, controlPointIndex, normalIndex, mesh->GetTextureUVIndex(i, j), 0); ReadTangents(fbxMeshData, controlPointIndex, normalIndex); ReadBinormals(fbxMeshData, controlPointIndex, normalIndex); } normalIndex++; } } SplitVertexByNormal(fbxMeshData); if (fbxMeshData->hasDiffuseTexture()) { SplitVertexByUV(fbxMeshData); } else { fbxMeshData->mUVs.resize(fbxMeshData->mVerticesCount); } if (fbxMeshData->hasNormalMapTexture()) { SplitVertexByTangent(fbxMeshData); SplitVertexByBinormal(fbxMeshData); } else { fbxMeshData->mTangents.resize(fbxMeshData->mVerticesCount); fbxMeshData->mBinormals.resize(fbxMeshData->mVerticesCount); } // 如果.fbx包含一个以上的mesh,需要计算当前FBXMeshData的索引在全局索引中的位置。 for (int i = 0; i < fbxMeshData->mIndicesCount; i++) { fbxMeshData->mIndices[i] = fbxMeshData->mIndices[i] + verticesIndexOffset; } mMeshData->verticesCount += fbxMeshData->mVerticesCount; mMeshData->indicesCount += fbxMeshData->mIndicesCount; mMeshData->meshesCount++; // 多材质的情况。 // 根据之前填充的materialIdOffsets容器保存的materialId和三角形的对应关系, // 计算每个RenderPackage渲染所需的索引数量和索引起始位置(偏移)。 if (isByPolygon && fbxMeshData->hasDiffuseTexture()) { vector<MaterialIdOffset> materialIdOffsets = mMeshData->materialIdOffsets; for (int i = 0; i < materialIdOffsets.size(); i++) { RenderPackage renderPacakge; renderPacakge.globalTransform = fbxMeshData->globalTransform; renderPacakge.indicesCount = materialIdOffsets[i].polygonCount * 3; if (i == 0) { renderPacakge.indicesOffset = indicesIndexOffset; } else { renderPacakge.indicesOffset += indicesIndexOffset; } renderPacakge.material = materialIdOffsets[i].material; mMeshData->renderPackages.push_back(renderPacakge); indicesIndexOffset += renderPacakge.indicesCount; } } else // 单一材质的情况。 { RenderPackage renderPackage; renderPackage.indicesCount = fbxMeshData->mIndicesCount; renderPackage.indicesOffset = indicesIndexOffset; renderPackage.material = fbxMeshData->mMaterial; renderPackage.globalTransform = fbxMeshData->globalTransform; mMeshData->renderPackages.push_back(renderPackage); indicesIndexOffset += fbxMeshData->mIndices.size(); } verticesIndexOffset += fbxMeshData->mVertices.size(); // 将当前mesh的数据追加到全局数据容器。 Merge(mMeshData->vertices, fbxMeshData->mVertices); Merge(mMeshData->indices, fbxMeshData->mIndices); Merge(mMeshData->normals, fbxMeshData->mNormals); Merge(mMeshData->uvs, fbxMeshData->mUVs); Merge(mMeshData->tangents, fbxMeshData->mTangents); Merge(mMeshData->binormals, fbxMeshData->mBinormals); mMeshData->materialIdOffsets.clear(); } clear(); return mMeshData; }
// Deform the vertex array in classic linear way. void fbxLoader2::ComputeLinearDeformation(FbxAMatrix& pGlobalPosition, FbxMesh* pMesh, FbxTime& pTime, FbxPose* pPose, int frame) { // All the links must have the same link mode. FbxCluster::ELinkMode lClusterMode = ((FbxSkin*)pMesh->GetDeformer(0, FbxDeformer::eSkin))->GetCluster(0)->GetLinkMode(); int lVertexCount = pMesh->GetControlPointsCount(); FbxAMatrix* lClusterDeformation = new FbxAMatrix[lVertexCount]; memset(lClusterDeformation, 0, lVertexCount * sizeof(FbxAMatrix)); double* lClusterWeight = new double[lVertexCount]; memset(lClusterWeight, 0, lVertexCount * sizeof(double)); if (lClusterMode == FbxCluster::eAdditive) { for (int i = 0; i < lVertexCount; ++i) { lClusterDeformation[i].SetIdentity(); } } // For all skins and all clusters, accumulate their deformation and weight // on each vertices and store them in lClusterDeformation and lClusterWeight. int lSkinCount = pMesh->GetDeformerCount(FbxDeformer::eSkin); for ( int lSkinIndex=0; lSkinIndex<lSkinCount; ++lSkinIndex) { FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin); int lClusterCount = lSkinDeformer->GetClusterCount(); for ( int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex) { FbxCluster* lCluster = lSkinDeformer->GetCluster(lClusterIndex); if (!lCluster->GetLink()) continue; FbxAMatrix lVertexTransformMatrix; ComputeClusterDeformation(pGlobalPosition, pMesh, lCluster, lVertexTransformMatrix, pTime, pPose, frame); //lVertexTransformMatrix.Transpose(); FbxAMatrix identityM; identityM.SetIdentity(); FbxVector4 rotation = lVertexTransformMatrix.GetROnly(); FbxVector4 translation = lVertexTransformMatrix.GetT(); FbxVector4 scaling = lVertexTransformMatrix.GetS(); //rotation = FbxVector4(rotation.mData[0], rotation.mData[1], rotation.mData[2], rotation.mData[3]); //translation = FbxVector4 (translation.mData[0], translation.mData[1], translation.mData[2], translation.mData[3]); //scaling = FbxVector4 (scaling.mData[0], scaling.mData[1], scaling.mData[2], scaling.mData[3]); //lVertexTransformMatrix = FbxAMatrix(translation, rotation, scaling); //lVertexTransformMatrix = FbxAMatrix(translation, rotation, scaling); identityM = lVertexTransformMatrix * identityM; D3DXMATRIX convert = D3DXMATRIX(1,0,0,0, 0,0,1,0, 0,1,0,0, 0,0,0,1); D3DXMATRIX setMatrix = D3DXMATRIX( (float)identityM.mData[0].mData[0], (float)identityM.mData[1].mData[0], (float)identityM.mData[2].mData[0], (float)identityM.mData[3].mData[0], (float)identityM.mData[0].mData[1], (float)identityM.mData[1].mData[1], (float)identityM.mData[2].mData[1], (float)identityM.mData[3].mData[1], (float)identityM.mData[0].mData[2], (float)identityM.mData[1].mData[2], (float)identityM.mData[2].mData[2], (float)identityM.mData[3].mData[2], (float)identityM.mData[0].mData[3], (float)identityM.mData[1].mData[3], (float)identityM.mData[2].mData[3],1); //setMatrix *=0.5f; setMatrix = D3DXMATRIX( (float)identityM.mData[0].mData[0], (float)identityM.mData[1].mData[0], (float)identityM.mData[2].mData[0], (float)identityM.mData[3].mData[0], (float)identityM.mData[0].mData[1], (float)identityM.mData[1].mData[1], (float)identityM.mData[2].mData[1], (float)identityM.mData[3].mData[1], //(float)identityM.mData[0].mData[2], (float)identityM.mData[1].mData[2], (float)identityM.mData[2].mData[2], (float)identityM.mData[3].mData[1], (float)identityM.mData[0].mData[2], (float)identityM.mData[1].mData[2], (float)identityM.mData[2].mData[2], (float)identityM.mData[3].mData[2], (float)identityM.mData[0].mData[3], (float)identityM.mData[1].mData[3], (float)identityM.mData[2].mData[3], 1); //setMatrix = setMatrix*convert; ///////// juz prawie dziala. sprawdz jeszcze te addytywne itp. /// generalnie dodaj to do włosów i dorzuć poprzednią macierz, żeby liczyć przesunięcia. //setMatrix /= 2.54f; //skala jedna jest w cm, druga w inchach, nieważne czy zmieniam system skali ręcznie... bzdurka fbxa std::string nametype = lCluster->GetLink()->GetName(); animationStructure->GetSkeleton(frame)->GetBone(animationStructure->GetSkeleton(frame)->GetBoneByName(lCluster->GetLink()->GetName()))->SetTransformation(setMatrix); }//lClusterCount } delete [] lClusterDeformation; delete [] lClusterWeight; }
BabylonLight::BabylonLight(BabylonNode & babnode) : diffuse(1, 1, 1), specular(1, 1, 1) { auto node = babnode.fbxNode(); std::string ansiName = node->GetName(); name = std::wstring(ansiName.begin(), ansiName.end()); id = getNodeId(node); auto parent = node->GetParent(); if (parent) { parentId = getNodeId(parent); } auto localTransform = babnode.GetLocal(); position = localTransform.translation(); auto light = node->GetLight(); switch (light->LightType) { case FbxLight::ePoint: type = type_omni; break; case FbxLight::eDirectional: type = type_direct; { FbxDouble3 vDir(0, -1, 0); FbxAMatrix rotM; rotM.SetIdentity(); rotM.SetQ(localTransform.fbxrot()); auto transDir = rotM.MultT(vDir); direction = transDir; } break; case FbxLight::eSpot: type = type_Spot; { FbxDouble3 vDir(0, -1, 0); FbxAMatrix rotM; rotM.SetIdentity(); rotM.SetQ(localTransform.fbxrot()); auto transDir = rotM.MultT(vDir); direction = transDir; exponent = 1; angle = static_cast<float>(light->OuterAngle*Euler2Rad); } break; default: break; } diffuse = light->Color.Get(); intensity = static_cast<float>(light->Intensity.Get() / 100.0); if (light->EnableFarAttenuation.Get()) { range = static_cast<float>(light->FarAttenuationEnd.Get()); } auto hasAnimStack = node->GetScene()->GetSrcObjectCount<FbxAnimStack>() > 0; if (!hasAnimStack) { return; } castShadows = light->CastShadows.Get(); if (castShadows) { shadowGenerator = std::make_shared<BabylonShadowGenerator>(node); } auto animStack = node->GetScene()->GetSrcObject<FbxAnimStack>(0); FbxString animStackName = animStack->GetName(); FbxTakeInfo* takeInfo = node->GetScene()->GetTakeInfo(animStackName); auto animTimeMode = GlobalSettings::Current().AnimationsTimeMode; auto animFrameRate = GlobalSettings::Current().AnimationsFrameRate(); auto startFrame = takeInfo->mLocalTimeSpan.GetStart().GetFrameCount(animTimeMode); auto endFrame = takeInfo->mLocalTimeSpan.GetStop().GetFrameCount(animTimeMode); auto animLengthInFrame = endFrame - startFrame + 1; auto posAnimName = getNodeId(node); auto dirAnimName = getNodeId(node); posAnimName.append(L"_position"); dirAnimName.append(L"_direction"); auto posAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), posAnimName, L"position", true, 0, static_cast<int>(animLengthInFrame), true); auto dirAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), dirAnimName, L"direction", true, 0, static_cast<int>(animLengthInFrame), true); if (node->LclRotation.GetCurveNode() || node->LclTranslation.GetCurveNode()) { for (auto ix = 0; ix < animLengthInFrame; ix++) { babylon_animation_key<babylon_vector3> key; key.frame = ix; FbxTime currTime; currTime.SetFrame(startFrame + ix, animTimeMode); auto currTransform = babnode.GetLocal(currTime); key.values = currTransform.translation(); posAnim->appendKey(key); if (type == type_direct || type == type_Spot) { babylon_animation_key<babylon_vector3> dirkey; dirkey.frame = ix; FbxDouble3 vDir(0, -1, 0); FbxAMatrix rotM; rotM.SetIdentity(); rotM.SetQ(currTransform.fbxrot()); auto transDir = rotM.MultT(vDir); dirkey.values = transDir; dirAnim->appendKey(dirkey); } } } if (!posAnim->isConstant()) { animations.push_back(posAnim); } if (!dirAnim->isConstant()) { animations.push_back(dirAnim); } }