几何尺寸与公差论坛

 找回密码
 注册
查看: 4067|回复: 0

【转帖】OpenGL可视和转换

[复制链接]
发表于 2007-6-5 17:37:06 | 显示全部楼层 |阅读模式
01.相机如何在OpenGL中工作?
02.我怎样才可以移动我的视点, 或者是相机,在我的场景中?
03.我的相机该去哪, 模型视点矩阵还是投射矩阵?
04.我该怎么执行一个缩放操作?
05.给出当前模型视点矩阵,我怎么才可以确定相机的物体空间位置?
06.我怎样才可以使照相机在我的场景中围绕一个点转?
07.如何自动计算一个观察点可以显示全部的场景?(我知道边界球体和向上分量(bounding sphere
and up vector ). )
08.gluLookAt是如何工作的?
09.我怎样才可以得到一个在场景正中间的点?
10.我把我的gluLookAt调用放在我的投影矩阵中,现在雾, 光线, 纹理贴图都不能正确工作了, 究竟
发生什么了?
11.我怎样才可以建造一个立体的视觉?
12.我不能使转换正常的工作,哪里才可以知道更多的关于矩阵的东西?
13.OpenGL的矩阵是纵排列,还是横排列的?
14.OpenGL的坐标单位是什么?
15.坐标是如何转换的?坐标空间有什么不同?
16.我怎么样才可以转换我场景中的唯一一个物体或者给每个物体都有单独的变换?
17.如何才可以在3D渲染图上绘制2D图?
18.我如何才可以饶过OpenGL的矩阵转换, 而直接把2D坐标光栅化?
19.使用绝对坐标和相对坐标的优缺点在哪呢?
20.我怎样才可以画一个场景中的不同视图?
21.我怎么样才可以使我的物体围绕一个固定的坐标系统转换, 而不是本地的坐标系统?
22.相对于使用gluPerspective, 使用glFrustum的优缺点?
23.我怎样才可以调用glFrustum来匹配调用gluPerspective?
24.我怎样才可以画一个全屏幕的矩形?
25.对于一个给定的物体空间坐标, 我如何确定相应的屏幕坐标?
26.怎么样才可以找到一个屏幕上点的物体空间坐标?
27.怎样才可以找到一个被模型视点矩阵转换过的顶点坐标?
28.怎样计算观察者到给定点的物体空间距离?
29.在窗口被重定义大小后, 我怎么样才可以保持我的比例系数?
30.我怎么样才可以使OpenGL使用左手坐标系?
31.怎样转换一个物体是它可以指向或者紧跟着另一个场景中的物体或点
32.我如何才可以使用倾角, 仰角,斜角来转换一个物体?
33.我怎样才可以渲染一个镜面?
34.我怎样才可以做我自己的透视缩放?


==================================================================================

1.OpenGL的照相机是如何工作的?

OpenGL是非常注意的,这里是没有照相机的.更确切的说是, 这个站相机总是位于眼空间坐标处( 0.0, 0.0, 0.0, 0.0 ).为了给出移动相机的效果,你必须反向的移动你的场景,把转换矩阵放入模型视点矩阵来实现.这就是通常被引用的视点转换.

在实际练习中, 这是一个和相机转换相等的等式, 但更有效率,因为更多的模型转换 和相机转换被连接到了一个单独的矩阵中去.因此,但相机且只有相机在模型视点当中时,这些操作是必须被执行的.比如,当安置一个光源在世界坐标系的时候, 当视点转换且只有视点转换被应用于模型视点矩阵的时候, 它是必须被重安置的.
---------------------------------------------------------------------------------
2.我如何才可以移动我的眼睛, 或者相机在我的场景中?


OpenGL并没有使用相机模型来提供一个接口完成这项工作.然后, GLU的库提供了一个gluLookAt函数, 它可以确定一个眼睛的位置, 一个可以看, 有向上向量,在物体空间中的坐标.这个函数可以根据它的参数,计算出它的相机的反向转换然后在乘以系统的当前矩阵.
----------------------------------------------------------------------------------
3.我的照相机该去哪儿, 模型视点矩阵还是投影矩阵?


这GL_PROJECTION矩阵只能够包含投影变换,它转换眼坐标到裁减坐标.

这GL_MODELVIEW矩阵, 正如它名字所暗示的那样,包含了模型和视点转换, 它将会转换物体的空间坐标到眼坐标.请记住把相机转换代码放入GL_MODELVIEW矩阵中去, 不要放入GL_PROJECTION 去.

考虑投影矩阵就好像在描述照相机的特性一样, 例如field of view, focal length, fish eye lens, etc.考虑模型视点矩阵, 就好像你和照相机的位置, 以及你的朝向.

在 gamedev FAQ有更多的描述两个矩阵的信息.

读 Steve Bakers's 文章关于滥用投影.这篇文章是被高度评价和推荐的.它帮助了很多的OpenGL的新程序员们.
----------------------------------------------------------------------------------
4. 我如何执行一个缩放操作?


一个简单的来缩放的方法就是使用统一的模型视点矩阵.然后, 这通常容易导致假如模型被放的太大的话, 会被zNear和zFar所裁减.

一个更好的方法就是通常对投影的视景体进行宽和高的限制.

例如,你的程序通常会根据用户的输入, 来提供一个缩放的参数,可能是一个浮点数.当设置了一个1.0的值后,将会没有缩放操作执行. 更大的值会有更大的缩放,和更多的关于视景体的限制, 而更小的值将会导致相反的情况.制造这种效果的代码有可能像这样:

static float zoomFactor; /* 全局变量, 假如你需要,可以通过用户输入来改变,初始值为1.0*/

/* 一段函数来设置投影矩阵. 可能的调用会来自一段典型的程序的重定义穿口大小的句柄. 将会
给出重画大小的宽和高的整数值. 使用正确的画面比例系数和缩放因子建造一个投影矩阵 */
void setProjectMatrix( int width, int height )
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 50.0*zoomFactor, (float)width/(float)height, zNear, zFar );
/* zNear 和 zFar 将会由你来填入*/
}


为了代替gluPerspective, 你的程序有可能使用glFrustum().这里有点小技巧,因为这个左, 右, 底,顶部参数, 还有近平面参数, 也会影响到可视域. 假设你想保持一个固定的zNear面的距离(非常合理的假设),glFrustum的代码可能会看起来如下:

glFrustum( left *zoomFactor, right *zoomFactor,
bottom *zoomFactor, top *zoomFactor,
zNear, zFar );
glOrtho()也是类似的.
----------------------------------------------------------------------------------
5.给出了当前的模型视点矩阵, 我如何确定相机的物体空间位置?


这个"相机"或者视点在眼坐标中是在( 0.0, 0.0, 0.0 ).当你把它转换成( 0, 0, 0, 1)并与模型视点矩阵的逆矩阵相乘时, 得出来的向量就是相机的物体空间坐标.

OpenGL并没有方法(使用glGet* 相关的函数)来得到模型视点矩阵的逆矩阵.你需要使用自己的代码来计算它.
----------------------------------------------------------------------------------
6.我怎样才可以使我场景中的照相机围绕一个顶点在转动?


你可以在同样的场景中通过平移/转动 场景/物体来模拟轨道 .例如, 围绕一个在Y轴上的物体, 而且不间断的望向原点, 有可能会这样写:

gluLookAt( camera[0], camera[1], camera[2], /* 相机位置 */
0, 0, 0, /* 相机朝向原点 */
0, 1, 0 ); /* 正Y轴方向 */
glRotatef( orbitDegree, 0.0f,1.0f, 0.0f ); /* 围绕 Y 轴 */
/* ... 旋转角度, 也可以来自于鼠标的运动 */

glCallList( SCENE ); /* 绘制场景 */
假如你坚持使用物理的移动这个相机的位置, 那么在把它放进你的模型视点转换中之前,你必须得转换当前相机位置的向量.


在任意一种事件中,我都建议你研究下gluLookAt(如果你已经没有是用它了);
----------------------------------------------------------------------------------
7.我如何才可以自动计算一个点,使它可以显示我场景中的全部模型(我知道球体范围和向上向量)?


接下来的是来自Dave Shreiner 设置的一个可视系统.

首先,计算所有在你的场景中的物体的球体范围. 这些将会提供给你两点信息: 球体的中心位置 (让 (cx, cy, cz) 来记录这点)和它的直径.

接下来,选择一个zNear剪裁面距离的值.大部分的建议都是选择一个大于,但接近一的数, 所以,让我们把它设为:

zNear = 1.0;
zFar = zNear + diam;


按下面这种方式,组织你的矩阵调用(对一个正射投影矩阵)

GLdouble left = c.x - diam;
GLdouble right = c.x + diam;
GLdouble bottom = c.y - diam;
GLdouble top = c.y + diam;


glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( left, right, bottom, top, zNear, zFar );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();


这种方法会设置你的物体在窗口的正中心, 伸展边界以符合.(i.e.,这个是假设你窗口的比例系数为1.0).假如你的窗口是非正方形的, 将会按上面的方式计算左, 右, 上, 下, 在调用glOrtho以前放入下面的逻辑代码段中.

GLdouble aspect = (GLdouble) windowWidth / windowHeight;

if ( aspect < 1.0 ) { /* 窗口的高比宽长 */
bottom /= aspect;
top /= aspect;
} else {
left *= aspect;
right *= aspect;
}


上面的的代码将会把你的 场景中的物体放在相对正确的位置. 假如你想试着去操作它( i.e.旋转,etc), 你需要增加一个可视转换.

一个典型的可视转换将会和模型视点矩阵想混和, 而且看起来,应该是这样:

gluLookAt( 0.0, 0.0, 2.0 * diam, c.x, c.y, c.z, 0.0, 1.0, 0.0 );
----------------------------------------------------------------------------------
8.为什么gluLookAt()不能工作?


这个通常是被不正确的转换所导致的.

假设你使用投影矩阵堆栈中的gluPerspective的zNear, zFar来作为第三, 第四个参数,你就必须设置模型视点矩阵堆栈上的gluLookAt(), 并传递相应的参数,使你的物体, 可以落在zNear和zFar之间.

当你正试图去了解可视转换的时候,最好的方法就是写一些代码来做试验.让我们想一下,你正在看一个位于原点的一单位的球体.你可能想按下面的方式来设置你的转换:

glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 50.0, 1.0, 3.0, 7.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
gluLookAt( 0.0, 0.0, 5.0,
0.0, 0.0, 0.0,
0.0, 1.0, 0.0 );


非常重要的一点就是,知道投影和模型视点矩阵是如何一起工作的.

在这个例子中, 这个投影转换,设立了一个50度的可视角度的观察域, 和一个窗口的为1的比例系数. 这个zNear的剪裁面是视点的前三个单位,这个zFar的剪裁面的是视点前的7个单位.它们分配了一个在Z轴长度为4的视景体,对于一个单位的球体是绝对足够的.

这个模型视点转换设置了眼坐标为(0.0, 0.0, 5.0), 而所观看的点是原点,也就是我们单位圆的正中心.请注意这个眼坐标的位置离观察点的位置有5个单位的距离. 这点是相当重要的,因为眼睛前面的5个单位的距离是在投影转换所定义的视景体的正中间.假如这个gluLookAt()把眼睛设置在( 0.0, 0.0, 1.0 )它只会离原点一个单位的距离.它将会没有足够的长度去包含物体在视景体中, 物体将会被zNear所剪裁.

相同地,假如你把眼坐标设置在( 0.0, 0.0, 10.0 ), 10个单位的离观察点的距离,将会导致这个球体和视点有10个单位的距离, 并且被zFar剪裁面在7单位距离处, 被剪裁.

假如这些东西, 困扰着你,读OpenGL红皮书,或者OpenGL详解(specification)中有关于转换的内容.在你理解了物体空间坐标, 眼坐标空间,和剪裁面坐标空间, 这些上面的知识, 将会变的非常的容易, 清晰. 最好, 在经常写些小的测试程序来实践一下. 假如你在你的主程序中依然有相当的困难来使用正确的变换矩阵,那么写些更简单几何体的测试程序是非常有意义的.
--------------------------------------------------------------------------------
9.我如何去设置一个精确的点在场景的中间显示?


gluLookAt是非常容易做到这个的.简单的设置你的点的X, Y, 和Z值作为你的gluLookAt的第三, 第四, 第5个参数.
---------------------------------------------------------------------------------
10.我把我的gluLookAt调用放入我的投影矩阵中, 现在雾,光线,和纹理映射都不能正常工作了, 这
是为什么?


这个通常是因为把转换放在错误的矩阵中所导致的, 看下问题三对这个问题的解释. 然后也有可能, 是因为特殊的光照问题, 所导致的,因为有错误的矩阵被放入模型视点矩阵中,然后定义了光照的位置. 当一个光源点被定位在眼空间坐标中,i.e.和眼睛相关,它将会被重新定位到一个单位矩阵在模型视点矩阵堆栈中的时候.当可视矩阵被放入模型视点堆栈中时, 原先世界坐标系中的光源位置讲会被重定位. 当一个光源的位置是和一个转换的物体相关的时候, 当物体的模型矩阵和在模型视点矩阵堆栈中的可视矩阵想乘时,这个光源也会被重新定位,请记住在任何的光源被渲染前, 它都有可能被重新定位.假如光源在结构中相对于眼睛在移动, 那么每个结构都必须使用合适的矩阵来进行重定位.
----------------------------------------------------------------------------------
11.我如何可以建造一个立体视图?


立体视图就是通过展现观察者观察到的左眼和右眼所看见的画面来形成的.这些图像必须正确的匹配到显示器上,一符合观察者实际所看到的, 更多的习惯是使用多于一副的3D图像. 附加一点就是这种方法会和被使用的显示器技术有相当紧密的联系. 一些图形系统和显示设备, 会在硬件上支持立体视图和支持像左缓存和右缓存, 另外就是在系统上支持双缓存的前缓存和后缓存. 另外的系统就会在显示屏幕显示两个视口来支持立体视图, 并详细定义显卡的模式来发送这些图像到显示屏幕.另外与此相关的就是观察者通常带着一个特殊的眼镜,它会自动对图像进行拣选来以此来符合每个眼睛所看到的.然而即使没有这些图像特性, 一个开发者仍然可以使用颜色过滤在一些基于红或蓝色过滤器的选择图像的地方来实现立体视图,例如画左眼和右眼的图像到到红,蓝帧缓中来实现这点. 或者更加简单的就是有多个系统或是图形显卡(或者一块显卡)来产生两个完全分离的视频信号, 来分别画一个左眼的和右眼的图像.这个视频将会被发送到正确的眼睛中,使用一个display employing polarizing filters 或者一个 head mounted display 或者一些别的用户自己的显示设备, 执行一些原理相同的操作.

从一个OpenGL透视投影中, 立体渲染的设备将会使用合适的操作来渲染到左眼和右眼(作图像掩码, 分离上下文 或是不同视口)并且匹配到与OpenGL投影相关的观察者的左眼和右眼的几何图像到显示器上. 这个最后的OpenGL设备要求是这个在"虚拟"世界中的眼睛位置必须得来自模型视点矩阵中的分离的瞳孔位置, 这种分离会在眼空间坐标产生一个转换 但不会在别的相同的方法中被计算.

Paul Bourke 整理了很多关于立体OpenGL立体视图的资料:

· 3D Stereo Rendering Using OpenGL
· Calculating Stereo Pairs
· Creating Anaglyphs using OpenGL
----------------------------------------------------------------------------------
12.我不能使转换正常的工作. 我可以从哪里得到更多的关于矩阵的知识?


一个系统的关于基础的矩阵数学和线性代数的知识已经超出这份FAQ的范围. 相关的概念已经在美国的高校数学课上解释过了。

假如你知道这些基本概念, 但还是有点糊涂(一个共同的问题就是经验), 读下Steve Baker's
review of matrix concepts 和他的 article on Euler angles.


执行基本向量, 矩阵, 四元数的操作的delphi代码 可以在这里找到.
----------------------------------------------------------------------------------
13.OpenGL的矩阵是行排列的, 还是纵排列的?


出于编程的原因, OpenGL的矩阵是一个在内存中依次相连的16元素的数组,转换部分占据了16元素的矩阵中的第13, 14, 15, 16位置.

纵队排列相对横队排列纯粹就是一种符号协定. 注意自右的和纵排列矩阵相乘将会产生和自左的和行排列矩阵相乘产生同样的结果. 在 OpenGL详解和OpenGL参考手册都使用了纵排列矩阵. 你可以使用任意一种, 只要你清楚的声明了。

不辛地,使用在spec和蓝皮书中的纵排列格式会在OpenGL社区中导致无止境的困扰.纵排列的格式会导致一个程序员不期望的矩阵在内存中的排列格式.

更多的关于这方面的内容, 请点击:这儿.
----------------------------------------------------------------------------------
14.OpenGL的坐标单位是什么?


最简短的回答就是. 只要你希望, 它可以使用任何你所希望的单位.

根据你几何数据库中的内容, 对于你的程序可能非常方便的处理OpenGL的坐标单位,比如一个毫米,或者一光年, 或者这其中的任何距离(或大或小).

OpenGL也允许你自己定义你的几何体使用不同值的坐标系统.例如, 你可能会发现在对飞机模型控制的时候使用厘米, 而对机身使用米, 而对所飞行的空间使用千米.OpenGL的模型视点矩阵可以缩放不同的坐标系统来形成同样的眼坐标系统.

程序有义务来确定投影和模型视点矩阵的构造所提供的图像和观察者保持一个合适的距离, 和合适的可视域, 以及能够保持zNear和zFar剪裁面在一个合适的范围内.一个在微米程度缩放的显示分子的程序, 例如, 就不能把观察者放在一个10英尺距离, 60度观察域的地方.
----------------------------------------------------------------------------------
15.坐标是如何转换的?坐标空间有什么不同?


物体坐标被模型视点矩阵所转换来产生眼坐标.

眼坐标被投影矩阵所转换来产生裁减坐标.

裁减坐标 X, Y, Z将会被裁减坐标W所除来产生设备规范化坐标.

设备规范化坐标会被视口参数所缩放和转移来产生窗口坐标.

物体坐标也就是当你提交给OpenGL glVertex*()或着是 glVertexPointer()的时候的原始坐标.它将会显示你的物体或者别的你想渲染的几何体的坐标.

许多的程序设计者使用世界坐标系统. 物体通常在同一个坐标系统中被模型化, 缩放, 平移, 旋转都会在你的建造的世界中转换. 世界坐标系统是通过存储在模型视点矩阵中的模型转换而形成的物体坐标转换而来. 然而,OpenGL并没有世界坐标系统的概念. 世界坐标系统纯粹就是一个程序架构.

眼坐标是通过被模型视点矩阵转换的物体坐标而来. 这个模型视点矩阵中包含了模型转换和视点转换, 它定义了观察者位于原点,而且朝向Z的负半轴.

裁减坐标是由眼坐标通过投影转换而来.裁减坐标空间范围是从 -Wc 到 Wc 在所有的三个轴方向上, Wc 是裁减坐标W的值. OpenGL会裁减所有位于范围之外的东西.

裁减坐标上所执行的透视除法会产生标准设备规范化坐标, 在三个轴的范围是从 -1 到 1.

窗口坐标是来通过视口来缩放,平移设备规范化坐标转换而来. glViewport()和glDepthRange()的参数控制这些转换.使用视口, 你可以映射设备规范化坐标的立方体到你的窗口的任何位置 和深度缓存中.

更多的信息, 请看 OpenGL specification , 图解2.6
----------------------------------------------------------------------------------
16. 我如何转换我场景中的唯一物体或者是给我场景中的每一个物体都有单独转换?


OpenGL提供了矩阵堆栈来实现这个功能. 这样的话, 就是使用模型视点矩阵堆栈.

一个典型的OpenGL程序第一次设置这个矩阵模式是使用 glMatrixMode( GL_MODELVIEW )并且加载一个可视转换, 例如一个到gluLookAt().更多的信息可利用的在 gluLookAt.

然后这个代码渲染每个场景中的物体使用他们自己的转换通过包装这个调用glPushMatrix()和glPopMatrix().例如:

glPushMatrix();
glRotatef( 90.0, 1.0, 0.0, 0.0 );
gluCylinder( quad, 1, 1, 2, 36, 12 );
glPopMatrix();


上面的代码渲染一个圆柱体围绕X轴旋转90度. 这个模型视点矩阵将会被重新存储为先前的值在glPopMatrix()调用后. 相似的调用序列可以渲染场景中的并发物体.

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|Archiver|小黑屋|几何尺寸与公差论坛

GMT+8, 2024-12-22 01:47 , Processed in 0.045734 second(s), 19 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表