void Parser::bake_global_positions(FbxVector4* control_points, int control_points_count, FbxAMatrix& global_offset_position) { for (int i = 0; i < control_points_count; i++) { control_points[i] = global_offset_position.MultT(control_points[i]); } }
bool Submesh::load(FbxNode* pNode, FbxMesh* pMesh, const std::vector<face>& faces, const std::vector<vertexInfo>& vertInfo, const std::vector<FbxVector4>& points, const std::vector<FbxVector4>& normals, const std::vector<int>& texcoordsets, ParamList& params, const FbxAMatrix& bindPose, bool opposite ) { //save the mesh from which this submesh will be created m_pNode = pNode; size_t i,j,k; FxOgreFBXLog( "Loading submesh associated to material: %s ...\n", m_pMaterial->name().c_str()); //save uvsets info for (i=m_uvsets.size(); i<texcoordsets.size(); i++) { uvset uv; uv.size = 2; m_uvsets.push_back(uv); } //iterate over faces array, to retrieve vertices info for (i=0; i<faces.size(); i++) { face newFace; // if we are using shared geometry, indexes refer to the vertex buffer of the whole mesh if (params.useSharedGeom) { if(opposite) { // reverse order of face vertices for correct culling newFace.v[0] = faces[i].v[2]; newFace.v[1] = faces[i].v[1]; newFace.v[2] = faces[i].v[0]; } else { newFace.v[0] = faces[i].v[0]; newFace.v[1] = faces[i].v[1]; newFace.v[2] = faces[i].v[2]; } } // otherwise we create a vertex buffer for this submesh else { // faces are triangles, so retrieve index of the three vertices for (j=0; j<3; j++) { vertex v; vertexInfo vInfo = vertInfo[faces[i].v[j]]; // save vertex coordinates (rescale to desired length unit) assert(vInfo.pointIdx >= 0 && vInfo.pointIdx < static_cast<int>(points.size())); FbxVector4 point = points[vInfo.pointIdx] * params.lum; if (fabs(point[0]) < PRECISION) point[0] = 0; if (fabs(point[1]) < PRECISION) point[1] = 0; if (fabs(point[2]) < PRECISION) point[2] = 0; v.x = point[0]; v.y = point[1]; v.z = point[2]; // save vertex normal assert(vInfo.normalIdx >= 0 && vInfo.normalIdx < static_cast<int>(normals.size())); FbxVector4 normal = normals[vInfo.normalIdx]; if (fabs(normal[0]) < PRECISION) normal[0] = 0; if (fabs(normal[1]) < PRECISION) normal[1] = 0; if (fabs(normal[2]) < PRECISION) normal[2] = 0; v.n.x = normal[0]; v.n.y = normal[1]; v.n.z = normal[2]; if (opposite) { // Reversing the winding order appears to be sufficent. v.n.x = -normal[0]; v.n.y = -normal[1]; v.n.z = -normal[2]; } v.n.Normalize(); // save vertex color v.r = vInfo.r; v.g = vInfo.g; v.b = vInfo.b; v.a = vInfo.a; // save vertex bone assignements for (k=0; k<vInfo.vba.size(); k++) { vba newVba; newVba.jointIdx = vInfo.jointIds[k]; newVba.weight = vInfo.vba[k]; v.vbas.push_back(newVba); } // save texture coordinates for (k=0; k<vInfo.u.size(); k++) { texcoord newTexCoords; newTexCoords.u = vInfo.u[k]; newTexCoords.v = vInfo.v[k]; newTexCoords.w = 0; v.texcoords.push_back(newTexCoords); } // save vertex index in mesh, to retrieve future positions of the same vertex v.index = vInfo.pointIdx; // add newly created vertex to vertex list m_vertices.push_back(v); if (opposite) // reverse order of face vertices to get correct culling newFace.v[2-j] = static_cast<int>(m_vertices.size()) - 1; else newFace.v[j] = static_cast<int>(m_vertices.size()) - 1; } } m_faces.push_back(newFace); } // set use32bitIndexes flag if (params.useSharedGeom || (m_vertices.size() > 65535) || (m_faces.size() > 65535)) m_use32bitIndexes = true; else m_use32bitIndexes = false; pMesh->ComputeBBox(); FbxDouble3 minDouble = pMesh->BBoxMin.Get(); FbxDouble3 maxDouble = pMesh->BBoxMax.Get(); FbxVector4 min = bindPose.MultT( FbxVector4(minDouble[0],minDouble[1],minDouble[2],0)); FbxVector4 max = bindPose.MultT( FbxVector4(maxDouble[0],maxDouble[1],maxDouble[2],0)); m_bbox.merge(Point3(max[0], max[1], max[2])); m_bbox.merge(Point3(min[0], min[1], min[2])); // add submesh pointer to m_params list params.loadedSubmeshes.push_back(this); FxOgreFBXLog( "DONE\n"); return true; }
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 ); }
void CameraOrbit(FbxScene* pScene, FbxVector4 lOrigCamPos, double OrigRoll, int dX, int dY) { // Orbit the camera horizontally dX degrees, vertically dY degrees. FbxCamera* lCamera = GetCurrentCamera(pScene); if (!lCamera) return; FbxGlobalCameraSettings& lGlobalCameraSettings = pScene->GlobalCameraSettings(); if (lCamera != lGlobalCameraSettings.GetCameraProducerPerspective()) return; if (lCamera->LockMode.Get()) return; if (dX == 0 && dY == 0) return; FbxVector4 lRotationVector, lNewPosition, lCurPosition; FbxAMatrix lRotation; FbxVector4 lCenter = lCamera->InterestPosition.Get(); // current position FbxVector4 lPosition = lCamera->Position.Get(); lCurPosition = lPosition-lCenter; // translate lNewPosition = lOrigCamPos-lCenter; int rotX; if (lNewPosition[2] == 0) { rotX = 90; } else { rotX = (int) (atan((double)lNewPosition[0]/(double)lNewPosition[2]) * FBXSDK_180_DIV_PI); } bool bRoll = (((int)OrigRoll % 360) != 0); if ( (lNewPosition[2] < 0 && !bRoll) || (lNewPosition[2] > 0 && bRoll) ) { dY = -dY; } if (bRoll) dX = -dX; // Center on the X axis (push) lRotationVector[1] = -rotX; lRotation.SetR(lRotationVector); lNewPosition = lRotation.MultT(lNewPosition); // Rotation for the vertical movement: around the X axis lRotationVector[1] = 0; lRotationVector[0] = dY; lRotation.SetR(lRotationVector); lNewPosition = lRotation.MultT(lNewPosition); // Back from the X axis (pop) lRotationVector[0] = 0; lRotationVector[1] = rotX; lRotation.SetR(lRotationVector); lNewPosition = lRotation.MultT(lNewPosition); // Rotation for the horizontal movement lRotationVector[1] = -dX; lRotation.SetR(lRotationVector); lNewPosition = lRotation.MultT(lNewPosition); // Detect camera flip if ( lNewPosition[0]*lCurPosition[0] < 0 && lNewPosition[2]*lCurPosition[2] < 0) { // flip -> roll 180. double lRoll = lCamera->Roll.Get(); lRoll = 180.0-lRoll; lCamera->Roll.Set(lRoll); } // Back from center lNewPosition = lNewPosition + lCenter; lCamera->Position.Set(lNewPosition); }
void CameraZoom(FbxScene* pScene, int pZoomDepth, int pZoomMode) { FbxCamera* lCamera = GetCurrentCamera(pScene); if( lCamera == NULL) return; if( pZoomMode == SceneContext::ZOOM_FOCAL_LENGTH) { if (lCamera->ProjectionType.Get() == FbxCamera::ePerspective) { double lTransform = 0 - pZoomDepth / 100.0; double lApertureW = lCamera->GetApertureWidth(); lApertureW = TransformAperture( lApertureW, lTransform); double lApertureH = lCamera->GetApertureHeight(); lApertureH = TransformAperture( lApertureH, lTransform); UpdatePerspCameraAttributes( lCamera, lApertureW, lApertureH); } else { if( pZoomDepth > 0) gsOrthoCameraScale *= 0.8; else gsOrthoCameraScale *= 1.25; } } else { FbxNode* lCameraNode = lCamera ? lCamera->GetNode() : NULL; // Compute the camera position and direction. FbxVector4 lEye(0,0,1); FbxVector4 lCenter(0,0,0); FbxVector4 lForward(0,0,0); if (lCamera) { lEye = lCamera->Position.Get(); } if (lCameraNode && lCameraNode->GetTarget()) { lCenter = lCameraNode->GetTarget()->LclTranslation.Get(); lForward = lCenter - lEye; } else { if (!lCameraNode || IsProducerCamera(pScene, lCamera)) { if (lCamera) { lCenter = lCamera->InterestPosition.Get(); lForward = lCenter - lEye; } } else { // Get the direction FbxAMatrix lGlobalRotation; FbxVector4 lRotationVector( lCameraNode->LclRotation.Get()); lGlobalRotation.SetR(lRotationVector); // Set the center. // A camera with rotation = {0,0,0} points to the X direction. So create a // vector in the X direction, rotate that vector by the global rotation amount // and then position the center by scaling and translating the resulting vector lRotationVector = FbxVector4(1.0,0,0); lForward = lGlobalRotation.MultT(lRotationVector); } } lForward.Normalize(); lEye += lForward * pZoomDepth; FbxDouble3 lPosition(lEye[0], lEye[1], lEye[2]); lCamera->Position.Set(lPosition); } }
// Set the view to the current camera settings. void SetCamera(FbxScene* pScene, FbxTime& pTime, FbxAnimLayer* pAnimLayer, const FbxArray<FbxNode*>& pCameraArray, int pWindowWidth, int pWindowHeight) { // Find the current camera at the given time. FbxCamera* lCamera = GetCurrentCamera(pScene, pTime, pAnimLayer, pCameraArray); if( lCamera == NULL) return; FbxNode* lCameraNode = lCamera ? lCamera->GetNode() : NULL; // Compute the camera position and direction. FbxVector4 lEye(0,0,1); FbxVector4 lCenter(0,0,0); FbxVector4 lUp(0,1,0); FbxVector4 lForward, lRight; if (lCamera) { lEye = lCamera->Position.Get(); lUp = lCamera->UpVector.Get(); } if (lCameraNode && lCameraNode->GetTarget()) { lCenter = GetGlobalPosition(lCameraNode->GetTarget(), pTime).GetT(); } else { if (!lCameraNode || IsProducerCamera(pScene, lCamera)) { if (lCamera) lCenter = lCamera->InterestPosition.Get(); } else { // Get the direction FbxAMatrix lGlobalRotation; FbxVector4 lRotationVector(GetGlobalPosition(lCameraNode, pTime).GetR()); lGlobalRotation.SetR(lRotationVector); // Get the length FbxVector4 lInterestPosition(lCamera->InterestPosition.Get()); FbxVector4 lCameraGlobalPosition(GetGlobalPosition(lCameraNode, pTime).GetT()); double lLength = (FbxVector4(lInterestPosition - lCameraGlobalPosition).Length()); // Set the center. // A camera with rotation = {0,0,0} points to the X direction. So create a // vector in the X direction, rotate that vector by the global rotation amount // and then position the center by scaling and translating the resulting vector lRotationVector = FbxVector4(1.0,0,0); lCenter = lGlobalRotation.MultT(lRotationVector); lCenter *= lLength; lCenter += lEye; // Update the default up vector with the camera rotation. lRotationVector = FbxVector4(0,1.0,0); lUp = lGlobalRotation.MultT(lRotationVector); } } // Align the up vector. lForward = lCenter - lEye; lForward.Normalize(); lRight = lForward.CrossProduct(lUp); lRight.Normalize(); lUp = lRight.CrossProduct(lForward); lUp.Normalize(); // Rotate the up vector with the roll value. double lRadians = 0; if (lCamera) lRadians = lCamera->Roll.Get() * FBXSDK_PI_DIV_180; lUp = lUp * cos( lRadians) + lRight * sin(lRadians); double lNearPlane = 0.01; if (lCamera) lNearPlane = lCamera->GetNearPlane(); double lFarPlane = 4000.0; if (lCamera) lFarPlane = lCamera->GetFarPlane(); //Get global scaling. FbxVector4 lCameraScaling = GetGlobalPosition(lCameraNode, pTime).GetS(); static const int FORWARD_SCALE = 2; //scaling near plane and far plane lNearPlane *= lCameraScaling[ FORWARD_SCALE]; lFarPlane *= lCameraScaling[ FORWARD_SCALE]; // Get the relevant camera settings for a perspective view. if (lCamera && lCamera->ProjectionType.Get() == FbxCamera::ePerspective) { //get the aspect ratio FbxCamera::EAspectRatioMode lCamAspectRatioMode = lCamera->GetAspectRatioMode(); double lAspectX = lCamera->AspectWidth.Get(); //ºñÀ² double lAspectY = lCamera->AspectHeight.Get(); double lAspectRatio = 1.333333; switch( lCamAspectRatioMode) { case FbxCamera::eWindowSize: lAspectRatio = lAspectX / lAspectY; break; case FbxCamera::eFixedRatio: lAspectRatio = lAspectX; break; case FbxCamera::eFixedResolution: lAspectRatio = lAspectX / lAspectY * lCamera->GetPixelRatio(); break; case FbxCamera::eFixedWidth: lAspectRatio = lCamera->GetPixelRatio() / lAspectY; break; case FbxCamera::eFixedHeight: lAspectRatio = lCamera->GetPixelRatio() * lAspectX; break; default: break; } //get the aperture ratio double lFilmHeight = lCamera->GetApertureHeight(); double lFilmWidth = lCamera->GetApertureWidth() * lCamera->GetSqueezeRatio(); //here we use Height : Width double lApertureRatio = lFilmHeight / lFilmWidth; //change the aspect ratio to Height : Width lAspectRatio = 1 / lAspectRatio; //revise the aspect ratio and aperture ratio FbxCamera::EGateFit lCameraGateFit = lCamera->GateFit.Get(); switch( lCameraGateFit ) { case FbxCamera::eFitFill: if( lApertureRatio > lAspectRatio) // the same as eHORIZONTAL_FIT { lFilmHeight = lFilmWidth * lAspectRatio; lCamera->SetApertureHeight( lFilmHeight); lApertureRatio = lFilmHeight / lFilmWidth; } else if( lApertureRatio < lAspectRatio) //the same as eVERTICAL_FIT { lFilmWidth = lFilmHeight / lAspectRatio; lCamera->SetApertureWidth( lFilmWidth); lApertureRatio = lFilmHeight / lFilmWidth; } break; case FbxCamera::eFitVertical: lFilmWidth = lFilmHeight / lAspectRatio; lCamera->SetApertureWidth( lFilmWidth); lApertureRatio = lFilmHeight / lFilmWidth; break; case FbxCamera::eFitHorizontal: lFilmHeight = lFilmWidth * lAspectRatio; lCamera->SetApertureHeight( lFilmHeight); lApertureRatio = lFilmHeight / lFilmWidth; break; case FbxCamera::eFitStretch: lAspectRatio = lApertureRatio; break; case FbxCamera::eFitOverscan: if( lFilmWidth > lFilmHeight) { lFilmHeight = lFilmWidth * lAspectRatio; } else { lFilmWidth = lFilmHeight / lAspectRatio; } lApertureRatio = lFilmHeight / lFilmWidth; break; case FbxCamera::eFitNone: default: break; } //change the aspect ratio to Width : Height lAspectRatio = 1 / lAspectRatio; double lFieldOfViewX = 0.0; double lFieldOfViewY = 0.0; if ( lCamera->GetApertureMode() == FbxCamera::eVertical) { lFieldOfViewY = lCamera->FieldOfView.Get(); lFieldOfViewX = VFOV2HFOV( lFieldOfViewY, 1 / lApertureRatio); } else if (lCamera->GetApertureMode() == FbxCamera::eHorizontal) { lFieldOfViewX = lCamera->FieldOfView.Get(); //get HFOV lFieldOfViewY = HFOV2VFOV( lFieldOfViewX, lApertureRatio); } else if (lCamera->GetApertureMode() == FbxCamera::eFocalLength) { lFieldOfViewX = lCamera->ComputeFieldOfView(lCamera->FocalLength.Get()); //get HFOV lFieldOfViewY = HFOV2VFOV( lFieldOfViewX, lApertureRatio); } else if (lCamera->GetApertureMode() == FbxCamera::eHorizAndVert) { lFieldOfViewX = lCamera->FieldOfViewX.Get(); lFieldOfViewY = lCamera->FieldOfViewY.Get(); } double lRealScreenRatio = (double)pWindowWidth / (double)pWindowHeight; int lViewPortPosX = 0, lViewPortPosY = 0, lViewPortSizeX = pWindowWidth, lViewPortSizeY = pWindowHeight; //compute the view port if( lRealScreenRatio > lAspectRatio) { lViewPortSizeY = pWindowHeight; lViewPortSizeX = (int)( lViewPortSizeY * lAspectRatio); lViewPortPosY = 0; lViewPortPosX = (int)((pWindowWidth - lViewPortSizeX) * 0.5); } else { lViewPortSizeX = pWindowWidth; lViewPortSizeY = (int)(lViewPortSizeX / lAspectRatio); lViewPortPosX = 0; lViewPortPosY = (int)((pWindowHeight - lViewPortSizeY) * 0.5); } //revise the Perspective since we have film offset double lFilmOffsetX = lCamera->FilmOffsetX.Get(); double lFilmOffsetY = lCamera->FilmOffsetY.Get(); lFilmOffsetX = 0 - lFilmOffsetX / lFilmWidth * 2.0; lFilmOffsetY = 0 - lFilmOffsetY / lFilmHeight * 2.0; GlSetCameraPerspective( lFieldOfViewY, lAspectRatio, lNearPlane, lFarPlane, lEye, lCenter, lUp, lFilmOffsetX, lFilmOffsetY); //glMatrixMode(GL_PROJECTION); //double lTestPerpMatrix[ 16]; //glGetDoublev( GL_PROJECTION_MATRIX, lTestPerpMatrix); //lTestPerpMatrix[ 8] -= lFilmOffsetX; //lTestPerpMatrix[ 9] -= lFilmOffsetY; // //glLoadMatrixd( lTestPerpMatrix); //glMatrixMode(GL_MODELVIEW); glViewport( lViewPortPosX, lViewPortPosY, lViewPortSizeX, lViewPortSizeY); } // Get the relevant camera settings for an orthogonal view. else { double lPixelRatio = 1.0; if (lCamera) lPixelRatio = lCamera->GetPixelRatio(); double lLeftPlane, lRightPlane, lBottomPlane, lTopPlane; if(pWindowWidth < pWindowHeight) { lLeftPlane = -gsOrthoCameraScale * lPixelRatio; lRightPlane = gsOrthoCameraScale * lPixelRatio; lBottomPlane = -gsOrthoCameraScale * pWindowHeight / pWindowWidth; lTopPlane = gsOrthoCameraScale * pWindowHeight / pWindowWidth; } else { pWindowWidth *= (int) lPixelRatio; lLeftPlane = -gsOrthoCameraScale * pWindowWidth / pWindowHeight; lRightPlane = gsOrthoCameraScale * pWindowWidth / pWindowHeight; lBottomPlane = -gsOrthoCameraScale; lTopPlane = gsOrthoCameraScale; } GlSetCameraOrthogonal(lLeftPlane, lRightPlane, lBottomPlane, lTopPlane, lNearPlane, lFarPlane, lEye, lCenter, lUp); } }
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); } }