bool CheckControllerSkin(FULogFile& fileOut, FCDSkinController* controller) { FailIf(controller == NULL); // Check the base target's identity FailIf(controller->GetTarget() == NULL); PassIf(controller->GetTarget()->GetType() == FCDEntity::GEOMETRY); PassIf(controller->GetTarget()->GetDaeId() == meshId); // Retrieve the two joints and verify their ids/bind-pose. PassIf(controller->GetJointCount() == 2); const FMMatrix44* joint1 = NULL,* joint2 = NULL; for (size_t i = 0; i < 2; ++i) { FCDSkinControllerJoint* joint = controller->GetJoint(i); if (joint->GetId() == jointId1) { FailIf(joint1 != NULL); joint1 = &joint->GetBindPoseInverse(); } else if (joint->GetId() == jointId2) { FailIf(joint2 != NULL); joint2 = &joint->GetBindPoseInverse(); } else Fail; } FailIf(joint1 == NULL || joint2 == NULL); PassIf(IsEquivalent(*joint1, FMMatrix44::Identity)); FMMatrix44 sbp = FMMatrix44(sampleBindPose1).Inverted(); PassIf(IsEquivalent(*joint2, FMMatrix44(sampleBindPose1).Inverted())); // Verify the influences PassIf(controller->GetInfluenceCount() == 4); FCDSkinControllerVertex* influence = controller->GetVertexInfluence(0); FailIf(influence == NULL); PassIf(influence->GetPairCount() == 2); PassIf(IsEquivalent(influence->GetPair(0)->jointIndex, 0)); PassIf(IsEquivalent(influence->GetPair(0)->weight, 0.5f)); PassIf(IsEquivalent(influence->GetPair(1)->jointIndex, 1)); PassIf(IsEquivalent(influence->GetPair(1)->weight, 0.5f)); influence = controller->GetVertexInfluence(1); FailIf(influence == NULL); PassIf(influence->GetPairCount() == 0); influence = controller->GetVertexInfluence(2); FailIf(influence == NULL); PassIf(influence->GetPairCount() == 1); PassIf(IsEquivalent(influence->GetPair(0)->jointIndex, 0)); PassIf(IsEquivalent(influence->GetPair(0)->weight, 1.0f)); // the weight should have been normalized. influence = controller->GetVertexInfluence(3); FailIf(influence == NULL); PassIf(influence->GetPairCount() == 1); PassIf(IsEquivalent(influence->GetPair(0)->jointIndex, 1)); PassIf(IsEquivalent(influence->GetPair(0)->weight, 1.0f)); return true; }
ColladaAnimatedMesh::ColladaAnimatedMesh(FCDController * animationController ) { mesh = 0; controller = animationController; bool isMorph = animationController->IsMorph(); bool isSkin = animationController->IsSkin(); if (isSkin) { FCDSkinController * skinController = animationController->GetSkinController(); int jointCount = skinController->GetJointCount(); FCDSkinControllerJoint * origJoints = skinController->GetJoints(); joints.resize(jointCount); for (int j = 0; j < jointCount; ++j) { joints[j].joint = &origJoints[j]; joints[j].parentJoint = 0; joints[j].node = 0; joints[j].index = j; joints[j].parentIndex = -1; FMMatrix44 bindPoseInverse = joints[j].joint->GetBindPoseInverse(); joints[j].colladaInverse0 = bindPoseInverse; joints[j].inverse0 = ConvertMatrix(joints[j].colladaInverse0); printf("%s, ", joints[j].joint->GetId().c_str()); } colladaBindShapeMatrix = skinController->GetBindShapeTransform(); bindShapeMatrix = ConvertMatrix(colladaBindShapeMatrix); printf("- controller: %s influence: %ld influence-entity: %s\n", animationController->GetDaeId().c_str(), skinController->GetInfluenceCount(), skinController->GetTarget()->GetDaeId().c_str()); vertexWeights.resize(skinController->GetInfluenceCount()); int maxJoints = 0; for (int index = 0; index < (int)skinController->GetInfluenceCount(); ++index) { FCDSkinControllerVertex * vert = skinController->GetVertexInfluence(index); vertexWeights[index].jointCount = 0; for (int pp = 0; pp < (int)vert->GetPairCount(); ++pp) { FCDJointWeightPair * jointWeightPar = vert->GetPair(pp); vertexWeights[index].AddWeight(jointWeightPar->jointIndex, jointWeightPar->weight); } if (vertexWeights[index].jointCount > maxJoints) maxJoints = vertexWeights[index].jointCount; vertexWeights[index].Normalize(); } printf("- max joints: %d\n", maxJoints); mesh = new ColladaMesh( animationController->GetBaseGeometry()->GetMesh(), &(vertexWeights.front())); } }
void ColladaMeshFactory::GenerateMeshDatafromPolygonsFull( RevModel** aModel, RevIndexData& aIndexData, RevVertexDataNormal& aVertexData, RevInputData& aInputData, FCDGeometryInstance* aInstance, FCDGeometryMesh* aMesh, FCDocument* aColladaDocument, bool aHasBoneWeightsFlag, FCDController* aController, FCDControllerInstance* aControllerInstance) { int polygonalMeshes= static_cast<int>(aMesh->GetPolygonsCount()); // assert(polygonalMeshes==1); // how to handle multiple meshes ? handle later // To do add support for multiple meshes ? FCDSkinController* skinControl=NULL; if(aHasBoneWeightsFlag==true) { skinControl=aController->GetSkinController(); skinControl->ReduceInfluences(4); } int myVertexCount=0; int duplicatesCount=0; int currentIndex=0; std::map<RevVertexIndexmapKey,int> vertexList; std::map<RevVertexIndexmapKey,int>::iterator vertexIterator; std::vector<RevVertexIndexmapKey> vertexes; aIndexData.myNrOfIndexes =0; aIndexData.myFormat =DXGI_FORMAT_R32_UINT; for(int polygonMeshIndex=0;polygonMeshIndex<static_cast<int>(polygonalMeshes);polygonMeshIndex++) { FCDGeometryPolygons* somePolygons=aMesh->GetPolygons(polygonMeshIndex); FCDGeometryPolygonsInput* positionInput=somePolygons->FindInput(FUDaeGeometryInput::POSITION); aIndexData.myNrOfIndexes+=positionInput->GetIndexCount(); } aIndexData.mySize=aIndexData.myNrOfIndexes*sizeof(unsigned int); aIndexData.myIndexData = new char [aIndexData.mySize] (); UINT* indexArray=reinterpret_cast<unsigned int*>(aIndexData.myIndexData); FCDGeometrySource* positionSource=aMesh->FindSourceByType(FUDaeGeometryInput::POSITION); FCDGeometrySource* normalSource=aMesh->FindSourceByType(FUDaeGeometryInput::NORMAL); FCDGeometrySource* colorSource=aMesh->FindSourceByType(FUDaeGeometryInput::COLOR); FCDGeometrySource* textureCordinatesSource=aMesh->FindSourceByType(FUDaeGeometryInput::TEXCOORD); FCDGeometrySource* geoTangentSource=aMesh->FindSourceByType(FUDaeGeometryInput::GEOTANGENT); FCDGeometrySource* texTangentSource=aMesh->FindSourceByType(FUDaeGeometryInput::TEXTANGENT); FCDGeometrySource* geoBiNormalSource=aMesh->FindSourceByType(FUDaeGeometryInput::GEOBINORMAL); FCDGeometrySource* texBiNormalSource=aMesh->FindSourceByType(FUDaeGeometryInput::TEXBINORMAL); RevModelRenderEssentials renderEssentials( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); SelectEffectOnModel(aModel, aInputData); RevTextures tex; for(int polygonMeshIndex=0;polygonMeshIndex<polygonalMeshes;polygonMeshIndex++) { (*aModel)->SetIsNullObjectFlag( false ); FCDGeometryPolygons* somePolygons=aMesh->GetPolygons(polygonMeshIndex); FCDGeometryPolygonsInput* positionInput=somePolygons->FindInput(FUDaeGeometryInput::POSITION); FCDGeometryPolygonsInput* normalInput=somePolygons->FindInput(FUDaeGeometryInput::NORMAL); FCDGeometryPolygonsInput* colorInput=somePolygons->FindInput(FUDaeGeometryInput::COLOR); FCDGeometryPolygonsInput* texCoordInput=somePolygons->FindInput(FUDaeGeometryInput::TEXCOORD); FCDGeometryPolygonsInput* geoTangentInput=somePolygons->FindInput(FUDaeGeometryInput::GEOTANGENT); FCDGeometryPolygonsInput* texTangentInput=somePolygons->FindInput(FUDaeGeometryInput::TEXTANGENT); FCDGeometryPolygonsInput* geoBiNormalInput=somePolygons->FindInput(FUDaeGeometryInput::GEOBINORMAL); FCDGeometryPolygonsInput* texBiNormalInput=somePolygons->FindInput(FUDaeGeometryInput::TEXBINORMAL); somePolygons->GetFaceVertexCount(); renderEssentials.myVertexStart = 0; renderEssentials.myIndexStart = currentIndex; renderEssentials.myIndexCount = positionInput->GetIndexCount(); for(int i=0;i<static_cast<int>(positionInput->GetIndexCount());i++) { RevVertexIndexmapKey key; if(positionInput!=NULL) { key.myKeys[0]=positionInput->GetIndices()[i]; } if(normalInput!=NULL) { key.myKeys[1]=normalInput->GetIndices()[i]; } if(colorInput!=NULL) { key.myKeys[2]=colorInput->GetIndices()[i]; } if(texCoordInput!=NULL) { key.myKeys[3]=texCoordInput->GetIndices()[i]; } if(geoTangentInput!=NULL) { key.myKeys[4]=geoTangentInput->GetIndices()[i]; } if(texTangentInput!=NULL) { key.myKeys[5]=texTangentInput->GetIndices()[i]; } if(geoBiNormalInput!=NULL) { key.myKeys[6]=geoBiNormalInput->GetIndices()[i]; } if(texBiNormalInput!=NULL) { key.myKeys[7]=texBiNormalInput->GetIndices()[i]; } vertexIterator=vertexList.find(key); if(vertexIterator==vertexList.end()) { indexArray[currentIndex]=myVertexCount; std::pair<RevVertexIndexmapKey,int> tempPair(key,myVertexCount); vertexList.insert(tempPair); vertexes.push_back(key); myVertexCount++; // create indexes } else { indexArray[currentIndex]=(*vertexIterator).second; duplicatesCount++; // Read Created Vertex } currentIndex++; } for (unsigned int k=0; k<aInstance->GetMaterialInstanceCount(); k++) { FCDMaterialInstance* materialInstance; materialInstance=aInstance->GetMaterialInstance(k); if(aMesh->GetPolygons(polygonMeshIndex)->GetMaterialSemantic()==materialInstance->GetSemantic()) { LoadMaterialNew(polygonMeshIndex,materialInstance->GetMaterial(),aColladaDocument, tex); } } } (*aModel)->SetModelTextures( tex ); aVertexData.myNrOfVertexes=myVertexCount; aVertexData.mySize=aVertexData.myStride*aVertexData.myNrOfVertexes; aVertexData.myVertexData =new char [aVertexData.mySize] (); for(int i=0;i<aIndexData.myNrOfIndexes;i+=3) { unsigned int temp; temp=indexArray[i+0]; indexArray[i+0]=indexArray[i+2]; indexArray[i+2]=temp; } myVertexCount=0; for(int i=0;i<static_cast<int>(vertexes.size());i++) { RevVertexIndexmapKey key=vertexes[i]; int offset=0; std::pair<RevVertexIndexmapKey,int> tempPair(key,myVertexCount); vertexList.insert(tempPair); // Create Vertex if(key.myKeys[0]!=-1) { CU::Vector3f pos; memcpy(&pos, &positionSource->GetData()[key.myKeys[0]*positionSource->GetStride()],12); // pos.y=-pos.y; // pos.z=-pos.z; memcpy(&aVertexData.myVertexData[myVertexCount*aVertexData.myStride+offset], &pos,12); offset+=12; } if(aHasBoneWeightsFlag==true) { assert(key.myKeys[0]!=-1); FCDSkinControllerVertex* vertexsInfluence; vertexsInfluence=skinControl->GetVertexInfluence(key.myKeys[0]); int boneData=0; int weightData=0; assert(vertexsInfluence->GetPairCount()<=4); for(int j=0;j<static_cast<int>(vertexsInfluence->GetPairCount());j++) { assert(j<4); FCDJointWeightPair* pair=vertexsInfluence->GetPair(j); assert(pair->jointIndex<256); boneData |= pair->jointIndex << (j*8); int weight=static_cast<int>((pair->weight*255.0f+0.5)); assert(weight>=0); assert(weight<=255); weightData |= weight << (j*8); } memcpy(&aVertexData.myVertexData[myVertexCount*aVertexData.myStride+offset],&weightData,4); offset+=4; memcpy(&aVertexData.myVertexData[myVertexCount*aVertexData.myStride+offset],&boneData,4); offset+=4; } if(key.myKeys[1]!=-1) { CU::Vector3f normal; memcpy(&normal, &normalSource->GetData()[key.myKeys[1]*normalSource->GetStride()],12); // normal.y=-normal.y; memcpy(&aVertexData.myVertexData[myVertexCount*aVertexData.myStride+offset], &normal,12); offset+=12; } if(key.myKeys[2]!=-1) { memcpy(&aVertexData.myVertexData[myVertexCount*aVertexData.myStride+offset], &colorSource->GetData()[key.myKeys[2]*colorSource->GetStride()],16); offset+=16; } if(key.myKeys[3]!=-1) { CU::Vector2f UV; memcpy(&UV, &textureCordinatesSource->GetData()[key.myKeys[3]*textureCordinatesSource->GetStride()],8); UV.v=1.0f-UV.v; memcpy(&aVertexData.myVertexData[myVertexCount*aVertexData.myStride+offset], &UV,8); offset+=8; } if(key.myKeys[4]!=-1) { CU::Vector3f tangent; memcpy(&tangent, &geoTangentSource->GetData()[key.myKeys[4]*geoTangentSource->GetStride()],12); // tangent.y=-tangent.y; memcpy(&aVertexData.myVertexData[myVertexCount*aVertexData.myStride+offset], &tangent,12); offset+=12; } if(key.myKeys[5]!=-1) { CU::Vector3f tangent; memcpy(&tangent, &texTangentSource->GetData()[key.myKeys[5]*texTangentSource->GetStride()],12); // tangent.y=-tangent.y; memcpy(&aVertexData.myVertexData[myVertexCount*aVertexData.myStride+offset], &tangent,12); offset+=12; } if(key.myKeys[6]!=-1) { memcpy(&aVertexData.myVertexData[myVertexCount*aVertexData.myStride+offset], &geoBiNormalSource->GetData()[key.myKeys[6]*geoBiNormalSource->GetStride()],12); offset+=12; } if(key.myKeys[7]!=-1) { memcpy(&aVertexData.myVertexData[myVertexCount*aVertexData.myStride+offset], &texBiNormalSource->GetData()[key.myKeys[7]*texBiNormalSource->GetStride()],12); offset+=12; } myVertexCount++; } if( (*aModel)->Init( aVertexData, aIndexData, aInputData, renderEssentials ) ==false) { assert(0 && "Something went wrong in trying to init the current model"); } }
void ReindexGeometry(FCDGeometryPolygons* polys, FCDSkinController* skin) { // Given geometry with: // positions, normals, texcoords, bone blends // each with their own data array and index array, change it to // have a single optimised index array shared by all vertexes. FCDGeometryPolygonsInput* inputPosition = polys->FindInput(FUDaeGeometryInput::POSITION); FCDGeometryPolygonsInput* inputNormal = polys->FindInput(FUDaeGeometryInput::NORMAL); FCDGeometryPolygonsInput* inputTexcoord = polys->FindInput(FUDaeGeometryInput::TEXCOORD); size_t numVertices = polys->GetFaceVertexCount(); assert(inputPosition->GetIndexCount() == numVertices); assert(inputNormal ->GetIndexCount() == numVertices); assert(inputTexcoord->GetIndexCount() == numVertices); const uint32* indicesPosition = inputPosition->GetIndices(); const uint32* indicesNormal = inputNormal->GetIndices(); const uint32* indicesTexcoord = inputTexcoord->GetIndices(); assert(indicesPosition); assert(indicesNormal); assert(indicesTexcoord); // TODO - should be optional, because textureless meshes aren't unreasonable FCDGeometrySourceList texcoordSources; polys->GetParent()->FindSourcesByType(FUDaeGeometryInput::TEXCOORD, texcoordSources); FCDGeometrySource* sourcePosition = inputPosition->GetSource(); FCDGeometrySource* sourceNormal = inputNormal ->GetSource(); const float* dataPosition = sourcePosition->GetData(); const float* dataNormal = sourceNormal ->GetData(); if (skin) { #ifndef NDEBUG size_t numVertexPositions = sourcePosition->GetDataCount() / sourcePosition->GetStride(); assert(skin->GetInfluenceCount() == numVertexPositions); #endif } uint32 stridePosition = sourcePosition->GetStride(); uint32 strideNormal = sourceNormal ->GetStride(); std::vector<uint32> indicesCombined; std::vector<VertexData> vertexes; InserterWithoutDuplicates<VertexData> inserter(vertexes); for (size_t i = 0; i < numVertices; ++i) { std::vector<FCDJointWeightPair> weights; if (skin) { FCDSkinControllerVertex* influences = skin->GetVertexInfluence(indicesPosition[i]); assert(influences != NULL); for (size_t j = 0; j < influences->GetPairCount(); ++j) { FCDJointWeightPair* pair = influences->GetPair(j); assert(pair != NULL); weights.push_back(*pair); } CanonicaliseWeights(weights); } std::vector<uv_pair_type> uvs; for (size_t set = 0; set < texcoordSources.size(); ++set) { const float* dataTexcoord = texcoordSources[set]->GetData(); uint32 strideTexcoord = texcoordSources[set]->GetStride(); uv_pair_type p; p.first = dataTexcoord[indicesTexcoord[i]*strideTexcoord]; p.second = dataTexcoord[indicesTexcoord[i]*strideTexcoord + 1]; uvs.push_back(p); } VertexData vtx ( &dataPosition[indicesPosition[i]*stridePosition], &dataNormal [indicesNormal [i]*strideNormal], uvs, weights ); size_t idx = inserter.add(vtx); indicesCombined.push_back((uint32)idx); } // TODO: rearrange indicesCombined (and rearrange vertexes to match) to use // the vertex cache efficiently // (<http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html> etc) FloatList newDataPosition; FloatList newDataNormal; FloatList newDataTexcoord; std::vector<std::vector<FCDJointWeightPair> > newWeightedMatches; for (size_t i = 0; i < vertexes.size(); ++i) { newDataPosition.push_back(vertexes[i].x); newDataPosition.push_back(vertexes[i].y); newDataPosition.push_back(vertexes[i].z); newDataNormal .push_back(vertexes[i].nx); newDataNormal .push_back(vertexes[i].ny); newDataNormal .push_back(vertexes[i].nz); newWeightedMatches.push_back(vertexes[i].weights); } // (Slightly wasteful to duplicate this array so many times, but FCollada // doesn't seem to support multiple inputs with the same source data) inputPosition->SetIndices(&indicesCombined.front(), indicesCombined.size()); inputNormal ->SetIndices(&indicesCombined.front(), indicesCombined.size()); inputTexcoord->SetIndices(&indicesCombined.front(), indicesCombined.size()); for (size_t set = 0; set < texcoordSources.size(); ++set) { newDataTexcoord.clear(); for (size_t i = 0; i < vertexes.size(); ++i) { newDataTexcoord.push_back(vertexes[i].uvs[set].first); newDataTexcoord.push_back(vertexes[i].uvs[set].second); } texcoordSources[set]->SetData(newDataTexcoord, 2); } sourcePosition->SetData(newDataPosition, 3); sourceNormal ->SetData(newDataNormal, 3); if (skin) { skin->SetInfluenceCount(newWeightedMatches.size()); for (size_t i = 0; i < newWeightedMatches.size(); ++i) { skin->GetVertexInfluence(i)->SetPairCount(0); for (size_t j = 0; j < newWeightedMatches[i].size(); ++j) skin->GetVertexInfluence(i)->AddPair(newWeightedMatches[i][j].jointIndex, newWeightedMatches[i][j].weight); } } }