OpenGL: glDepthRange的理解

192 篇文章 38 订阅
与x和y窗口坐标不同,在OpenGL中,z坐标总是被认为位于0.0~1.0的范围之间。可通过glDepthRange()调整。

API中队glDepthRange的解释:
After clipping and division by w, depth coordinates range from -1 to 1,corresponding to the near and far clipping planes.glDepthRange specifies a linear mapping of the normalized depth coordinates in this range to window depth coordinates. Regardless of the actual depth buffer implementation, window coordinate depth values are treated as though they range from 0 through 1 (like color components). Thus, the values accepted by glDepthRange are both clamped to this range before they are accepted.

也就是说,在OpenGL中绘制的时候所使用的三维坐标(x,y,z),其深度坐标z最后都会被压缩到[0,1]的范围存储起来。

为了证明这一点,使用gluUnProject来进行验证:

#include <windows.h>
#include <GL/glut.h>
#include <GL/glaux.h>
#pragma comment(lib,"glut32.lib")
#pragma comment(lib,"glu32.lib")
#pragma comment(lib,"opengl32.lib")
 
#include <math.h>
#include <iostream>
using namespace std;
GLfloat vertexArr1[] = {    -5.0,    0.0,    0.0,
5.0,    0.0,    0.0,
0.0,    10.0,    0.0,
-5.0,    5.0,    -5.0,
5.0,    5.0,    -5.0,
0.0,    -5.0,    -5.0};
int vertArrSize = 6;
double calcDist(GLdouble _x,GLdouble _y,GLdouble _z,GLdouble _wx0,GLdouble _wy0,GLdouble _wz0,GLdouble _wx1,GLdouble _wy1,GLdouble _wz1) {
	double tDx = _wx1 - _wx0;
	double tDy = _wy1 - _wy0;
	double tDz = _wz1 - _wz0;
	double tDisUnit = sqrt(tDx*tDx + tDy*tDy + tDz * tDz);
	tDx = tDx / tDisUnit;
	tDy = tDy / tDisUnit;
	tDz = tDz / tDisUnit;
	double tVecX = _wx0 - _x;
	double tVecY = _wy0 - _y;
	double tVecZ = _wz0 - _z;
 
	double tDisX = tDy*tVecZ - tDz*tVecY;
	double tDisY = -tDx*tVecZ + tDz*tVecX;
	double tDisZ = tDx*tVecY - tDy*tVecX;
	return sqrt(tDisX*tDisX + tDisY*tDisY + tDisZ*tDisZ);
}
int findClosestPt(GLdouble _wx0,GLdouble _wy0,GLdouble _wz0,GLdouble _wx1,GLdouble _wy1,GLdouble _wz1) {
	double minDis;
	int minDisPos;
	minDisPos = 0;
	minDis = calcDist((double)vertexArr1[0], (double)vertexArr1[1], (double)vertexArr1[2], _wx0, _wy0, _wz0, _wx1, _wy1, _wz1);
	for(int i=1; i<vertArrSize; i++) {
		int offset = i * 3;
		double tmpDis = calcDist(vertexArr1[offset], vertexArr1[offset+1], vertexArr1[offset+2], _wx0, _wy0, _wz0, _wx1, _wy1, _wz1);
		if(tmpDis < minDis) {
			minDis = tmpDis;
			minDisPos = i;
		}   
	}
	return minDisPos;
}
void init() {
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glShadeModel(GL_SMOOTH);
}
void display() {
	glClear(GL_COLOR_BUFFER_BIT);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0, 1.0, 0.1, 500.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0.0, 0.0, 50.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	glColor3f(1.0, 0.0, 0.0);
	glBegin(GL_LINE_LOOP);
	for(int i=0; i<3; i++) {
		int offset = i*3;
		glVertex3f(vertexArr1[offset], vertexArr1[offset+1], vertexArr1[offset+2]);
	}
	glEnd();
	glColor3f(0.0, 1.0, 0.0);
	glBegin(GL_LINE_LOOP);
	for(int i=3; i<6; i++) {
		int offset = i*3;
		glVertex3f(vertexArr1[offset], vertexArr1[offset+1], vertexArr1[offset+2]);
	}
	glEnd();
	glFlush();
}
void mouse(int button, int state, int x, int y) {
	GLint viewport[4];
	GLdouble mvmatrix[16], projmatrix[16];
	GLint realy;
	GLdouble wx0, wy0, wz0;
	GLdouble wx1, wy1, wz1;
	switch(button) {
	case GLUT_LEFT_BUTTON:
		if(state == GLUT_DOWN) {
			//printf(" %d %d \n", x, y);
			glGetIntegerv(GL_VIEWPORT, viewport);
			glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
			glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
			realy = viewport[3] - (GLint)y - 1;
			//printf("Coordinates at cursor are (M, M)\n", x, realy);
			gluUnProject((GLdouble)x, (GLdouble)realy, 0.0, mvmatrix, projmatrix, viewport,
				&wx0, &wy0, &wz0);
			printf("World coords at z=0.0 are (%.3f, %.3f, %.3f)\n", wx0, wy0, wz0);
			gluUnProject((GLdouble)x, (GLdouble)realy, 1.0, mvmatrix, projmatrix, viewport,
				&wx1, &wy1, &wz1);
			printf("World coords at z=1.0 are (%.3f, %.3f, %.3f)\n", wx1, wy1, wz1);
			int i = findClosestPt(wx0, wy0, wz0, wx1, wy1, wz1);
			int offset = i*3;
			printf("Choose Point (%.3f, %.3f, %.3f)\n\n", vertexArr1[offset], vertexArr1[offset+1], vertexArr1[offset+2]);
		}
		break;
	default:
		break;
	}
}
int main(int argc, char** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(300, 300);
	glutCreateWindow(argv[0]);
	init();
	glutDisplayFunc(display);
	glutMouseFunc(mouse);
	glutMainLoop();
	return 0;
}

结果如下:




上述代码的部分返回结果为:

World coords at z=0.0 are (0.000, 0.020, 49.900)
World coords at z=1.0 are (1.381, 100.795, -450.017)
Choose Point (0.000, 10.000, 0.000)


在z=0.0 & z=1.0反算出的三维点坐标的z相差刚好约为500,与视景体的设置(500)吻合。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ZBuffer(深度缓冲)算法是一种图形渲染技术,用于在计算机屏幕上精确地绘制3D场景中的对象,根据每个像素的深度值决定其最终的可见性。在C++中实现ZBuffer,你需要了解以下几个关键步骤: 1. **深度缓冲区**:创建一个与屏幕分辨率相匹配的数组或纹理,用于存储每个像素的深度值。通常是一个整数类型,如`unsigned int`或`float`。 2. **初始化**:对每个像素设置初始深度值(通常是无穷大),表示所有像素都位于屏幕后面。 3. **像素比较**:对于渲染管线中的每个像素,计算其相对于视图和投影矩阵的位置(即世界空间坐标)。然后,将这个深度值与缓冲区中对应位置的深度值进行比较。 4. **深度测试**:如果新像素的深度小于或等于当前缓冲区值,执行深度写入;否则,保持原样,不改变颜色或透明度。 5. **抗锯齿**:为了平滑边界,可以使用一些技术,比如硬件支持的逐像素Z测试(如MSAA)或后处理中的模糊处理。 6. **清理**:在渲染完成后,可能需要更新其他数据结构,如隐藏面剔除或影子映射,以便下一次渲染。 在C++中,你可以使用OpenGL、DirectX等图形API提供的函数来操作ZBuffer。例如,在OpenGL中,你可以使用`glDepthFunc()`设置深度测试函数,`glClear(GL_DEPTH_BUFFER_BIT)`初始化深度缓冲,`glDepthRange()`调整视口范围。 ```cpp // 假设你有一个GLenum depthFunction(例如GL_LESS) glDepthFunc(depthFunction); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除颜色和深度缓冲 // ... 然后在渲染循环中使用glDraw*函数 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值