D3D中的拾取

转载自:http://www.cppblog.com/lovedday/archive/2008/04/04/46264.html

假设用户点击了屏幕上的点 s (x, y)。 从图15.1我们能看到用户选取了茶壶。无论如何,应用程序无法根据给定的s点就立即确定茶壶是被选取。

我们知道一些知识:关于茶壶和它的关联点s,茶壶投影在围绕s点的区域,更准确的说是:它投影到投影窗口上围绕p点的区域,与它对应的屏幕点是s。因为这个问题依赖于3D物体与它的投影之间的关系,我们看图15.2就可以了解。

图15.2我们看到如果我们发射一条选取射线,从原点发出,经过点p,会与围绕p点投影的对象相交,即茶壶。所以一旦我们计算选取射线,我们可以遍例场景中的每个对象并测试,看射线是否与它相交。与射线相交的对象即是用户选择的对象,在这个例子中用户选取的对象是茶壶。

上面的例子讲解了点s与茶壶的关系。通常我们任意点击屏幕上的点,我们遍例场景中的每个对象,如果对象与射线相交,那么这个对象就是用户选取的对象。例如,图15.1中,如果用户没有点击5个对象中的一个,而是点击了白色的背景区域,射线将不能相交任何对象。因此,结论是:如果射线没有与场景中的任何对象相交,则用户没有点击任何一个对象,其它的我们不关心。

“选取”适用于所有种类的游戏和3D程序。例如,玩家通过用鼠标点击来影响3D世界中的不同对象,玩家可能点击向敌人射击,或点击拾取物品。好的程序会适当做出反应,程序需要知道哪个对象被选取(是敌人还是物品),和在3D空间中的位置(开枪会击中哪?或玩家将要移动到哪去拾取物品?)。选取回答了我们这些问题。

我们将选取分解成四步:

1)       给一个屏幕点s,找出它在投影窗口上相交的点,即p

2)       计算射线,它是从原点出发并经过点p

3)       转换射线与模型到同一空间。

4)       测试与射线相交的对象,相交的对象即是屏幕上点击的对象。


15.1屏幕到投影窗口的转换

首先,转换屏幕点到投影窗口,视口变换矩阵是:

因为前面的定义,投影窗口就是z=1的平面,所以pz = 1。

投影矩阵缩放投影窗口上的点,来模拟不同的视角。为了返回缩放前的点值,我们必须用与缩放相反的操作来转换点。P是投影矩阵,因为P00和 P11转换距阵缩放点的x和y坐标,我们得到:


15.2计算射线

回忆一下,射线能够描述参数方程:p(t) = p0 + tu。其中p0是射线的起点,用来描述它的位置,u是向量,用来描述它的方向。

如图15.2,我们知道射线的起点总是视图空间的原点,所以p0 = (0, 0, 0),如果p是射线穿过投影窗口上的点,方向向量u给出:u = p - p0 = (px, py, 1) - (0, 0, 0) = p

下面的方法用来计算选取射线(从屏幕空间点击的点所对应的视图空间的点x、y坐标):

struct sRay
{
    D3DXVECTOR3 origin;
    D3DXVECTOR3 direction;
};

sRay calculate_picking_ray(int x, int y)
{
        D3DVIEWPORT9 viewport;
        g_device->GetViewport(&viewport);
    
        D3DXMATRIX proj_matrix;
        g_device->GetTransform(D3DTS_PROJECTION, &proj_matrix);
    
        
float px = ((( 2.0f * x) / viewport.Width)  - 1.0f) / proj_matrix(0, 0);
        
float py = (((-2.0f * y) / viewport.Height) + 1.0f) / proj_matrix(1, 1);
    
        sRay ray;
        ray.origin      = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
        ray.direction = D3DXVECTOR3(px, py, 1.0f);
    
        
return ray;

}

15.3变换射线

选取射线的计算被描述在视图空间,为了完成射线的相交的测试,射线和对象必须在同一个坐标系统。通常转换射线到世界空间(甚至对象在本地空间)要好于将所有对象转换到视图空间。

我们能够将一个变换矩阵转换为一条原点为p0,方向为u的射线r(t) = p0 + tu,注意:原点转换为一个点,方向转换为一个向量,下列函数转换一条射线:

     void  transform_ray(sRay* ray, D3DXMATRIX* trans_matrix)
    {
        
// transform the ray's origin, w = 1.
    
        D3DXVec3TransformCoord(&ray->origin, &ray->origin, trans_matrix);
    
        
// transform the ray's direction, w = 0.
    
        D3DXVec3TransformNormal(&ray->direction, &ray->direction, trans_matrix);
    
        
// normalize the direction
    
        D3DXVec3Normalize(&ray->direction, &ray->direction);
    }

D3DXVec3TransformCoord和D3DXVec3TransformNormal接受一个Ray类型参数(包含二个3D向量成员)。 D3DXVec3TransformCoord函数中,射线的原点(origin)向量的第四部分w = 1。相反,函数D3DXVec3TransformNormal中,射线的方向(direction)向量的第四部分w = 0。

这样,当我们向世界空间转换时,能够用D3DXVec3TransformCoord转换一个点,用D3DXVec3TransformNormal转换一个向量。


15.4射线-对象 交点

我们将射线和对象转换到同一坐标系统后,准备测试哪个对象与射线相交。因为我们将对象描述为三角形组成的网络,下面详细说明这种方法。遍例场景中每个对象的三角形列表并测试,如果射线相交于一个三角形,它就与三角形所在的对象相交。然而,通过遍例场景中的每个三角形来实现射线相交在计算上会增加时间,一种比较快的方法,虽然准确性会差一点。它将每个对象围成一个近似的球形(边界球),这样我们就能通过遍例每个边界球来测试射线相交。用边界球来描述相交的对象。

注意:射线可能相交多个对象,然而离照相机近的对象会被选取。因为近距离对象遮挡了后面的对象

给出一个边界球的圆心c和半径r,使用下列恒等式能够测试点p是否在边界球上:

||p-c||-r = 0

如果恒等式满足,则点p在边界球上。如图15.3

假定射线p(t) = p0 + tu相交于边界球,我们将射线代入球的恒等式中,使参数t满足了球的恒等式。

将射线p(t) = p0 + tu代入球的恒等式:

||p(t) - c|| r = 0   à  ||p0 + tu - c|| r = 0

通过以上推导,我们得到二次方程:

At2 + Bt + C = 0

其中A = · uB = 2(u · (p0 - c)),而C = (p0 - c) . (p0 - c) – 2

如果u是标准化的,那么A = 1。

因为u是标准化的,我们解t0和 t1

图15.4显示可能返回的t0和 t1,并显示了一些返回值的几何意义:

下列函数测试如果射线与边界球相交,返回true;射线错过边界球,返回false。

     bool  ray_sphere_intersect(sRay* ray, cBoundingSphere* sphere)
    {
        D3DXVECTOR3 v = ray->origin - sphere->m_center;
    
        
float  b = 2.0f * D3DXVec3Dot(&ray->direction, &v);
        
float  c = D3DXVec3Dot(&v, &v) - (sphere->m_radius * sphere->m_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 one solution is >= 0, then we intersected the sphere.
    
     return  (s0 >= 0.0f || s1 >= 0.0f);
    }

15.5例子程序:选取

下图显示了该示例的屏幕截图,茶壶绕着屏幕移动,你可以用鼠标试着点击它。如果你点击到茶壶的边界球上,一个消息框将弹出,表示你点中了。我们通过测试WM_LBUTTONDOWN消息来处理鼠标点击事件。


下面来自:http://www.cnblogs.com/lancidie/archive/2010/10/08/1845772.html

简单总结一下D3D中的拾取问题,所谓拾取就是3D程序中当用户使用鼠标同3D世界内的物体进行交互的时候,如何能正确的实现从用户的鼠标到3D世界中的变换。 
    呵呵,如果要是推及到原理的话比较复杂,需要好好总结,先从简单的入手,D3D中提供了很多易用的API,使用这些API的话就可以绕过复杂的数学原理,所以呢,我们先来看实际应用中是怎样实现它的。 
    //首先获取世界、视角、投影矩阵 
    D3DXMATRIX matWorld,matView,matProj; 
    pd3dDevice->GetTransform(D3DTS_WORLD,&matWorld); 
    pd3dDevice->GetTransform(D3DTS_VIEW,&matView); 
    pd3dDevice->GetTransform(D3DTS_PROJECTION,&matProj); 
    //获取平面坐标 
    POINT ptCursor; 
    GetCursorPos(&ptCursor); 
    ScreenToClient(DXUTGetHWND(),&ptCursor); 
    D3DXVECTOR3 vScreen((float)ptCursor.x,(float)ptCursor.y,0.0f),vOut; 
    //创建视窗接口 
    D3DVIEWPORT9 viewPort; 
    pd3dDevice->GetViewport( &viewPort ); 
    //从屏幕空间投影到3D空间 
    D3DXVec3Unproject(&vOut,&vScreen,&viewPort,&matProj,&matView,&matWorld); 
    D3DXVECTOR3 vMousePt; 
    D3DXPLANE plane; 
    D3DXVECTOR3 v1(1.0f,1.0f,0.0f); 
    D3DXVECTOR3 v2(1.0f,-1.0f,0.0f); 
    D3DXVECTOR3 v3(-1.0f,1.0f,0.0f); 
    D3DXPlaneFromPoints( &plane,&v1,&v2,&v3); 
    D3DXPlaneIntersectLine(&vMousePt,&plane,pCamera->GetEyePt(),&vOut); 
    //vMousePt.x,vMousePt.y和vMousePt.z就是鼠标根据视角所投射线同所指定平面的交点 
    很简单的一段代码,为了确保它的正确性,测试倒是费了半天劲-。-,全部都是用API来实现的,看程序不难理解,这段程序重点是D3DXVec3Unproject()函数,这个函数的作用便是进行屏幕到空间的投影(还有一个D3DXVec3project()函数是用来进行空间到屏幕的投影的^_^),这个函数需要的是设备的Viewport、决定3D空间的三个矩阵和屏幕的坐标,函数可以算出结果向量,不过测试的时候我发现这个向量好像既不是近裁剪面的投影点也不是远裁剪面的,这个地方确实还是存在疑惑的,不过不影响使用,呵呵。 
    其实有了这个向量后面的怎么用就看大家了,上面是通过D3DXPlaneIntersectLine()函数(计算直线与平面交点用函数)来实现的,还可以用D3DXIntersect()来做与三角面片的相交。 


Direct3D 中实现图元的鼠标.pdf 看网上好多关于该文章的图片丢失,有幸找到个有完整图片的。

BY 重剑,2004.5.28 重剑空间  

索引:

1、 什么是拾取,拾取能做什么?

2、 拾取操作的步骤和实现

    2.1.  变换并获得通过视点和屏幕上点击点的射线矢量(Dir)

 

2.1.1 确定鼠标选取点的屏幕坐标

 

2.1.2 得到Dir在观察坐标空间内的表示

 

2.1.3 转换Dir到世界坐标空间,并得到观察点在世界坐标系中的坐标

 

    2.2   使用射线矢量对场景中的所有三角形图元求交,获得三角形索引值和重心坐标。

 

2.2.1 D3D扩展函数实现求交

2.2.2射线三角面相交的数学算法

2.2.3  拾取完成根据获得的中心坐标计算我们关心的常见量

3、 结束及声明

4、 参考文献

 

补 充:重心坐标的概念

 

 

 

3D 交互图形应用程序中,常常要用鼠标去选择图形,其实现的机制基于鼠标拾取算法。本文主要讲述如何在D3D 中实现图元的鼠标拾取。为了讨论简 单,本文假定读者理解 D3D 坐标变换流程和基本的图形学知识,如果阅读有困难请参考相关资料。

1、什么是拾取,拾取能做什么?

首先,拾取操作指当我们在屏幕上用鼠标点击某个图元应用程序能返回该图元的一个标志和某些相关信息。有图形程序设计经验的人都知道,有这些信息就表示我们 有了对该图元的控制权,我们可以删除,可以编辑,可以任意对待该图元,至于你到底想干什么,就是阁下自己的事了 ^_^ 。

2、拾取操作的步骤和实现

拾取算法的思想很简单:得到鼠标点击处的屏幕坐标,通过投影矩阵和观察矩阵把该坐标转换为通过视点和鼠标点击点的一条射入场景的光线,该光线如果与场景模 型的三角形相交(本文只处理三角形图元),则获取该相交三角形的信息。本文讲述的方法除可以得到三角形的一个索引号以外还可以得到相交点的重心坐标。

    从数学角度来看,我们只要得到射线的方向矢量和射线的出射点,我们就具备了判断射线与空间一个三角面是否相交的条件,本文主要讨论如何获得这些条件,并描 述了射线三角面相交判断算法和 D3D 的通常实现方法。    

根据拾取操作的处理顺序,大概可以依次分为 以下几个步骤

2.1 .   变换并获得通过视点和屏幕上点击点的射线矢量( Dir )

详细介绍之前,为了大家方便理解,我们要先简单说一下 d3d 坐标转换的大概流程,如下图 :

 

所以我们要通过一系列的反变换,得到我们关心的值在世界坐标中的表示。

2.1.1 确定鼠标选取点的屏幕坐标

这一步是非常简单的 Windows 给我们提供了 API 来完成屏幕坐标的获取,使用 GetCursorPos 获得鼠标指针位置,然后再利用 ScreenToClient 转换坐标到客户区坐标系 ( 以窗口视区左上角为坐标原点,单位为像素 ) ,设该坐标为( POINT screenPt )。

2.1.2 得到Dir在观察坐标空间内的表示

在观察坐标系中, Dir 是一条从观察坐标原点出发的射线,所以我们只需要再确定一个该射线经过的点,就可以得到它在观察坐标系中的表示。假设我们要求的射线上的另外一 点为该射线与透视投影平截头体近剪切面的交点,针对最普遍的透视投影而言,透视投影平截头体经投影变换后,变成一个 1/2 立方体(请允许我这么叫^_^ ,因为它的大小为一个正方体的一半, x,y 方向边长为 2 , z 方向为 1 )如图:

投影坐标系以近剪切面中心为坐标原点,该立方体从 z 轴负向看过去与图形程序视区相对应,最终近 剪切面(前剪切面)上一点与屏幕坐标之间的对应关系如下图所示:

根据比例关系, screenPt 与投影空间上的点 projPt 之间的关系为

假设图形程序窗口的宽为 screenWidth, 高为 screenHeight,

projPt.x = (screenPt.x-screenWidth/2)/screenWidth*2; (公式1)

projPt.y = (screenPt.y-screenHeight/2)/screenHeight*2; (公式2)

projPt.z =0;(实际该值可任意取,不影响最终结果。为了处理简单,我们取改值为0,表示该点取在近剪切面上)

得到 projPt 后,我们需要做的是把该点坐标从投影空间转换到观察空间 (view space),

根据透视投影的定义,可假设点 (projPt.x , projPt.y , projPt.z)

对应的其次坐标为

(projPt.x*projPt.w , projPt.y*projPt.w , projPt.z*projPt.w , projPt.w)

 

我们可以通过  GetTransform(      D3DTS_PROJECTION,    &ProjMatrix) 函数获得投影矩阵 ProjMatrix, 则根据观察空间到投影空间的变换关系则

(projPt.x*projPt.w , projPt.y*projPt.w , projPt.z*projPt.w , projPt.w)

 = (viewPt.x , viewPt.y , viewPt.z, 1)*pProjMatrx;

根据定义和图形学原理

 

所以 ,

(projPt.x*projPt.w , projPt.y*projPt.w , projPt.z*projPt.w , projPt.w)

= ( viewPt.x*ProjMatrix._m11,

viewPt.y*ProjMatrix._m22,

viewPt.z*Q-QZn,

viewPt.z)

 

所以

projPt.x*projPt.w = viewPt.x*ProjMatrix._m11

projPt.y*projPt.w = viewPt.y*ProjMatrix._m22

projPt.z*projPt.w = viewPt.z*Q-QZn (注意 projPt.z = 0 

projPt.w = viewPt.z;

解得

viewPt.x = projPt.x*Zn/ ProjMatrix._m11;

viewPt.y = projPt.y*Zn/ ProjMatrix._m22;

viewPt.z = Zn;

好了,到这里为止我们终于求出了射线与近剪切面交点在观察坐标系中的坐标,现在我们拥有了射线的出发点(0,0,0) 和射线方向上另外一点 (viewPt.x,viewPt.y,viewPt.z), 则该射线的方向矢量在观察空间中的表示可确定为(viewPt.x-0,viewPt.y-0,viewPt.z-0 ) , 化简一下三个分量同除近剪切面 z 坐标 Zn ,该方向矢量可写作

DIRview = (projPt.x/projMatrix._m11,projPt.y/projMatrix._m22,1)

代入公式 1 ,公式 2

DIRview.x = (2*screenPt.x/screenWidth-1)/projMatrix._m11;

DIRview.y = (2*screenPt.y/screenHeight-1)/projMatrix._m22;

DIRview.z = 1;

其中screenWidth 和screenHeight可以通过图像显示的backBuffer的目标表面(D3DSURFACE_DESC)来获得,该表面在程序初始化时由用户创 建。

2.1.3 转换Dir到世界坐标空间,并得到观察点在世界坐标系中的坐标

由于最终的运算要在世界坐标空间中进行,所以我们还 需要把矢量DIRview从观察空间转换为世界坐标空间中的矢量DIRworld。

因为

DIRview = DIRworld*ViewMatrix;

其中ViewMatrix 为观察矩阵,在D3D中可以用函数GetTransform( D3DTS_VIEW, &ViewMatrix )得到。

所以DIRworld = DIRview * inverse_ViewMatrix,其中inverse_ViewMatrix为

ViewMatrix的 逆矩阵。

     观察点在观察坐标系中坐标为OriginView(0,0,0,1),所以其在世界坐标系中的坐标同样可以利用ViewMatrix矩阵,反变换至世界坐 标系中,事实上我们可以很简单的判断出,其在世界坐标系中的表示为:

OriginWorld = (inverse_ViewMatrix._41,

inverse_ViewMatrix._42,

inverse_ViewMatrix._43,

1);

到这里为止,判断射线与三角面是否相交的条件就完全 具备了。

 

2.2   使用射线矢量对场景中的所有三角形图元求交,获得三角形索引值和重心坐标。

这一步骤地实现由两种途径 :

第一种方法非常简单,利用 D3D 提供的扩展函数 D3DXIntersect 可以轻松搞定一 切。见 2.1

第二种方法就是我们根据空间解析几何的知识,自己来完成射线三角形的求交算法。一般来讲,应用上用第一种方法就足够了,但是我们如果要深入的话,必须理解 相交检测的数学算法,这样才能自由的扩展,面对不同的需求,内容见 2.2

下面分别讲解两种实现途径:

2.2.1 D3D扩展函数实现求交

这种方法很简单也很好用,对于应用来说应尽力是用这种方式来实现,毕竟效率比自己写得要高得多。

实际上其实没什么好讲的,大概讲一下函数 D3DXIntersect 吧

HRESULT D3DXIntersect(      

    LPD3DXBASEMESH pMesh,

    CONST D3DXVECTOR3 *pRayPos,

    CONST D3DXVECTOR3 *pRayDir,

    BOOL *pHit,

    DWORD *pFaceIndex,

    FLOAT *pU,

    FLOAT *pV,

    FLOAT *pDist,

    LPD3DXBUFFER *ppAllHits,

    DWORD *pCountOfHits

);

l          pMesh指向一个ID3DXBaseMesh的对象,最简单的方式是从.x文件获得,描述了要进行相交检测的三角面元集合的信息,具体规范参阅direct9 SDK

l          pRayPos 指向射线发出点

l          pRayDir 指向前面我们辛辛苦苦求出的射线方向的向量

l          pHit 当检测到相交图元时,指向一个true,不与任何图元相交则为假

l          pU 用于返回重心坐标U分量

l          pV返回重心坐标V分量

l          pDist 返回射线发出点到相交点的长度

注意:以上红色字体部分均指最近的一个返回结果(即*pDist最小)
 

l          ppAllHits用于如果存在多个相交三角面返回相交的所有结果

l          pCountOfHits 返回共有多少个三角形与该射线相交
 

 

补充:重心坐标的概念

其中pU和pV用到了重心坐标的概念,下面稍作描述

一个三角形有三个顶点,在迪卡尔坐标系中假设表示为V1(x1,y1,z1),V2(x2,y2,z2),V3(x3,y3,z3), 则三角形内任意一点的坐标可以表示为 pV = V1 + U(V2-V1) + V(V3-V1),所以已知三个顶点坐标的情况下,任意一点可用坐标(U,V)来表示,其中 参数U控制V2在结果中占多大的权值,参数V控制V3占多大权值,最终1-U-V控制V1占多大权值,这种坐标定义方式就叫重心坐标。

 

 

2..2.2射线三角面相交的数学算法

     使用 d3d 扩展函数,毕竟有时不能满足具体需求,掌握了该方法,我们才能够获得最大的控制自由度,任意修改算 法。

    

已知条件 : 射线源点 orginPoint, 三角形三个顶点 v1,v2,v3, 射线方向 Dir

(均以三维坐标向量形式表示)

算法目的 : 判断射线与三角形是否相交,如果相交求出交点的重心坐标 (U,V) 和射线原点到交点的距离 T 。

 

我们可先假设射线与三角形相交则交点 ( 注以下均为向量运算, * 数乘, dot(X,Y) X , Y 点乘, cross ( X , Y) X , Y 叉乘; U , V , T 为标量 )

则:

IntersectPoint = V1 + U*(V2-V1) + V*(V3-V1) ;

IntersectPoint = originPoint + T*Dir ;

 

所以

orginPoint + T*Dir = V1 + U*(V2-V1) + V*(V3-V1);

整理得:

orginPoint - V1 = U×(V2-V1) + V×(V3-V1) - T×Dir;

这是一个简单的线性方程组,若有解则行列式 [ -Dir, V2-V1, V3-V1 ]不为 0 。

根据 T,U,V 的含义当 T>0, 0<U<1,0<V<1,0<U+V<1 时该交点在三角形内部,

解此方程组即可获得我们关心的值 , 具体解法不再赘述,克莱姆法则就够了(详 细见线性代数) : 射 线原点到相交点的距离 T, 和交点的中心坐标 (U,V) 。

下面给出 Direct 9 SDK 示例程序中的实现代码

[cpp]  view plain  copy
  1. IntersectTriangle( const D3DXVECTOR3& orig,  
  2.                   const D3DXVECTOR3& dir, D3DXVECTOR3& v0,  
  3.                   D3DXVECTOR3& v1, D3DXVECTOR3& v2,  
  4.                   FLOAT* t, FLOAT* u, FLOAT* v )  
  5. {  
  6.     // 算出两个边的向量  
  7.     D3DXVECTOR3 edge1 = v1 - v0;  
  8.     D3DXVECTOR3 edge2 = v2 - v0;  
  9.     D3DXVECTOR3 pvec;  
  10.     D3DXVec3Cross( &pvec, &dir, &edge2 );  
  11.     // 如果 det 为 0 ,或接近于零则射线与三角面共面或平行,不相交  
  12.     // 此处 det 就相当于上面的 [-Dir, V2-V1, V3-V1] ,  
  13.     FLOAT det = D3DXVec3Dot( &edge1, &pvec );  
  14.     D3DXVECTOR3 tvec;  
  15.     if ( det > 0 )  
  16.     {  
  17.         tvec = orig - v0;  
  18.     }  
  19.     else  
  20.     {  
  21.         tvec = v0 - orig;  
  22.         det = -det;  
  23.     }  
  24.     if ( det < 0.0001f )  
  25.         return FALSE;  
  26.     // 计算 u 并<a href="http://lib.csdn.net/base/softwaretest" class='replace_word' title="软件测试知识库" target='_blank' style='color:#df3434; font-weight:bold;'>测试</a>是否合法(在三角形内)  
  27.     *u = D3DXVec3Dot( &tvec, &pvec );  
  28.     if ( *u < 0.0f || *u > det )  
  29.         return FALSE;  
  30.     // Prepare to test V parameter  
  31.     D3DXVECTOR3 qvec;  
  32.     D3DXVec3Cross( &qvec, &tvec, &edge1 );  
  33.     // 计算 u 并测试是否合法(在三角形内)  
  34.     *v = D3DXVec3Dot( &dir, &qvec );  
  35.     if ( *v < 0.0f || *u + *v > det )  
  36.         return FALSE;  
  37.         /* 计算 t, 并把 t,u,v 放缩为合法值(注意前面的 t,v,u 不同于算法描述中的相应量,乘了一个 系 
  38.         数 det ) , 注意:由于该步运算需要使用除法,所以放到最后来进行,避免不必要的运算,提高 
  39.     算法效率 */  
  40.     *t = D3DXVec3Dot( &edge2, &qvec );  
  41.     FLOAT fInvDet = 1.0f / det;  
  42.     *t *= fInvDet;  
  43.     *u *= fInvDet;  
  44.     *v *= fInvDet;  
  45.     return TRUE;  
  46. }  

 

2.2.3  拾取完成根据获得的中心坐标计算我们关心的常见量,。

根据重心坐标( U,V ) , 我们可以很容易的算出各种相关量比如纹理坐 标和交点的差值颜色,假设以纹理坐标为例设 V1,V2,V3 的纹理坐标分别为 T1(tu1,tv1),T2(tu2,tv2),T3(tu3,tv3) 则交点的坐标为

 

IntersectPointTexture = T1 + U(T2-T1) + V(T3-T1)

 

3、结束及声明

Ok, 到这里为止关于拾取的相关知识就介绍完了,小弟第一次写这种文章,不知道有没有把问题说清楚,希望对大家有所帮助,有任何问题可以给我发 email: jzhang1@mail.xidian.edu.cn

或者到我的网站留言: www.heavysword.com

 

声明:

本文写作的目的是为了广大 D3D 学习者方便学习服务,文中算法为作者 参考相关文献总结,作者无意把这些据为自己的成果,所有权原算法提出者所有(参阅参考文献),文中代码为 D3d SDK 的示例内容,由笔者进行了必要的解释,代码版权归 microsoft 所有。

4、参考文献

【1】Microsoft DirectX 9.0 SDK,microsoft

【2】fast,Minimun Storage Ray/Triangle Intersection,Tomas Moler,Ben Trumbore

 

 BY

(转 载请注明出处)



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值