튀김족발
공부 끄적이는 공간
튀김족발
전체 방문자
오늘
어제
  • 분류 전체보기 (33)
    • C++ (10)
    • DirectX (12)
    • Unreal (11)
    • Unity (0)
    • EASTL (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
튀김족발

공부 끄적이는 공간

7. Maya 2011 모델 불러오기
DirectX

7. Maya 2011 모델 불러오기

2022. 12. 5. 19:59

마야 프로그램에서 모델을 불러와야 하지만, 없기 때문에 불러오는 법은 생략 하겠습니다. ㅎㅎ;;

 

Cube.obj

# This file uses centimeters as units for non-parametric coordinates.

mtllib cube.mtl
g default
v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.998008 0.998008
vt 0.001992 0.998008
vt 0.998008 0.001992
vt 0.001992 0.001992
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
s 1
g pCube1
usemtl file1SG
f 1/1/1 2/2/2 3/3/3
f 3/3/3 2/2/2 4/4/4
s 2
f 3/13/5 4/14/6 5/15/7
f 5/15/7 4/14/6 6/16/8
s 3
f 5/21/9 6/22/10 7/23/11
f 7/23/11 6/22/10 8/24/12
s 4
f 7/17/13 8/18/14 1/19/15
f 1/19/15 8/18/14 2/20/16
s 5
f 2/5/17 8/6/18 4/7/19
f 4/7/19 8/6/18 6/8/20
s 6
f 7/9/21 1/10/22 5/11/23
f 5/11/23 1/10/22 3/12/24

위의 .obj모델 파일은 3D상의 육면체를 표현합니다. 8개의 정점, 24개의 텍스쳐 좌표와 법선 벡터, 그리고 6개의 면이 총 12개의 폴리곤을 구성합니다. 파일을 읽을 때 "V", "VT", "VN" 또는 "F"로 시작하지 않는 줄은 무시해도 됩니다. 파일의 추가적인 정보들은 우리 포멜으로 바꿀 때 필요하지 않습니다. 이제 각 중요한 줄들이 어떤 의미들인지 살펴보겠습니다.

 

1. "V"는 정점을 의미합니다. 육면체는 꼭지점이 8개 이므로 8개의 정점을 가집니다. 각각의 정점은 X, Y, Z의 float형 포맷으로 나열되어 있습니다.

 

2. "VT"는 텍스쳐 좌표를 의미합니다. 육면체에는 24개의 텍스쳐 좌표가 있고 대부분 육면체 모델의 모든 삼각형의 모든 정점에 대한 기록을 하기 때문에 중복되는 내용이 많습니다. 각 좌표에는 TU, TV로 float형 포멧입니다.

 

3. "VN"은 법선 벡터입니다. 육면체는 24개의 법선 벡터가 있고 역시 모든 삼각형의 모든 정점에 대한 기록을 하기 때문에 중복 되는 내용이 많습니다. NX, NY, NZ의 float형 포맷으로 나열되어 있습니다.

 

4. "F" 줄은 육면체 모델의 삼각형(표면)을 의미합니다. 나열된 값들은 정점의 순서(인덱스), 텍스쳐 좌표들, 그리고 법선 벡터들입니다. 각면의 포맷은 다음과 같습니다.
f 정점1/텍스쳐1/법선1 정점2/텍스쳐2/법선2 정점3/텍스쳐3/법선3
따라서 "f 3/13/5 4/14/6 5/15/7" 이라고 하는 라인은 "Vertex3/Texture13/Normal5 Vertex4/Texture14/Normal6 Vertex5/Texture15/Normal7" 로 해석할 수 있습니다.

 

.obj 파일에서의 데이터의 배치 순서는 매우 중요합니다. 예를 들어 파일의 첫번째 정점은 삼각형 리스트에서의 정점1에 해당합니다. 텍스쳐 좌표나 법선 벡터도 역시 동일합니다.

삼각형 라인을 보고 있다보면 라인마다 세 개의 인덱스 그룹들이 하나의 삼각형을 구성한다는 것을 알게 될 것입니다. 그리고 이 육면체의 경우 각 면마다 2개의 삼각형이 있어 총 12개의 삼각형이 육면체를 만들게 됩니다.

 

오른손 좌표계에서 왼손 좌표계로

마야 2011에서는 기본적으로 오른손 좌표계를 사용하며 .obj파일도 오른손 좌표계 체제로 내보냅니다. 이 데이터들을 DirectX 11의 기본인 왼손 좌표계로 바꾸기 위해서는 다음과 같이 해야 합니다.
1. 정점의 Z좌표를 뒤집습니다. 소스에서 다음과 같은 것을 볼 것입니다.
vertices[vertexIndex].z = vertices[vertexIndex].z * -1.0f
2. 텍스쳐 좌표의 TV를 뒤집습니다. 소스에서 다음과 같은 것을 볼 것입니다.
texcoords[texcoordIndex].y = 1.0f - texcoords[texcoordIndex].y;
3. 법선의 NZ를 뒤집습니다. 소스에서 다음과 같은 것을 볼 것입니다.
normals[normalIndex].z = normals[normalIndex].z * -1.0f;
4. 그리기 방향을 반시계방향에서 시계방향으로 바꿉니다. 소스에서는 순서를 재구성하기보다는 단순히 읽을 때 저장을 반대되는 순서로 하였습니다.
fin >> faces[faceIndex].vIndex3 >> input2 >> faces[faceIndex].tIndex3 >> input2 >> faces[faceIndex].nIndex3;
fin >> faces[faceIndex].vIndex2 >> input2 >> faces[faceIndex].tIndex2 >> input2 >> faces[faceIndex].nIndex2;
fin >> faces[faceIndex].vIndex1 >> input2 >> faces[faceIndex].tIndex1 >> input2 >> faces[faceIndex].nIndex1;
위 4단계를 거치면 DirectX 11에서 올바로 그려지는 모델 데이터가 완성됩니다.

main.cpp

#include <iostream>
#include <fstream>
using namespace std;

typedef struct
{
	float x, y, z;
}VertexType;

typedef struct
{
	int vIndex1, vIndex2, vIndex3;
	int tIndex1, tIndex2, tIndex3;
	int nIndex1, nIndex2, nIndex3;
} FaceType;

void GetModelFileName(char* fileName);
bool ReadFileCounts(char* fineName, int& vertexCount, int& textureCount, int& normalCount, int& faceCount);
bool LoadDataStructures(char* fileName, const int& vertexCount, const int& textureCount, const int& normalCount, const int& faceCount);

int main()
{
	bool result;
	char fileName[256];
	int vertexCount, textureCount, normalCount, faceCount;
	char garbage;

	GetModelFileName(fileName);

	result = ReadFileCounts(fileName, vertexCount, textureCount, normalCount, faceCount);
	if (result == false)
	{
		return -1;
	}

	cout << endl;
	cout << "Vertices : " << vertexCount << endl;
	cout << "UVs : " << textureCount << endl;
	cout << "Normals : " << normalCount << endl;
	cout << "Faces : " << faceCount << endl;

	result = LoadDataStructures(fileName, vertexCount, textureCount, normalCount, faceCount);
	if (result == false)
	{
		return -1;
	}

	cout << "\nFile has been converted." << endl;
	cout << "\nDo you wish to exit (y/n)" << endl;
	cin >> garbage;

	return 0;
}

void GetModelFileName(char* fileName)
{
	bool done;
	ifstream fin;

	done = false;
	while (done == false)
	{
		cout << "Enter model fileName : " ;
		cin >> fileName;

		fin.open(fileName);

		if (fin.good())
		{
			done = true;
		}
		else
		{
			fin.clear();
			cout << endl;
			cout << "File " << fileName << " could not be opened." << endl << endl;
		}
	}

	return;
}

bool ReadFileCounts(char* fileName, int& vertexCount, int& textureCount, int& normalCount, int& faceCount)
{
	ifstream fin;
	char input;

	vertexCount = 0;
	textureCount = 0;
	normalCount = 0;
	faceCount = 0;

	fin.open(fileName);

	if (fin.fail() == true)
	{
		return false;
	}

	fin.get(input);
	while (fin.eof() == false)
	{
		if (input == 'v')
		{
			fin.get(input);
			if(input == ' ') {vertexCount++;}
			if(input == 't') {textureCount++;}
			if(input == 'n') {normalCount++;}
		}

		if (input == 'f')
		{
			fin.get(input);
			if(input == ' ') {faceCount++;}
		}

		while (input != '\n')
		{
			fin.get(input);
		}

		fin.get(input);
	}

	fin.close();

	return true;
}

bool LoadDataStructures(char* fileName, const int& vertexCount, const int& textureCount, const int& normalCount, const int& faceCount)
{
	VertexType *vertices, *texcoords, *normals;
	FaceType *faces;
	ifstream fin;
	int vertexIndex, texcoordIndex, normalIndex, faceIndex, vIndex, tIndex, nIndex;
	char input, input2;
	ofstream fout;

	vertices = new VertexType[vertexCount];
	if (vertices == nullptr)
	{
		return false;
	}

	texcoords = new VertexType[textureCount];
	if (texcoords == nullptr)
	{
		return false;
	}

	normals = new VertexType[normalCount];
	if (normals == nullptr)
	{
		return false;
	}

	faces = new FaceType[faceCount];
	if (faces == nullptr)
	{
		return false;
	}

	vertexIndex = 0;
	texcoordIndex = 0;
	normalIndex = 0;
	faceIndex = 0;

	fin.open(fileName);

	if (fin.fail() == true)
	{
		return false;
	}

	// Read in the vertices, texture coordinates, and normals into the data structures
	// Important : Also convert to left hand coordinate system since Maya uses right hand coordinate system
	fin.get(input);
	while (fin.eof() == false)
	{
		if (input == 'v')
		{
			fin.get(input);

			// Read in th vertices
			if (input == ' ')
			{
				fin >> vertices[vertexIndex].x >> vertices[vertexIndex].y >> vertices[vertexIndex].z ;

				// Invert the Z vertex to change to left hand system
				vertices[vertexIndex].z = vertices[vertexIndex].z * -1.0f;
				vertexIndex++;
			}

			// Read in the texture uv coordinates.
			if(input == 't')
			{
				fin >> texcoords[texcoordIndex].x >> texcoords[texcoordIndex].y;

				// Invert the V texture coordnates to left hand system.
				texcoords[texcoordIndex].y = 1.0f - texcoords[texcoordIndex].y;
				texcoordIndex++;
			}

			// Read in the normals
			if (input == 'n')
			{
				fin >> normals[normalIndex].x >> normals[normalIndex].y >> normals[normalIndex].z;

				// Invert the Z normal to change to left hand system
				normals[normalIndex].z == normals[normalIndex].z * -1.0f;
				normalIndex++;
			}
		}

		if (input == 'f')
		{
			fin.get(input);
			if (input == ' ')
			{
				// Read the face data in backwards to convert it to a left hand system from right hand system.
				fin >> faces[faceIndex].vIndex3 >> input2 >> faces[faceIndex].tIndex3 >> input2 >> faces[faceIndex].nIndex3
				>> faces[faceIndex].vIndex2 >> input2 >> faces[faceIndex].tIndex1 >> input2 >> faces[faceIndex].nIndex2
				>> faces[faceIndex].vIndex1 >> input2 >> faces[faceIndex].tIndex2 >> input2 >> faces[faceIndex].nIndex1;

				faceIndex++;
			}
		}

		// Read in the remainder of the line
		while (input != '\n')
		{
			fin.get(input);
		}

		// Start reading the beginning of the next line
		fin.get(input);
	}

	// Close the file
	fin.close();

	// Open the output file
	fout.open("model.txt");

	// Write out the file header that our model format uses
	fout << "Vertex Count : " << (faceCount * 3) << endl;
	fout << endl;
	fout << "Data : " << endl;
	fout << endl;

	// Now loop through all the faces and output the three vertices for each face.
	for (int i = 0; i < faceIndex; i++)
	{
		vIndex = faces[i].vIndex1 - 1;
		tIndex = faces[i].tIndex1 - 1;
		nIndex = faces[i].nIndex1 - 1;

		fout << vertices[vIndex].x << ' ' << vertices[vIndex].y << ' ' << vertices[vIndex].z << ' '
			<< texcoords[tIndex].x << ' ' << texcoords[tIndex].y << ' '
			<< normals[nIndex].x << ' ' << normals[nIndex].y << ' ' << normals[nIndex].z << endl;

		vIndex = faces[i].vIndex2 - 1;
		tIndex = faces[i].tIndex2 - 1;
		nIndex = faces[i].nIndex2 - 1;

		fout << vertices[vIndex].x << ' ' << vertices[vIndex].y << ' ' << vertices[vIndex].z << ' '
			<< texcoords[tIndex].x << ' ' << texcoords[tIndex].y << ' '
			<< normals[nIndex].x << ' ' << normals[nIndex].y << ' ' << normals[nIndex].z << endl;

		vIndex = faces[i].vIndex3 - 1;
		tIndex = faces[i].tIndex3 - 1;
		nIndex = faces[i].nIndex3 - 1;

		fout << vertices[vIndex].x << ' ' << vertices[vIndex].y << ' ' << vertices[vIndex].z << ' '
			<< texcoords[tIndex].x << ' ' << texcoords[tIndex].y << ' '
			<< normals[nIndex].x << ' ' << normals[nIndex].y << ' ' << normals[nIndex].z << endl;
	}

	// Close the output file.
	fout.close();

	// Release the four data structures.
	if (vertices)
	{
		delete[] vertices;
		vertices = 0;
	}
	if (texcoords)
	{
		delete[] texcoords;
		texcoords = 0;
	}
	if (normals)
	{
		delete[] normals;
		normals = 0;
	}
	if (faces)
	{
		delete[] faces;
		faces = 0;
	}

	return true;
}

출력화면

'DirectX' 카테고리의 다른 글

9. 정반사광  (0) 2022.12.13
8. 주변광  (0) 2022.12.06
6. 3D 모델 렌더링  (0) 2022.11.26
5. 조명  (0) 2022.11.21
4. 텍스쳐  (0) 2022.11.11
    'DirectX' 카테고리의 다른 글
    • 9. 정반사광
    • 8. 주변광
    • 6. 3D 모델 렌더링
    • 5. 조명
    튀김족발
    튀김족발

    티스토리툴바