跳轉到內容

DirectX/10.0/Direct3D/載入 Maya

來自 Wikibooks,開放世界開放書籍

本教程將介紹如何從 Maya 2011 匯入靜態 3D 模型。請注意,本教程將重點介紹 Maya,但它也適用於幾乎任何其他 3D 建模軟體包,只需稍微修改一下。

在之前的教程中,我們已經建立了自己的模型格式並使用該格式渲染了 3D 模型。現在的目標是將 Maya 2011 模型轉換為我們的格式並渲染它們。我不會詳細介紹如何在 Maya 中建模 3D 物件,因為網路上已經存在數百個專門針對該主題的教程,我們將從您擁有一個已紋理化和三角化的 3D 模型準備匯出開始。

對於 Maya 匯出格式,我們將使用 .OBJ 格式,因為它易於閱讀,非常適合初學者入門。

要在 .obj 格式中匯出您的模型,您必須首先在 Maya 中啟用 .OBJ 匯出器。點選“視窗”,然後點選“設定/首選項”,然後點選“外掛管理器”。向下滾動到 objExport.mll 並選擇“已載入”和“自動載入”。現在要以這種格式匯出您的模型,請點選“檔案”,然後點選“全部匯出”。現在在底部選擇“檔案型別:”並向下滾動並選擇“OBJexport”。為其指定一個檔名,然後點選“全部匯出”,它將將其匯出到具有 .obj 副檔名的文字檔案中。要檢視該檔案,您可以右鍵點選並選擇“開啟方式”,然後選擇 WordPad 閱讀該檔案。然後您將看到類似以下內容的內容

# 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”開頭的所有行。檔案中額外的資訊將不需要用於將 .obj 轉換為我們的檔案格式。讓我們看看每條重要行是什麼意思

1. “V”行用於頂點。立方體由 8 個頂點組成,代表立方體的八個角。每個頂點都以 X、Y、Z 浮點格式列出。

2. “VT”行用於紋理座標。立方體有 24 個紋理座標,其中大多數是重複的,因為它記錄了立方體模型中每個三角形的每個頂點的紋理座標。它們以 TU、TV 浮點格式列出。

3. “VN”行用於法線向量。立方體有 24 個法線向量,其中大多數是重複的,因為它記錄了立方體模型中每個三角形的每個頂點的法線向量。它們以 NX、NY、NZ 浮點格式列出。

4. “F”行用於立方體模型中的每個三角形(面)。列出的值是頂點、紋理座標和法線向量的索引。每個面的格式為

f Vertex1/Texture1/Normal1 Vertex2/Texture2/Normal2 Vertex3/Texture3/Normal3

因此,一條說“f 3/13/5 4/14/6 5/15/7”的行則轉換為“Vertex3/Texture13/Normal5 Vertex4/Texture14/Normal6 Vertex5/Texture15/Normal7”。

.obj 檔案中資料列出的順序非常重要。例如,檔案中第一個頂點對應於面列表中的 Vertex1。紋理座標和法線也是如此。

檢視 .obj 檔案中的面行,請注意每行三個索引組構成一個三角形。在這個立方體模型的情況下,12 個總面組成了立方體的 6 個面,每個面有 2 個三角形。

右手到左手轉換

[編輯 | 編輯原始碼]

預設情況下,Maya 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;

完成這四個步驟後,模型資料將準備好在 DirectX 11 中正確渲染。

將 Maya 2011 .obj 檔案轉換為 DirectX 11 格式的程式非常簡單,它是一個名為 main.cpp 的單個程式檔案。它開啟一個命令提示符並詢問要轉換的 .obj 檔案的名稱。一旦使用者輸入了名稱,它將嘗試開啟該檔案並讀取資料計數,並構建讀取資料所需的結構。之後,它將資料讀入這些結構並將它們轉換為左手系統。完成後,它將資料寫入 model.txt 檔案。然後,可以重新命名該檔案並在 DirectX 11 中使用,使用之前教程中的 3D 模型渲染專案。

////////////////////////////////////////////////////////////////////////////////
// Filename: main.cpp
////////////////////////////////////////////////////////////////////////////////


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


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

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


/////////////////////////
// FUNCTION PROTOTYPES //
/////////////////////////
void GetModelFilename(char*);
bool ReadFileCounts(char*, int&, int&, int&, int&);
bool LoadDataStructures(char*, int, int, int, int);


//////////////////
// MAIN PROGRAM //
//////////////////
int main()
{
	bool result;
	char filename[256];
	int vertexCount, textureCount, normalCount, faceCount;
	char garbage;


	// Read in the name of the model file.
	GetModelFilename(filename);

	// Read in the number of vertices, tex coords, normals, and faces so that the data structures can be initialized with the exact sizes needed.
	result = ReadFileCounts(filename, vertexCount, textureCount, normalCount, faceCount);
	if(!result)
	{
		return -1;
	}

	// Display the counts to the screen for information purposes.
	cout > garbage;

	return 0;
}


void GetModelFilename(char* filename)
{
	bool done;
	ifstream fin;


	// Loop until we have a file name.
	done = false;
	while(!done)
	{
		// Ask the user for the filename.
		cout > filename;

		// Attempt to open the file.
		fin.open(filename);

		if(fin.good())
		{
			// If the file exists and there are no problems then exit since we have the file name.
			done = true;
		}
		else
		{
			// If the file does not exist or there was an issue opening it then notify the user and repeat the process.
			fin.clear();
			cout > 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 coordinates 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++; 
			}
		}

		// Read in the faces.
		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].tIndex2 >> input2 >> faces[faceIndex].nIndex2
				    >> faces[faceIndex].vIndex1 >> input2 >> faces[faceIndex].tIndex1 >> 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 

現在,我們可以將 Maya 2011 .obj 檔案轉換為我們的簡單模型格式。

待辦事項練習

[編輯 | 編輯原始碼]

1. 重新編譯該程式,並使用提供的 .obj 模型檔案執行它。

2. 建立(或讓其他人為您建立)一個 Maya 2011 模型,並將其匯出為 .obj 格式,然後執行此程式進行轉換。

3. 將此程式碼轉換為讀取和匯出您可能喜歡的其他模型格式。

華夏公益教科書