Esempio n. 1
0
    SkinData *XMLDataParser::parseSkinData(const dragonBones::XMLElement *skinXML, SkeletonData *data)
    {
        SkinData *skinData = new SkinData();
        skinData->name = skinXML->Attribute(ConstValues::A_NAME.c_str());

        for(const dragonBones::XMLElement* slotXML = skinXML->FirstChildElement(ConstValues::SLOT.c_str()) ; slotXML ; slotXML = slotXML->NextSiblingElement(ConstValues::SLOT.c_str()))
        {
            skinData->addSlotData(parseSlotData(slotXML, data));
        }

        return skinData;
    }
SkinData * ObjectDataParser::parseSkinData(Json::Value & skinObject, SkeletonData * data) {
	SkinData* skinData = new SkinData();
	int nameVal = skinObject[ConstValues::A_NAME].asInt();
	char temp[64];
	sprintf(temp, "%d", nameVal);
	skinData->name = temp;

	Json::Value & slots = skinObject[ConstValues::SLOT];

	for (uint i = 0; i < slots.size(); i++) {
		Json::Value & slotObject = slots[i];
		skinData->addSlotData(parseSlotData(slotObject, data));
	}

	return skinData;
}
Esempio n. 3
0
static void initBones(const aiScene * scene, const aiMesh * nodeMesh, Mesh * mesh, SubMesh * subMesh)
{
	Armature * armature = mesh->getArmature();
	
	BoneData bdata;
	map<unsigned int, AssimpSkinData> skinDatas;
	
	
	// bones
	for(unsigned int i=0; i<nodeMesh->mNumBones; i++)
	{
		aiBone * nodeBone = nodeMesh->mBones[i];
		
		unsigned int boneId;
		if(! armature->getBoneId(nodeBone->mName.data, &boneId))
			continue;
		
		OBone * bone = armature->getBone(boneId);
		
		aiMatrix4x4 offsetMat = nodeBone->mOffsetMatrix;
		aiTransposeMatrix4(&offsetMat);
		Matrix4x4 matrix = (*bone->getMatrix()) * Matrix4x4((float*)&offsetMat);
		
		
		// pose skinning
		Vector3 * vertices = subMesh->getVertices();
		Vector3 * normals = subMesh->getNormals();
		Vector3 * tangents = subMesh->getTangents();
		
		unsigned int w;
		for(w=0; w<nodeBone->mNumWeights; w++)
		{
			unsigned int vid = nodeBone->mWeights[w].mVertexId;
			float weight = nodeBone->mWeights[w].mWeight; 
			
			bdata.id = boneId;
			bdata.weight = weight;
			skinDatas[vid].bones.push_back(bdata);

			if(skinDatas[vid].bones.size() == 1)
			{
				if(vertices) vertices[vid] = Vector3(0, 0, 0);
				if(normals) normals[vid] = Vector3(0, 0, 0);
				if(tangents) tangents[vid] = Vector3(0, 0, 0);
			}
			
			if(vertices)
				vertices[vid] += matrix * Vector3(nodeMesh->mVertices[vid].x, nodeMesh->mVertices[vid].y, nodeMesh->mVertices[vid].z) * weight;
			
			if(normals)
				normals[vid] += matrix.getRotatedVector3(Vector3(nodeMesh->mNormals[vid].x, nodeMesh->mNormals[vid].y, nodeMesh->mNormals[vid].z)) * weight;
			
			if(tangents)
				tangents[vid] += matrix.getRotatedVector3(Vector3(nodeMesh->mTangents[vid].x, nodeMesh->mTangents[vid].y, nodeMesh->mTangents[vid].z)) * weight;
		}
	}
	
	
	// alloc skin
	unsigned int skinSize = skinDatas.size();
	if(skinSize > 0)
	{
		SkinData * skin = subMesh->createSkinData();
		SkinPoint * skinPoints = skin->allocPoints(skinSize);
		
		map<unsigned int, AssimpSkinData>::iterator
			mit (skinDatas.begin()),
			mend(skinDatas.end());
		
		unsigned int p = 0;
		for(; mit!=mend; ++mit)
		{
			unsigned int vertexId = mit->first;
			AssimpSkinData * sdata = &mit->second;
			
			unsigned int b, bSize = sdata->bones.size();
			
			if(skinPoints[p].allocateBonesLinks(bSize))
			{
				skinPoints[p].setVertexId(vertexId);
				
				unsigned short * ids = skinPoints[p].getBonesIds();
				float * weights = skinPoints[p].getBonesWeights();
				
				for(b=0; b<bSize; b++)
				{
					ids[b] = sdata->bones[b].id;
					weights[b] = sdata->bones[b].weight;
				}
			}
			
			p++;
		}
	}
}
Esempio n. 4
0
    /**
    * Build and returns a new Armature instance.
    * @example 
    * <listing>
    * var armature:Armature = factory.buildArmature('dragon');
    * </listing>
    * @param    armatureName The name of this Armature instance.
    * @param    The name of this animation
    * @param    The name of this SkeletonData.
    * @param    The name of this textureAtlas.
    * @param    The name of this skin.
    * @return A Armature instance.
    */
    Armature* BaseFactory::buildArmature(const String &armatureName,
                                         const String &animationName,
                                         const String &skeletonName,
                                         const String &textureAtlasName,
                                         const String &skinName)
    {
        ArmatureData* armatureData = 0;
        SkeletonData *data = 0;
        if(!skeletonName.empty())
        {
            std::map<String , SkeletonData*>::iterator iter = _dataDic.find(skeletonName);
            if(iter != _dataDic.end())
            {
                data = iter->second;
                armatureData = data->getArmatureData(armatureName);
            }
        }
        //else
        //{
        //    for(skeletonName in _dataDic)
        //    {
        //        data = _dataDic[skeletonName];
        //        armatureData = data->getArmatureData(armatureName);
        //        if(armatureData)
        //        {
        //            break;
        //        }
        //    }
        //}

        if(!armatureData)
        {
            return nullptr;
        }

        _currentDataName = skeletonName;
        _currentTextureAtlasName = textureAtlasName.empty() ? skeletonName : textureAtlasName;

        Armature* armature = generateArmature();
        armature->name = armatureName;
        Bone* bone;
        for(size_t i = 0 ; i < armatureData->boneDataList.size() ; i ++)
        {
            BoneData* boneData = armatureData->boneDataList[i];
            bone = new Bone();
            bone->name = boneData->name;
            bone->fixedRotation = boneData->fixedRotation;
            bone->scaleMode = boneData->scaleMode;
            bone->origin = boneData->transform;
            if(armatureData->getBoneData(boneData->parent))
            {
                armature->addBone(bone, boneData->parent);
            }
            else
            {
                armature->addBone(bone);
            }
        }

        ArmatureData* animationArmatureData = 0;
        SkinData *skinDataCopy = 0;
        if(!animationName.empty() && animationName != armatureName)
        {
            //ArmatureData* animationArmatureData = data->getArmatureData(animationName);
            // Get the default animation
            //if(!animationArmatureData)
            //{
            //    for (skeletonName in _dataDic)
            //    {
            //        data = _dataDic[skeletonName];
            //        animationArmatureData = data->getArmatureData(animationName);
            //        if(animationArmatureData)
            //        {
            //            break;
            //        }
            //    }
            //}

            ArmatureData* armatureDataCopy = data->getArmatureData(animationName);
            if(armatureDataCopy)
            {
                skinDataCopy = armatureDataCopy->getSkinData("");
            }
        }

        if(animationArmatureData)
        {
            armature->getAnimation()->setAnimationDataList(animationArmatureData->animationDataList);
        }
        else
        {
            armature->getAnimation()->setAnimationDataList(armatureData->animationDataList);
        }

        SkinData* skinData = armatureData->getSkinData(skinName);
        if(!skinData)
        {
            return nullptr;
            //throw new ArgumentError();
        }

        Slot* slot;
        DisplayData* displayData;
        Armature* childArmature;
        size_t i;
        //var helpArray:Array = [];
        for(size_t j = 0 ; j < skinData->slotDataList.size() ; j ++)
        {
            SlotData* slotData = skinData->slotDataList[j];
            bone = armature->getBone(slotData->parent);
            if(!bone)
            {
                continue;
            }
            slot = generateSlot();
            slot->name = slotData->name;
            slot->setBlendMode(slotData->blendMode);
            slot->_originZOrder = slotData->zOrder;
            slot->_dislayDataList = slotData->displayDataList;

            std::vector<Object*> helpArray;

            i = slotData->displayDataList.size();
            helpArray.resize(i);
            while(i --)
            {
                displayData = slotData->displayDataList[i];

                if(displayData->type == DisplayData::ARMATURE)
                {
                    DisplayData* displayDataCopy = 0;
                    if(skinDataCopy)
                    {
                        SlotData* slotDataCopy = skinDataCopy->getSlotData(slotData->name);
                        if(slotDataCopy)
                        {
                            displayDataCopy = slotDataCopy->displayDataList[i];
                        }
                    }
                    else
                    {
                        displayDataCopy = 0;
                    }

                    childArmature = buildArmature(displayData->name, displayDataCopy?displayDataCopy->name:"", _currentDataName, _currentTextureAtlasName);
                    if(childArmature)
                    {
                        helpArray[i] = childArmature;
                    }
				   //fix by Wayne Dimart:
                   // break; we don't use break here, or will crach the program due to incomplete helpArray.
					continue;
                }
                else
                {
                    helpArray[i] = generateDisplay(getTextureAtlas(_currentTextureAtlasName), displayData->name, displayData->pivot.x, displayData->pivot.y);
                }
            }
            slot->setDisplayList(helpArray);
            slot->changeDisplay(0);
            bone->addChild(slot);
        }

        //
        i = armature->_boneList.size();
        while(i --)
        {
            armature->_boneList[i]->update();
        }

        i = armature->_slotList.size();
        while(i --)
        {
            slot = armature->_slotList[i];
            slot->update();
        }
        armature->updateSlotsZOrder();

        return armature;
    }
Esempio n. 5
0
VOID ParseMesh( KFbxMesh* pFbxMesh, ExportFrame* pParentFrame, BOOL bSubDProcess, const CHAR* strSuffix )
{
    if( !g_pScene->Settings().bExportMeshes )
        return;

    if( pFbxMesh == NULL )
        return;

	const CHAR* strName = pFbxMesh->GetName();
	if( strName == NULL || strName[0] == '\0' )
		strName = pParentFrame->GetName().SafeString();

    if( strSuffix == NULL )
    {
        strSuffix = "";
    }
	CHAR strDecoratedName[512];
	sprintf_s( strDecoratedName, "%s_%s%s", g_pScene->Settings().strMeshNameDecoration, strName, strSuffix );
	ExportMesh* pMesh = new ExportMesh( strDecoratedName );
	pMesh->SetDCCObject( pFbxMesh );

    BOOL bSmoothMesh = FALSE;

    KFbxMesh::MeshSmoothness Smoothness = pFbxMesh->GetMeshSmoothness();
    if( Smoothness != KFbxMesh::HULL && g_pScene->Settings().bConvertMeshesToSubD )
    {
        bSubDProcess = TRUE;
        bSmoothMesh = TRUE;
    }

    ExportLog::LogMsg( 2, "Parsing %s mesh \"%s\", renamed to \"%s\"", bSmoothMesh ? "smooth" : "poly", strName, strDecoratedName );

    SkinData skindata;
    BOOL bSkinnedMesh = ParseMeshSkinning( pFbxMesh, &skindata );
    if( bSkinnedMesh )
    {
        DWORD dwBoneCount = skindata.GetBoneCount();
        for( DWORD i = 0; i < dwBoneCount; ++i )
        {
            pMesh->AddInfluence( skindata.InfluenceNodes[i]->GetName() );
        }
    }

    pMesh->SetVertexColorCount( 0 );

    KFbxLayerElementArrayTemplate<KFbxVector4> *pNormals = NULL;
    pFbxMesh->GetNormals( &pNormals );
    if( pNormals == NULL )
    {
        pFbxMesh->InitNormals();
        pFbxMesh->ComputeVertexNormals();
    }
    // Vertex normals and tangent spaces
    if( !g_pScene->Settings().bExportNormals )
    {
        pMesh->SetVertexNormalCount( 0 );
    }
    else if( g_pScene->Settings().bComputeVertexTangentSpace )
    {
        if( g_pScene->Settings().bExportBinormal )
            pMesh->SetVertexNormalCount( 3 );
        else
            pMesh->SetVertexNormalCount( 2 );
    }
    else
    {
        pMesh->SetVertexNormalCount( 1 );
    }

    DWORD dwLayerCount = pFbxMesh->GetLayerCount();
    ExportLog::LogMsg( 4, "%d layers in FBX mesh", dwLayerCount );

    DWORD dwVertexColorCount = 0;
    KFbxLayerElementVertexColor* pVertexColorSet = NULL;
    DWORD dwUVSetCount = 0;
    std::vector<KFbxLayerElementUV*> VertexUVSets;
    KFbxLayerElementMaterial* pMaterialSet = NULL;
    std::vector<ExportMaterial*> MaterialList;
    for( DWORD dwLayerIndex = 0; dwLayerIndex < dwLayerCount; ++dwLayerIndex )
    {
        if( pFbxMesh->GetLayer(dwLayerIndex)->GetVertexColors() != NULL )
        {
            if( dwVertexColorCount == 0 )
            {
                dwVertexColorCount++;
                pVertexColorSet = pFbxMesh->GetLayer(dwLayerIndex)->GetVertexColors();
            }
            else
            {
                ExportLog::LogWarning( "Only one vertex color set is allowed; ignoring additional vertex color sets." );
            }
        }
        if( pFbxMesh->GetLayer(dwLayerIndex)->GetUVs() != NULL )
        {
            dwUVSetCount++;
            VertexUVSets.push_back( pFbxMesh->GetLayer(dwLayerIndex)->GetUVs() );
        }
        if( pFbxMesh->GetLayer(dwLayerIndex)->GetMaterials() != NULL )
        {
            if( pMaterialSet != NULL )
            {
                ExportLog::LogWarning( "Multiple material layers detected on mesh %s.  Some will be ignored.", pMesh->GetName().SafeString() );
            }
            pMaterialSet = pFbxMesh->GetLayer(dwLayerIndex)->GetMaterials();
            DWORD dwMaterialCount = pMaterialSet->GetDirectArray().GetCount();
            for( DWORD i = 0; i < dwMaterialCount; ++i )
            {
                ExportMaterial* pMaterial = ParseMaterialInLayer( pFbxMesh, pFbxMesh->GetLayer( dwLayerIndex ), i );
                MaterialList.push_back( pMaterial );
            }
        }
    }

    ExportLog::LogMsg( 4, "Found %d UV sets", dwUVSetCount );
    dwUVSetCount = min( dwUVSetCount, (DWORD)g_pScene->Settings().iMaxUVSetCount );
    ExportLog::LogMsg( 4, "Using %d UV sets", dwUVSetCount );

    pMesh->SetVertexColorCount( dwVertexColorCount );
    pMesh->SetVertexUVCount( dwUVSetCount );
    // TODO: Does FBX only support 2D texture coordinates?
    pMesh->SetVertexUVDimension( 2 );

    DWORD dwMeshOptimizationFlags = 0;
    if( g_pScene->Settings().bCompressVertexData )
        dwMeshOptimizationFlags |= ExportMesh::COMPRESS_VERTEX_DATA;

    DWORD dwPolyCount = pFbxMesh->GetPolygonCount();
    // Assume that polys are usually quads.
    g_MeshTriangleAllocator.SetSizeHint( dwPolyCount * 2 );

    DWORD dwVertexCount = pFbxMesh->GetControlPointsCount();
    KFbxVector4* pVertexPositions = pFbxMesh->GetControlPoints();

    if( bSkinnedMesh )
    {
        assert( skindata.dwVertexCount == dwVertexCount );
    }
    
    ExportLog::LogMsg( 4, "%d vertices, %d polygons", dwVertexCount, dwPolyCount );

    DWORD dwNonConformingSubDPolys = 0;

    // Loop over polygons.
    for( DWORD dwPolyIndex = 0; dwPolyIndex < dwPolyCount; ++dwPolyIndex )
    {
        // Triangulate each polygon into one or more triangles.
        DWORD dwPolySize = pFbxMesh->GetPolygonSize( dwPolyIndex );
        assert( dwPolySize >= 3 );
        DWORD dwTriangleCount = dwPolySize - 2;
        assert( dwTriangleCount > 0 );

        if( dwPolySize > 4 )
        {
            ++dwNonConformingSubDPolys;
        }

        DWORD dwMaterialIndex = 0;
        if( pMaterialSet != NULL )
        {
            switch( pMaterialSet->GetMappingMode() )
            {
            case KFbxLayerElement::eBY_POLYGON:
                switch( pMaterialSet->GetReferenceMode() )
                {
                case KFbxLayerElement::eDIRECT:
                    dwMaterialIndex = dwPolyIndex;
                    break;
                case KFbxLayerElement::eINDEX:
                case KFbxLayerElement::eINDEX_TO_DIRECT:
                    dwMaterialIndex = pMaterialSet->GetIndexArray().GetAt( dwPolyIndex );
                    break;
                }
            case KFbxLayerElement::eALL_SAME:
                break;
            }
        }

        const BOOL bInvertTexVCoord = g_pScene->Settings().bInvertTexVCoord;

        DWORD dwCornerIndices[3];
        // Loop over triangles in the polygon.
        for( DWORD dwTriangleIndex = 0; dwTriangleIndex < dwTriangleCount; ++dwTriangleIndex )
        {
            dwCornerIndices[0] = pFbxMesh->GetPolygonVertex( dwPolyIndex, 0 );
            dwCornerIndices[1] = pFbxMesh->GetPolygonVertex( dwPolyIndex, dwTriangleIndex + 1 );
            dwCornerIndices[2] = pFbxMesh->GetPolygonVertex( dwPolyIndex, dwTriangleIndex + 2 );

            //ExportLog::LogMsg( 4, "Poly %d Triangle %d: %d %d %d", dwPolyIndex, dwTriangleIndex, dwCornerIndices[0], dwCornerIndices[1], dwCornerIndices[2] );

            KFbxVector4 vNormals[3];
            ZeroMemory( vNormals, 3 * sizeof(KFbxVector4) );
            INT iPolyIndex = (INT)dwPolyIndex;
            INT iVertIndex[3] = { 0, (INT)dwTriangleIndex + 1, (INT)dwTriangleIndex + 2 };
            //INT iVertIndexUV[3] = { (INT)dwTriangleIndex, (INT)dwTriangleIndex + 1, (INT)dwTriangleIndex + 2 };
            pFbxMesh->GetPolygonVertexNormal( iPolyIndex, iVertIndex[0], vNormals[0] );
            pFbxMesh->GetPolygonVertexNormal( iPolyIndex, iVertIndex[1], vNormals[1] );
            pFbxMesh->GetPolygonVertexNormal( iPolyIndex, iVertIndex[2], vNormals[2] );

            // Build the raw triangle.
            ExportMeshTriangle* pTriangle = g_MeshTriangleAllocator.GetNewTriangle();

            // Store polygon index
            pTriangle->PolygonIndex = (INT)dwPolyIndex;

            // Store material subset index
            pTriangle->SubsetIndex = dwMaterialIndex;

            for( DWORD dwCornerIndex = 0; dwCornerIndex < 3; ++dwCornerIndex )
            {
                const DWORD& dwDCCIndex = dwCornerIndices[dwCornerIndex];
                // Store DCC vertex index (this helps the mesh reduction/VB generation code)
                pTriangle->Vertex[dwCornerIndex].DCCVertexIndex = dwDCCIndex;

                // Store vertex position
                pTriangle->Vertex[dwCornerIndex].Position.x = (FLOAT)pVertexPositions[dwDCCIndex].mData[0];
                pTriangle->Vertex[dwCornerIndex].Position.y = (FLOAT)pVertexPositions[dwDCCIndex].mData[1];
                pTriangle->Vertex[dwCornerIndex].Position.z = (FLOAT)pVertexPositions[dwDCCIndex].mData[2];

                // Store vertex normal
                pTriangle->Vertex[dwCornerIndex].Normal.x = (FLOAT)vNormals[dwCornerIndex].mData[0];
                pTriangle->Vertex[dwCornerIndex].Normal.y = (FLOAT)vNormals[dwCornerIndex].mData[1];
                pTriangle->Vertex[dwCornerIndex].Normal.z = (FLOAT)vNormals[dwCornerIndex].mData[2];

                // Store UV sets
                for( DWORD dwUVIndex = 0; dwUVIndex < dwUVSetCount; ++dwUVIndex )
                {
                    // Crack apart the FBX dereferencing system for UV coordinates
                    KFbxLayerElementUV* pUVSet = VertexUVSets[dwUVIndex];
                    KFbxVector2 Value( 0, 0 );
                    INT iUVIndex = 0;
                    switch( pUVSet->GetMappingMode() )
                    {
                    case KFbxLayerElement::eBY_CONTROL_POINT:
                        iUVIndex = pFbxMesh->GetPolygonVertex( iPolyIndex, iVertIndex[dwCornerIndex] );
                        break;
                    case KFbxLayerElement::eBY_POLYGON_VERTEX:
                        iUVIndex = pFbxMesh->GetTextureUVIndex( iPolyIndex, iVertIndex[dwCornerIndex] );
                        break;
                    }
                    Value = pUVSet->GetDirectArray().GetAt( iUVIndex );

                    // Store a single UV set
                    pTriangle->Vertex[dwCornerIndex].TexCoords[dwUVIndex].x = (FLOAT)Value.mData[0];
                    if( bInvertTexVCoord )
                    {
                        pTriangle->Vertex[dwCornerIndex].TexCoords[dwUVIndex].y = 1.0f - (FLOAT)Value.mData[1];
                    }
                    else
                    {
                        pTriangle->Vertex[dwCornerIndex].TexCoords[dwUVIndex].y = (FLOAT)Value.mData[1];
                    }
                }

                // Store vertex color set
                if( dwVertexColorCount > 0 && pVertexColorSet != NULL )
                {
                    // Crack apart the FBX dereferencing system for Color coordinates
                    KFbxColor Value( 0, 0, 0, 1 );
                    switch( pVertexColorSet->GetMappingMode() )
                    {
                    case KFbxLayerElement::eBY_CONTROL_POINT:
                        switch( pVertexColorSet->GetReferenceMode() )
                        {
                        case KFbxLayerElement::eDIRECT:
                            Value = pVertexColorSet->GetDirectArray().GetAt( dwDCCIndex );
                            break;
                        case KFbxLayerElement::eINDEX_TO_DIRECT:
                            Value = pVertexColorSet->GetDirectArray().GetAt( pVertexColorSet->GetIndexArray().GetAt( dwDCCIndex ) );
                            break;
                        }
                        break;
                    case KFbxLayerElement::eBY_POLYGON_VERTEX:
                        switch( pVertexColorSet->GetReferenceMode() )
                        {
                        case KFbxLayerElement::eDIRECT:
                            Value = pVertexColorSet->GetDirectArray().GetAt( iVertIndex[dwCornerIndex] );
                            break;
                        case KFbxLayerElement::eINDEX_TO_DIRECT:
                            Value = pVertexColorSet->GetDirectArray().GetAt( pVertexColorSet->GetIndexArray().GetAt( iVertIndex[dwCornerIndex] ) );
                            break;
                        }
                        break;
                    }

                    // Store a single vertex color set
                    pTriangle->Vertex[dwCornerIndex].Color.x = (FLOAT)Value.mRed;
                    pTriangle->Vertex[dwCornerIndex].Color.y = (FLOAT)Value.mGreen;
                    pTriangle->Vertex[dwCornerIndex].Color.z = (FLOAT)Value.mBlue;
                    pTriangle->Vertex[dwCornerIndex].Color.w = (FLOAT)Value.mAlpha;
                }

                // Store skin weights
                if( bSkinnedMesh )
                {
                    memcpy( &pTriangle->Vertex[dwCornerIndex].BoneIndices, skindata.GetIndices( dwDCCIndex ), sizeof(ByteVector4) );
                    memcpy( &pTriangle->Vertex[dwCornerIndex].BoneWeights, skindata.GetWeights( dwDCCIndex ), sizeof(D3DXVECTOR4) );
                }
            }

            // Add raw triangle to the mesh.
            pMesh->AddRawTriangle( pTriangle );
        }
    }

    if( bSubDProcess )
    {
        dwMeshOptimizationFlags |= ExportMesh::FORCE_SUBD_CONVERSION;
    }

    pMesh->Optimize( dwMeshOptimizationFlags );

    ExportModel* pModel = new ExportModel( pMesh );
    DWORD dwMaterialCount = (DWORD)MaterialList.size();
    if( pMesh->GetSubDMesh() == NULL )
    {
        for( DWORD dwSubset = 0; dwSubset < dwMaterialCount; ++dwSubset )
        {
            ExportMaterial* pMaterial = MaterialList[dwSubset];
            ExportIBSubset* pSubset = pMesh->GetSubset( dwSubset );
            CHAR strUniqueSubsetName[100];
            sprintf_s( strUniqueSubsetName, "subset%d_%s", dwSubset, pMaterial->GetName().SafeString() );
            pSubset->SetName( strUniqueSubsetName );
            pModel->SetSubsetBinding( pSubset->GetName(), pMaterial );
        }
    }
    else
    {
        ExportSubDProcessMesh* pSubDMesh = pMesh->GetSubDMesh();
        DWORD dwSubsetCount = pSubDMesh->GetSubsetCount();
        for( DWORD dwSubset = 0; dwSubset < dwSubsetCount; ++dwSubset )
        {
            ExportSubDPatchSubset* pSubset = pSubDMesh->GetSubset( dwSubset );
            assert( pSubset != NULL );
            assert( pSubset->iOriginalMeshSubset < (INT)dwMaterialCount );
            ExportMaterial* pMaterial = MaterialList[pSubset->iOriginalMeshSubset];
            CHAR strUniqueSubsetName[100];
            sprintf_s( strUniqueSubsetName, "subset%d_%s", dwSubset, pMaterial->GetName().SafeString() );
            pSubset->Name = strUniqueSubsetName;
            pModel->SetSubsetBinding( pSubset->Name, pMaterial, TRUE );
        }
    }

    if( bSubDProcess && ( dwNonConformingSubDPolys > 0 ) )
    {
        ExportLog::LogWarning( "Encountered %d polygons with 5 or more sides in mesh \"%s\", which were subdivided into quad and triangle patches.  Mesh appearance may have been affected.", dwNonConformingSubDPolys, pMesh->GetName().SafeString() );
    }

    // update statistics
    if( pMesh->GetSubDMesh() != NULL )
    {
        g_pScene->Statistics().SubDMeshesProcessed++;
        g_pScene->Statistics().SubDQuadsProcessed += pMesh->GetSubDMesh()->GetQuadPatchCount();
        g_pScene->Statistics().SubDTrisProcessed += pMesh->GetSubDMesh()->GetTrianglePatchCount();
    }
    else
    {
        g_pScene->Statistics().TrisExported += pMesh->GetIB()->GetIndexCount() / 3;
        g_pScene->Statistics().VertsExported += pMesh->GetVB()->GetVertexCount();
        g_pScene->Statistics().MeshesExported++;
    }

    pParentFrame->AddModel( pModel );
    g_pScene->AddMesh( pMesh );
}
Esempio n. 6
0
void ParseMesh( FbxNode* pNode, FbxMesh* pFbxMesh, ExportFrame* pParentFrame, bool bSubDProcess, const CHAR* strSuffix )
{
    if( !g_pScene->Settings().bExportMeshes )
        return;

    if( !pNode || !pFbxMesh )
        return;

    const CHAR* strName = pFbxMesh->GetName();
    if( !strName || strName[0] == '\0' )
        strName = pParentFrame->GetName().SafeString();

    if( !strSuffix )
    {
        strSuffix = "";
    }
    CHAR strDecoratedName[512];
    sprintf_s( strDecoratedName, "%s_%s%s", g_pScene->Settings().strMeshNameDecoration, strName, strSuffix );
    ExportMesh* pMesh = new ExportMesh( strDecoratedName );
    pMesh->SetDCCObject( pFbxMesh );

    bool bSmoothMesh = false;

    auto Smoothness = pFbxMesh->GetMeshSmoothness();
    if( Smoothness != FbxMesh::eHull && g_pScene->Settings().bConvertMeshesToSubD )
    {
        bSubDProcess = true;
        bSmoothMesh = true;
    }

    ExportLog::LogMsg( 2, "Parsing %s mesh \"%s\", renamed to \"%s\"", bSmoothMesh ? "smooth" : "poly", strName, strDecoratedName );

    SkinData skindata;
    bool bSkinnedMesh = ParseMeshSkinning( pFbxMesh, &skindata );
    if( bSkinnedMesh )
    {
        DWORD dwBoneCount = skindata.GetBoneCount();
        for( DWORD i = 0; i < dwBoneCount; ++i )
        {
            pMesh->AddInfluence( skindata.InfluenceNodes[i]->GetName() );
        }
    }

    bool bExportColors = g_pScene->Settings().bExportColors;
    pMesh->SetVertexColorCount( 0 );

    // Vertex normals and tangent spaces
    if( !g_pScene->Settings().bExportNormals )
    {
        pMesh->SetVertexNormalCount( 0 );
    }
    else if( g_pScene->Settings().bComputeVertexTangentSpace )
    {
        if( g_pScene->Settings().bExportBinormal )
            pMesh->SetVertexNormalCount( 3 );
        else
            pMesh->SetVertexNormalCount( 2 );
    }
    else
    {
        pMesh->SetVertexNormalCount( 1 );
    }

    DWORD dwLayerCount = pFbxMesh->GetLayerCount();
    ExportLog::LogMsg( 4, "%u layers in FBX mesh", dwLayerCount );

    if (!dwLayerCount || !pFbxMesh->GetLayer(0)->GetNormals())
    {
        ExportLog::LogMsg( 4, "Generating normals..." );
        pFbxMesh->InitNormals();
#if (FBXSDK_VERSION_MAJOR >= 2015)
        pFbxMesh->GenerateNormals();
#else
        pFbxMesh->ComputeVertexNormals();
#endif
    }

    DWORD dwVertexColorCount = 0;
    FbxLayerElementVertexColor* pVertexColorSet = nullptr;
    DWORD dwUVSetCount = 0;
    FbxLayerElementMaterial* pMaterialSet = nullptr;
    std::vector<FbxLayerElementUV*> VertexUVSets;
    for( DWORD dwLayerIndex = 0; dwLayerIndex < dwLayerCount; ++dwLayerIndex )
    {
        if( pFbxMesh->GetLayer(dwLayerIndex)->GetVertexColors() && bExportColors )
        {
            if( dwVertexColorCount == 0 )
            {
                dwVertexColorCount++;
                pVertexColorSet = pFbxMesh->GetLayer(dwLayerIndex)->GetVertexColors();
            }
            else
            {
                ExportLog::LogWarning( "Only one vertex color set is allowed; ignoring additional vertex color sets." );
            }
        }
        if( pFbxMesh->GetLayer(dwLayerIndex)->GetUVs() )
        {
            dwUVSetCount++;
            VertexUVSets.push_back( pFbxMesh->GetLayer(dwLayerIndex)->GetUVs() );
        }
        if( pFbxMesh->GetLayer(dwLayerIndex)->GetMaterials() )
        {
            if( pMaterialSet )
            {
                ExportLog::LogWarning( "Multiple material layers detected on mesh %s.  Some will be ignored.", pMesh->GetName().SafeString() );
            }
            pMaterialSet = pFbxMesh->GetLayer(dwLayerIndex)->GetMaterials();
        }
    }

    std::vector<ExportMaterial*> MaterialList;
    for( int dwMaterial = 0; dwMaterial < pNode->GetMaterialCount(); ++dwMaterial )
    {
        auto pMat = pNode->GetMaterial( dwMaterial );
        if ( !pMat )
            continue;

        auto pMaterial = ParseMaterial( pMat );
        MaterialList.push_back( pMaterial );
    }

    ExportLog::LogMsg( 4, "Found %u UV sets", dwUVSetCount );
    dwUVSetCount = std::min<DWORD>( dwUVSetCount, g_pScene->Settings().iMaxUVSetCount );
    ExportLog::LogMsg( 4, "Using %u UV sets", dwUVSetCount );

    pMesh->SetVertexColorCount( dwVertexColorCount );
    pMesh->SetVertexUVCount( dwUVSetCount );
    // TODO: Does FBX only support 2D texture coordinates?
    pMesh->SetVertexUVDimension( 2 );

    DWORD dwMeshOptimizationFlags = 0;
    if( g_pScene->Settings().bCompressVertexData )
        dwMeshOptimizationFlags |= ExportMesh::COMPRESS_VERTEX_DATA;

    DWORD dwPolyCount = pFbxMesh->GetPolygonCount();
    // Assume that polys are usually quads.
    g_MeshTriangleAllocator.SetSizeHint( dwPolyCount * 2 );

    DWORD dwVertexCount = pFbxMesh->GetControlPointsCount();
    auto pVertexPositions = pFbxMesh->GetControlPoints();

    if( bSkinnedMesh )
    {
        assert( skindata.dwVertexCount == dwVertexCount );
    }
    
    ExportLog::LogMsg( 4, "%u vertices, %u polygons", dwVertexCount, dwPolyCount );

    DWORD dwNonConformingSubDPolys = 0;

    // Compute total transformation
    FbxAMatrix vertMatrix;
    FbxAMatrix normMatrix;
    {
        auto trans = pNode->GetGeometricTranslation( FbxNode::eSourcePivot );
        auto rot = pNode->GetGeometricRotation( FbxNode::eSourcePivot );
        auto scale = pNode->GetGeometricScaling( FbxNode::eSourcePivot );

        FbxAMatrix geom;
        geom.SetT( trans );
        geom.SetR( rot );
        geom.SetS( scale );

        if ( g_pScene->Settings().bExportAnimations || !g_pScene->Settings().bApplyGlobalTrans )
        {
            vertMatrix = geom;
        }
        else
        {
            auto global = pNode->EvaluateGlobalTransform();
            vertMatrix = global * geom;
        }

        // Calculate the normal transform matrix (inverse-transpose)
        normMatrix = vertMatrix;
        normMatrix = normMatrix.Inverse();
        normMatrix = normMatrix.Transpose();
    }

    const bool bInvertTexVCoord = g_pScene->Settings().bInvertTexVCoord;
    
    // Loop over polygons.
    DWORD basePolyIndex = 0;
    for( DWORD dwPolyIndex = 0; dwPolyIndex < dwPolyCount; ++dwPolyIndex )
    {
        // Triangulate each polygon into one or more triangles.
        DWORD dwPolySize = pFbxMesh->GetPolygonSize( dwPolyIndex );
        assert( dwPolySize >= 3 );
        DWORD dwTriangleCount = dwPolySize - 2;
        assert( dwTriangleCount > 0 );

        if( dwPolySize > 4 )
        {
            ++dwNonConformingSubDPolys;
        }

        DWORD dwMaterialIndex = 0;
        if( pMaterialSet )
        {
            switch( pMaterialSet->GetMappingMode() )
            {
            case FbxLayerElement::eByPolygon:
                switch( pMaterialSet->GetReferenceMode() )
                {
                case FbxLayerElement::eDirect:
                    dwMaterialIndex = dwPolyIndex;
                    break;
                case FbxLayerElement::eIndex:
                case FbxLayerElement::eIndexToDirect:
                    dwMaterialIndex = pMaterialSet->GetIndexArray().GetAt( dwPolyIndex );
                    break;
                }
            }
        }

        DWORD dwCornerIndices[3];
        // Loop over triangles in the polygon.
        for( DWORD dwTriangleIndex = 0; dwTriangleIndex < dwTriangleCount; ++dwTriangleIndex )
        {
            dwCornerIndices[0] = pFbxMesh->GetPolygonVertex( dwPolyIndex, 0 );
            dwCornerIndices[1] = pFbxMesh->GetPolygonVertex( dwPolyIndex, dwTriangleIndex + 1 );
            dwCornerIndices[2] = pFbxMesh->GetPolygonVertex( dwPolyIndex, dwTriangleIndex + 2 );

            //ExportLog::LogMsg( 4, "Poly %d Triangle %d: %d %d %d", dwPolyIndex, dwTriangleIndex, dwCornerIndices[0], dwCornerIndices[1], dwCornerIndices[2] );

            FbxVector4 vNormals[3];
            ZeroMemory( vNormals, 3 * sizeof(FbxVector4) );
            INT iPolyIndex = static_cast<INT>( dwPolyIndex );
            INT iVertIndex[3] = { 0, static_cast<INT>( dwTriangleIndex + 1 ), static_cast<INT>( dwTriangleIndex + 2 ) };
            pFbxMesh->GetPolygonVertexNormal( iPolyIndex, iVertIndex[0], vNormals[0] );
            pFbxMesh->GetPolygonVertexNormal( iPolyIndex, iVertIndex[1], vNormals[1] );
            pFbxMesh->GetPolygonVertexNormal( iPolyIndex, iVertIndex[2], vNormals[2] );

            // Build the raw triangle.
            auto pTriangle = g_MeshTriangleAllocator.GetNewTriangle();

            // Store polygon index
            pTriangle->PolygonIndex = static_cast<INT>( dwPolyIndex );

            // Store material subset index
            pTriangle->SubsetIndex = dwMaterialIndex;

            for( DWORD dwCornerIndex = 0; dwCornerIndex < 3; ++dwCornerIndex )
            {
                const DWORD& dwDCCIndex = dwCornerIndices[dwCornerIndex];
                // Store DCC vertex index (this helps the mesh reduction/VB generation code)
                pTriangle->Vertex[dwCornerIndex].DCCVertexIndex = dwDCCIndex;

                // Store vertex position
                auto finalPos = vertMatrix.MultT( pVertexPositions[dwDCCIndex] );

                pTriangle->Vertex[dwCornerIndex].Position.x = (float)finalPos.mData[0];
                pTriangle->Vertex[dwCornerIndex].Position.y = (float)finalPos.mData[1];
                pTriangle->Vertex[dwCornerIndex].Position.z = (float)finalPos.mData[2];

                // Store vertex normal
                auto finalNorm = vNormals[dwCornerIndex];
                finalNorm.mData[3] = 0.0;
                finalNorm = normMatrix.MultT( finalNorm );
                finalNorm.Normalize();

                pTriangle->Vertex[dwCornerIndex].Normal.x = (float)finalNorm.mData[0];
                pTriangle->Vertex[dwCornerIndex].Normal.y = (float)finalNorm.mData[1];
                pTriangle->Vertex[dwCornerIndex].Normal.z = (float)finalNorm.mData[2];

                // Store UV sets
                for( DWORD dwUVIndex = 0; dwUVIndex < dwUVSetCount; ++dwUVIndex )
                {
                    // Crack apart the FBX dereferencing system for UV coordinates
                    FbxLayerElementUV* pUVSet = VertexUVSets[dwUVIndex];
                    FbxVector2 Value( 0, 0 );
                    switch( pUVSet->GetMappingMode() )
                    {
                    case FbxLayerElement::eByControlPoint:
                        switch (pUVSet->GetReferenceMode())
                        {
                        case FbxLayerElement::eDirect:
                            Value = pUVSet->GetDirectArray().GetAt(dwDCCIndex);
                            break;

                        case FbxLayerElement::eIndex:
                        case FbxLayerElement::eIndexToDirect:
                            {
                                int iUVIndex = pUVSet->GetIndexArray().GetAt(dwDCCIndex);
                                Value = pUVSet->GetDirectArray().GetAt(iUVIndex);
                            }
                            break;
                        }
                        break;

                    case FbxLayerElement::eByPolygonVertex:
                        switch (pUVSet->GetReferenceMode())
                        {
                        case FbxLayerElement::eDirect:
                            Value = pUVSet->GetDirectArray().GetAt( basePolyIndex + iVertIndex[dwCornerIndex] );
                            break;

                        case FbxLayerElement::eIndex:
                        case FbxLayerElement::eIndexToDirect:
                            {
                                int iUVIndex = pUVSet->GetIndexArray().GetAt( basePolyIndex + iVertIndex[dwCornerIndex] );
#ifdef _DEBUG
                                if (!dwUVIndex)
                                {
                                    // Warning: pFbxMesh->GetTextureUVIndex only works for the first layer of the mesh
                                    int iUVIndex2 = pFbxMesh->GetTextureUVIndex(iPolyIndex, iVertIndex[dwCornerIndex]);
                                    assert(iUVIndex == iUVIndex2);
                                }
#endif
                                Value = pUVSet->GetDirectArray().GetAt( iUVIndex );
                            }
                            break;
                        }
                        break;
                    }

                    // Store a single UV set
                    pTriangle->Vertex[dwCornerIndex].TexCoords[dwUVIndex].x = (float)Value.mData[0];
                    if( bInvertTexVCoord )
                    {
                        pTriangle->Vertex[dwCornerIndex].TexCoords[dwUVIndex].y = 1.0f - (float) Value.mData[1];
                    }
                    else
                    {
                        pTriangle->Vertex[dwCornerIndex].TexCoords[dwUVIndex].y = (float)Value.mData[1];
                    }
                }

                // Store vertex color set
                if( dwVertexColorCount > 0 && pVertexColorSet )
                {
                    // Crack apart the FBX dereferencing system for Color coordinates
                    FbxColor Value( 1, 1, 1, 1 );
                    switch( pVertexColorSet->GetMappingMode() )
                    {
                    case FbxLayerElement::eByControlPoint:
                        switch( pVertexColorSet->GetReferenceMode() )
                        {
                        case FbxLayerElement::eDirect:
                            Value = pVertexColorSet->GetDirectArray().GetAt( dwDCCIndex );
                            break;
                        case FbxLayerElement::eIndex:
                        case FbxLayerElement::eIndexToDirect:
                            {
                                int iColorIndex = pVertexColorSet->GetIndexArray().GetAt(dwDCCIndex);
                                Value = pVertexColorSet->GetDirectArray().GetAt(iColorIndex);
                            }
                            break;
                        }
                        break;

                    case FbxLayerElement::eByPolygonVertex:
                        switch( pVertexColorSet->GetReferenceMode() )
                        {
                        case FbxLayerElement::eDirect:
                            Value = pVertexColorSet->GetDirectArray().GetAt( basePolyIndex + iVertIndex[dwCornerIndex] );
                            break;
                        case FbxLayerElement::eIndex:
                        case FbxLayerElement::eIndexToDirect:
                            {
                                int iColorIndex = pVertexColorSet->GetIndexArray().GetAt( basePolyIndex + iVertIndex[dwCornerIndex] );
                                Value = pVertexColorSet->GetDirectArray().GetAt(iColorIndex);
                            }
                            break;
                        }
                        break;
                    }

                    // Store a single vertex color set
                    pTriangle->Vertex[dwCornerIndex].Color.x = (float)Value.mRed;
                    pTriangle->Vertex[dwCornerIndex].Color.y = (float)Value.mGreen;
                    pTriangle->Vertex[dwCornerIndex].Color.z = (float)Value.mBlue;
                    pTriangle->Vertex[dwCornerIndex].Color.w = (float)Value.mAlpha;
                }

                // Store skin weights
                if( bSkinnedMesh )
                {
                    memcpy( &pTriangle->Vertex[dwCornerIndex].BoneIndices, skindata.GetIndices( dwDCCIndex ), sizeof(PackedVector::XMUBYTE4) );
                    memcpy( &pTriangle->Vertex[dwCornerIndex].BoneWeights, skindata.GetWeights( dwDCCIndex ), sizeof(XMFLOAT4) );
                }
            }

            // Add raw triangle to the mesh.
            pMesh->AddRawTriangle( pTriangle );
        }

        basePolyIndex += dwPolySize;
    }

    if( bSubDProcess )
    {
        dwMeshOptimizationFlags |= ExportMesh::FORCE_SUBD_CONVERSION;
    }

    if ( g_pScene->Settings().bCleanMeshes )
    {
        dwMeshOptimizationFlags |= ExportMesh::CLEAN_MESHES;
    }

    if ( g_pScene->Settings().bOptimizeVCache )
    {
        dwMeshOptimizationFlags |= ExportMesh::CLEAN_MESHES | ExportMesh::VCACHE_OPT;
    }

    pMesh->Optimize( dwMeshOptimizationFlags );

    ExportModel* pModel = new ExportModel( pMesh );
    size_t dwMaterialCount = MaterialList.size();
    if( !pMesh->GetSubDMesh() )
    {
        for( size_t dwSubset = 0; dwSubset < dwMaterialCount; ++dwSubset )
        {
            auto pMaterial = MaterialList[dwSubset];
            auto pSubset = pMesh->GetSubset( dwSubset );
            CHAR strUniqueSubsetName[100];
            sprintf_s( strUniqueSubsetName, "subset%Iu_%s", dwSubset, pMaterial->GetName().SafeString() );
            pSubset->SetName( strUniqueSubsetName );
            pModel->SetSubsetBinding( pSubset->GetName(), pMaterial );
        }
    }
    else
    {
        auto pSubDMesh = pMesh->GetSubDMesh();
        size_t dwSubsetCount = pSubDMesh->GetSubsetCount();
        for( size_t dwSubset = 0; dwSubset < dwSubsetCount; ++dwSubset )
        {
            auto pSubset = pSubDMesh->GetSubset( dwSubset );
            assert( pSubset != nullptr );
            assert( pSubset->iOriginalMeshSubset < static_cast<INT>( dwMaterialCount ) );
            auto pMaterial = MaterialList[pSubset->iOriginalMeshSubset];
            CHAR strUniqueSubsetName[100];
            sprintf_s( strUniqueSubsetName, "subset%Iu_%s", dwSubset, pMaterial->GetName().SafeString() );
            pSubset->Name = strUniqueSubsetName;
            pModel->SetSubsetBinding( pSubset->Name, pMaterial, true );
        }
    }

    if( bSubDProcess && ( dwNonConformingSubDPolys > 0 ) )
    {
        ExportLog::LogWarning( "Encountered %u polygons with 5 or more sides in mesh \"%s\", which were subdivided into quad and triangle patches.  Mesh appearance may have been affected.", dwNonConformingSubDPolys, pMesh->GetName().SafeString() );
    }

    // update statistics
    if( pMesh->GetSubDMesh() )
    {
        g_pScene->Statistics().SubDMeshesProcessed++;
        g_pScene->Statistics().SubDQuadsProcessed += pMesh->GetSubDMesh()->GetQuadPatchCount();
        g_pScene->Statistics().SubDTrisProcessed += pMesh->GetSubDMesh()->GetTrianglePatchCount();
    }
    else
    {
        g_pScene->Statistics().TrisExported += pMesh->GetIB()->GetIndexCount() / 3;
        g_pScene->Statistics().VertsExported += pMesh->GetVB()->GetVertexCount();
        g_pScene->Statistics().MeshesExported++;
    }

    pParentFrame->AddModel( pModel );
    g_pScene->AddMesh( pMesh );
}