관리 메뉴

fatalite

OBJ to FBX Converting 본문

게임/컴퓨터 그래픽스

OBJ to FBX Converting

fataliteforu 2023. 1. 3. 14:58

문제정의

3D Reconstruction의 결과가 obj만으로 나옴

OBJ가 가지고 있는건 VERTICES(Color, Position), FACE이다.

OBJ에는 원래 Vertex color가 따로 없고, MTL 파일에 존재해야하는데,

Realtime Plugin이나 모델에 해당 코드가 없다.

//vertices
if (line.StartsWith("v ")) {
	lineElements.Empty();
	int32 elementCount = line.ParseIntoArray(lineElements, TEXT(" "), true);
	if (elementCount == 4) {
		if (coordinateSystem == ERTICoordinateSystem::E_RightHanded) {
			verticesLines.Add(FVector(FCString::Atof(*lineElements[1]), FCString::Atof(*lineElements[3]), FCString::Atof(*lineElements[2])));
			}
			else {
				verticesLines.Add(FVector(FCString::Atof(*lineElements[1]), FCString::Atof(*lineElements[2]), FCString::Atof(*lineElements[3])));
			}
		}
		else {
			UE_LOG(LogTemp, Warning, TEXT("RealTimeImportPlugin:(%i) Vertices line corrupted: %s"), (i + 1), *line);
		}
		continue;
	}

 

따라서 

3D Reconstruction Application에서 vertex color를 유의미하게 출력해야한다.


문제접근

Vertex Color 정보로 어떻게 Material을 만들 수 있을까?

 

관련 정보가 잘 검색되지 않았다.

Meshlab에서 obj를 import하고, ply로 export하면 된다는 영상을 보고 Meshlab의 소스코드를 살펴보았다.

 

Meshlab의 io_base.h에서 VCGlib의 import, export library를 쓰고 있음을 알 수있었다.

VCGlib의 Github에 가서, wrap/io_trimesh/import_obj.h를 확인해본다.

 

그러면 Open 함수를 볼 수 있다. https://github.com/cnr-isti-vclab/vcglib/blob/main/wrap/io_trimesh/import_obj.h

 

GitHub - cnr-isti-vclab/vcglib: The VCGlib is a C++, templated, no dependency, library for manipulation, processing and cleaning

The VCGlib is a C++, templated, no dependency, library for manipulation, processing and cleaning of triangle meshes - GitHub - cnr-isti-vclab/vcglib: The VCGlib is a C++, templated, no dependency, ...

github.com

269번째 줄 보면, vectorColorVector에 값이 대입되어지지 않았다.

273번째 줄에 !stream.eof() 부터 살펴보면 되겠다.

TokenizeNextLine(stream, tokens, line, &vertexColorVector);

다음 줄을 토큰화한다.

 

303번째줄 부터 vertex color의 코드이다.

0-255 범위의 RGB 값으로 저장한다.

// assigning vertex color

if (((oi.mask & vcg::tri::io::Mask::IOM_VERTCOLOR) != 0) && (HasPerVertexColor(m)))
     {
     if(numTokens>=7)
     {
         ScalarType rf(atof(tokens[4].c_str())), gf(atof(tokens[5].c_str())), bf(atof(tokens[6].c_str()));
         ScalarType scaling = (rf<=1 && gf<=1 && bf<=1) ? 255. : 1;
              
         unsigned char r			= (unsigned char) ((ScalarType) atof(tokens[4].c_str()) * scaling);
         unsigned char g			= (unsigned char) ((ScalarType) atof(tokens[5].c_str()) * scaling);
         unsigned char b			= (unsigned char) ((ScalarType) atof(tokens[6].c_str()) * scaling);
         unsigned char alpha = (unsigned char) ((numTokens>=8 ? (ScalarType) atof(tokens[7].c_str()) : 1)  * scaling);
         (*vi).C() = Color4b(r, g, b, alpha);
      }
         else
         {
           (*vi).C() = currentColor;
         }
     }

atof 함수는 무슨 역할을 할까? 

vcg의 추상적인 3D 객체의 자료형으로 바꾸어주는 것이 아닐까?

 

아니었다. atof는 C++의 함수다.

ASCII(Char)을 Double 형으로 반환한다.(왜 atod가 아닐까?..)

 

암튼, RGBA 값만 VCG에서 저장하는 듯하다.

그러면 Vertex color가 있으면 PLY, FBX 모두 출력이 가능하다는 뜻이다.

 

다음은 Save 함수로, FBX file로 export 해준다.

말했듯이, FBX는 그들만의 SDK를 사용하기 때문에 FBX SDK를 이해해야지 아래 코드를 이해할 수 있을 듯하다.

 

	static int Save(SaveMeshType &m, const char * filename,const bool binary,const bool embed,const int mask)
	{
		KFbxSdkManager* sdkman = KFbxSdkManager::Create();

		KFbxIOSettings * ios = KFbxIOSettings::Create(sdkman, IOSROOT );
		ios->SetBoolProp(EXP_FBX_MATERIAL,true);
		ios->SetBoolProp(EXP_FBX_TEXTURE,true);
		ios->SetBoolProp(EXP_FBX_EMBEDDED,embed);
		ios->SetBoolProp(EXP_FBX_SHAPE,true);
		ios->SetBoolProp(EXP_FBX_ANIMATION,false);
		ios->SetBoolProp(EXP_FBX_GLOBAL_SETTINGS, true);
		sdkman->SetIOSettings(ios);

		if(sdkman == NULL) 
			return -1;

		KFbxExporter* lExporter = KFbxExporter::Create(sdkman,"VCGFbxFileExporter");
		int asciiexportind = -1;

		if ((!binary) && (!embed))
		{
			int formatnum = sdkman->GetIOPluginRegistry()->GetWriterFormatCount();
			bool asciifound = false;
			int ii = 0;
			while ((!asciifound) && (ii<formatnum))
			{
				if (sdkman->GetIOPluginRegistry()->WriterIsFBX(ii))
				{
					KString plugdesc =sdkman->GetIOPluginRegistry()->GetWriterFormatDescription(ii);
					if (plugdesc.Find("ascii")>=0)
					{
						asciiexportind = ii;
						asciifound = true;
					}
				}
				++ii;
			}
		}


		if(!lExporter->Initialize(filename, asciiexportind,ios))
			return false;

		KFbxScene* scene = KFbxScene::Create(sdkman,"VCGScene");
		bool result = fillScene(m,*scene,mask);
		if (!result)
			return -1;
		result = lExporter->Export(scene);
		lExporter->Destroy();
		if (!result)
			return -1;
		return 0;
	}

보면 SDK Manager로 Exporter를 설정하고, Scene에는 Mesh 정보를 넣는다.

그럼 Scene 정보를 통해 Exporter가 이를 출력해준다.

그렇다면 Scene에는 어떤 정보가 들어가야하는지 살펴봐야겠다.

 

이는 static bool fillScene(SaveMeshType& m,KFbxScene& scene,const int mask)를 살펴본다.

이 부분이 vertex color와 관련 있어 보인다.

bool vertcol = (vcg::tri::HasPerVertexColor(m) && (mask | vcg::tri::io::Mask::IOM_VERTCOLOR)) && !facecolasmaterial;

KFbxMesh* vcgmesh = KFbxMesh::Create(&scene,"VCGMeshAttribute");
KFbxNode* meshnode = KFbxNode::Create(&scene,"VCGMeshNode");
meshnode->SetNodeAttribute(vcgmesh);

meshnode에 Attribution을 세팅한다.

KFbxGeometryElementVertexColor* vcolorlay = NULL;
		if (vertcol)
		{
			vcolorlay = vcgmesh->CreateElementVertexColor();
			vcolorlay->SetMappingMode(KFbxGeometryElement::eBY_CONTROL_POINT);
			vcolorlay->SetReferenceMode(KFbxGeometryElement::eDIRECT);
		}
for(std::set<vcg::Color4b>::iterator it = matset.begin();it != matset.end();++it)
		{
			vcg::Color4b vcgcol = *it;
			fbxDouble3 fbxcol(vcgcol[0] / 255.0f,vcgcol[1]/ 255.0f,vcgcol[2]/ 255.0f);
			KFbxSurfacePhong* phong = newPhongMaterial(scene,createName("mat_",zz).c_str(),NULL,fbxcol);
			KFbxNode* meshnode = vcgmesh->GetNode();
			if(meshnode == NULL) 
				return false;
			meshnode->AddMaterial(phong);
			++zz;
}

fbx scene의 구조


문제 해결

위와 같은 분석과정으로, 다음과 같은 시나리오를 작성했다.

답은 간단했다.

Reconstruction하는 소스코드에, FBX SDK(Python Binding)를 넣어서 Exporting 한다.

'게임 > 컴퓨터 그래픽스' 카테고리의 다른 글

스켈레톤 - 애니메이션  (0) 2023.08.17
FBX Format  (0) 2023.01.03