游戏开发基础(十五)

原创 2012年03月29日 12:37:18

第十五章
通常,在屏幕上任意位置点击,点击之后,计算出拾取射线,然后对场景中的每个物体进行遍历,并检测其是否与该射线相交,与射线相交的物体即为用户所拾取的物体

拾取步骤:
1 给定所点击的屏幕点s,求出它在投影窗口中的对应点p
2 计算拾取射线,即自坐标原点发出且通过点p的那条射线
3 将拾取射线和物体模型变换至同一坐标系中
4 进行物体/射线的相交判断,相交物体即为用户所拾取的屏幕对象

屏幕到投影窗口看的变换

将屏幕点到投影窗口中,视口变换(viewport transformaion)矩阵为:
 2/Width     0         0         0  
 0       -Height/2     0         0
      [ 0           0       MaxZ-MinZ   0   ]
    X+Width/2   Y+Height/2   MinZ       1
对投影窗口中的点p=(px,py,pz)实施视口变换,就得到了屏幕点s = (sx,sy)
 sx = px(Width/2) + X + Width/2
 sy = py(Height/2) + Y + Height/2

拾取变换之后,z坐标并不作为2D图像的一部分进行存储,而是被保存在深度缓存中

已知的是屏幕点s,求点p的位置,得: 
 px = (2sx -2X-Width)/Width
 py = (-2sy + 2Y + Height)/Height

假定视口中的X和Y成员都为0,得到
 px = 2*sx/Width -1
 py = 2*sy/Width +1
 pz = 1
按照定义,投影窗口与平面z=1重合,所以,pz =1
 
由于投影矩阵已对投影窗口中的点进行了比例变换以模拟不同的视场,即呈现近大远小的效果,为了求出缩放之前该点的位置,必须对该点做一次比例变换的逆运算,设P为投影矩阵,由项P00和P11是该变换矩阵中对应于x和y坐标的比例系数,所以有:
 px = (2x/viewporWidth -1)(1/P00)
 py = (2y/viewporHeight +1)(1/P11)
 pz = 1


拾取射线计算,射线参数方程p(t) = p0+tu来表示,p0是射线的起点,它描述了射线位置,u是一个描述了射线方向的向量

射线的起点与坐标原点重合,所以p0=(0,0,0),如果射线经过了投影窗口中的p点,则方向向量u:
 u = p-p0 = (px,py,1) - (0,0,0) = p

该函数用于在给定屏幕坐标系中选定的x和y坐标的条件下,计算观察坐标系中拾取的射线:
d3d::Ray CalcPickingRay(int x,int y)
{
 float px = 0.0f;
 float py = 0.0f;

 D3DVIEWPORT9 vp;
 Device->GetViewport(&vp);

 D3DXMATRIX proj;
 Device->GetTransfrom(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);

 d3d::Ray ray;
 ray._origin    = D3DXVECTOR3(0.0f,0.0f,0.0f);
 ray._direction = D3DXVECTOR3(px,py,1.0f);
 
 return ray;
}

Ray结构:
struct Ray
{
 D3DXVECTOR3 _origin;
 D3DXVECTOR3 _direction;
};


为了进行射线/物体相交测试,射线和物体必须位于同一坐标系中,我们并不打算将所有的物体变换至观察坐标系中,这是因为将射线变换至世界坐标系甚至某个物体的局部坐标系往往更容易

借助变换矩阵对其起点p0和方向u分别进行变换,就实现了射线p(t)=p0+tu的变换,注意,起点是按照点来变换的,而方向是按照向量来变换的

该函数用于对射线进行变换
void TransformRay(d3d::Ray* ray,D3DXMATRIX * T)
{
 //transform the ray's origin ,w = 1
 D3DXVec3TransformCoord(
    &ray->_origin,
    &ray->_origin,
    T);
 // transfrom the ray's direction ,w = 0
 D3DXVec3TransformNormal(
    &ray->_direction,
    &ray->_direction,
    T);
 // normalize the direction
 D3DXVec3Normalize(&ray->_direction,&ray->_direction);
}

D3DXVec3TransformCoord和D3DXVec3TransformNormal均以3D向量作为其参数,注意,D3DXVec3TransformCoord参数第4个分量应理解为w = 1,而是用D3DXVec3TransformNormal时,参数第4个分量应理解为w = 0 ,所以,用D3DXVec3TransformCoord来实现点变换,用D3DXVec3TransformNormal实现向量变换

射线/物体相交判定:用外接球去近似表示每个物体,然后进行射线/外接球的相交测试

注意,射线可能会与多个物体相交,但只有距离摄像机最近的那个物体被拾取,因为距离摄像机较近的物体遮挡了位于其后的物体

给定一个球的圆心点c和半径r,可用隐式方程(implicit equation)来测试点p是否在求面上
 || p -c || - r = 0
如果p满足该方程,称p在球面上

为了判定球体与射线p(t) = p0 + tu是否相交,可将射线方程的参数方程代入隐式的球面方程中,并解出满足球面方程的参数t,这样就求出对应交点的那个参数t。

将射线参数方程代入球面方程,的:
  ||p(t) -c|| -r = 0 
  ||p0 + tu -c || -r = 0
导出一个二次方程(quadratic equation):
 At*t +Bt +C = 0;
其中,A=u*u,B=2(u*(p0-c)),C = (p0-c)*(p0-c)-r*r,若u是单位向量,则A为1
假定u为单位向量,则可解出t0和t1:
 
 t0 = (-B +squrt(B*B-4AC))/2A, t1 = (-B -squrt(B*B-4AC))/2A

下面函数如果射线与球体相交,则返回true,否则返回false
bool RaySphereIntTest(d3d::Ray* ray,d3d::BoundingSphere* sphere)
{

 D3DXVECTOR3 v = ray ->_origin-sphere->_center;
 float b = 2.0f * D3DXVec3Dot(&ray->_direction,&v);
 float c = D3DXVec3Dot(&v,&v) - (sphere->_radius * sphere->_radius) ;
 
 // find the discriminant
 float discriminant = (b*b) - (4.0f*c);

 // test for imaginary number
 float discriminant = (b*b) - (4.0f*c);

 // test for imaginary number
 if(discriminant < 0.0f)
  return false ;

 discriminant = sqrtf(discriminant )

 float s0  = (-b + discriminant) /2.0f;
 float s1  = (-b - discriminant) /2.0f;

        //if a solution is >= 0,then we intersected the sphere
 if (s0 >= 0.0f || s1 >= 0.0f)
  return true;

 return false;
}

struct BoundingSphere
{
 BoundingSphere();
 D3DXVECTOR3 _center;
 float       _radius; 
};

 

Direct 3D和XNA游戏开发基础(C#语言版)(奋斗的小鸟)_PDF 电子书

下载地址:   内容简介   使用C#语言可以编写基于DirectX和微软最新游戏开发平台XNA(仅支持C#语言)的3D图形和3D游戏程序,其运行速度已接近于C++代码的运行速度,一些商业游戏已经使...
  • tjoy2005
  • tjoy2005
  • 2013年10月11日 19:32
  • 1534

游戏编程之十五 DirectDraw 的基本知识

DirectDraw 游戏编程基础(2) 游戏使计算机的发展超越了晶体管时代              例程1(DDEX1):DirectDraw 的基本知识 在使用 Dir...
  • zhangchen124
  • zhangchen124
  • 2016年06月22日 21:32
  • 699

15数码问题

15数码问题 1878年,美国最伟大的谜题专家"Sam Loyd发明了15数码谜题。这个谜题由一个正方形盒子和15个编号为1,2,...,15的正方形滑块组成,每个滑块的边长是盒子边长的1/4,因此...
  • jiyanfeng1
  • jiyanfeng1
  • 2013年01月27日 10:55
  • 3981

[从头读历史] 第280节 诗经目录以及十五国风的地域分布

剧情提要: 诗经中十五国风的采集地都是在哪呢?小雅、大雅,还有颂词都是讲些什么呢? 正剧开始: 星历2016年07月01日 14:35:31, 银河系厄尔斯星球中华帝国江南行省。 [工程师阿伟]正在...
  • mwsister
  • mwsister
  • 2016年07月01日 14:40
  • 670

Android开发入门——推箱子游戏开发实战(十五,终结)

终结篇 首先,发布推箱子游戏程序的源码链接:https://github.com/yeahatgithub/TuiXiangzi。 接下来,我作出几点说明。...
  • yedouble
  • yedouble
  • 2017年07月03日 13:24
  • 593

15个数字由大到小排序

看到程序运行的时候特别开心,但是什么都不看只是自己背着写出来真的很困难 Private Sub Command1_Click()     Dim n As Integer     Dim sie...
  • abcd12fg34567
  • abcd12fg34567
  • 2016年04月03日 14:14
  • 212

[UVA10181]十五数码解题报告

对于有解的情况,只需ID-A*即可。 首先谈一谈估价函数,估价函数表示的应该是对期望步数的下界。我一开始想的是用所有数现在的位置到应该在的位置的曼哈顿距离和,考虑到一次交换最多令其减少2,所...
  • TA201314
  • TA201314
  • 2015年05月05日 21:44
  • 1261

uva 10181 - 15-Puzzle Problem 十五数码 IDA*

照上一个题八数码修改来的,只是十五数码和八数码判断是否有解的方法不同,八数码0的移动不影响其余7个数字逆序数的奇偶性,而十五数码0的左右移动不影响其余15个数逆序数的奇偶性(顺序不变),但上下移动改变...
  • yan_____
  • yan_____
  • 2012年11月24日 12:45
  • 2330

USB开发基础:USB命令(请求)和USB描述符

在USB规范里,对命令一词提供的单词为“Request”,但这里为了更好的理解主机与设备之间的主从关系,将它定义成“命令”。...
  • kevinhg
  • kevinhg
  • 2010年10月01日 00:16
  • 3773

【基础】web开发基础知识

摘要: 有时候是想分享一些知识给大家,但是鉴于各种原因实在是不能达到理想的博客状态。 今天有时间抽点时间给大家写下web开发的基础知识,也是整理。 这篇博客是基础知识,万丈高楼平地起从事web开...
  • my_God_sky
  • my_God_sky
  • 2016年01月19日 18:23
  • 1071
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:游戏开发基础(十五)
举报原因:
原因补充:

(最多只允许输入30个字)