跳转到内容

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. 将此代码转换为读取和导出您可能喜欢的其他模型格式。

华夏公益教科书