开发过程中,遇到了模型颠倒和纹理错位等现象。
由于一个人搞确实太累,还要为老板做事,那是必须做的事情,所以有时候思考问题不到位,曾几何时竟然还怀疑过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!