位置: 编程技术 - 正文

OpenGL教程翻译 第十三课 相机空间(opengl learn)

编辑:rootadmin
OpenGL教程翻译 第十三课 相机空间原文地址: 2D平面能看见的部分只是一个矩形。在该矩形的外部所有东西都将被减掉。把这个矩形渲染到屏幕是我们的目标。

推荐整理分享OpenGL教程翻译 第十三课 相机空间(opengl learn),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:opengl transform,opengl英文,opengl英文,opengl语言,opengl英文,opengl英文,opengl中文教程,opengl translate,内容如对您有帮助,希望把文章链接给更多的朋友!

理论上可以生成这样的变化矩阵,实现把一个位于3D空间的对象投影到坐落在世界坐标系任意位置的相机正前方的2D平面上。然而,这其中的数学变换比我们之前遇见的要复杂很多。而当相机被置于3D世界坐标系的源点并且方向沿着Z轴时的投影就简单了很多。比如,一个对象放在(0,0,5)处,同时相机放在(0,0,1)处并且方向朝向Z轴。如果我们把相机和对象朝着原点移动一个单位,那时两者的相对距离和方向(就相机的方向而言)保持不变,而区别只是相机此时位于原点。以同种方式移动场景中的所有物体使得我们能够正确渲染场,用之前学到的方法。

上面的例子很简单,因为相机的方向已经沿着Z轴,并且通常对准坐标系的轴。但是如果相机指向其他方向将会发生什么呢?看下面的图片。简单的说,这是一个2D坐标系统,我们从顶部看相机。

相机的方向原本是指向Z轴的,但是之后顺时针旋转度。就如你看到的,相机定义它自己的坐标系统,这个坐标系可能与世界坐标系相同(上面的图片),也可能不同(下面的图片)。所以实际上同时存在两个坐标系统。即一个用来指定对象的世界坐标系,和一个与相机的“轴”(target, up and right)对齐的相机坐标系统。这两个坐标系就是我们所知的世界空间和相机/视图空间。

上图中,绿球在世界空间中位于(0,y,z)。在相机空间中,它位于坐标系的左上角(换言之,它的X坐标为负,Z坐标为正)。我们需要找到绿球在相机空间中的位置。此时我们可以先简单的忘记所有关于世界空间的,仅仅只使用相机空间。在相机空间中,相机位于原点方向,指向Z轴。对象的指定和相机有关,并且可以用我们学过的方法来渲染对象。

相机顺时针旋转了度相当于绿球逆时针旋转了度。对象的移动总是和相机的移动相反。所以总的来说,我们需要增加两个新的变换,并将它们加入我们已有的变换管线中。我们需要,在让相机移动到原点的过程中保持对象和相机之间相对位置不变,同时也需要让对象沿着与相机旋转方向的反方向转动。

移动相机是非常简单的。如果相机位于(x,y,z),那么平移变换就是(-x,-y,-y)。原因很明显——相机在世界坐标系下用向量(x,y,z)做平移变换,所以想要相机回到原点,那么我们就需要使用此向量的相反向量进行平移。变换矩阵如下所示:

下一步是将相机转向世界坐标系中指定的位置。我们想要找到在相机定义的新坐标系下顶点的位置。所以实际的问题是:我们如何从一个坐标系转换到另一个坐标系?

再看看上面的图。世界坐标系是由三个线性无关的向量(1,0,0), (0,1,0) 和 (0,0,1)定义的。线性无关意思是我们找不到不全为0的x,y,z使得x*(1,0,0) &#; y(0,1,0) &#; z*(0,0,1) = (0,0,0)。用几何术语来说,这意味着这三个向量中的任意两个都可以确定一个垂直于第三个向量的平面。很容易可以看到相机坐标系是由向量(1,0,-1), (0,1,0), (1,0,1)确定的。标准化这些向量后,我们得到(0.,0,-0.),(0,1,0) 和(0.,0,0.)。

下面的图片展示了向量的位置是如何在两个不同的坐标系被指定的。

我们知道在世界坐标系空间中如何得到代表相机空间坐标轴的单位向量,也知道了在世界坐标系空间中向量的位置(x,y,z)。我们要找的是向量(x',y',z')。我们现在利用点积的一个叫做“标量投影”的属性。标量投影是一个任意的向量A和一个单位向量B点积的结果,产生B向量方向上A向量的延伸。换句话说,这个结果就是向量A在向量B上的投影。在上面的例子中,如果我们让向量(x,y,z)和代表相机X轴的单位向量之间做点积,那么我们将得到x'&#;。相同的方法我们可以得到y',z'。(x',y',z')是在相机空间中(x,y,z)的位置。

让我们看看如何把这个想法变成一个完整的标定相机方向的办法。这个办法叫做“UVN相机”,它仅仅是众多指定相机方向的办法中的一个。这个方法就是是,相机被下列的矩阵所定义:

1:N – 由相机指向它的目标的向量。在一些3D的文献中也被称为'look at'。这个向量对应于Z轴。

2:V – 直立时,这个向量是竖直向上的。如果你正在编写飞机模拟仿真的程序并且飞机是被反转的,那么向量最好是朝向地面的。这个向量对应于Y轴。

3:U – 这个向量从相机指向其右侧。它对应于X轴。

为了把一个位置从世界坐标系空间转换到被UVN向量定义的相机坐标系空间,我们需要在位置和UVN向量之间进行一个点乘运算。如下面的矩阵所示:

这一节的代码中,你将会注意到着色器中的全局变量'gWorld'已经被重命名为'gWVP'。这个改变体现了在许多书籍中这一系列变换为我们所知的方式。WVP代表World-View-Projection。

Code Walkthru在这一节中我决定做一个小的设计改变,把低级的矩阵操作代码从Pipeline类移到Matrix4f类中。Pipeline类让Matrix4f类调用不同的方法初始化它自己并且链接几个矩阵来生成最终的矩阵变换。

(pipeline.h:)

struct { Vector3f Pos; Vector3f Target; Vector3f Up;} m_camera;

Pipeline类有一些新的成员来储存相机参数。注意相机参数中缺少'U'轴。它将通过在target和up之间进行叉乘计算得到。此外这里有一个新的函数SerCamera来传递这些&#;。

(math3d.h:)

Vector3fVector3f::Cross(const Vector3f& v) const

{

const float _x = y * v.z - z * v.y;

const float _y = z * v.x - x * v.z;

const float _z = x * v.y - y * v.x;

return Vector3f(_x, _y, _z);

}

Vector3f类中有一个新的方法来计算两个Vector3f对象的叉积。两个向量的叉积会产生一个向量,它垂直于两个相乘向量组成的平面。当你记住这些向量有方向和幅度但是没有位置时,这个变的更直观。所有拥有相同的方向和大小的向量被认为是相等的,不论它们的起点在哪里。所以你也可以让两个向量的起点位于原点。这意味着你可以创建一个三角形,这个三角形有一个顶点是位于起点而另外两个顶点是向量的终点。这个三角形定义了一个平面,叉积产生了一个垂直于这个平面的向量。在维基百科(Wikipedia)中可以了解到更多关于叉积。

(math3d.h:)

Vector3f&Vector3f::Normalize()

{

const float Length = sqrtf(x * x &#; y* y &#; z * z);

x /= Length;

y /= Length;

z /= Length;

OpenGL教程翻译 第十三课 相机空间(opengl learn)

return *this;

}

为了生成UVN矩阵我们需要让这些向量成为单位向量。这个操作术语称作是向量的标准化,它由让向量的每个分量除以向量的长度得来。

(math3d.cpp:)

voidMatrix4f::InitCameraTransform(const Vector3f& Target, const Vector3f&Up)

{

Vector3f N = Target;

N.Normalize();

Vector3f U = Up;

U.Normalize();

U = U.Cross(Target);

Vector3f V = N.Cross(U);

m[0][0] = U.x; m[0][1] = U.y; m[0][2]= U.z; m[0][3] = 0.0f;

m[1][0] = V.x; m[1][1] = V.y; m[1][2]= V.z; m[1][3] = 0.0f;

m[2][0] = N.x; m[2][1] = N.y; m[2][2]= N.z; m[2][3] = 0.0f;

m[3][0] = 0.0f; m[3][1] = 0.0f;m[3][2] = 0.0f; m[3][3] = 1.0f;

}

这个函数生成了稍后在pipeline类中使用的相机转化矩阵。U,V,N向量计算后置于矩阵的每一行。因为顶点的位置向量将在矩阵的右边被乘(作为一列)。这意味着在U,V,N向量和位置向量之间做点乘。这将生成三个标量&#;,这三个&#;是在屏幕坐标系下XYZ的&#;。

这个函数被提供的参数是target和up向量。“right”向量是通过这两个向量的叉乘得到。因为不确定参数是否为单位向量,所以我们标准化这些向量。在生成U向量后,我们再通过target和right向量之间进行叉乘来计算up向量。在后面我们开始移动相机的时候,将会发现重新计算up向量的原因,只更新target向量而up向量保持不变是较为简单的。然而,这意味着在target和up向量之间的角度将不是度,导致这个坐标系统变得无效。通过计算right向量和up向量,我们将的得到一个每一对轴之间的角度都是度的坐标系统。

(pipeline.cpp:)

constMatrix4f* Pipeline::GetTrans()

{

Matrix4f ScaleTrans, RotateTrans,TranslationTrans, CameraTranslationTrans, CameraRotateTrans,PersProjTrans;

ScaleTrans.InitScaleTransform(m_scale.x,m_scale.y, m_scale.z);

RotateTrans.InitRotateTransform(m_rotateInfo.x,m_rotateInfo.y, m_rotateInfo.z);

TranslationTrans.InitTranslationTransform(m_worldPos.x,m_worldPos.y, m_worldPos.z);

CameraTranslationTrans.InitTranslationTransform(-m_camera.Pos.x,-m_camera.Pos.y, -m_camera.Pos.z);

CameraRotateTrans.InitCameraTransform(m_camera.Target,m_camera.Up);

PersProjTrans.InitPersProjTransform(m_persProj.FOV,m_persProj.Width, m_persProj.Height, m_persProj.zNear, m_persProj.zFar);

m_transformation = PersProjTrans *CameraRotateTrans * CameraTranslationTrans * TranslationTrans *

RotateTrans * ScaleTrans;

return &m_transformation;

}

让我们更新生成一个对象完整的变化矩阵的函数。现在只是新增了两个关于相机的新的矩阵就已经变得相当复杂。在完成了世界坐标系下的变换(结合对象的缩放,旋转,平移)后,我们通过移动相机到原点开始了对相机的变换。这个平移转换通过使用相机位置向量的反向量完成的。所以如果相机在(1,2,3),那么为了让相机回到原点我们需要把相机沿(-1,-2,-3)这个向量移动。之后我们基于相机的target和up向量而生成相机的旋转矩阵。那么相机部分的变换就完成了。最后生成坐标。

(tutorial.cpp:)

Vector3fCameraPos(1.0f, 1.0f, -3.0f);

Vector3fCameraTarget(0.f, 0.0f, 1.0f);

Vector3fCameraUp(0.0f, 1.0f, 0.0f);

p.SetCamera(CameraPos,CameraTarget, CameraUp);

在主渲染循环中我们使用新的方法。为了放置相机,我们从原点沿着Z轴的负方向后移动,然后向右移和向上移动。up向量就是Y轴的正半轴。我们把所有的这些送进Pipeline对象中,Pipeline类将处理接下来的工作。

3D图象算法(转) 原文链接3D简介我们首先从坐标系统开始。你也许知道在2D里我们经常使用Ren?笛卡儿坐标系统在平面上来识别点。我们使用二维(X,Y):X表示水平轴坐标,Y表

雨滴波纹核心代码 一、案例效果图:二、源代码下载地址:

opengl配置glut.h问题 注意:这解决方法不是所有人都适用,就如我,我只有把subsystem:console依然保持不变才能运行

标签: opengl learn

本文链接地址:https://www.jiuchutong.com/biancheng/369630.html 转载请保留说明!

上一篇:OpenCV2学习笔记(十七):VS2013中运行支持OpenGL的OpenCV工程(opencv轻松入门)

下一篇:3D图象算法(转)(3d图形计算器)

  • 税务局退税多久到账
  • 实际已缴纳所得税额在汇算清缴报告里怎么看
  • 非税收入票据能否税前扣除
  • 网上社保增减员操作流程
  • 借方是收入还是支出 正负号
  • 增值税不达起征点处理
  • 增值税税额由哪方承担
  • 短期借款在房地产怎么算
  • 电子商务交易成本
  • 物业公司临时工的工资可以进成本吗
  • 贷款利息进项税额转出
  • 无形资产转让计入什么科目
  • 2021虚开发票案例
  • 免税销售额怎么算出来的
  • 新办的营业执照多久可以注销
  • 呆帐死帐处理
  • 租赁机器的支出怎么算
  • 外贸企业出口退税账务处理
  • 委托加工白酒的计税依据
  • 计提固定资产减值准备会计科目
  • 华为鸿蒙系统开发平台
  • 发生额对照表
  • 会计差错更正账务处理 对股价影响
  • 以前年度的账错了怎么办
  • 不予抵扣的进项税额是什么意思
  • php的数组函数
  • 电脑不能连接wifi只能连宽带
  • php实现查询功能
  • Linux Mount NTFS分区造成的权限问题如何解决?
  • PHP:pg_escape_string()的用法_PostgreSQL函数
  • 总部资产减值测试例题
  • 二手房过户提供发票好还是不提供
  • 出租不动产预缴增值税计算公式
  • 代理业如何交增值税
  • 在承租土地上建房是否应核算为固定资产会计视野
  • 解决口苦最快的方法
  • php安装及使用教程
  • 劳务费用 税
  • 营业外收入不算收入吗
  • yolo系列的优缺点
  • bert的原理
  • python进行数学建模
  • od输出结构
  • python如何提取字典中的键
  • 个人独资企业所得税弥补亏损
  • 租房发票怎么缴税
  • 记账凭证中的会计科目错误导致账簿错误的更正法
  • 汇兑损益的会计处理原则
  • 外商独资企业资本金要求
  • 3月1日前包括什么意思
  • 免增值税项目可以抵扣吗
  • 公司购买手机的发票
  • 国内源码平台
  • 投资款未备注
  • 员工出差回来会计分录
  • 特许经营企业的特点
  • sql server 2012安装无网络可以OK?
  • sql-server
  • 跨年取得的费用票怎么做账
  • 出售固定资产如何缴纳增值税
  • 管理费用科目余额表有余额怎么办
  • 收到投资款如何做税务登记
  • 脚手架租赁费发票内容开劳务可以吗
  • 原材料入库单应根据采购订单还是到货数量
  • 会计的总目标是什么意思
  • dropbox windows
  • 双系统重装win11
  • 桌面上家庭组图标是干嘛
  • 安装centos7.0
  • 如何在linux中添加环境变量
  • 侠客驱动是什么意思
  • js模拟登录网站
  • win10 putty
  • shell脚本实际运用
  • ajax与java使用实例
  • js new()
  • python列表的常用方法有哪些
  • 重庆车位过户需要多久时间
  • 河南省郸城县教育局举报电话
  • 预缴税款怎么做账
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设