以前由于任务要求,曾对编写仿真环境中有简单的了解。

而三维转二维通过一定的转化时可以实现的,其中大多游戏引擎都是经过以下四步:

1.世界转换。世界转换是从物体的相对坐标转为世界坐标,包含物体以哪条轴转动及平移

2.相机转换。相机转换相当于人眼的观察方向。

3.投影转换。投影变换时三维转二维的重要步骤,是把物体投影到垂直于相机的平面,其中分为正投影及透视投影。

4.视角变换。是将其按照投影后平面与计算机屏幕关系进行线形插补得出图像。

从而一个点(X,Y,Z)变为(Sx,Sy)

对于三维转二维,重要的计算机应用为鼠标的拾取,在网上大多数都有教程及数学关系的转换,本文不再提及。

其中拾取的主要思想为以相机作为原点,以鼠标点击的点作为向量,其中得出的点向式射线与三角形进行相交判断。

其中

假设图形程序窗口的宽为ScreenWidth,高为ScreenHeigh

Px=(ScreenWidth.x-ScreenWidth/2)/ScreenWidth*2

py=(-ScreenWidth.y-ScreenHeigh/2)/ScreenHeigh*2

pz=0

得出在投影面上的点后,由于三维点是通过上面四大变换中的4个矩阵的相乘的出二维点的,所以二维点得出三维点为上面矩阵的逆矩阵,

其中已存在的矩阵可通过g_pd3dDevice->GetTransfrom()函数得出相对应的投影矩阵及相机矩阵,然后通过D3DXMatrixInverse函数得出矩阵的逆,将点相乘便可得出三维点。

后面有很多文章推荐使用D3D的拓展函数D3DXIntersect快速检测三角形,但我以前却发现使用该函数得出的结果不正确,不知道是哪方面出现问题,一天后也得不出自己的想要的结果。无奈,只能采用别的办法。

以下为主要思想:通过D3D中的D3DXIntersectTri函数检测,该函数能正确检测结果,但需要自己把三角形的三个顶点及射线输进为参数。

通过.X文件读取三维模型中的所有三角形的顶点数据,根据其索引找到每个三角形对应的顶点,以下为部分代码

int ReadXFile(IDirect3DDevice9* pd3dDevice)
{MaterixSet(pd3dDevice);//先调到初始矩阵,读取世界矩阵,方便将从网格取出的局部坐标转为世界坐标char Buf[2000] = {0};//存放临时一行总元素数组,这个要足够大内存空间,否则内存太小读不完一直循环std::string TxtA;//临时存放的文本unsigned short VertMount = 0,i = 0,mount = 0;//顶点的数目,循环数目,顶点分割循环数目unsigned short VertInxMount = 0;//获取顶点索引数目char A[20] = {0};//定义一个临时数组存放临时内容char token[100]={0};//复制一行的数组到分割数组中char *tokenremain = token;//获得原始字符串指针,但该指针可变,适应下文分割语句char *tok1 = NULL;//分割后存坐标数值得指针char* BufZ = NULL;//临时存放读取的字符串比较//取得D3D初始世界矩阵模块D3DXMATRIX matWorld ;//获得观察矩阵,世界矩阵pd3dDevice->GetTransform(D3DTS_WORLD,&matWorld);//获得了世界矩阵//获取面模块unsigned short a = 0,b = 0,c = 0;//临时获取相对应面的顶点的索引的变量,用于放进数组中//获取.X文件内部矩阵模块std::string JuZhen;//源字符串float m[17]={0};//矩阵元素std::string B;//临时存放分割的数组Vert VertRHWTran;//矩阵转换临时存放结果,防止坐标值结果影响正在的计算std::ifstream fn("MaTong.x",std::ios::_Nocreate);//打开文件if (fn.fail() == 1)//检查文件是否失败{std::cerr<<"error opening the File\n"<<std::endl;}while(fn.eof() != 1)//文件没到尾就一直读取{fn.getline(Buf,sizeof(Buf));BufZ = Buf;//获取.X文件内部矩阵模块if(strcmp(BufZ," FrameTransformMatrix {") == 0)//检测字符串是否相等,读矩阵{fn.getline(Buf,sizeof(Buf));JuZhen = Buf;for (i = 1;i< 16;i++){mount = JuZhen.find(",",0);//首先找到分割符B = JuZhen.substr(0,mount);//取分割符前的m[i] = atof(B.c_str());//将字符串变为数字,JuZhen = JuZhen.substr(mount+1);//去掉已分割的字符串}m[16] = atof(JuZhen.c_str());//最后将剩下的一个不能分割的字符串转变为数字,完成全部提取}//获取顶点坐标及索引总模块if(strcmp(BufZ," Mesh  {") == 0)//检测字符串是否相等,读顶点{fn.getline(Buf,sizeof(Buf));BufZ = Buf;VertMount = atoi(BufZ);//获取顶点数目//获取顶点数目模块for ( i = 0;i < VertMount;i++){fn.getline(Buf,sizeof(Buf));strncpy( token, Buf, 50); // 最后一个位置为\0保留*/,复制指针内容到数组里去//分割坐标字符串模块tok1 = strtok(tokenremain,";");//第一次分割字符串,将,改变为\0,作用先跳一行strncpy( A, tok1, 19); // 将文本拷贝到数组VertRHW[i].x = atof(A);//获取x值for (mount = 0; mount < 2;mount++){tok1 = strtok(NULL,";");//继续分割字符串,指针改为空,停留strncpy( A, tok1, 19); // 将文本拷贝到数组switch(mount){case 0: VertRHW[i].y = atof(A);break;//赋值y值case 1:VertRHW[i].z = atof(A);break;//赋值Z值default:                  ;break;//其余为空语句,防止出错}    }   }//.X文件内部顶点矩阵装换模块for ( i = 0;i < VertMount;i++){VertRHWTran.x = VertRHW[i].x;VertRHWTran.y = VertRHW[i].y;VertRHWTran.z = VertRHW[i].z;//临时存放结果,防止矩阵转换时影响计算VertRHW[i].x = VertRHWTran.x*m[1]+VertRHWTran.y*m[5]+VertRHWTran.z*m[9]+m[13];VertRHW[i].y = VertRHWTran.x*m[2]+VertRHWTran.y*m[6]+VertRHWTran.z*m[10]+m[14];VertRHW[i].z = VertRHWTran.x*m[3]+VertRHWTran.y*m[7]+VertRHWTran.z*m[11]+m[15];}D3D世界矩阵,使其局部坐标变为世界坐标//for ( i = 0;i < VertMount;i++)//{//  VertRHWTran.x = VertRHW[i].x;VertRHWTran.y = VertRHW[i].y;VertRHWTran.z = VertRHW[i].z;//临时存放结果,防止矩阵转换时影响计算// VertRHW[i].x = VertRHWTran.x*matWorld._11+VertRHWTran.y*matWorld._21+VertRHWTran.z*matWorld._31+matWorld._41;// VertRHW[i].y = VertRHWTran.x*matWorld._12+VertRHWTran.y*matWorld._22+VertRHWTran.z*matWorld._32+matWorld._42;// VertRHW[i].z = VertRHWTran.x*matWorld._13+VertRHWTran.y*matWorld._23+VertRHWTran.z*matWorld._33+matWorld._43;//}//获取顶点索引模块fn.getline(Buf,sizeof(Buf));BufZ = Buf;VertInxMount = atoi(BufZ);//获取顶点索引数目for (i = 0;i < VertInxMount;i++){fn.getline(Buf,sizeof(Buf));strncpy( token, Buf, 50); // 最后一个位置为\0保留*/,复制指针内容到数组里去//将多少个点与索引模块隔离模块tok1 = strtok(tokenremain,";");//第一次分割字符串//提取顶点索引模块for (mount = 0;mount < 3 ; mount++){tok1 = strtok(NULL,",");//第一次分割字符串,将,改变为\0,作用先跳一行strncpy( A, tok1, 19); // 将文本拷贝到数组VertInxRHW[3*i+mount] = atoi(A);//依次获取索引值}}fn.close();//获取完索引,关闭文件//综合结合顶点及索引的面模块MianMount = VertInxMount;for (mount= 0;mount < MianMount;mount++)//第几个面{for(i = 0;i < 3;i++){a = VertInxRHW[i+3*mount];switch (i){case 0 :VertMian[mount].Vertor1 = VertRHW[a];break;case 1 :VertMian[mount].Vertor2 = VertRHW[a];break;case 2 :VertMian[mount].Vertor3 = VertRHW[a];break;default:                                    ;break;}}}return 1;//完成所有信息的提取,跳出函数,减小计算,返回1表示正常}}fn.close();//关闭文件return(0);//返回0,表示异常,没有获取顶点与索引
};

获取三角形后根据D3DXIntersectTri函数检测其与所有三角形是否相交,并保留最小的相交的距离的三角形,该三角形即为该鼠标拾取的三角形。以下为部分代码

//初始化参数INTERSECTION g_IntersectionArray; // 临时存放相交面的总信息D3DXVECTOR3 vPickRayDir;//拾取向量D3DXVECTOR3 vPickRayOrig;//拾取起点float uz = 0.0,vz = 0.0;//击中三角形相交点的权重float distanceZ = 0.0;//距离BOOL bInt = FALSE;//是否该面相交标志g_IntersectionArray.dis = 0.0;//初始化相交距离PointAB JixiebiAB;D3DXVECTOR3 Vectorz1;//三角形第一点D3DXVECTOR3 Vectorz2;//三角形第二点D3DXVECTOR3 Vectorz3;//三角形第三点D3DXVECTOR3 Vectorzz;//三角形相交点//循环参数初始化unsigned short mount = 0;//循环三角形面的次数float AngleMount = 0.0;//角度的变量unsigned short YuanMount = 0;unsigned short SuiMount = 0;for (SuiMount = 0; SuiMount < 30 ; SuiMount++){for( YuanMount = 0; YuanMount < 360; YuanMount++ )//圆周循环次数{//初始化参数g_IntersectionArray.dis = 0;//初始化击中距离用于判断!!必须,否则上一个的距离影响下一个的判断bInt = FALSE;//不与面相交if (SuiMount % 2 == 0)//180度顺时针与逆时针旋转{AngleMount =PI+0.5*YuanMount*(PI/180);//逆时针加旋转角度} else{AngleMount =-0.5*YuanMount*(PI/180);//顺时针加旋转角度}uz = 0.0,vz = 0.0;// 射线转换vPickRayDir.x = -1.0*sin(AngleMount);//射线向量点vPickRayDir.y = 0.0;vPickRayDir.z = -1.0*cos(AngleMount);vPickRayOrig.x = 1000.0*sin(AngleMount);//射线起点,设置相机为300的位置观察vPickRayOrig.y = 770+SuiMount;//加一点高度避免射线同时点到底部三角形的边,而重心公式反推三维公式不适用vPickRayOrig.z = 1000.0*cos(AngleMount);D3DXVec3Normalize( &vPickRayDir, &vPickRayDir);  //单位化向量   for (mount = 0; mount < MianMount;mount++)//历遍全部面返回与射线相交最短距离的面{Vectorz1.x = VertMian[mount].Vertor1.x;Vectorz1.y = VertMian[mount].Vertor1.y;Vectorz1.z = VertMian[mount].Vertor1.z;Vectorz2.x = VertMian[mount].Vertor2.x;Vectorz2.y = VertMian[mount].Vertor2.y;Vectorz2.z = VertMian[mount].Vertor2.z;Vectorz3.x = VertMian[mount].Vertor3.x;Vectorz3.y = VertMian[mount].Vertor3.y;Vectorz3.z = VertMian[mount].Vertor3.z;bInt = D3DXIntersectTri(&Vectorz1, &Vectorz2, &Vectorz3, &vPickRayOrig, &vPickRayDir,&uz, &vz, &distanceZ);if( bInt ){g_dwIntersections = TRUE;if (g_IntersectionArray.dis == 0)//初始化获取与第一个相交面的距离{g_IntersectionArray.dis = distanceZ;}if (distanceZ <= g_IntersectionArray.dis )//判断上一个面与下一个面相交距离,返回相交距离的最小值{g_IntersectionArray.Vector1 =Vectorz1;g_IntersectionArray.Vector2 =Vectorz2;g_IntersectionArray.Vector3 =Vectorz3;g_IntersectionArray.u =uz;g_IntersectionArray.v =vz;g_IntersectionArray.MianNumMount = mount;g_IntersectionArray.dis = distanceZ;}}}

其中要注意.X文件中获取的点不是真正的点,要乘上.X文件中的内部矩阵转换后才是真正的点,内部矩阵位置格式如下图

Frame o {

FrameTransformMatrix {
  1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,61.909517,0.175235,-34.152534,1.000000;;
 }
经测试,此方法可行,能实现拾取功能,但运算量太大,实用性不高,但在不考虑时间成本的前提下,也是一种方法。

个人观点,新手,错了希望提出,会改正。代码下载点击作者的上传的资源即可找到

关于DirectX中的三角形拾取的的另一种方法相关推荐

  1. 页面中如何引用外部的HTML(四种方法)

    页面中如何引用外部的HTML(四种方法) 一.总结 一句话总结:a.iframe标签        b.ajax引入代码片段        c.link import的方法导入        d.re ...

  2. python获取绝对路径_python3中获取文件当前绝对路径的两种方法

    方法1: import sys print(sys.argv) 得到文件当前绝对路径字符串的一个列表 ['D:/pycharm/PracticeProject/ClientServerNetworki ...

  3. ​linux中使用文本工具截取ip 的几种方法

    linux中使用文本工具截取ip 的几种方法 1,使用awk工具 [root@mycentos data]# ifconfig ens33 ens33: flags=4163<UP,BROADC ...

  4. js判断wifi_使用JS在浏览器中判断当前网络连接状态的几种方法

    使用JS在浏览器中判断当前网络状态的几种方法如下: 1. navigator.onLine 2. ajax请求 3. 获取网络资源 4. bind() 1. navigator.onLine 通过na ...

  5. 计算机怎么删除表格,电脑中删除Excel2010表格多余图片的三种方法

    为了让表格看起来更加直观,很多朋友都会在Excel中插入图片.那么,当我们大批量插入图片时,如果想要删除的话,应该怎么办呢?以下是系统城小编为您带来的电脑中删除Excel2010表格多余图片的三种方法 ...

  6. 在Arcmap中加载互联网地图资源的4种方法

    在Arcmap中加载互联网地图资源的4种方法 前一段时间想在Arcmap中打开互联网地图中的地图数据,如影像数据.基础地图数据等,经过简单研究目前总结了四种方法,整理下与大家分享,有些内容可能理解有误 ...

  7. 在HTML中嵌入PHP代码,有以下几种方法,其中错误的是( )

    在HTML中嵌入PHP代码,有以下几种方法,其中错误的是( D) A.以"<?php开头,以"?>"结束,中间为PHP代码. B.以<script la ...

  8. js计算数组中每个元素出现的次数(2种方法)

    js计算数组中每个元素出现的次数(2种方法) js动态生成唯一id Javascript生成全局唯一标识符(GUID,UUID)的方法

  9. python列表统计每个元素出现次数_python 统计list中各个元素出现的次数的几种方法...

    利用字典dict来完成统计 举例: a = [1, 2, 3, 1, 1, 2] dict = {} for key in a: dict[key] = dict.get(key, 0) + 1 pr ...

最新文章

  1. python递归_纯Python递归计算行列式
  2. java 只提取数字_如何从字符串中批量的提取数字-百度经验
  3. Mysql 8 密码策略之组件方式及ERROR 1819
  4. 转载:Spring AOP (下)
  5. 终端服务器安全层在协议流中检测到错误,终端服务器安全层在协议流中检测到错误,并已取消客户端连接...
  6. 【计算机科学基础】图灵机原理概述
  7. php 如何执行top命令,linux命令:top命令
  8. 入行AI最需要的五大技能
  9. JavaScript变量复制
  10. 在myql sqlserver 快速找到带有关键字的表
  11. 自学人工智能 日记2017, ,搞定了
  12. Mysql索引失效OR语句
  13. App架构设计经验谈
  14. 设计规约(Designing Specification)
  15. HashMap 如何解决 hash 冲突
  16. c#+wps插件开发(1)
  17. 低功耗蓝牙开发入门概念科普
  18. [Android] 隐藏头顶状态栏
  19. 并发(concurrency)和并行(parallelism)的区别
  20. 一个类似JQuery的精简版框架

热门文章

  1. 如何理解EOS使用的 DPOS 机制
  2. 知道表格文字识别哪个好吗?三招教你轻松表格文字识别
  3. Python爬取链家网24685个租房信息并进行数据分析
  4. C语言中的Sleep函数的解读
  5. 【效率特工队】记事本txt文本号码如何转换安卓苹果手机通讯录vCard(vcf)格式,最快的方法
  6. 离散数学试设计一个算法,对给定的集合A和集合A上的一个二元关 系R,判断R是否具有对称性
  7. 学习J2ME时,一些帮助链接
  8. 输入捕获模块的使用–超声波测距
  9. [DGMGRL]Dgmgrl管理Dataguard(1)
  10. WordPress博客主题:Free 1白色两栏自适应模板