有人能解释如何将ozz::math::float4x4
转换为glm::mat4
,然后再乘以fbxsdk::fbxdouble4
吗?
void updateUniformBuffer(const uint32_t ¤tImage) {
static auto startTime = std::chrono::high_resolution_clock::now();
auto currentTime = std::chrono::high_resolution_clock::now();
float time = std::chrono::duration<float,std::chrono::seconds::period>(currentTime - startTime).count();
UniformBufferObject ubo = {};
ubo.model = glm::rotate(glm::mat4(1.0f),time * glm::radians(30.0f),glm::vec3(0.0f,0.0f,1.0f));
controller_.Update(animation_,1.0f);
// Samples optimized animation at t = animation_time_
ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &animation_;
sampling_job.cache = &cache_;
sampling_job.ratio = controller_.time_ratio();
sampling_job.output = make_range(locals_);
if (!sampling_job.Run()) {
printf("Sampling Job Failed\n");
return;
}
// Converts from local space to model space matrices
ozz::animation::LocalToModelJob ltm_job;
ltm_job.skeleton = &skeleton_;
ltm_job.input = make_range(locals_);
ltm_job.output = make_range(models_);
if (!ltm_job.Run()) {
printf("LocalToModel Job Failed\n");
return;
}
auto joints = skeleton_.num_joints();
printf("UBO Joints %i\n",joints);
for (int i = 0; i < joints; i++) {
if (i >= bindPoses.size()) { break; }
FbxAMatrix InvBind = bindPoses[i].Inverse();
// glm_row* == Final Bone Matrix Sent To GPU
// ozz_row* == Bone Matrix After Animation
// fbx_row* == Bone Inverse Bind Pose
glm::vec4* glm_row1 = &ubo.bones[i][0];
ozz::math::SimdFloat4 ozz_row1 = models_[i].cols[0];
FbxDouble4 fbx_row1 = InvBind.mData[0];
glm_row1->x = ozz_row1.m128_f32[0] * fbx_row1.mData[0];
glm_row1->y = ozz_row1.m128_f32[1] * fbx_row1.mData[1];
glm_row1->z = ozz_row1.m128_f32[2] * fbx_row1.mData[2];
glm_row1->w = ozz_row1.m128_f32[3] * fbx_row1.mData[3];
glm::vec4* glm_row2 = &ubo.bones[i][1];
ozz::math::SimdFloat4 ozz_row2 = models_[i].cols[1];
FbxDouble4 fbx_row2 = InvBind.mData[1];
glm_row2->x = ozz_row2.m128_f32[0] * fbx_row2.mData[0];
glm_row2->y = ozz_row2.m128_f32[1] * fbx_row2.mData[1];
glm_row2->z = ozz_row2.m128_f32[2] * fbx_row2.mData[2];
glm_row2->w = ozz_row2.m128_f32[3] * fbx_row2.mData[3];
glm::vec4* glm_row3 = &ubo.bones[i][2];
ozz::math::SimdFloat4 ozz_row3 = models_[i].cols[2];
FbxDouble4 fbx_row3 = InvBind.mData[2];
glm_row3->x = ozz_row3.m128_f32[0] * fbx_row3.mData[0];
glm_row3->y = ozz_row3.m128_f32[1] * fbx_row3.mData[1];
glm_row3->z = ozz_row3.m128_f32[2] * fbx_row3.mData[2];
glm_row3->w = ozz_row3.m128_f32[3] * fbx_row3.mData[3];
glm::vec4* glm_row4 = &ubo.bones[i][3];
ozz::math::SimdFloat4 ozz_row4 = models_[i].cols[3];
FbxDouble4 fbx_row4 = InvBind.mData[3];
glm_row4->x = ozz_row4.m128_f32[0] * fbx_row4.mData[0];
glm_row4->y = ozz_row4.m128_f32[1] * fbx_row4.mData[1];
glm_row4->z = ozz_row4.m128_f32[2] * fbx_row4.mData[2];
glm_row4->w = ozz_row4.m128_f32[3] * fbx_row4.mData[3];
}
// Send updated bone matrices to GPU
_Mesh->updateUniformBuffer(currentImage,ubo);
}
我正在尝试从mat4
构建float4x4
,然后将其乘以fbxdouble4
。 float4x4
保持动画后的骨骼矩阵,fbxdouble4
保持骨骼的反向绑定姿势。 mat4
通过UniformBufferObject
发送到GPU。
我不确定是否要正确转换float4x4
和fbxdouble4
以便在mat4
中使用。我也相信我需要在某个地方glm::transpose
,但不能完全确定如何或在何处。现在,我基本上在GPU上变得越来越垃圾:
为了确保我做得透彻,以下是我如何构建骨骼信息(包括绑定姿势)的方法:
FBXObject* Import(const char* File) {
FbxImporter* Importer = FbxImporter::Create(_FbxManager,"");
if (!Importer->Initialize(File,-1,_FbxManager->GetIOSettings())) {
printf("FBX Import Initialize Failed: %s",Importer->GetStatus().GetErrorString());
return nullptr;
}
FbxScene* Scene = FbxScene::Create(_FbxManager,"NewScene");
Importer->Import(Scene);
Importer->Destroy();
GeometryConverter->Triangulate(Scene,true);
FbxNode* RootNode = Scene->GetRootNode();
if (RootNode) {
std::vector<fbxsdk::FbxNode*> Nodes;
SearchNodes(RootNode,Nodes);
printf("Nodes Size: %i (%i)\n",RootNode->getchildCount(true),Nodes.size());
std::vector<Vertex> OutVertices = {};
std::vector<uint32_t> OutIndices = {};
std::unordered_map<int,VertexBoneInfo> BoneData = {};
FBXObject* NewFBX = new FBXObject;
uint32_t IndexCount = 0;
for (auto Node : Nodes) {
FbxMesh* Mesh = (FbxMesh*)Node->GetNodeAttribute();
FbxVector4* Vertices = Mesh->getcontrolPoints();
int Deformers = Mesh->GetDeformerCount();
printf("Deformers %i\n",Deformers);
FbxSkin* pSkin = (FbxSkin*)Mesh->GetDeformer(0,FbxDeformer::eSkin);
if (pSkin) {
int ncBones = pSkin->getclusterCount();
printf("Bones: %i\n",ncBones);
for (int boneIndex = 0; boneIndex < ncBones; ++boneIndex)
{
FbxCluster* cluster = pSkin->getcluster(boneIndex);
FbxNode* pBone = cluster->GetLink();
FbxAMatrix bindPoseMatrix,transformMatrix;
cluster->GetTransformMatrix(transformMatrix);
cluster->GetTransformLinkMatrix(bindPoseMatrix);
NewFBX->bindPoses.push_back(bindPoseMatrix);
int* pVertexIndices = cluster->getcontrolPointIndices();
double* pVertexWeights = cluster->getcontrolPointWeights();
// Iterate through all the vertices,which are affected by the bone
int ncVertexIndices = cluster->getcontrolPointIndicesCount();
for (int iBoneVertexIndex = 0; iBoneVertexIndex < ncVertexIndices; iBoneVertexIndex++)
{
// vertex
int niVertex = pVertexIndices[iBoneVertexIndex];
// weight
float fWeight = (float)pVertexWeights[iBoneVertexIndex];
BoneData[niVertex].Bones.push_back(boneIndex);
BoneData[niVertex].Weights.push_back(fWeight);
}
}
}
else {
printf("Model Has No Skin\n");
}
//
// UV Mapping
FbxStringList lUVSetNameList;
Mesh->GetUVSetNames(lUVSetNameList);
int UVSets = lUVSetNameList.getcount();
printf("UV Sets: %i\n",UVSets);
//if (UVSets > 0) {
const char* lUVSetName = lUVSetNameList.GetStringAt(0);
const FbxGeometryElementUV* lUVElement = Mesh->GetElementUV(lUVSetName);
printf("UV Set Name: %s\n",lUVSetName);
//if (lUVElement->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) {
printf("Polygon Vertex Mapping\n");
const bool lUseIndex = lUVElement->GetReferenceMode() != FbxGeometryElement::eDirect;
const int lIndexCount = (lUseIndex) ? lUVElement->GetIndexArray().getcount() : 0;
//}
//}
//
// Normal Mapping
FbxGeometryElementNormal* lNormalElement = Mesh->GetElementNormal();
int lPolyIndexCounter = 0;
for (int j = 0; j < Mesh->GetPolygonCount(); j++) {
int NumVerts = Mesh->GetPolygonSize(j);
if (NumVerts != 3 ) { continue; }
for (int k = 0; k < NumVerts; k++) {
Vertex NewVertex{};
//
// Bone Data
if (BoneData.count(j) == 1) {
const unsigned int Bonesize = BoneData[j].Bones.size();
if (Bonesize > 0) {
NewVertex.Bones.x = BoneData[j].Bones[0];
}
if (Bonesize > 1) {
NewVertex.Bones.y = BoneData[j].Bones[1];
}
if (Bonesize > 2) {
NewVertex.Bones.z = BoneData[j].Bones[2];
}
if (Bonesize > 3) {
NewVertex.Bones.w = BoneData[j].Bones[3];
}
const unsigned int WeightSize = BoneData[j].Weights.size();
if (WeightSize > 0) {
NewVertex.Weights.x = BoneData[j].Weights[0];
}
if (WeightSize > 1) {
NewVertex.Weights.y = BoneData[j].Weights[1];
}
if (WeightSize > 2) {
NewVertex.Weights.z = BoneData[j].Weights[2];
}
if (WeightSize > 3) {
NewVertex.Weights.w = BoneData[j].Weights[3];
}
}
//
// Normap Mapping Data
int lNormalIndex = 0;
//reference mode is direct,the normal index is same as lIndexByPolygonVertex.
if (lNormalElement->GetReferenceMode() == FbxGeometryElement::eDirect)
lNormalIndex = lPolyIndexCounter;
//reference mode is index-to-direct,get normals by the index-to-direct
if (lNormalElement->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
lNormalIndex = lNormalElement->GetIndexArray().Getat(lPolyIndexCounter);
//Got normals of each polygon-vertex.
FbxVector4 lNormal = lNormalElement->GetDirectArray().Getat(lNormalIndex);
NewVertex.normal.x = lNormal[0];
NewVertex.normal.y = lNormal[1];
NewVertex.normal.z = lNormal[2];
//
// UV Mapping Data
if (lPolyIndexCounter < lIndexCount)
{
FbxVector2 lUVValue;
//the UV index depends on the reference mode
int lUVIndex = lUseIndex ? lUVElement->GetIndexArray().Getat(lPolyIndexCounter) : lPolyIndexCounter;
lUVValue = lUVElement->GetDirectArray().Getat(lUVIndex);
NewVertex.texCoord.x = lUVValue.mData[0];
NewVertex.texCoord.y = -lUVValue.mData[1];
lPolyIndexCounter++;
}
//
// Vertex & Index data
int VertID = Mesh->GetPolygonVertex(j,k);
NewVertex.pos.x = (float)Vertices[VertID].mData[0];
NewVertex.pos.y = (float)Vertices[VertID].mData[1];
NewVertex.pos.z = (float)Vertices[VertID].mData[2];
OutVertices.push_back(NewVertex);
OutIndices.push_back(IndexCount++);
}
}
}
NewFBX->Vertices.swap(OutVertices);
NewFBX->Indices.swap(OutIndices);
printf("Out Vertex Count: %i\n",NewFBX->Vertices.size());
return NewFBX;
}
}
还有蒙皮着色器:
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(binding = 0) uniform UniformBufferObject {
mat4 model;
mat4 view;
mat4 proj;
mat4 bones[128];
} ubo;
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec4 inColor;
layout(location = 2) in vec2 inTexCoord;
layout(location = 3) in vec3 inNormal;
layout(location = 4) in ivec4 inBones;
layout(location = 5) in vec4 inWeights;
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec2 fragTexCoord;
layout(location = 2) out vec3 fragNormal;
out gl_PerVertex
{
vec4 gl_Position;
};
void main() {
mat4 boneTransform = ubo.bones[inBones[0]] * inWeights[0];
boneTransform += ubo.bones[inBones[1]] * inWeights[1];
boneTransform += ubo.bones[inBones[2]] * inWeights[2];
boneTransform += ubo.bones[inBones[3]] * inWeights[3];
gl_Position = ubo.proj * ubo.view * ubo.model * boneTransform * vec4(inPosition,1.0);
fragColor = inColor;
fragTexCoord = inTexCoord;
}