D3D开发-摇摇球

来源:互联网 发布:域名解析 非80端口 编辑:程序博客网 时间:2024/04/27 21:22

经过2个月的D3D学习,再经过了几个星期的开发,完成了摇摇球的初步开发,仍有许多不足之处。仍有许多地方需要进行改进与学习。尤其是碰撞测试方面。

程序简介:该程序最初灵感来自于小时候所玩了迷宫尺子,有小球在带有迷宫的尺子上滚动,后了解到这时著名的重力迷宫球游戏,普及在iphone、android等手机中,通过手机的重力感应模拟小球在迷宫中的重力效果。该程序暂且开发到在一个正方形的地板中,用鼠标操控地板的倾斜方向与角度,模拟小球在地板上滚动及与墙面的碰撞。在此中,难点在于鼠标旋转算法、重力模拟与碰撞测试。

难点一:鼠标旋转算法

                该算法是通过鼠标在窗口中的位置调整地板的旋转方向与角度。

               首先说明下理论部分,模拟一个半径为1的球体,初始时记录下了正向上的法向量g_vCenterPt,通过鼠标在窗口中的移动,计算得到新的向量g_vCurrentPt,再有这2个轴得到从g_vCenterPt旋转到g_vCurrentPt四元数,最后由该四元数转换得到旋转矩阵进行绘制。

D3DXVECTOR3 ScreenToVector(float fScreenPtX, float fScreenPtY) {float x = -(fScreenPtX - SCREEN_WIDTH/2) / (g_fRadius * 5 * SCREEN_WIDTH/2);// 以窗口宽度的一半作为物体中心x坐标,以窗口宽度的一半*g_fRadius作为椭圆x半径float z = (fScreenPtY - SCREEN_HEIGHT/2) / (g_fRadius * 5 * SCREEN_HEIGHT/2);// 以窗口高度的一半作为物体中心y坐标,以窗口高度的一半*g_fRadius作为椭圆y半径float y = 0.0f;float mag = x*x + z*z;if (mag > 1.0f) {// 如果mag大于1即说明鼠标位置在球体之外,将xy标准化,z为0。即绕z轴旋转float scale = 1.0f / sqrtf(mag);x *= scale;z *= scale;} elsey = sqrtf(1.0f - mag);return D3DXVECTOR3(x, y, z);}D3DXQUATERNION QuatFromBallPoints(const D3DXVECTOR3 &vFrom, const D3DXVECTOR3 &vTo) {D3DXVECTOR3 vPart;float fDot = D3DXVec3Dot(&vFrom, &vTo);// 取得两向量的点乘,因为两个都是单位向量,所以fDot等于cos thetaD3DXVec3Cross(&vPart, &vFrom, &vTo);// 叉乘,获得的是垂直于两个向量的一个向量,即旋转轴。其模等于|a||b|sin theta等于sin thetareturn D3DXQUATERNION(vPart.x, vPart.y, vPart.z, fDot); //正好构成一个旋转2*theta角度的四元数}

ScreenToVector(float fScreenPtX, float fScreenPtY):函数是获取鼠标的屏幕坐标,返回g_pNow。(当输入的参数是ScreenX/2与ScreenY/2时,得到的就是g_vCenterPt)
QuatFromBallPoints(const D3DXVECTOR3 &vFrom, const D3DXVECTOR3 &vTo):就是调入g_vCenterPt与g_vCurrentPt得到从g_vCenterPt旋转到g_vCurrentPt的四元数。

 

难点二:重力模拟

                首先要得到小球的加速度方向:

D3DXVec3Cross(&CurrentAxis, &g_vCurrentPt, &g_vCenterPt);D3DXVec3Cross(&PreDist, &g_vCenterPt, &CurrentAxis);D3DXVec3TransformNormal(&BallDist, &PreDist, &Rotation);// 得到小球滚动方向

由g_vCenterPt与g_vCurrentPt叉乘得到CurrentAxis,再与g_vCenterPt叉乘得到PreDist。再通过Roation(是场景的旋转矩阵)变换PreDist得到BallDist。

 

                再次是要让小球跟踪地面,再进行移动。我的办法是:

matBall = matBall * matPreRotation * matBallMove * Rotation;//当前小球的偏移矩阵 = 初始位置 * 回归旋转矩阵 * 小球偏移矩阵 * 旋转矩阵

matPreRotation是将matBall旋转回去,回到水平位置。再由水平位置出发进行小球的偏移,最后再旋转回去。

matPreRotation可以由之前的旋转矩阵Rotation的逆矩阵得到(在此逆矩阵与转置矩阵是一样的)

 

最后的问题是matBallMove的偏移量的大小,因为加速度的方向已经确定了。偏移量可以由每次的加速度方向累加得到。

static D3DXVECTOR3 BallMove(0.0f, 0.0f, 0.0f);BallMove.x = BallMove.x + BallDist.x * dateDist;BallMove.z = BallMove.z + BallDist.z * dateDist;
当然y方向上是没有偏移的,为0;

难点三:碰撞测试

碰撞测试还有很多BUG。暂且不攻了。先再学习学习。现贴上有点问题的代码(该代码是由以前的打砖块的碰撞测试改编而来)。


 

D3DXVECTOR3 Colloding(D3DXVECTOR3 BallMove, D3DXVECTOR3 BallPosition, D3DXVECTOR3 BallDist){float dateDist = 0.05f;// 偏移系数float collod = 0.4f;// 弹性系数if(collodx[12 - int(BallPosition.z - BALLR + 70.0f + BallMove.z + BallDist.z * dateDist)/WALLHIGHT][int(BallPosition.x + 60.0f + BallMove.x + BallDist.x * dateDist)/WALLWIDE]!=0&& BallDist.z < 0)// 上边界碰撞{BallMove.x =  (BallMove.x + BallDist.x * dateDist) * collod;BallMove.z = -(BallMove.z + BallDist.z * dateDist) * collod;}else if(collodx[12 - int(BallPosition.z + BALLR + 70.0f + BallMove.z + BallDist.z * dateDist)/WALLHIGHT][int(BallPosition.x + 60.0f + BallMove.x + BallDist.x * dateDist)/WALLWIDE]!=0&& BallDist.z > 0)// 下边界碰撞{BallMove.x =  (BallMove.x + BallDist.x * dateDist) * collod;BallMove.z = -(BallMove.z + BallDist.z * dateDist) * collod;}else if(collody[12 - int(BallPosition.z + 70.0f + BallMove.z + BallDist.z * dateDist)/WALLHIGHT][int(BallPosition.x + BALLR + 60.0f + BallMove.x + BallDist.x * dateDist)/WALLWIDE]!=0&& BallDist.x > 0)// 左边界碰撞 {BallMove.x = -(BallMove.x + BallDist.x * dateDist) * collod;BallMove.z =  (BallMove.z + BallDist.z * dateDist) * collod;}else if(collody[12 - int(BallPosition.z + 70.0f + BallMove.z + BallDist.z * dateDist)/WALLHIGHT][int(BallPosition.x - BALLR + 60.0f + BallMove.x + BallDist.x * dateDist)/WALLWIDE]!=0 && BallDist.x < 0)// 右边界碰撞{BallMove.x = -(BallMove.x + BallDist.x * dateDist) * collod;BallMove.z =  (BallMove.z + BallDist.z * dateDist) * collod;}else {// 未碰撞BallMove.x = BallMove.x + BallDist.x * dateDist;BallMove.z = BallMove.z + BallDist.z * dateDist;}BallMove.y = 0;return BallMove;}


 

总结:该程序是本人的第一个3D程序,看了龙书与《精通DirectX 3D图形与动画程序设计》。如果仅依靠这2本基础的书籍想要开发真正的游戏还是相当有差距的。想要开发的好,还要牢牢掌握图形化的知识,很好的数学功底特别是矩阵,还有物理知识。因此,在今后的学习中注重实际的开发。灵活运用D3D库,强化图形学。暂且先读《real-time Rendering》。也好强化下英文的阅读。