您的位置:首页 > 编程语言

打造3D游戏中第一人称视觉效果 - 带可测试源代码下载

2013-11-02 15:07 330 查看
首先解决的一个问题:什么是镜头?

我们可以想象拍戏那种镜头,对着什么东西,就能拍出什么东西,然后我们就可以在电视屏幕或者电影屏幕上看到这些东西。3D世界里面也是这样定义一个镜头,在这个镜头范围之内的东西就可以显示在电脑屏幕中。

如下图在一个方各地上行走:






下面是把镜头抽象起来:

拍戏的时候,这个镜头是个实体,那么在我们的3D世界里面我们也是这样把镜头当做一个实体,在代码中体现出来就是一个类。

在游戏中控制镜头前进,后退,左移,右移,其实就是在代码中操作这个类。

所以问题就归结为如何构建这个类,和如何操作这个类了。

首先构建这个类的对象成员有如下数据:

class Camera
{
protected:
	D3DXMATRIX mView;//操作镜头的主要矩阵
	D3DXMATRIX mProj;//投影到屏幕上的矩阵
	D3DXMATRIX mViewProj;//从镜头空间到投影到屏幕上的矩阵
 
	D3DXVECTOR3 mPosW;//镜头位置
 	D3DXVECTOR3 mRightW;//镜头的由向量
 	D3DXVECTOR3 mUpW;//镜头的上向量
 	D3DXVECTOR3 mLookW;//镜头的前向量
 	float mSpeed;//镜头的速度



镜头的坐标如下:



右上角的代表镜头,指向前的叫前向量,指向上的叫上向量,指向右的叫右向量。这样就构成了镜头坐标空间。就是构建了这样的空间,才可以让镜头前面的物体相对于镜头的位置得以确定!是在看不懂的朋友先熟记一下这个概念,然后建议补一补几何学。

mProj和mViewProj矩阵基本上在所有3D世界都要用到的。这是图形学的构造原理,有空再专门解析一下吧。简单解析一下就是说:利用这些矩阵才能把定位在世界坐标空间的物体投影到屏幕上。

跟本章相关的就是mView矩阵了,就是利用了这个矩阵才能操作镜头的。这个矩阵的计算方法如下:

定义在类中:

class Camera
{
public:
	Camera();
protected:
	void buildView();


实现函数:

void Camera::buildView()
{
	// 这里是前向量单位化.
	D3DXVec3Normalize(&mLookW, &mLookW);

     	D3DXVec3Cross(&mUpW, &mLookW, &mRightW);//作叉乘可以确保这2个向量是正交的,也就是都互相垂直。
	D3DXVec3Normalize(&mUpW, &mUpW);

	D3DXVec3Cross(&mRightW, &mUpW, &mLookW);//再次叉乘保证正交
 	D3DXVec3Normalize(&mRightW, &mRightW);

	//这里是根据几何公式来填写这个需要的变换矩阵的,至于是什么公式,我也不记得了,因为公式很复杂,死背不是好办法,但是原理要知道,就是利用这样的矩阵来转换镜头。

	float x = -D3DXVec3Dot(&mPosW, &mRightW);
	float y = -D3DXVec3Dot(&mPosW, &mUpW);
	float z = -D3DXVec3Dot(&mPosW, &mLookW);

	mView(0,0) = mRightW.x; 
	mView(1,0) = mRightW.y; 
	mView(2,0) = mRightW.z; 
	mView(3,0) = x;   

	mView(0,1) = mUpW.x;
	mView(1,1) = mUpW.y;
	mView(2,1) = mUpW.z;
	mView(3,1) = y;  

	mView(0,2) = mLookW.x; 
	mView(1,2) = mLookW.y; 
	mView(2,2) = mLookW.z; 
	mView(3,2) = z;   

	mView(0,3) = 0.0f;
	mView(1,3) = 0.0f;
	mView(2,3) = 0.0f;
	mView(3,3) = 1.0f;
}


下面就是以鼠标和键盘为参数不断更新上面这些参数,得到不断移动镜头的感觉:

void Camera::update(float dt)
{
	// 这里是控制方法wsda为前后左右。
	D3DXVECTOR3 dir(0.0f, 0.0f, 0.0f);
	if( gDInput->keyDown(DIK_W) )
		dir += mLookW;
	if( gDInput->keyDown(DIK_S) )
		dir -= mLookW;
	if( gDInput->keyDown(DIK_D) )
		dir += mRightW;
	if( gDInput->keyDown(DIK_A) )
		dir -= mRightW;
	
	// Move at mSpeed along net direction.
	D3DXVec3Normalize(&dir, &dir);
	mPosW += dir*mSpeed*dt;//这里是控制其速度,可以改变mSpeed的大小以改变其速度,记得mSpeed为类的私有成员。
 	mPosW.y = 2.0f;//这里是限制其高度,相当于人的高度。如果把这里去掉的话,就可以飞起来了。
 	if(mPosW.x >= 49.0f)//这下面的代码是控制不要超出了方格地的范围了。
		mPosW.x = 49.0f;
	if(mPosW.x <=-49.0f)
		mPosW.x = -49.0f;
	if(mPosW.z >= 49.0f)
		mPosW.z = 49.0f;
	if(mPosW.z <= -49.0f)
		mPosW.z = -49.0f;
	
	// 下面是鼠标控制代码,控制其向左和向右,向上和向下看.
	float pitch  = gDInput->mouseDY() / 150.0f;
	float yAngle = gDInput->mouseDX() / 150.0f;

	// 向上下方向看时的变换算法.
	D3DXMATRIX R;
	D3DXMatrixRotationAxis(&R, &mRightW, pitch);
	D3DXVec3TransformCoord(&mLookW, &mLookW, &R);
	D3DXVec3TransformCoord(&mUpW, &mUpW, &R);

	// 向左向右看时的算法.
	D3DXMatrixRotationY(&R, yAngle);
	D3DXVec3TransformCoord(&mRightW, &mRightW, &R);
	D3DXVec3TransformCoord(&mUpW, &mUpW, &R);
	D3DXVec3TransformCoord(&mLookW, &mLookW, &R);

	// 然后需要重新调用前面的函数根据上面的新参数更新计算,这样达到移动镜头的目的.
	buildView();
	mViewProj = mView * mProj;
}


下面是调用函数,我写了个namespace包起来,方便修改:

#include "CameraRun.h"
#include "Camera.h"

namespace CameraRun
{
	Camera camera;
	
	void initData()
	{
		gCamera = &camera;
		gCamera->pos() = D3DXVECTOR3(-20.0f, 2.0f, 0.0f);
	}

	void updateAll(float dt)
	{
		gCamera->update(dt);
	}
}


玩这个程序只需要修改上面说明的地方就可以自己测试了。

可以修改的地方:

1 修改成为可以飞起来的

2 修改其速度

3 改成不受方格地限制

4 更难的就是修改限制其俯视的角度



这里是镜头类下载:

http://download.csdn.net/detail/kenden23/6491871

这里是框架下载:

http://download.csdn.net/detail/kenden23/6491875

都是源代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: