现在的位置: 首页 > 综合 > 正文

大战2013之六:解决3DSMax右手坐标系转换左手坐标系的问题

2013年12月12日 ⁄ 综合 ⁄ 共 2392字 ⁄ 字号 评论关闭

开发过程中,遇到了模型颠倒和纹理错位等现象。

 

由于一个人搞确实太累,还要为老板做事,那是必须做的事情,所以有时候思考问题不到位,曾几何时竟然还怀疑过discreet

当然我最怀疑的是汉化版的翻译问题,最后一一排除了这些怀疑以后,我理清了思路,并把过程跟大家分享一下。

 

我们先看下我问题出现的过程:

1.首先建立一个长方体,一个一个面去选择,如图选择顶面

再选择前面

有了上面,前面,左右大家应该知道是哪个方向了吧。

然而,事实让人无法理解。

丫的居然在这边,这3dsMax不是操蛋吗?搞什么东西嘛。

左图是DirectX常用的左手坐标系,有图是右手坐标系,如OpenGL或3dsMax(Max是旋转了的,解析几何中一般也是用右手)

由于大学时候认为高等数学没什么用,所以根本没去学,以致从高数到立体几何一连串挂科……

 

现在Max究竟是哪种坐标系都完全懵了。

作为技术人员,我们是不会臣服与任何科学理论知识的,尽信书则不如无书,父老常讲……

什么都不知道的好处之一就是可以持着怀疑的态度去考究新的知识。

 

现在我就不纠结于这些理论了,因为我也不能保证我的理解是完全正确的,以免误人子弟。

总之根据理论来计算式很难了,我现在给大家说说我的解决过程。

 

我换了老一点的Max版本,回到古董7.0版。首先最大化透视图,隐藏栅格:

然后创建三条直接,染色为红绿蓝,代表三条轴,进入顶点编辑,把坐标设在+100和-100.

如第一条红线代表X轴,两端坐标是(-100,0,0)和(100,0,0),一次类推……

创建一个多边形,边数设为3,然后进入顶点编辑,把1点(A点放在X=50上),2点在Y轴,3点在Z轴,为ABC三点,如图:

(把曲面步数设为1,调整的时候面就不会扭曲了)

然后我们展开UVW坐标,编辑纹理UV(垂直坐标V是倒置的,跟位图一样,后面会说)

调整ABC点到对应的坐标,注意对应好点的顺序,否则你试验的结果会与我不同。

当然,我保留了试验的Max文件,需要的朋友可以传给TA

开启背面消隐,然后渲染这个视口得到正常下Max的右手坐标系中的结果

然后我换到左手坐标系中来,具体过程是:X方向一致,交换Y和Z轴的坐标值,即:

A(50,0,0)B(0,0,50),C(0,50,0

红色部分是新的坐标值,我们会发现,视口中的三角形消失了

三个点还在那里,但是图形消失,那是因为背面消隐的缘故,旋转下视角就看到了。

现在的问题是,我们换到左手坐标系中观察。

我们变换了坐标轴的意义以符合左手左边系,而三角形的顺序也必须跟着换(除非我们关闭背面消隐,那样的话每个三角形要渲染两次)
变换后的坐标相当于原来的ABC变成了ACB,因此对应后来的定点顺序应该是ACB就相当于原来的顺序了,当然UV坐标还有必要说一下。

现在,导出3DS文件还是像展开UVW编辑界面一样,在垂直方向是反过来的。就好比如,你设计一个地球模型,但是结果地球是倒立的;
设计一个人,不是头朝下,而脸贴到脚上去了……(注意,不是屁股,除非人坐在平地上)
看下运行效果,那个还是半成品的飞船(不好看,需要专门设计一下,当然只是需要设计下):

 

那么,解决的方法有两种:
一种是将贴图文件垂直翻转,这个Windows画图工具都能做。
另外一种是读取V坐标的时候,用1减去读取到的V坐标,即原来0变1,1变0,原来0.3变0.7……

如果关闭背面消隐,可以不考虑顶点顺序,不过贴图可能会错乱,最起码,标题那里不会是442,而应该是221左右。
也就是每秒渲染的帧数会减半……

下面是读取到3ds文件数据后,转化为顶点列表的部分代码:

	// pVert 是3ds文件的顶点列表,直接读取到内存,按XYZ三个浮点的结构存储
	// pMap 是3ds文件的纹理坐标列表,按UV两个浮点结构存储
	// pFace 是3ds文件的面列表,按ABC三个顶点的索引存储,每个索引是一个WORD
	for(dwLoop = 0; dwLoop < dwNum; dwLoop++)
	{	// 有人说字节是逆过来的,其实x86的cpu都是这样存储数据的
		// 就是高高低低,低字节在低地址,高字节在高地址
		dwRet = dwLoop * 3;
		pGameVert[dwRet].PosX = pVert[pFace->Index1].X;
		pGameVert[dwRet].PosY = pVert[pFace->Index1].Z;
		pGameVert[dwRet].PosZ = pVert[pFace->Index1].Y;
		pGameVert[dwRet].uPos = pMap[pFace->Index1].U;
		pGameVert[dwRet].vPos = 1.0f - pMap[pFace->Index1].V;
		dwRet++;
		pGameVert[dwRet].PosX = pVert[pFace->Index3].X;
		pGameVert[dwRet].PosY = pVert[pFace->Index3].Z;
		pGameVert[dwRet].PosZ = pVert[pFace->Index3].Y;
		pGameVert[dwRet].uPos = pMap[pFace->Index3].U;
		pGameVert[dwRet].vPos = 1.0f - pMap[pFace->Index3].V;
		dwRet++;
		pGameVert[dwRet].PosX = pVert[pFace->Index2].X;
		pGameVert[dwRet].PosY = pVert[pFace->Index2].Z;
		pGameVert[dwRet].PosZ = pVert[pFace->Index2].Y;
		pGameVert[dwRet].uPos = pMap[pFace->Index2].U;
		pGameVert[dwRet].vPos = 1.0f - pMap[pFace->Index2].V;
		pFace++;
	}

ok!

抱歉!评论已关闭.