DirectX9.0 入门手册(6)
第一次写这种文章,再加上自己也是菜鸟,虽然有部分内容是参考一些书籍及自己翻译一些英文文章所写出来的,但我相信文章里面肯定也还有很多bug,如果你发现了请告诉我,或者你有什么想法也可以和我交流,我诚心和志同道合的人成为朋友,我的QQ是61010818,我的邮箱fowenler@126.com
无论计算机图形技术如何发展,只要它以二维的屏幕作为显示介质,那么它显示的图像即使多么的有立体感,也还是二维的。有时我会想,有没有以某个空间作为显示介质的的可能呢,不过即使有,也只能是显示某个范围内的图像,不可能有无限大的空间作为显示介质,如果有,那就是现实世界了。
既然显示器的屏幕是二维的,那么我们就要对图像作些处理,让它可以欺骗我们的眼睛,产生一种立体的真实感。在D3D中,这种处理就是一系列的空间变换,从模型空间变到世界空间,再变到视图空间,最后投影到我们的显示器屏幕上。
·世界空间与世界矩阵
什么是模型空间呢?每个模型(3D物体)都有它自己的空间,空间的中心(原点)就是模型的中心。在模型空间里,只有模型上的不同点有位置的相对关系。那什么是世界空间呢?世界就是物体(模型)所存在的地方。当我们把一个模型放进世界里面去,那么它就有了一个世界坐标,这个世界坐标是用来标记世界中不同的模型所处的位置的。在世界空间里,世界的中心就是原点(0, 0, 0),也就是你显示器屏幕中间的那一点。我们可以在世界空间里摆放很多个模型,并且设置它们在世界空间中的坐标,这样模型与模型之间就有了相对的位置。
世界矩阵有什么用呢?我们可以利用它来改变世界空间的坐标。这样,在世界空间里面的模型就可以移动、旋转和缩放了。
我们可以使用上一章末尾所讲的那几个函数来产生世界矩阵。例如产生一个绕X轴旋转的转阵:D3DXMatrixRotationX(&matrix,1)。利用matrix这个矩阵,就可以使世界空间中的物体绕X轴转动1弧度。
可以结合后面的例子来理解世界矩阵。
·视图空间与视图矩阵
世界空间建立起来后,我们不一定能看到模型,因为我们还没有“眼睛”啊。在视图空间里,我们可以建立我们在三维空间中的眼睛:摄像机。我们就是通过这个虚拟的摄像机来观察世界空间中的模型的。所以视图空间也叫摄像机空间。
要建立起这个虚拟的摄像机,我们需要一个视图矩阵,产生视图矩阵的一个函数是:
D3DXMATRIX *D3DXMatrixLookAtLH(
D3DXMATRIX* pOut,
CONST D3DXVECTOR3* pEye,
CONST D3DXVECTOR3* pAt,
CONST D3DXVECTOR3* pUp
);
pOut:返回的视图矩阵指针
pEye:设置摄像机的位置
pAt:设置摄像机的观察点
pUp:设置方向“上”
这个函数的后缀LH是表示左手系的意思,聪明的你一定能够猜出肯定有个叫D3DXMatrixLookAtRH的函数。至于左手系和右手系的区别,这里就不多说了,记住左手系中的Z正方向是指向显示器里面的就行了。只能弄懂了视图矩阵的含义,建立视图矩阵完成可以不依赖函数,自己手动完成。视图矩阵其实就是定义了摄像机在世界空间中的位置、观察点、方向“上”这些信息。
可以结合后面的例子来理解视图矩阵。
·投影与投影矩阵
定义投影矩阵很像是定义摄像机的镜头,下面看它的函数声明:
D3DXMATRIX *D3DXMatrixPerspectiveFovLH(
D3DXMATRIX* pOut,
FLOAT fovY,
FLOAT Aspect,
FLOAT zn,
FLOAT zf
);
pOut:返回的投影矩阵指针
fovY:定义镜头垂直观察范围,以弧度为单位。对于这个参数,下面是我的理解:如果定义为D3DX_PI/4(90度角),那么就是表示以摄像机的观察方向为平分线,上方45度角和下方45度角就是摄像机所能看到的垂直范围了。嗯,可以想象一下自己的眼睛,如果可以把自己眼睛的fovY值设为D3DX_PI/2(180度角),那么我们就可以不用抬头就看得见头顶的东西了。如果设为D3DX_PI的话。。。我先编译一下试试(building…)。哈哈,结果啥也看不见。很难想象如果自己能同时看到所有方向的物体,那么将是一个怎样的画面啊。
Aspect:设置纵横比。如果定义为1,那么所看到的物体大小不变。如果定义为其它值,你所看到的物体就会变形。不过一般情况下这个值设为显示器屏幕的长宽比。(终于明白为什么有些人会说电视上的自己看起来会比较胖了……)
zn:设置摄像机所能观察到的最远距离
zf:设置摄像机所能观察到的最近距离
·一小段代码
请看以下代码片段:
D3DXMATRIXA16 matWorld;
D3DXMatrixIdentity( &matWorld );
D3DXMatrixRotationX( &matWorld, timeGetTime()/1000.0f );
g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f );
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
D3DXMATRIXA16 matView;
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/2, 1.0f, 1.0f, 500.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
通过上面三个转换,就建立了一个我们可以通过显示器屏幕来观察的3D世界。上面三个转换分别是:
从模型空间到世界空间的世界转换:SetTransform( D3DTS_WORLD, &matWorld )。
从世界空间到视图空间的视图转换:SetTransform( D3DTS_VIEW, &matView )。
从视图空间到到屏幕的投影转换:SetTransform( D3DTS_PROJECTION, &matProj )。
现在来观察matWorld,matView,matProj这三个矩阵的特点。我们使用D3DXMatrixRotationX函数来产生了一个绕X轴旋转的转换矩阵,通过设置世界转换,在世界空间里面的物体将绕X轴作旋转。然后我们定义了三个三维的向量,用来设置摄像机的位置,观察方向和定义方向“上”。使用D3DXMatrixLookAtLH函数来把这三个向量放进视图矩阵里面去。然后通过设置视图转换,我们就建立了一个虚拟的摄像机。最后通过D3DXMatrixPerspectiveFovLH函数,我们得到一个投影矩阵,用来设置虚拟摄像机的镜头。
我还是解释一下上面说的那个方向“上”是什么东西吧。这个“上”其实指的就是摄像机在刚建立的时候是如何摆放的,是向左边侧着摆,还是向右边侧着摆,还是倒过来摆,都是通过这个方向“上”来指定的。按照正常的理解,摄像机的“上”方向就是Y轴的正方向,但是我们可以指定方向“上”为Y轴的负方向,这样世界建立起来后就是颠倒的了。不过颠倒与否,也是相对来说的了,试问在没有引力的世界中,谁能说出哪是上哪是下呢?是不是看得一头雾水啊?只要自己亲手改变一下这些参数,就可以体会到了。
设置上面三个转换的先后顺序并不一定得按照世界到视图到投影这个顺序,不过习惯上按照这种顺序来写,感觉会好一点。
·使用矩阵相乘来创建世界矩阵
在世界空间中的物体运动往往是很复杂的,比如物体自身旋转的同时,还绕世界的原点旋转。怎么实现这种运动呢?通过矩阵相乘来把两个矩阵“混”在一起。现在我们假设某一物体建立在世界的原点上,看以下代码:
//定义三个矩阵
D3DXMATRIX matWorld, matWorldY,matMoveLeft;
//一个矩阵把物体移到(30,0,0)处,一个矩阵使物体绕原点(0,0,0)旋转
D3DXMatrixTranslation(&matMoveRight,30,0,0);
D3DXMatrixRotationY(&matWorldY, radian/1000.0f);
//第一次矩阵相乘。先旋转,再平移
D3DXMatrixMultiply(&matWorld, &matWorldY, &matMoveRight);
//第二次矩阵相乘。在第一次矩阵相乘的结果上,再以Y轴旋转
D3DXMatrixMultiply(&matWorld, &matWorld, &matWorldY);
//设置世界矩阵
m_pD3DDevice->SetTransform( D3DTS_WORLD, &matWorld );
矩阵相乘的时候,矩阵的先后顺序很重要,如果顺序弄错了,物体就不会按我们预料的那样运动。从最后一次矩阵相乘看起,最后相乘的两个矩阵是matWorld和matWorldY,其中matWorld又是由matWorldY和matMoveRight相乘得来的,那么这三个矩阵相乘的顺序就是(matWorldY,matMoveRight,matWorldY)。这个顺序意味着什么呢?第一个matWorldY使物体绕Y轴旋转,这时候的物体还处于原点,所以它绕Y轴旋转也就是绕自身的旋转。它转呀转呀,这时候matMoveRight来了,它把物体从(0,0,0)移到了(30,0,0),这时候物体就不再是绕Y轴旋转了,它是在(30,0,0)这个位置继续绕自身旋转。然后matWorldY又来了,它使物体再次以Y轴旋转,不过此时物体不在原点了,所以物体就以原点为中心作画圆的运动(它自身的旋转仍在继续),这个圆的半径是30。如果换一个顺序,把matMoveRight放在第一的话,那么就是先移动再旋转再旋转(第二次旋转没用),这时候物体就只是画圆运动而已,它自身没有旋转。如果把matMoveRight放在最后,那么就是先旋转再旋转(第二次旋转没用)再移动,这时候物体就没有作画圆运动了,它只是在(30,0,0)这个位置上作自身旋转。好了,理解这个需要一点点想象力。你可以先写好几个矩阵相乘的顺序,自己想象一下相乘的结果会使物体作什么运动,然后再编译执行程序,看看物体的运动是不是和自己想像中的一样,这样可以锻炼自己的空间思维能力。
好了,又写完一章了。下一章可能要过一些日子才能写。因为自己还没找到工作,国庆过后就得出发去找工了,接下来的日子要作一些找工前的准备,所以就没什么时间继续写了。至于什么时候写第七篇,呵呵,应该不用很久,找到工作后立刻回来这里报道~~大家祝我好运吧^_^
DirectX9.0 入门手册(6)相关推荐
- DirectX9.0 入门手册
下面正式开始,先讲窗口类,创建窗口,销毁窗口,窗口消息处理函数. ·窗口类 WNDCLASS struct WNDCLASS { UINT style; WNDPROC lpfnWndProc; in ...
- DirectX9.0 入门手册【转贴】
这一章我先不写有关DX的东西,我先从最基本的窗口创建讲起,然后再慢慢讲解使用DX的一些内容. 我写这个指南的主要目的是为了学习.我希望自己可以通过写这个指南更快地学会DirectX.同时,我也希望为其 ...
- Shadow Map在DirectX9.0 SDK Sample 的实现方法
很宝贵的资料,总结的相当不错.目前原创作者未知,如有知情者肯请告知,感激不尽~ 一.前言 这个教程主要面对DirectX9.0的初学者,文中代码说明部分以DirectX9.0c SDK(Augus ...
- AI产品经理入门手册(下)
近两年来AI产业已然成为新的焦点和风口,各互联网巨头都在布局人工智能,不少互联网产品经理也开始考虑转型AI产品经理,本文作者也同样在转型中.本篇文章是通过一段时间的学习归纳总结整理而成,力图通过这篇文 ...
- rocketmq 顺序消费_必须先理解的RocketMQ入门手册,才能再次深入解读
推荐阅读一下下 2020年后想跳槽?MQ.ZK.Nginx.Kafk等分布式技术你都掌握了? 阿里架构师推荐学习的<RabbitMQ实战指南>,渣渣的你都看过吗? RocketMQ入门手册 ...
- 推荐算法炼丹笔记:CTR点击率预估系列入门手册
CTR点击率预估系列家谱 炼丹之前,先放一张CTR预估系列的家谱,让脉络更加清晰. (一)FiBiNET:结合特征重要性和双线性特征交互进行CTR预估 1.1 背景 本文发表在RecSys 2019 ...
- React 入门手册
大家好,我是若川.推荐这篇可收藏的React入门手册.也推荐之前一篇类似的文章<如何使用 React 和 React Hooks 创建一个天气应用>. 点击下方卡片关注我.加个星标 Rea ...
- rocketmq 订阅组_必须先理解的RocketMQ入门手册,才能再次深入解读
推荐阅读一下下 2020年后想跳槽?MQ.ZK.Nginx.Kafk等分布式技术你都掌握了? 阿里架构师推荐学习的<RabbitMQ实战指南>,渣渣的你都看过吗? RocketMQ入门手册 ...
- Tablestore入门手册-UpdateRow接口详解
表格存储Tablestore入门手册系列主要介绍表格存储的各个功能接口和适用场景,帮助客户了解和使用表格存储Tablestore.本文对表格存储Tablestore的UpdateRow接口进行介绍,包 ...
最新文章
- RecyclerView添加header与footer
- VTK:Utilities之SaveSceneToFile
- write up: web login1(SKCTF) --SQL约束攻击
- Android JNI_OnLoad()函数
- IOCP 下行为投递的关键点
- python面向对象:小结
- opencv常用函数整理(一)
- 【工具】Sublime Text 自动保存功能
- shell获取git最近一次提交信息_我低估了PowerShell:一个提取Git提交记录并生成文件Diff列表的脚本案例...
- 备战数学建模12-模糊综合评价模型
- 8位串行加法器 计算机组成原理,安尧-2013434158-计算机组成原理8位加法器实验报告.doc...
- 如何查看CentOS操作系统版本
- 中年,就是1个人演1部西游记
- 树莓派简单摄像头录像并保存视频文件
- PHP 8.1性能基准测试结果出炉,比7.0版本提升44%
- pip安装:Cannot uninstall ''. It is a distutils installed project and thus we cannot accurately....解决办法
- 跨浏览器的事件处理程序
- Milestone 系统架构 及产品白皮书
- 《近匠》从Cubieboard到radxa:汤亮的第二次硬件创业
- 微星绝影 GS77 评测
热门文章
- 小米5miui10android,小米又一款手机适配Android 10!MIUI开发版暂停,米粉别着急!...
- linux 433驱动程序,linux 433发送驱动
- linux下安装mysql和mysql主从配置
- dojo学习之2——使用 Dojo 掌握面向对象开发
- CSDN开发者周刊第 22期:谷歌 DeepMind 第四代:不学规则就可以玩游戏;图灵奖得主 Edmund Clarke 因感染“新冠”逝世;
- 英语发音之音标11---总结()
- 在“提示”框中:管理Android音频配置文件,Android上的Google书签和电缆固定
- 12306火车余票查询API
- 史上最新 PHP 调用 jar包教程
- Quarter II 13.0下载、安装、破解包括可能出现的几乎所有的问题详解