在计算机图形学中,坐标变换是渲染过程中不可或缺的一部分,它涉及一系列几何体从模型空间到最终屏幕空间的转换。以下是一般的坐标变换流程:
模型变换 (Model Transformation):
视图变换 (View Transformation):
投影变换 (Projection Transformation):
裁剪变换 (Clipping Transformation):
窗口变换 (Window Transformation):
深度值转换与归一化:
综上所述,这些连续的坐标变换共同确保了三维模型能够正确地呈现在二维屏幕上,并且每个步骤都有助于优化渲染性能以及实现各种视觉效果。
void glDepthRangeArrayv( uint first, sizei count, const double *v );
void glDepthRangeIndexed( uint index, double n, double f );
void glDepthRange( double n, double f );
void glDepthRangef( float n, float f );
在计算机图形学和帧缓冲对象的上下文中,深度值可以使用定点表示或浮点表示来存储。
定点表示:
浮点表示:
“如果绘制帧缓冲区具有浮点深度缓冲,则必须使用浮点表示”这句话意味着,当你的帧缓冲配置支持使用浮点数来存储深度值时,你必须使用浮点数据写入那个缓冲区。否则,如果你将定点值写入浮点缓冲区,结果将是不准确或无意义的。
例如,如果帧缓冲区配置了32位浮点深度缓冲区(如GL_DEPTH_COMPONENT32F),那么深度值将以单精度浮点数形式编码。相反,如果缓冲区设置为定点格式,比如GL_DEPTH_COMPONENT24,那么深度值会被表示为整数,并没有显式的小数点,但隐含地基于近裁剪距离和远裁剪距离进行缩放。
void glDepthRangeArrayv(
uint first, // 指定要修改的第一个视口的索引
sizei count, // 指定要修改的连续视口的数量
const double *v // 指向一个包含深度范围数据的双精度浮点数数组的指针
);
在 v
指向的数组中,每个连续的子数组对(n, f)代表了对应视口的深度范围,其中 n 是近裁剪面在归一化设备坐标系下的值,f 是远裁剪面对应的值。这两个值都会被自动限制在 [0, 1] 的范围内。
例如,如果要为从索引为 first
到 first + count - 1
的视口分别设置不同的深度范围,你需要提供一个大小为 2 * count
的数组,其中每一对相邻元素代表一个视口的深度范围。通过这种方式,你可以灵活地为多视口配置不同的深度缓冲区行为,以满足不同场景的需求。
void glDepthRangeIndexed( uint index, double n, double f );
// 等价于
double v[] = { n, f };
glDepthRangeArrayv(index, 1, v);
index
视口配置深度范围。void glDepthRange( double n, double f );
// 等价于
for (uint i = 0; i < MAX_VIEWPORTS; i++)
{
glDepthRangeIndexed(i, n, f);
}
void glDepthRangef( float n, float f );
glDepthRange
的float版本。void glViewportArrayv( uint first, sizei count, const float *v );
void glViewportIndexedf( uint index, float x, float y, float w, float h );
void glViewportIndexedfv( uint index, const float *v );
void glViewport( int x, int y, sizei w, sizei h );
在OpenGL中,视口变换的实现依赖于一系列状态变量。每个视口有四个整数和两个钳制浮点值作为其参数:
视口的位置(ox, oy):ox = x + w/2,oy = y + h/2,其中(x, y)为视口左下角在窗口坐标系中的位置,w和h分别为视口的宽度和高度。
视口尺寸(px, py):px = w,py = h。
在初始状态下,若渲染到默认帧缓冲区且存在关联的显示窗口,则w和h会被设置为窗口的实际宽度和高度;若无关联的默认帧缓冲区,则初始化为零。
深度范围(n, f):n 初始化为 0.0,f 初始化为 1.0,分别代表深度缓冲区近裁剪面和远裁剪面在归一化设备坐标下的值。
视口的位置及尺寸会受到实施相关的边界限制,可以通过调用GetFloatv
函数并传入VIEWPORT_BOUNDS_RANGE
来获取允许的范围。同时,视口的宽度和高度也会被钳制在实施所支持的最大尺寸内,可通过查询MAX_VIEWPORT_DIMS
得到。
视口变换处理浮点边界的精度是与具体实现有关的,可以通过查询实现定义的常量VIEWPORT_SUBPIXEL_BITS
来了解该精度。
void glViewportArrayv( uint first, sizei count, const float *v );
first
: 表示视口数组的起始索引。在支持视口数组的上下文中,可以同时定义多个连续的视口,并且通过这个参数指定要开始配置的第一个视口的位置。count
: 指定要设置的视口数量。它代表从 first
开始连续的视口个数。v
: 指向一个浮点型数组的指针,该数组包含了一系列的视口参数。每个视口由四个连续的浮点数 (x, y, width, height)
描述,其中 (x, y)
定义了视口在窗口坐标系中的左下角位置,而 width
和 height
则定义了视口的大小。因此,数组应至少包含 4 * count
个元素。void glViewportIndexedf( uint index, float x, float y, float w, float h );
// 等价于
float v[4] = { x, y, w, h };
ViewportArrayv(index, 1, v);
index
视口。void glViewportIndexedfv( uint index, const float *v );
// 等价于
glViewportArrayv(index, 1, v);
index
视口。void glViewport( int x, int y, sizei w, sizei h );
// 等价于
for (uint i = 0; i < MAX_VIEWPORTS; i++)
{
glViewportIndexedf(i, 1, (float)x, (float)y, (float)w, (float)h);
}