读书人

大战2013之六:解决3DSMax右手坐标系转

发布时间: 2013-03-01 18:33:02 作者: rapoo

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

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

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

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

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

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

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

再选择前面

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

// pVert 是3ds文件的顶点列表,直接读取到内存,按XYZ三个浮点的结构存储// pMap 是3ds文件的纹理坐标列表,按UV两个浮点结构存储// pFace 是3ds文件的面列表,按ABC三个顶点的索引存储,每个索引是一个WORDfor(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!

2楼liu765023051昨天 22:05
专业
Re: prsniper昨天 05:14
回复liu765023051n看你这动作我都想搞个纪录片:天外飞仙。n心有余力不足啊,我想第一个版本应该是:星河战队。ndemo还是漫游为主吧。
1楼jiangcaiyang123前天 08:38
只是更改了顶点的坐标,但是似乎忘记了3ds文件中还有模型矩阵这个信息。你是只想读取模型而不导入模型矩阵吗?
Re: prsniper昨天 19:29
回复jiangcaiyang123n只有顶点数据就够了,不播放Max动画何必要其他的呢,discreet并没有官方文档,解析3ds文件的做法不太正规,也不是首选,做游戏解析maya或者ae格式的最多

读书人网 >编程

热点推荐