拾取技术和图形管道逆变换

来源:互联网 发布:图像识别算法matlab 编辑:程序博客网 时间:2024/06/08 16:03

关于向量和点变换

3D数学中,向量可以表示点也可以表示向量,当表示点时候进行矩阵变换要用coord需要考虑平移w=1,当表示向量时候进行矩阵变换用normal不需要考虑平移w=0,用齐次向量常数是0表示向量不包括平移,非齐次向量常数是1表示的是空间点包括平移。

关于投影变换

矩阵变换:将屏幕空间捕获到的位置,转换为游戏世界坐标系中的位置
世界坐标系->观察坐标系->投影坐标系->屏幕坐标系。
对于投影坐标系有了更深入的理解:(1)投影坐标系因为透视投影面被放置到了正轴,避免了处理负数,同时避免了透视投影的上下左右颠倒。(2)矩阵没有缩放但是设置了m34=1,使得点变换时候会进行w=z变为w=1的除法,使得经过透视投影,物体点被放置到了x属于[-1,1],y属于[-1,1],z属于[0,1](dx中,opengl中是z为[-1,1])。
(3) 3D透视投影矩阵的Z轴是对1/z进行插值,因为要在1/z后插值到[0,1]中,所以得到的常数是矩阵中的z位置,1/z是矩阵中的平移位置。 2D正交投影矩阵只要对z插值在[0,1]中就可以了,常数矩阵中平移位置,z插值是矩阵中的z位置。

屏幕坐标系变换就是将x的[-1,1]转换为[0,width],将y的[1,-1]转换为[0,height]位置,点的z值用于光栅化深度测试,和模板测试使用
3D数学中,向量可以表示点也可以表示向量,当表示点时候进行矩阵变换要用coord需要考虑平移w=1,当表示向量时候进行矩阵变换用normal不需要考虑平移w=0.

关于世界坐标变换

世界坐标转换SetTransform(D3DTS_WORLD, &M)是将物体坐标系转换到世界坐标系需要进行的转换,基于当前物体坐标系需要进行的变换 就可以了,连续变换世界坐标也不会改变或者重置世界坐标系原点,只是对当前需要绘制的物体产生影响。 
 因为建立的包围盒是变换以后的数据,所以绘制的时候又会根据世界矩阵变换一遍,所以设置世界矩阵变换为单位矩阵不变换绘制包围盒即可。

开发中遇到的各种问题

// 熟悉各种类型的分类讨论。遇到的问题不熟悉的可以通过对比分析找到一些原因。
// 超过左边和右边
// 有的轴在物体内部
// 要根据射线原点开始大于最大缩放后还是大于,或者开始是小于包围盒最大点最大缩放后还是小于。
// 过程中还发现了,根据最迟到达的射线,其实可以求出最长的变换长度的,这样就可以把不符合条件转换为符合条件的已知变换。
// 网络中搜索了下其实大家用射线和包围盒的检测,大多数使用D3DXIntersectTri的方式进行包围盒检测。
1.把物体放置在了原点,导致每次点击都会命中。
2.记得固定管道渲染是4次坐标系变换过程,世界,视图,投影,屏幕,转换到世界空间需要进行屏幕,投影,视图就可以了。
3.调试算法问题:通过不符合的现象进行调试,分析出原因
4.包围盒的颜色没有,那么是因为启动了光照的原因且没有设置材质,所以禁止光照Device->SetRenderState(D3DRS_LIGHTING, FALSE);。
5.AABB的浮点数有问题,FLT_MIN和-FLT_MAX区别,所以建立的包围盒大小是有问题的。
6.世界坐标转换SetTransform(D3DTS_WORLD, &M)是将物体坐标系转换到世界坐标系需要进行的转换,基于当前物体坐标系需要进行的变换
// 就可以了,连续变换世界坐标也不会改变或者重置世界坐标系原点,只是对当前需要绘制的物体产生影响。
// 因为建立的包围盒是变换以后的数据,所以绘制的时候又会根据世界矩阵变换一遍,所以设置世界矩阵变换为单位矩阵不变换绘制包围盒即可。

正交投影和透视投影的深入理解

2D中的正交投影到屏幕坐标系的理解,和2D中的对象拾取技术和3D中的区别研究
 设置屏幕坐标系大小定义,多视图,可以实现屏幕分割
D3DVIEWPORT9 viewport = {0, 0, width, height, 0.0f, 1.0f} ;
(*device)->SetViewport(&viewport);
 设备规范坐标系到屏幕坐标系D3D会自动进行变换,3D透视投影中通过:
  W/2, 0, 0, 0
  0, -H/2, 0,0
  0, 0, MaxZ-MinZ, 0
  X0+W/2, Y0+H/2, MinZ,1
  上述的参数含义就是D3DVIEWPORT9中定义的参数含义。
  3D透视投影矩阵的Z轴是对1/z进行插值,因为要在1/z后插值到[0,1]中,所以得到的常数是矩阵中的z位置,1/z是矩阵中的平移位置。
  2D正交投影矩阵只要对z插值在[0,1]中就可以了,常数矩阵中平移位置,z插值是矩阵中的z位置。
 
  3D透视投影的设备规范坐标系由透视投影矩阵和顶点除法变换得到,x属于[-1,1],y属于[-1,1],z属于[0,1](但是OGL中z属于[-1,-1]
  可见深度缓存中存储的深度也就是z在设备规范坐标系中的值, 但程序员也可以在世界坐标系和视图坐标系中对物体按z值排序渲染。
 
  2D正交投影的设备规范坐标系直接由正交投影变换得到,不会再进行除法,且前面的世界坐标系视图坐标系都是一样的,只不过正交
  投影去掉了进大远小的效果(z值不能影响了),直接经过正交投影变换如果x在[-1,1],y在[-1,1]规范坐标内的可以渲染,在外的不会
  渲染,z值也被正交投影放置到了[0,1]中放入深度缓存中。
  一般设置的正交投影设置下,也就是不缩放,那么物体在世界坐标系中的点和屏幕坐标系中的像素是对应的。
 
  2D和3D的区别仅仅是投影那一刻,他们在世界坐标系中都是一样的世界坐标空间的,摄像机空间也是一样的空间,
  设备规范化坐标系x属于[-1,1]y属于[-1,1]z属于[0,1]OGLz属于[-1,1],屏幕坐标系也是一样的。
  一般2D中位置用像素和格子来衡量就可以了,3D中位置需要虚拟空间尺寸和格子来衡量。

  其实D3D,OGL中的透视投影和正交投影都是没有丢掉z值的,知道z值情况下都是可逆的
  但是在不知道z值情况下,比如设置设备规范坐标系中的z值是1或者0.5或者0.0:

  那么在透视投影情况下计算得到的摄像机坐标空间下的点会不一样,但是单位射线向量都是一样的,
  因为透视投影下摄像机空间下相同视锥夹角的点,是会被投影到相同的设备规范坐标系的(因为除以w=z)。

  而在正交投影情况下得到的摄像机空间下的点会不一样,且单位化法向量也不会一样, 
 只有知道真正的z值计算得到的法向量才是正确的(因为知道z值情况下D3DXMatrixOrthoLH正交投影也是可逆的)
 因为正交投影下摄像机空间下相同的视锥夹角的点,会被投影到不同的设备规范坐标系,因为没有除以w=z,正交投影只和x,y本身
 相关,和z不相关。在不同设备坐标系z下,所以得到摄像机坐标系中的变换射线向量是不成比例的,导致拾取算法的射线方向计算错误。

射线方向计算错误导致z轴上是最远的相交,但此时计算x,y轴并没有超出包围盒区域;而透视投影钟z轴也是最远的相交, 
 而此时x,y轴是超出了包围盒的。所以3D拾取算法不能用于2D中,2D需要一个忽略掉z值的鼠标点击点是否在包围盒矩形中就可以了。
 

AABB.h

#ifndef _AABB_H_#define _AABB_H_#include "d3dUtility.h"// AABB的顶点用于绘制struct AABBVertex{AABBVertex(){}AABBVertex(float x, float y, float z, D3DCOLOR color){_x = x;  _y = y;  _z = z;_color = color;}float _x, _y, _z;D3DCOLOR _color;static const DWORD FVF;};class AABB{public:AABB();~AABB();// 1.自己开发的射线和包围盒检测的方法RayIntersetBoxWithoutDirLength// 射线与AABB的检测,该射线不用考虑射线方向向量的大小,假设方向向量是无限长的,这个判断在用鼠标在3D世界中拾取常用到// 避免参数方程,代入球面方程判断解,只能用球形包围盒的模式inline bool CheckNotArrive(const D3DXVECTOR3 &rayOrg, D3DXVECTOR3 rayDelta,int  nWhich,float fMaxScale);bool CheckOneAxis(const D3DXVECTOR3 &rayOrg, D3DXVECTOR3 rayDelta, int nWhich);bool RayIntersetBoxWithoutDirLength(const D3DXVECTOR3 &rayOrg, D3DXVECTOR3 rayDelta);// 2D中的选择检测bool SelectObject2D(const D3DXVECTOR3 worldClickPos);// 2.变换后使用RayIntersect算法D3DXVECTOR3 GetRayDir(const D3DXVECTOR3 &rayOrg,const D3DXVECTOR3 &rayDelta);floatRayIntersect(const D3DXVECTOR3 &rayOrg,// orgin of the rayconst D3DXVECTOR3 &rayDelta,// length and direction of the rayD3DXVECTOR3 *returnNormal// optionally, the normal is returned) const;// 3.标准的使用D3DXIntersectTri,用射线和AABB的六个面进行检测,射线是不用求出长度的bool IsIntersect(const D3DXVECTOR3 &rayOrg,const D3DXVECTOR3 &rayDelta);// 一些公共的函数void CalculateBoudingBox(D3DXVECTOR3 *pVec, int n);void setToTransformedBox(const AABB &box, const D3DXMATRIX &m);void Reset();bool IsEmpty();// 建立包围盒模型并渲染的void Setup(IDirect3DDevice9 *pDevice);void Draw( IDirect3DDevice9 *pDevice );private:D3DXVECTOR3 min;D3DXVECTOR3 max;bool m_bEmpty;bool m_bSetup;IDirect3DVertexBuffer9* VB;IDirect3DIndexBuffer9*  IB;};#endif

AABB.cpp

#include "AABB.h"const DWORD AABBVertex::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;AABB::AABB(){VB = NULL;IB = NULL;Reset();}AABB::~AABB(){}void AABB::Reset(){min.x = min.y = min.z = FLT_MAX;// FLT_MIN 是最小正负数,但是我们需要的是最小的负数,所以这里如果用FLT_MIN会导致计算不正确max.x = max.y = max.z = -FLT_MAX;m_bEmpty = true;m_bSetup = false;d3d::Release<IDirect3DVertexBuffer9*>(VB);d3d::Release<IDirect3DIndexBuffer9*>(IB);}bool AABB::IsEmpty(){return m_bEmpty;}void AABB::Setup(IDirect3DDevice9 *pDevice){if( pDevice == NULL || m_bEmpty ){m_bSetup = false;return;}pDevice->CreateVertexBuffer(8 * sizeof(AABBVertex), D3DUSAGE_WRITEONLY,AABBVertex::FVF,D3DPOOL_MANAGED,&VB,0);pDevice->CreateIndexBuffer(36 * sizeof(WORD), // 索引缓存的字节数,个数是三角形的个数*3,索引缓存个数还是没有减少的。D3DUSAGE_WRITEONLY, // 使用类型为只读类型,获取指针然后写入数据,数据将会批量提交D3DFMT_INDEX16, // D3DFMT_INDEX16是16bit,D3DFMT_INDEX32是32bitD3DPOOL_MANAGED, // D3DPOOL类型,创建在SM中,需要时候拷贝到AGP内存/显存中&IB,0);//保留AABBVertex *vertices;D3DCOLOR blueColor = D3DCOLOR_XRGB(0,0,255);VB->Lock(0,0,(void**)&vertices, 0/*D3DLOCK_DISCARD*/);vertices[0] = AABBVertex(min.x, min.y, min.z, blueColor);vertices[1] = AABBVertex(min.x,  max.y,min.z, blueColor);vertices[2] = AABBVertex( max.x, max.y, min.z, blueColor);vertices[3] = AABBVertex( max.x, min.y, min.z, blueColor);vertices[4] = AABBVertex(min.x, min.y,  max.z, blueColor);vertices[5] = AABBVertex(min.x, max.y,  max.z, blueColor);vertices[6] = AABBVertex(max.x,  max.y,  max.z, blueColor);vertices[7] = AABBVertex( max.x, min.y,  max.z, blueColor);VB->Unlock();WORD *indices = NULL;IB->Lock(0,0,(void**)&indices, 0);indices[0]  = 0; indices[1]  = 1; indices[2]  = 2;indices[3]  = 0; indices[4]  = 2; indices[5]  = 3;// back sideindices[6]  = 4; indices[7]  = 6; indices[8]  = 5;indices[9]  = 4; indices[10] = 7; indices[11] = 6;// left sideindices[12] = 4; indices[13] = 5; indices[14] = 1;indices[15] = 4; indices[16] = 1; indices[17] = 0;// right sideindices[18] = 3; indices[19] = 2; indices[20] = 6;indices[21] = 3; indices[22] = 6; indices[23] = 7;// topindices[24] = 1; indices[25] = 5; indices[26] = 6;indices[27] = 1; indices[28] = 6; indices[29] = 2;// bottomindices[30] = 4; indices[31] = 0; indices[32] = 3;indices[33] = 4; indices[34] = 3; indices[35] = 7;IB->Unlock();m_bSetup = true;}void AABB::Draw( IDirect3DDevice9 *pDevice ){   if( pDevice == NULL || !m_bSetup ){return;}pDevice->BeginScene();pDevice->SetStreamSource(0, VB, 0, sizeof(AABBVertex));pDevice->SetIndices(IB);pDevice->SetFVF(AABBVertex::FVF);// Draw cube.pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);pDevice->EndScene();}bool AABB::SelectObject2D(const D3DXVECTOR3 worldClickPos){return worldClickPos.x >= min.x && worldClickPos.x<= max.x && worldClickPos.y >= min.y && worldClickPos.y <= max.y;}bool AABB::CheckNotArrive(const D3DXVECTOR3 &rayOrg, D3DXVECTOR3 rayDelta,int  nWhich,float fMaxScale ){float fCurWhich;float fRayOrgWhich;float fRayDeltaWhich;float fMinWhich;float fMaxWhich;if ( nWhich == 1){fRayOrgWhich = rayOrg.x;fRayDeltaWhich = rayDelta.x;fMinWhich = min.x;fMaxWhich = max.x;}else if( nWhich == 2){fRayOrgWhich = rayOrg.y;fRayDeltaWhich = rayDelta.y;fMinWhich = min.y;fMaxWhich = max.y;}else if( nWhich == 3){fRayOrgWhich = rayOrg.z;fRayDeltaWhich = rayDelta.z;fMinWhich = min.z;fMaxWhich = max.z;}else{MessageBox(NULL, "CheckNotArrive参数nWhich不对","调试",0);return false;}fCurWhich = fRayOrgWhich + fMaxScale * fRayDeltaWhich;// 转换为int是为了放宽点精度,避免选中了但是没有判断选中/*float fCurWhichAdd = 0.7f;fCurWhich += fCurWhichAdd;*/if( fRayOrgWhich < fMinWhich && int(fCurWhich) < int(fMinWhich) ){return false;}else if ( fRayOrgWhich > fMaxWhich && int(fCurWhich) > int(fMaxWhich) ){return false;}return true;}bool AABB::CheckOneAxis(const D3DXVECTOR3 &rayOrg, D3DXVECTOR3 rayDelta, int nWhich ){bool bIncrease = true;float fRayOrgWhich;float fRayDeltaWhich;float fMinWhich;float fMaxWhich;int nOtherAxis1;int nOtherAxis2;if ( nWhich == 1){fRayOrgWhich = rayOrg.x;fRayDeltaWhich = rayDelta.x;fMinWhich = min.x;fMaxWhich = max.x;nOtherAxis1 = 2;nOtherAxis2 = 3;}else if( nWhich == 2){fRayOrgWhich = rayOrg.y;fRayDeltaWhich = rayDelta.y;fMinWhich = min.y;fMaxWhich = max.y;nOtherAxis1 = 1;nOtherAxis2 = 3;}else if( nWhich == 3){fRayOrgWhich = rayOrg.z;fRayDeltaWhich = rayDelta.z;fMinWhich = min.z;fMaxWhich = max.z;nOtherAxis1 = 1;nOtherAxis2 = 2;}else{MessageBox(NULL, "CheckNotArrive参数nWhich不对","调试",0);return false;}if( d3d::FloatEquip(fRayDeltaWhich, 0.0f) ){return false;}if( fRayOrgWhich > fMaxWhich ){bIncrease = false;}if( bIncrease ){// rayDelta.x x正负都是不能判断一定不相交的,因为x可能在包围盒内,只能通过是向右增加还是向右增长来判断if( fRayDeltaWhich < 0.0f ){if( fRayOrgWhich < fMinWhich ){return false;}float fScaleMaxLimit = ( fMinWhich - fRayOrgWhich ) / fRayDeltaWhich;if( !CheckNotArrive(rayOrg, rayDelta, nOtherAxis1,fScaleMaxLimit) ){return false;}if( !CheckNotArrive(rayOrg, rayDelta, nOtherAxis2 ,fScaleMaxLimit) ){return false;}}else{if( fRayOrgWhich > fMaxWhich ){return false;}float fScaleMaxLimit = ( fMaxWhich - fRayOrgWhich ) / fRayDeltaWhich;if( !CheckNotArrive(rayOrg, rayDelta, nOtherAxis1,fScaleMaxLimit) ){return false;}if( !CheckNotArrive(rayOrg, rayDelta, nOtherAxis2, fScaleMaxLimit) ){return false;}}}else{// 射线原点一定在最大值右边了,不会在物体中间情况if( fRayDeltaWhich >= 0.0f ){return false;}float fScaleMax = (  fMinWhich - fRayOrgWhich ) / fRayDeltaWhich;if( !CheckNotArrive(rayOrg, rayDelta, nOtherAxis1,fScaleMax) ){return false;}if( !CheckNotArrive(rayOrg, rayDelta, nOtherAxis2, fScaleMax) ){return false;}}}// 还有一个最长的射线方式,转换为固定长度射线和AABB相交的判断bool AABB::RayIntersetBoxWithoutDirLength(const D3DXVECTOR3 &rayOrg, D3DXVECTOR3 rayDelta){// 如果原点在包围盒内,那么就直接返回了if ( rayOrg.x >= min.x && rayOrg.x <= max.x &&rayOrg.y >= min.y && rayOrg.y <= max.y &&rayOrg.z >= min.z && rayOrg.z <= max.z){return true;}// 1.先考虑x方向上,判断 方向if ( !CheckOneAxis(rayOrg, rayDelta, 1) ){return false;}// 2.先考虑x方向上,判断 方向if ( !CheckOneAxis(rayOrg, rayDelta, 2) ){return false;}// 3.先考虑x方向上,判断 方向if ( !CheckOneAxis(rayOrg, rayDelta, 3) ){return false;}// 哪里出现了问题return true;}void AABB::CalculateBoudingBox(D3DXVECTOR3 *pVec, int n){for( int i = 0; i < n; i++ ){if(pVec[i].x < min.x ){min.x = pVec[i].x;}if(pVec[i].y < min.y ){min.y = pVec[i].y;}if(pVec[i].z < min.z ){min.z = pVec[i].z;}if(pVec[i].x > max.x ){max.x = pVec[i].x;}if(pVec[i].y > max.y ){max.y = pVec[i].y;}if(pVec[i].z > max.z ){max.z = pVec[i].z;}}m_bEmpty = false;}D3DXVECTOR3 AABB::GetRayDir(const D3DXVECTOR3 &rayOrg, const D3DXVECTOR3 &rayDelta){float fMaxScale = 0.0f;float fMaxScaleNext = 0.0f;if( rayOrg.x < max.x && rayDelta.x > 0.0f ){fMaxScale = (max.x - rayOrg.x) / rayDelta.x;}else if( rayOrg.x > min.x && rayDelta.x < 0.0f ){fMaxScale = (min.x - rayOrg.x) / rayDelta.x;}if( rayOrg.y < max.y && rayDelta.y > 0.0f ){fMaxScaleNext = (max.y - rayOrg.y) / rayDelta.y;}else if( rayOrg.y > min.y && rayDelta.y < 0.0f ){fMaxScaleNext = (min.y - rayOrg.y) / rayDelta.y;}if( fMaxScaleNext > fMaxScale ){fMaxScale = fMaxScaleNext;}if( rayOrg.z < max.z && rayDelta.z > 0.0f ){fMaxScaleNext = (max.z - rayOrg.z) / rayDelta.z;}else if( rayOrg.z > min.z && rayDelta.z < 0.0f ){fMaxScaleNext = (min.z - rayOrg.z) / rayDelta.z;}if( fMaxScaleNext > fMaxScale ){fMaxScale = fMaxScaleNext;}return (fMaxScale * rayDelta);}floatAABB::RayIntersect(const D3DXVECTOR3 &rayOrg,// orgin of the rayconst D3DXVECTOR3 &rayDelta,// length and direction of the rayD3DXVECTOR3 *returnNormal// optionally, the normal is returned) const{ // We'll return this huge number if no intersectionconst float kNoIntersection = 1e30f;// Check for point inside box, trivial reject, and determine parametric// distance to each front facebool inside = true;float xt, xn;if (rayOrg.x < min.x) {xt = min.x - rayOrg.x;if (xt > rayDelta.x) return kNoIntersection;xt /= rayDelta.x;inside = false;xn = -1.0f;} else if (rayOrg.x > max.x) {xt = max.x - rayOrg.x;if (xt < rayDelta.x) return kNoIntersection;xt /= rayDelta.x;inside = false;xn = 1.0f;} else {xt = -1.0f;}float yt, yn;if (rayOrg.y < min.y) {yt = min.y - rayOrg.y;if (yt > rayDelta.y) return kNoIntersection;yt /= rayDelta.y;inside = false;yn = -1.0f;} else if (rayOrg.y > max.y) {yt = max.y - rayOrg.y;if (yt < rayDelta.y) return kNoIntersection;yt /= rayDelta.y;inside = false;yn = 1.0f;} else {yt = -1.0f;}float zt, zn;if (rayOrg.z < min.z) {zt = min.z - rayOrg.z;if (zt > rayDelta.z) return kNoIntersection;zt /= rayDelta.z;inside = false;zn = -1.0f;} else if (rayOrg.z > max.z) {zt = max.z - rayOrg.z;if (zt < rayDelta.z) return kNoIntersection;zt /= rayDelta.z;inside = false;zn = 1.0f;} else {zt = -1.0f;}// Inside box?if (inside) {if (returnNormal != NULL) {*returnNormal = -rayDelta;//returnNormal->normalize();D3DXVec3Normalize(returnNormal, returnNormal);}return 0.0f;}// Select farthest plane - this is// the plane of intersection.int which = 0;float t = xt;if (yt > t) {which = 1;t = yt;}if (zt > t) {which = 2;t = zt;}switch (which) {case 0: // intersect with yz plane{float y = rayOrg.y + rayDelta.y*t;if (y < min.y || y > max.y) return kNoIntersection;float z = rayOrg.z + rayDelta.z*t;if (z < min.z || z > max.z) return kNoIntersection;if (returnNormal != NULL) {returnNormal->x = xn;returnNormal->y = 0.0f;returnNormal->z = 0.0f;}} break;case 1: // intersect with xz plane{float x = rayOrg.x + rayDelta.x*t;if (x < min.x || x > max.x) return kNoIntersection;float z = rayOrg.z + rayDelta.z*t;if (z < min.z || z > max.z) return kNoIntersection;if (returnNormal != NULL) {returnNormal->x = 0.0f;returnNormal->y = yn;returnNormal->z = 0.0f;}} break;case 2: // intersect with xy plane{float x = rayOrg.x + rayDelta.x*t;if (x < min.x || x > max.x) return kNoIntersection;float y = rayOrg.y + rayDelta.y*t;if (y < min.y || y > max.y) return kNoIntersection;if (returnNormal != NULL) {returnNormal->x = 0.0f;returnNormal->y = 0.0f;returnNormal->z = zn;}} break;}// Return parametric point of intersectionreturn t;}bool AABB::IsIntersect(const D3DXVECTOR3 &rayOrg,const D3DXVECTOR3 &rayDelta){if( m_bEmpty ){return false;}if( !m_bSetup ){return false;}D3DXVECTOR3 v0(min.x, min.y, min.z);D3DXVECTOR3 v1(min.x, max.y, min.z);D3DXVECTOR3 v2(max.x, max.y, min.z);D3DXVECTOR3 v3(max.x, min.y, min.z);D3DXVECTOR3 v4(min.x, min.y, max.z);D3DXVECTOR3 v5(max.x, min.y, max.z);D3DXVECTOR3 v6(max.x, max.y, max.z);D3DXVECTOR3 v7(min.x, max.y, max.z);// frontif( D3DXIntersectTri(&v0, &v1, &v2, &rayOrg,&rayDelta, NULL, NULL, NULL) ){return true;}if( D3DXIntersectTri(&v0, &v2, &v3, &rayOrg,&rayDelta, NULL, NULL, NULL) ){return true;}// backif( D3DXIntersectTri(&v4, &v5, &v6, &rayOrg,&rayDelta, NULL, NULL, NULL) ){return true;}if( D3DXIntersectTri(&v4, &v6, &v7, &rayOrg,&rayDelta, NULL, NULL, NULL) ){return true;}// leftif( D3DXIntersectTri(&v4, &v7, &v1, &rayOrg,&rayDelta, NULL, NULL, NULL) ){return true;}if( D3DXIntersectTri(&v4, &v1, &v0, &rayOrg,&rayDelta, NULL, NULL, NULL) ){return true;}// rightif( D3DXIntersectTri(&v5, &v3, &v2, &rayOrg,&rayDelta, NULL, NULL, NULL) ){return true;}if( D3DXIntersectTri(&v5, &v2, &v6, &rayOrg,&rayDelta, NULL, NULL, NULL) ){return true;}// topif( D3DXIntersectTri(&v7, &v6, &v2, &rayOrg,&rayDelta, NULL, NULL, NULL) ){return true;}if( D3DXIntersectTri(&v7, &v2, &v1, &rayOrg,&rayDelta, NULL, NULL, NULL) ){return true;}// bottomif( D3DXIntersectTri(&v0, &v3, &v5, &rayOrg,&rayDelta, NULL, NULL, NULL) ){return true;}if( D3DXIntersectTri(&v0, &v5, &v4, &rayOrg,&rayDelta, NULL, NULL, NULL) ){return true;}}voidAABB::setToTransformedBox(const AABB &box, const D3DXMATRIX &m) {// If we're empty, then bailif ( box.m_bEmpty ) {return;}// Start with the translation portionmin = max = D3DXVECTOR3(m._41, m._42, m._43);// Examine each of the 9 matrix elements// and compute the new AABBif (m._11 > 0.0f) {min.x += m._11 * box.min.x; max.x += m._11 * box.max.x;} else {min.x += m._11 * box.max.x; max.x += m._11 * box.min.x;}if (m._12 > 0.0f) {min.y += m._12  * box.min.x; max.y += m._12  * box.max.x;} else {min.y += m._12  * box.max.x; max.y += m._12  * box.min.x;}if (m._13 > 0.0f) {min.z += m._13 * box.min.x; max.z += m._13 * box.max.x;} else {min.z += m._13 * box.max.x; max.z += m._13 * box.min.x;}if (m._21 > 0.0f) {min.x += m._21 * box.min.y; max.x += m._21 * box.max.y;} else {min.x += m._21 * box.max.y; max.x += m._21 * box.min.y;}if (m._22 > 0.0f) {min.y += m._22 * box.min.y; max.y += m._22 * box.max.y;} else {min.y += m._22 * box.max.y; max.y += m._22 * box.min.y;}if (m._23 > 0.0f) {min.z += m._23 * box.min.y; max.z += m._23 * box.max.y;} else {min.z += m._23 * box.max.y; max.z += m._23 * box.min.y;}if (m._31 > 0.0f) {min.x += m._31 * box.min.z; max.x += m._31 * box.max.z;} else {min.x += m._31 * box.max.z; max.x += m._31 * box.min.z;}if (m._32 > 0.0f) {min.y += m._32 * box.min.z; max.y += m._32 * box.max.z;} else {min.y += m._32* box.max.z; max.y += m._32 * box.min.z;}if (m._33 > 0.0f) {min.z += m._33 * box.min.z; max.z += m._33 * box.max.z;} else {min.z += m._33 * box.max.z; max.z += m._33 * box.min.z;}m_bEmpty = false;}

PickingTechnology.h

struct Ray{D3DXVECTOR3 _origin;D3DXVECTOR3 _direction;};struct BoudingSphere{D3DXVECTOR3 _center;float _radius;};class CPickingTechnology{public:CPickingTechnology(int nWidth, int nHeight, IDirect3DDevice9 *pDevice);~CPickingTechnology();// 构建包围盒void BuildObjectBox(D3DXVECTOR3 *pVec, int n, const string strObjectMarkNmae);bool IsPickingOK(const POINT &cursorPoint);void SetupAABB();void DrawAABB();void setToTransformedBox(const AABB &box, const D3DXMATRIX &m);// 和包围球的相交检测Ray CalcPickingRay(int x, int y);void TransFormRay(Ray *ray, D3DXMATRIX *T);bool PickingTest(int x, int y);bool RaySphereIntTest( Ray *ray, BoudingSphere *sphere);private:// 自己写的转换函数验证过是正确的,而且非常清晰void CalculateRayDirFromScreenToWorld(const POINT &cursorPoint);private:// 包围盒物体的名字,用于调试string m_strObjectName;// 当前的包围盒对象 AABB m_AABB;// 鼠标点击世界坐标系中原点D3DXVECTOR3 m_cursorWorldOrigin;// 鼠标点击的世界坐标系中射线方向向量D3DXVECTOR3 m_cursorWorldDir;// 设备对象IDirect3DDevice9 *m_pDevice;// 宽高int m_nWidth;int m_nHeight;// 包围球BoudingSphere m_Shere;};#endif

PickingTechnology.cpp

#include "PickingTechnology.h"CPickingTechnology::CPickingTechnology(int nWidth, int nHeight, IDirect3DDevice9 *pDevice){m_nWidth = nWidth;m_nHeight = nHeight;m_pDevice = pDevice;}CPickingTechnology::~CPickingTechnology(){}void CPickingTechnology::BuildObjectBox(D3DXVECTOR3 *pVec, int n,  const string strObjectMarkNmae){m_AABB.CalculateBoudingBox(pVec, n);m_strObjectName = strObjectMarkNmae;}void CPickingTechnology::CalculateRayDirFromScreenToWorld(const POINT &cursorPoint){if(m_pDevice == NULL){return;}// 由屏幕变换到x,y属于[-1,1], z属于1的裁剪除以w = z后的空间为float x = 2.0f * cursorPoint.x / m_nWidth - 1;float y = 1 - 2.0f * cursorPoint.y / m_nHeight;D3DXVECTOR3 vecPointInCube(x, y, 0.0f);// 由cube空间通过透视投影求逆,得到鼠标点击点在透视投影空间中的位置D3DXMATRIX perspectiveMatrix;m_pDevice->GetTransform(D3DTS_PROJECTION,&perspectiveMatrix);D3DXMATRIX perspectiveMatrixInverse;D3DXMatrixInverse(&perspectiveMatrixInverse, NULL, &perspectiveMatrix);D3DXVECTOR3 vecPointInPerspective;// 视图空间的透视投影变换内部仅仅是放缩,尽管没有进行4D 到3D的除法运算,就是除以w = z的运算, 但是因为需要的是单位向量.// 其逆运算cube空间内乘以w = z,后计算得到的方向向量和没有乘以w = z的运算得到的单位向量都是一样的。// 所以直接透视逆矩阵乘法,就得到视图空间中所求的方向向量// Transforms a 3D vector by a given matrix, projecting the result back into w = 1.// 当投影变换时候虽然没有4D 到3D的除以了w = z 等于1,但是向量点进行变换时候,却会进行除以w = z的变换,使得透视投影变换// 向量点,会使得向量点被投影到xy属于[-1,1],z属于[0,1]的小立方体中;// 同时投影矩阵求逆时也是没有进行乘以w=z的乘法,但是 D3DXVec3TransformCoord变换时候,会使得w=z,变为w = 1,从而进行乘法。D3DXVec3TransformCoord(&vecPointInPerspective, &vecPointInCube, &perspectiveMatrixInverse);// 测试//D3DXMATRIX projMatrix(1.33f, 0.0f, 0.0f, 0.0f,//0.0f, 1.0f, 0.0f, 0.0f,//0.0f, 0.0f, 0.0f, -0.999f,// 一定要-0.999因为是D3DTS_PROJECTION//0.0f, 0.0f, 1.0f, 1.0f//);//D3DXVECTOR3 vecTest(-0.0094f, 0.054, 1);////D3DXVec3Normalize(&vecTest, &vecTest);//D3DXVECTOR3 vecOut;//// 归一化处理如果w=0.001,那么乘以1000就得到投影坐标系中的坐标;这里其实逆向运算是需要真正的z的值,才能进行更准确的变换//// 对于拾取技术,是不需要z的值的,因为用一个点击的原点和射线单位向量就可以了,检测单位向量穿过的最前面的物体//// 置于屏幕中斜线前面和后面的物体并不是同一个射线的,正对z轴里面的物体才是同一个射线选中的//D3DXVec3TransformCoord(&vecOut, &vecTest, &projMatrix);//// 测试结束// 鼠标点击的原点是(0,0,0)和方向向量进行规范化D3DXVECTOR3 cursorPersOrigin(0.0f, 0.0f, 0.0f);/*D3DXVECTOR3 cursorPersDir;D3DXVec3Normalize(&cursorPersDir, &vecPointInPerspective);*/// 视图空间到世界坐标系的变换D3DXMATRIX viewMatrix;D3DXMATRIX viewInverseMatrix;m_pDevice->GetTransform(D3DTS_VIEW, &viewMatrix);D3DXMatrixInverse(&viewInverseMatrix, NULL, &viewMatrix);// 原点进行点变换,需要考虑平移,w = 1D3DXVec3TransformCoord(&m_cursorWorldOrigin, &cursorPersOrigin, &viewInverseMatrix);// 鼠标射线进行点变换,需要考虑平移,w = 0D3DXVec3TransformNormal(&m_cursorWorldDir, &vecPointInPerspective, &viewInverseMatrix);// 单位化,因为拾取技术,只需要知道射线方向选择第一个相交的物体旧可以了// 2D中可以不用单位化,通过世界坐标系中的x,y进行判断即可D3DXVec3Normalize(&m_cursorWorldDir, &m_cursorWorldDir);}bool CPickingTechnology::IsPickingOK(const POINT &cursorPoint){if( m_AABB.IsEmpty() ){MessageBox(NULL, "没有设置需要判断的物体", "鼠标拾取判断", 0);return false;}/*POINT point;point.x = 576;point.y = 425;*/CalculateRayDirFromScreenToWorld(cursorPoint);//  m_cursorWorldDir是世界坐标系中的点// 2D的自己写的//bool bSelect = m_AABB.SelectObject2D(m_cursorWorldDir);// 3D通用的标准做法//bool bSelect = m_AABB.IsIntersect(m_cursorWorldOrigin, m_cursorWorldDir);// 3D的改用的标准算法D3DXVECTOR3 rayDir = m_AABB.GetRayDir(m_cursorWorldOrigin, m_cursorWorldDir);float ft = m_AABB.RayIntersect(m_cursorWorldOrigin, rayDir/*m_cursorWorldDir*/, NULL);// 3D的自己写的算法//bool bSelect = m_AABB.RayIntersetBoxWithoutDirLength(m_cursorWorldOrigin, m_cursorWorldDir);string strMsg = "拾取对象:"; if ( ft >= 0.0f && ft <=1.0f/*bSelect*/ ) { strMsg += m_strObjectName; } else { strMsg += "没有选择对象"; } MessageBox(NULL, strMsg.c_str(), "鼠标拾取判断", 0);}void CPickingTechnology::SetupAABB(){m_AABB.Setup(m_pDevice);}void CPickingTechnology::DrawAABB(){m_AABB.Draw(m_pDevice);}void CPickingTechnology::setToTransformedBox(const AABB &box, const D3DXMATRIX &m){m_AABB.setToTransformedBox(box, m);}Ray CPickingTechnology::CalcPickingRay(int x, int y){float px = 0.0f;float py = 0.0f;D3DVIEWPORT9 vp;m_pDevice->GetViewport(&vp);D3DXMATRIX proj;m_pDevice->GetTransform(D3DTS_PROJECTION, &proj);px = ( ((2.0f * x) / vp.Width) - 1.0f) / proj(0,0);py = ( ((-2.0f * y) / vp.Height) + 1.0f) / proj(1,1);Ray ray;ray._origin = D3DXVECTOR3(0.0f, 0.0f, 0.0f);ray._direction = D3DXVECTOR3(px, py, 1.0f);return ray;}void CPickingTechnology::TransFormRay(Ray *ray, D3DXMATRIX *T){D3DXVec3TransformCoord(&(ray->_origin), &(ray->_origin),T);// 鼠标射线进行点变换,需要考虑平移,w = 1D3DXVec3TransformNormal(&(ray->_direction), &(ray->_direction),T);D3DXVec3Normalize(&(ray->_direction), &(ray->_direction));}bool CPickingTechnology::RaySphereIntTest( Ray *ray, BoudingSphere *sphere){D3DXVECTOR3 v = ray->_origin - sphere->_center;float b = 2.0f * D3DXVec3Dot(&ray->_direction, &v);float c = D3DXVec3Dot(&v, &v) - sphere->_radius * sphere->_radius;float discriminant = b * b - 4.0f * c;if( discriminant < 0.0f){return false;}discriminant = sqrt(discriminant);float s0 = (-b + discriminant) / 2.0f;float s1 = (-b -discriminant) / 2.0f;if(s0 >= 0.0f || s1 >= 0.0f){return true;}return false;}bool CPickingTechnology::PickingTest(int x, int y){Ray ray = CalcPickingRay(x, y);D3DXMATRIX viewMatrix;D3DXMATRIX viewInverseMatrix;m_pDevice->GetTransform(D3DTS_VIEW, &viewMatrix);D3DXMatrixInverse(&viewInverseMatrix, NULL, &viewMatrix);//float ft = m_AABB.RayIntersect(ray._origin, ray._direction, NULL);m_Shere._center = D3DXVECTOR3(0.0f, 0.0f, 0.0f);m_Shere._radius = 1.732f;//bool bSelect = m_AABB.RayIntersectLimitless(m_cursorWorldOrigin, m_cursorWorldDir);string strMsg = "拾取对象:"; bool bOK = RaySphereIntTest(&ray, &m_Shere);if ( bOK/*ft >= 0.0f && ft <=1.0f*/ ){strMsg += m_strObjectName;bOK = true;}else{strMsg += "没有选择对象";}MessageBox(NULL, strMsg.c_str(), "鼠标拾取判断", 0);return bOK;}

cube.cpp

//////////////////////////////////////////////////////////////////////////////////////////////////// // File: cube.cpp// // Author: Frank Luna (C) All Rights Reserved//// System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 //// Desc: Renders a spinning cube in wireframe mode.  Demonstrates vertex and //       index buffers, world and view transformations, render states and//       drawing commands.//          //////////////////////////////////////////////////////////////////////////////////////////////////#include "d3dUtility.h"#include "PickingTechnology.h"// 拾取对象CPickingTechnology *g_pPickingObj =  NULL;//// Globals//IDirect3DDevice9* Device = 0; const int Width  = 640;const int Height = 480;IDirect3DVertexBuffer9* VB = 0;IDirect3DIndexBuffer9*  IB = 0;//// Classes and Structures//struct Vertex{Vertex(){}Vertex(float x, float y, float z, D3DCOLOR color){_x = x;  _y = y;  _z = z;_color = color;}float _x, _y, _z;D3DCOLOR _color;static const DWORD FVF;};const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;//// Framework Functions//bool Setup(){//// Create vertex and index buffers.//Device->CreateVertexBuffer(8 * sizeof(Vertex), D3DUSAGE_WRITEONLY,Vertex::FVF,D3DPOOL_MANAGED,&VB,0);Device->CreateIndexBuffer(36 * sizeof(WORD), // 索引缓存的字节数,个数是三角形的个数*3,索引缓存个数还是没有减少的。D3DUSAGE_WRITEONLY, // 使用类型为只读类型,获取指针然后写入数据,数据将会批量提交D3DFMT_INDEX16, // D3DFMT_INDEX16是16bit,D3DFMT_INDEX32是32bitD3DPOOL_MANAGED, // D3DPOOL类型,创建在SM中,需要时候拷贝到AGP内存/显存中&IB,0);//保留//// Fill the buffers with the cube data.//// define unique vertices:Vertex* vertices;// Locks a range of vertex data and obtains a pointer to the vertex buffer memory./* nOffset: 0 whole   nSize: 0 Whole   void **ppbDatanFlags: Combination of zero or more locking flags that describe the type of lock to perform. For this method, the valid flags are:D3DLOCK_DISCARD *///D3DLOCK_DISCARD//char szDebugInfo[256];VB->Lock(0, 0, (void**)&vertices, 0/*D3DLOCK_DISCARD*/);// vertices of a unit cube/*vertices[0] = Vertex(-1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255,0,0));vertices[1] = Vertex(-1.0f,  1.0f, -1.0f, D3DCOLOR_XRGB(255,255,0));vertices[2] = Vertex( 1.0f,  1.0f, -1.0f, D3DCOLOR_XRGB(0,255,0));vertices[3] = Vertex( 1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255,255,0));vertices[4] = Vertex(-1.0f, -1.0f,  1.0f, D3DCOLOR_XRGB(255,255,0));vertices[5] = Vertex(-1.0f,  1.0f,  1.0f, D3DCOLOR_XRGB(255,255,0));vertices[6] = Vertex( 1.0f,  1.0f,  1.0f, D3DCOLOR_XRGB(255,255,0));vertices[7] = Vertex( 1.0f, -1.0f,  1.0f, D3DCOLOR_XRGB(255,255,0));*/vertices[0] = Vertex(-100.0f, -100.0f, -1.0f, D3DCOLOR_XRGB(255,0,0));vertices[1] = Vertex(-100.0f,  100.0f, -1.0f, D3DCOLOR_XRGB(255,255,0));vertices[2] = Vertex( 100.0f,  100.0f, -1.0f, D3DCOLOR_XRGB(0,255,0));vertices[3] = Vertex( 100.0f, -100.0f, -1.0f, D3DCOLOR_XRGB(255,255,0));vertices[4] = Vertex(-100.0f, -100.0f,  1.0f, D3DCOLOR_XRGB(255,255,0));vertices[5] = Vertex(-100.0f,  100.0f,  1.0f, D3DCOLOR_XRGB(255,255,0));vertices[6] = Vertex( 100.0f,  100.0f,  1.0f, D3DCOLOR_XRGB(255,255,0));vertices[7] = Vertex( 100.0f, -100.0f,  1.0f, D3DCOLOR_XRGB(255,255,0));VB->Unlock();// define the triangles of the cube:WORD* indices = 0;IB->Lock(0, 0, (void**)&indices, 0);// DX中三角形顺时针(左手定则)为正面, 逆时针为背面会被消隐,OGL则相反。// 索引缓存点的个数是三角形片面数 * 3得到的个数。// 所有索引缓存表面从外往物体里看都是顺时针给出的(例如六面体背面的索引缓存顺序),索引缓存每连续三个为一个三角形即可。// 索引缓存的好处:// 1.减少了顶点缓存的顶点个数(不需重复顶点)// 2.灵活修改图形(通过修改索引而不是顶点)// 3.提高渲染runtime将多次用到的数据放置在相近的地方Cache中(local reference)// front sideindices[0]  = 0; indices[1]  = 1; indices[2]  = 2;indices[3]  = 0; indices[4]  = 2; indices[5]  = 3;// back sideindices[6]  = 4; indices[7]  = 6; indices[8]  = 5;indices[9]  = 4; indices[10] = 7; indices[11] = 6;// left sideindices[12] = 4; indices[13] = 5; indices[14] = 1;indices[15] = 4; indices[16] = 1; indices[17] = 0;// right sideindices[18] = 3; indices[19] = 2; indices[20] = 6;indices[21] = 3; indices[22] = 6; indices[23] = 7;// topindices[24] = 1; indices[25] = 5; indices[26] = 6;indices[27] = 1; indices[28] = 6; indices[29] = 2;// bottomindices[30] = 4; indices[31] = 0; indices[32] = 3;indices[33] = 4; indices[34] = 3; indices[35] = 7;IB->Unlock();//// Position and aim the camera.//// 视图坐标系和局部坐标系是一样的,都是世界坐标系转换为指定的局部坐标系,从局部点到世界点需要先旋转后平移Mx*My*Mz*P的变换矩阵,//而从世界点到局部点要进行先平移后旋转的逆过程P-1Mz-1My-1Mx-1的变换矩矩阵(PMzMyMx是重用局部点到世界的变换).//矩阵是重新分解和组合空间位置和方位的空间变换过程;//矩阵行是新坐标系的基向量或表示平移,用变换后的向量在原坐标系各轴分解得的向量表示;//矩阵列是对应原坐标系的各轴,是各新基向量在列对应原坐标系的轴上的累积(组合)向量。D3DXVECTOR3 position(0.0f, 0.0f, -100.0f);//camera在世界坐标系中的位置向量D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);//target是camera需要平移到的且旋转所在的点,可以是原点,也 可以是其它观察点D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);//定义向上的方向,一般是[0,1,0]    D3DXMATRIX V;// V是world-to-view空间的变换矩阵,内部会计算世界坐标系到观察坐标系的变换(物体假设不动),// 其实新的坐标系下所有物体的位置时重新计算了的。D3DXMatrixLookAtLH(&V, &position, &target, &up);    Device->SetTransform(D3DTS_VIEW, &V);////设置变换的状态,待最后综合各种变换得到最终实际变换时才变换(可暂时理解为世界坐标系中的物体被变换到观察坐标系中)//// Set the projection matrix.//D3DXMATRIX proj;D3DXMatrixPerspectiveFovLH(// 假设物体不动,观察坐标系到投影坐标系的转换矩阵// 待最后综合各种变换得到最终实际变换时才变换(可暂时理解为观察坐标系中的物体被变换到投影坐标系内)&proj, D3DX_PI * 0.5f, // 90 - degree 观察坐标系中的上下夹角(float)Width / (float)Height, // 宽高比例1.0f, // 观察坐标系视锥体的近截面1000.0f);// 观察坐标系视锥体的远截面D3DXMATRIX proj2D;D3DXMatrixOrthoLH(&proj2D, float(Width), float(Height), 1.0f, 1000.0f);Device->SetTransform(D3DTS_PROJECTION, &proj);//// Switch to wireframe mode.//Device->SetRenderState(D3DRS_LIGHTING, FALSE);Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID/*D3DFILL_WIREFRAME*/);Device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);//Device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, true);//D3DXMATRIX Rx, Ry;static float y = 2.0f;D3DXMATRIX T;D3DXMatrixTranslation(&T, -3.0f, 2.0f, 6.0f); //D3DXMatrixRotationY(&Ry, y);//D3DXMatrixIdentity(&Ry);// 缩放或旋转会导致包围盒拉伸变形,而不正确D3DXMATRIX M =T /*T * Ry*/;AABB originBox;D3DXVECTOR3 pVertex[8];for ( int i = 0; i < 8; i++){ pVertex[i] = D3DXVECTOR3(vertices[i]._x, vertices[i]._y, vertices[i]._z);D3DXVec3TransformCoord(&pVertex[i], &pVertex[i], &M);}//originBox.CalculateBoudingBox(pVertex, 8);//g_pPickingObj->setToTransformedBox(originBox, M);g_pPickingObj->BuildObjectBox(pVertex, 8, "茶壶");// 设置包围盒/*VB->Lock(0, 0, (void**)&vertices, 0);if( g_pPickingObj != NULL ){g_pPickingObj->BuildObjectBox( pVertex, 8, "茶壶");}VB->Unlock();*/if( g_pPickingObj != NULL ){g_pPickingObj->SetupAABB();}return true;}void Cleanup(){d3d::Release<IDirect3DVertexBuffer9*>(VB);d3d::Release<IDirect3DIndexBuffer9*>(IB);}bool Display(float timeDelta){if( Device ){//// spin the cube://D3DXMATRIX Rx, Ry;// rotate 45 degrees on x-axisD3DXMatrixRotationX(&Rx, 3.14f / 4.0f);// incremement y-rotation angle each framestatic float y = 2.0f;D3DXMatrixRotationY(&Ry, y);y += timeDelta;// reset angle to zero when angle reaches 2*PIif( y >= 6.28f )y = 0.0f;// combine x- and y-axis rotation transformations.//D3DXMATRIX p = Rx * Ry;// 世界坐标系的转换命令会被runtime commmand buffer调度,因为前面的D3DTS_VIEW,D3DTS_PROJECTION会被真正渲染管道中的时候排序到后面去了/*D3DXMATRIX T = D3DXMATRIX( 1.0f, 0.0f, 0.0f, 0.0f,0.0f, 1.0f, 0.0f, 0.0f,0.0f, 0.0f, 1.0f, 0.0f,0.0f, 1.0f,5.0f,1.0f);D3DXMATRIX M = T * Ry;Device->SetTransform(D3DTS_WORLD, &M);*/D3DXMATRIX T;D3DXMatrixTranslation(&T, -3.0f, 2.0f, 6.0f); Device->SetTransform(D3DTS_WORLD, &T); // draw the scene://Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);Device->BeginScene();Device->SetStreamSource(0, VB, 0, sizeof(Vertex));Device->SetIndices(IB);Device->SetFVF(Vertex::FVF);// Draw cube.Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);Device->EndScene();D3DXMATRIX T2;D3DXMatrixIdentity(&T2);Device->SetTransform(D3DTS_WORLD, &T2); if( g_pPickingObj != NULL ){g_pPickingObj->DrawAABB();}Device->Present(0, 0, 0, 0);}return true;}//// WndProc//LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){switch( msg ){case WM_DESTROY:::PostQuitMessage(0);break;case WM_KEYDOWN:if( wParam == VK_ESCAPE )::DestroyWindow(hwnd);break;case WM_LBUTTONDOWN:{POINT p;GetCursorPos(&p);if( g_pPickingObj != NULL ){g_pPickingObj->IsPickingOK(p);//g_pPickingObj->PickingTest/*IsPickingOK*/(p.x, p.y);}}break;}return ::DefWindowProc(hwnd, msg, wParam, lParam);}//// WinMain//int WINAPI WinMain(HINSTANCE hinstance,   HINSTANCE prevInstance,    PSTR cmdLine,   int showCmd){if(!d3d::InitD3D(hinstance,Width, Height, true, D3DDEVTYPE_HAL, &Device)){::MessageBox(0, "InitD3D() - FAILED", 0, 0);return 0;}g_pPickingObj = new CPickingTechnology(Width, Height, Device);if(!Setup()){::MessageBox(0, "Setup() - FAILED", 0, 0);return 0;}d3d::EnterMsgLoop( Display );Cleanup();Device->Release();return 0;}


0 0