关于对静态模型(.x)做的地形高度检测的研究(mesh顶点转换数组,射线与模型的相交检测)

        这几天一直在研究怎样取得由静态模型(.x)所建立的地形中取得对应坐标的高度值。期间研究了很多的问题,.x文件的格式,从mesh的buffer中读取得到其顶点信息,射线跟面的相交检测等等。最后终于做了个实验模型出来了,现在在这里总结一下经验,以及期间发现的一些已解决,未解决的问题。希望各位如果发现文章中有什么需要改善或者不对的地方,指出来一起研究。

        首先要从.x格式讲起。

        由于.x格式真要讲的话,就这一点也能写一篇很长的文章了,而且在Gameres就已经有高手写了一篇很详尽的了,在这里我就只是说一些简单的,我知道的一些,如果想详细研究的,这里给出地址:

        http://www.gameres.com/document.asp?TopicID=47493

        用3dmax建好模型后,用熊猫插件输出.x文件~记得选择输出为text文件的,如果选择输出为二进制(Binary)的,那么你用记事本打开的时候就只会看到很多乱码,当然,文件体积小了,但不方便我们研究。

        用记事本打开.x文件后,你会看到很多含template关键字的模板。

        例如:

        template Mesh

       {
        <3d82ab44-62da-11cf-ab39-0020af71e433>
        DWORD nVertices; //顶点数量
        array Vector vertices[nVertices];  //顶点数组
        DWORD nFaces;  //面片个数
        array MeshFace faces[nFaces]; //面片数组
        [...]
       }

        这个就告诉你对应模板名称的模板里面是怎么定义的

        这里的模板名称为Mesh,

        我们再找到对应的~

        Mesh  {
          5;    //对应模板中的DWORD nVertices(顶点数量)
          -1068.06445;0.000000;-80.981415;,   //对应array Vector vertices[nVertices](顶点数组)
          1057.55237;6.156775;-80.981415;,
          -1068.06445;0.000000;-26.824957;,
          -537.72321;-2.920163;-25.445328;,
          1057.55249;6.156775;-25.445328;,

          4;  //对应DWORD nFaces;  //面片个数
          3;2,8,0;,  //对应array MeshFace faces[nFaces]; //面片数组
          3;2,5,10;,
          3;3,6,16;,
          3;9,8,11;,

           }

 

        由上面我们可以知道这个.x文件时由5个点,4个面组成。并且第一个面由2,8,0三个点组成。(因为太多点,篇幅太长,所以我删了一些点,改了一下点的总数那些数据,所以可能你会有疑问,怎么总共就5个点,第一个面却由2,8,0,这第八个点是怎么来的。其实只是被我删了改了一下数据,大家理解就好。)

         ps:这里虽然不相干,但是因为发现身边以及网上都有很多人问道关于贴图的问题,附加说一下.x文件内部的贴图。

              由direct读取.x的知识我们知道,.x内部是不储存纹理文件的,只储存一个纹理的名字(准确点讲是路径,如果你输出的.x文件使

         用绝对路径的话)。

              而纹理名称是储存在.x的材质中的。

              通过在.x文件中搜索纹理的文件名我们可以找到这个纹理所在的材质模板。

              如“头副本”:

                    Material PDX23_-_Default {
                     1.000000;1.000000;1.000000;1.000000;;
                     3.200000;
                     0.000000;0.000000;0.000000;;
                     0.000000;0.000000;0.000000;;

                     TextureFilename {
                      "/315/头3/270/副/261/本.jpg";
                     }

               “PDX23”是这个材质的名字,后面会用到。

               下面的"/315/头3/270/副/261/本.jpg"就是我们“PDX23”材质中的纹理的名称了,要注意的是!很多朋友说用3dmax导出.x文

          件后无法贴图,这是因为你的纹理名称使用了中文命名的缘故,可能因为一些字符转换的原因,DIRECTX在读取纹理名称的时候不能

          正确读取以中文命名的纹理文件,所以就会导致了无法贴图。以我现在的技术水平,我能想到的解决方法只有:

                    1.让你的美工人员在更改贴图名称为英文名称再重新生成文件。

                    2.。。。。自己手工更改,自己动手,风衣足食。

               这里说一下手工更改的方法。

               这里就将"/315/头3/270/副/261/本.jpg";本去掉,然后改为"head.jpg"然后你的纹理文件名称也改为"head.jpg"......其实

          就系这么简单。

 

               然后我不知道大家有没有遇到过。生成的.x文件就算名称都是用英文的,但是有些地方会出现纹理错误的状况,就是这个地方本来

          应该贴草地的贴图,但是现在却变成了水的纹理。

               这个。。。我想原因是因为输出.x的时候一些设置不正确而导致的。至于应该怎么设置才正确,这个我也还未知道,但是我们可以

          在.x文件内部去更改。

              在用于表示模型中每一个物体的Frame模板内部,都可以找到一个“MeshMaterialList”

              例如上面的例子中我们通过搜索该材质的名称“PDX23_-_Default”可以找到,该纹理是位于文件中“Frame pPlane08”物体模

          板里面的其中,“pPlane08”对应你在3dmax中该物体使用的名字,你可以通过打开3dmax中的层管理器展开查看对应的是什么物

          体。

MeshMaterialList  {
                 1;           //材质数量
                 12;         //该材质对应的面数
                 0,          //面索引数组
                 0,
                 0,
                 0,
                 0,
                 0,
                 0,
                 0,
                 0,
                 0,
                 0,
                 0;
                 { PDX23_-_Default }  //对应的材质

              }

            通过更改这里的“对应材质”以及上面的纹理名称就可以达到更改纹理或者更改材质的效果了。

        现在开始说读取高度坐标。

        我的思路是,先去取得.x导进来的mesh文件中的buffer然后再将buffer内的顶点信息放到一个顶点数组中,然后找到指定点位于mesh网格中的哪一个面片,然后由该面片所组成的三个顶点用线性插值求得高度y的值。

       首先将顶点输出到数组。

       

         这里要

        1.先构造一个顶点灵活格式的数组。

        2.再用自定的顶点灵活格式将mesh复制一个出来。

        3.再用新复制的mesh去去得他的顶点缓存。

        这里要说一下lock跟顶点的赋值,用上面的方法锁定缓存并赋值后,我调试的时候发现,虽然成功赋值到顶点数组中了~但是里面的顶点信息跟.x文本打开查看的点位置不一样~在网上看到一些人说是导入的时候经过d3d优化了~

        到这里都不是问题然后当我用相同的方式(声明一个DWORD * index,然后用去得的索引缓存去lock然后赋值)但是我在调试的时候发现得到的索引值为4862,我那个模型只是一个很简单的面片,不可能有那么多的索引值~所以当我尝试将索引值放到顶点数组中使用的时候就出错了~

       这里给出我出错的代码

      

       想了很久找不到原因,望各位高手指出其中的问题。

       于是我原本的设想的实现在这一步受到很大的阻碍,但是后来我发现了一个在d3d中很有用的函数,D3DXIntersect。

       这个函数的原型是

       HRESULT D3DXIntersect(
         LPD3DXBASEMESH pMesh,   //模型文件
         CONST D3DXVECTOR3 * pRayPos,  //一个射线的发出点
         CONST D3DXVECTOR3 * pRayDir,   //射线的方向向量
         BOOL * pHit,  //这条射线是否跟这个MESH相交?
         DWORD * pFaceIndex,  //返回跟射线相交的面的最近射线点。
         FLOAT * pU,  // 射线跟相交面的U分量
         FLOAT * pV,  //射线跟相交面的V分量
         FLOAT * pDist, 射线起始点到相交点的距离 
         LPD3DXBUFFER * ppAllHits,  //如果相交的面不止一个,返回所有相交点所组成的缓存的指针。
         DWORD * pCountOfHits  //如果相交的面不止一个,相交点的数目。
       );

       有了这个函数碰撞检测,地形高度这些都不是问题了。

 

       先定义一个高度的最大值。x,z坐标我这里是我摄像机的坐标,取得了y的高度后,就可以做到画面跟着地形起伏而起伏的效果。

       一直想要求得的高度坐标就是你定义的最大高度值,减去相交检测返回的距离pDist。

       其中使用上面的D3DXIntersect函数要注意的是,定义向量的时候,向量的长度即为返回的pDist的一个单位的距离。

       我的GETHEIGHT函数

      

 

 

 

       由于开始学习不久,还有很多不会的地方,就总结的目的写了这篇文章,希望各位能指出文中不好的地方,教导我更好的方法,一起交流,一起学习。

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值