마야 프로그램에서 모델을 불러와야 하지만, 없기 때문에 불러오는 법은 생략 하겠습니다. ㅎㅎ;;
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개의 삼각형이 육면체를 만들게 됩니다.
오른손 좌표계에서 왼손 좌표계로
vertices[vertexIndex].z = vertices[vertexIndex].z * -1.0f
texcoords[texcoordIndex].y = 1.0f - texcoords[texcoordIndex].y;
normals[normalIndex].z = normals[normalIndex].z * -1.0f;
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;
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 |