ImageVerifierCode 换一换
格式:DOCX , 页数:7 ,大小:20.14KB ,
资源ID:16713479      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/16713479.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(从零实现3D图像引擎12构建支持欧拉和UVN的相机系统Word格式.docx)为本站会员(b****3)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

从零实现3D图像引擎12构建支持欧拉和UVN的相机系统Word格式.docx

1、它使用三个相互垂直的向量来表示相机的朝向:1) 相机注视的向量N2) 相机的上方向向量V3) 相机的右方向向量U如下图,是在世界坐标系下的UVN相机的向量表示:UVN来表示方向有什么好处呢?首先,我们如果想让相机跟踪某个点来拍摄的话,这种方式无疑要比每次去计算欧拉旋转角好很多。比如第三人称视角的游戏,一般都是以玩家为注视点。想象一下对于这种情况,能够很直观的想到去转多少欧拉角度吗。这里有几点非常值得注意:1) 如果我们有了注视点,通过用注视点坐标减去相机世界坐标,就可以求得N。(尚未归一化的)2) 如果我们已知上向量V,那么就可以通过NV求得右向量U。3) 我们如果把上向量V通过直角三角形分解

2、成在nv平面和uv平面上的两个分量的话,可以发现在nv平面上的分量没有意义,因为相机仰头或低头的方向已经由向量N来决定了。所以实质上向量V是决定相机是否倾斜的,所谓的倾斜是指让左耳靠向肩部的动作,而不是头部向左转头的动作。4) 而且即使给定的上向量V与向量N不垂直,也可以根据NV求得U,因为N和V可以构成一个平面了,自然可以求其法向量。然后再通过UN反求V,而这个V则是垂直于U和N的真正的V,其实也就是nv平面上的分量为0的V了。3. 定义相机结构cpp view plain copy typedef struct CAMERA_TYPE / 相机 POINT4D WorldPos; / 相机

3、在世界的坐标 VECTOR4D Direction; / 相机的朝向,相机默认的朝向 int Type; / 相机类型 CAMERA_TYPE_ELUER 或CAMERA_TYPE_UVN VECTOR4D U, V, N; / UVN相机的u,v,n向量 POINT4D UVNTarget; / UVN相机的目标点 int UVNTargetNeedCompute; / UVN相机的目标点是否需要根据朝向计算,1-是, 0-否,UVNTarget已给定 double ViewDistance; / 视距 double FOV; / 视野角度 double NearZ; / 近裁剪距离 dou

4、ble FarZ; / 远裁剪距离 PLANE3D ClipPlaneLeft, ClipPlaneRight, ClipPlaneUp, ClipPlaneDown; / 上下左右裁剪平面 double ViewPlaneWidth, ViewPlaneHeight; / 透视平面的宽和高 double ScreenWidth, ScreenHeight; / 屏幕宽高 double ScreenCenterX, ScreenCenterY; / 屏幕中心坐标 double AspectRatio; / 宽高比 MATRIX4X4 MatrixCamera; / 相机变换矩阵 MATRIX4

5、X4 MatrixProjection; / 透视投影变换矩阵 MATRIX4X4 MatrixScreen; / 屏幕变换矩阵 CAMERA, *CAMERA_PTR; 都有注释,没啥好说的了,都是上面介绍的参数,最后有3个矩阵缓存变换矩阵。4. 创建相机并计算需要计算的相机参数创建相机的函数除了把参数赋值外,要计算下列东西:宽高比、视距、各裁剪面。1) 求宽高比就是屏幕宽除以高。cam->AspectRatio = (double)screenWidth / (double)screenHeight;2) 求视距求视距OA很简单,已知视平面宽度为2,所以AB=1。tan(FOV/2)

6、 = AB : AO所以,AO = AB / tan(FOV/2)3) 求各裁剪面我们知道可以用平面上一点和平面的法向量来表示平面,因为所有的裁剪面都过原点O,所以只要找到法向量即可。找法向量最简单的方法就是在平面上找到另外两个点,然后就这两个点的叉乘,就可以得到法向量。找哪两个点呢?看下图,是找右裁剪面上的另外两点,这两个点真爽:再复习一遍叉乘公式吧:uv = <uy*vz - vy*uz , -ux*vz + vx*uz , ux*vy - vx*uy&把上面的两点分别作为u和v代入:&w*d / 2 + w*d / 2 , -w*d / 2 + w*d / 2 , -w*w / 4

7、 - w*w / 4&计算一下:w*d , 0 , - w*w&,我们可以把各分量缩放1/w,得:d, 0, -w/2&呵呵,法向量就搞定了。下面的函数,负责填充Camera的参数,并且计算上面这三个参数:cpp view plain copy void _CPPYIN_3DLib:CameraCreate(CAMERA_PTR cam, int type, POINT4D_PTR pos, VECTOR4D_PTR dir, POINT4D_PTR target, VECTOR4D_PTR v, int needtarget, double nearz, double farz, doubl

8、e fov, double screenWidth, double screenHeight) / 创建相机 / 相机类型 cam-&Type = type; / 设置位置和朝向 VectorCopy(&(cam-&WorldPos), pos); VectorCopy(&Direction), dir); / 设置UVN相机的目标点 if (target != NULL) VectorCopy(&UVNTarget), target); else VectorCreate(&UVNTarget), 0, 0, 0); if (v !V), v); cam-&UVNTargetNeed

9、Compute = needtarget; / 裁剪面和屏幕参数 cam-&NearZ = nearz; cam-&FarZ = farz;ScreenWidth = screenWidth;ScreenHeight = screenHeight;ScreenCenterX = (screenWidth - 1) / 2;ScreenCenterY = (screenHeight - 1) / 2;FOV = fov;ViewPlaneWidth = 2.0;ViewPlaneHeight = 2.0 / cam-&AspectRatio; / 根据FOV和视平面大小计算d cam-&View

10、Distance = (0.5) * (cam-&ViewPlaneWidth) / tan(AngelToRadian(fov/2); / 所有裁剪面都过原点 POINT3D po; VectorCreate(&po, 0, 0, 0); / 面法线 VECTOR3D vn; if (fov = 90.0) / 右裁剪面 VectorCreate(&vn, 1, 0, -1); PlaneCreate(&ClipPlaneRight, &po, &vn, 1); / 左裁剪面 VectorCreate(&vn, -1, 0, -1);ClipPlaneLeft, & / 上裁剪面 Vecto

11、rCreate(&vn, 0, 1, -1);ClipPlaneUp, & / 下裁剪面 VectorCreate(&vn, 0, -1, -1);ClipPlaneDown, & else / 如果视野不是90度,则在算某个裁剪面的法向量时,先去视平面上四个角上在该平面上的两个角作为该裁剪面上的两个向量,然后求叉乘,即可 / 下面的法向量vn直接使用了结果 / 右裁剪面 VectorCreate(&vn, cam-&ViewDistance, 0, -cam-&ViewPlaneWidth / 2.0);vn, -cam-&vn, 0, cam-&ViewDistance, -cam-&vn

12、, 0, -cam-& 5. 计算相机变换矩阵并缓存欧拉相机的变换矩阵在Hello3DWorld已经说的够多了,就是平移+旋转,但是位移和角度都是和物体变换相反而已。下面介绍下UVN相机的变换矩阵。平移是肯定要做的,这个不再多说了,说说平移之后,我们的变换矩阵是什么呢?再看一次UVN相机的示意图:U、V、N互相垂直,这不就是个坐标系么?还记得上次苍井空教给咱们如何推出变换矩阵么,就是找X,Y,Z轴作为操作柄,如何变换成新的坐标柄。设基向量&1,0,0& &0,1,0&0,0,1&为世界坐标系三个坐标轴向量,因为相机系的相机朝向为Z正方向,所以变换对应关系为:X轴-&UY轴-&VZ轴-&N所以变

13、换矩阵的X分量为&Ux, Uy, Uz&同理,Y分量&Vx, Vy, Vz&Z分量&Nx, Ny, Nz&所以UVN的变换矩阵为(不包括平移): Ux Uy Uz Vx Vy Vz Nx Ny Nz 所以可以写出下面的相机变换矩阵更新函数:CameraUpdateMatrix(CAMERA_PTR cam) / 更新相机中缓存的变换矩阵 VECTOR4D vmove;vmove, -cam-&WorldPos.x, -cam-&WorldPos.y, -cam-&WorldPos.z); MATRIX4X4 mmove; BuildMoveMatrix(&vmove, &mmove); if

14、(cam-&Type = CAMERA_TYPE_ELUER) MATRIX4X4 mrotation; BuildRotateMatrix(-cam-&Direction.x, -cam-&Direction.y, -cam-&Direction.z, &mrotation); MatrixMul(&mmove, &mrotation, &MatrixCamera); else if (cam-&Type = CAMERA_TYPE_UVN) if (cam-&UVNTargetNeedCompute) / 方向角、仰角 double phi = cam-&Direction.x; doub

15、le theta = cam-&Direction.y; double sin_phi = FastSin(phi); double cos_phi = FastCos(phi); double sin_theta = FastSin(theta); double cos_theta = FastCos(theta);UVNTarget.x = -1 * sin_phi * sin_theta;UVNTarget.y = 1 * cos_phi;UVNTarget.z = 1 * sin_phi * cos_theta; / 定义临时的UVN(未归一化) VECTOR4D u, v, n; /

16、 求N VectorSub(&UVNTarget, &WorldPos, &n); / 设置V VectorCopy(&v, &V); / 应为N和V可以组成一个平面,所以可求法向量U VectorCross(&n, &u); / 因为V和N可能不垂直,所以反求V,使得V和U、N都垂直 VectorCross(&u, &v); / UVN归一 VectorNormalize(&U); VectorNormalize(&V);N); / UVN变换矩阵 MATRIX4X4 muvn; MatrixCreate(&muvn, cam-&U.x, cam-&V.x, cam-&N.x, 0, cam

17、-&U.y, cam-&V.y, cam-&N.y, 0, cam-&U.z, cam-&V.z, cam-&N.z, 0, 0, 0, 0, 1);muvn, &6. 欧拉旋转角转UVN有一种非常常见的用法,就是相机只知道初始的朝向,并且是欧拉旋转角表示的。但我们还希望使用UVN系统的相机,那么就需要把欧拉相机朝向计算出UVN,这样相机就变成UVN相机了。要做这个转换,其实就是要求得目标注视点的坐标,这里要应用球面坐标系转笛卡尔坐标系的性质来完成了。我们先假设注视目标点在点P,我们用球面坐标系来表示这个点P(p, phi, theta):如果您对球面坐标系还有印象的话,可以发现其实球面坐标中

18、的phi就是欧拉旋转角中的绕Y轴旋转的角度,theta就是绕Z轴旋转的角度。所以:phi = cam-&theta = cam-&Direction.z;我自认为这个图画的立体效果很强哈,而且重要的直角都标出来了。因为我们只关系朝向不关系长度,所以我们设这个球面坐标的p为1。所以可以非常容易推得:r = sin(phi)x = cos(theta) * ry = sin(theta) * rz = cos(phi)好了,万事俱备,现在实现一个比较完善的更新缓存矩阵的函数:UVNTargetNeedCompute) / 欧拉角度求注视向量 double phi = cam-& double r

19、= sin_phi;UVNTarget.x = cos_theta * r;UVNTarget.y = sin_theta * r;UVNTarget.z = cos_phi;通过type判断是缓存欧拉变换矩阵还是UVN变换矩阵,如果是UVN变换,还要判断UVNTargetNeedCompute的值,来决定是否将欧拉角度转变为注视向量,否则直接使用结构体存放的Target向量。别的就不用多说了。7. 代码下载这次没有多演示DEMO做什么更新,但是因为使用比较完善的相机系统,所以已经可以支持随意的操纵相机了。完整项目代码下载:点击进入下载页&8. 补充说明这篇文章的知识用的比较多,我学习了好几本书,如3D数学基础:图形与游戏开发。结果发现有一本书中存不少的说法错误和问题,就是3D游戏编程大师技巧这本,有一些可能是翻译水平问题,还有一些光盘源码也有的问题,这里指出一下。1) 求视距,该书给出的推导公式和代码为 d = (0.5) * (cam-&viewplane_width)

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1