OpenGL学习笔记之坐标变换学习

Posted clever101

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL学习笔记之坐标变换学习相关的知识,希望对你有一定的参考价值。

作者:朱金灿
来源:clever101的专栏

为什么大多数人学不会人工智能编程?>>>

GDI、Qt和OpenGL三者之间的绘图区别

  开始学习OpenGL踩过一些坑。因为以前学过GDI和Qt绘图。GDI和Qt绘图都是比较直观的。如下图中就是使用GDI绘制一条从(0,0)到(100,100)的直线:

绘图代码如下:

HPEN  g_hPen = NULL;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

    switch (message)
    
	case WM_CREATE:
	
		g_hPen = CreatePen(PS_SOLID,2,RGB(255,0,0));
		break;
	
    case WM_PAINT:
        
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 在此处添加使用 hdc 的任何绘图代码...
			SelectPen(hdc, g_hPen);
            //从(0,0)到(100,100)画直线
			::MoveToEx(hdc, 0, 0, NULL);
			::LineTo(hdc, 100, 100);
			//以(100, 100)为圆心绘制一个半径为4的圆
            ::Ellipse(hdc,96,96,104,104);
            EndPaint(hWnd, &ps);
        
        break;
    case WM_DESTROY:
	
		DeletePen(g_hPen);
		PostQuitMessage(0);
	
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    
    return 0;

  可以看到GDI绘图中坐标(0,0)是在窗口的左上角。我们再试试使用Qt绘图,Qt绘图的效果图如下:

绘图代码如下:

void QtDraw::paintEvent(QPaintEvent *)

	QPainter painter(this);
	painter.setPen(QPen(Qt::red, 4));//设置画笔形式
	painter.drawLine(0, 0, 100, 100);//从(0,0)到(100,100)画直线
	painter.drawEllipse(100, 100, 4, 4);//以(100,100)为圆心,半径为4画圆

  可以看到Qt绘图中坐标(0,0)是在窗口的左上角。我们再看看OpenGL的绘图函数。表面上看,OpenGL的绘制直线的代码也很简单,如下:

glBegin(GL_LINES);
 glVertex2f(0, 0);
 glVertex2f(100, 100);
glEnd();

  但是上面这段代码并不能实现在窗口上绘制从(0,0)到(100,100)的直线。就是说glVertex2f函数的参数接受的并不是窗口坐标系的坐标。这个是跟GDI和Qt有着根本区别的。

OpenGL的坐标转换流程

  从上一节我们知道glVertex2f函数的参数接受的并不是窗口坐标系的坐标。那么问题来了,glVertex2f函数的参数值是在哪个坐标系的呢?经过研究我们发现,glVertex2f函数的参数值是在物体坐标下。问题又来了,物体坐标是经过怎么的流程转换到窗口坐标系的呢?经过阅读《OpenGL编程指南》,发现流程如下:

  问题又来了,假使我们要用OpenGL在窗口上绘制一条从(0,0)到(100,100)的直线,应该怎么做呢?根据上面的流程,就是说要将(0,0)和(100,100)进行一个逆变换,将这两个点从窗口坐标转变为物体坐标。代码如下:

void DrawGLScene(GLvoid)								

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);			// 清除屏幕和深度缓存
    glColor3f(1.0f, 0.0f, 0.0f);

	GLint viewport[4];
	//获取当前视口的范围
	glGetIntegerv(GL_VIEWPORT, viewport);
	GLdouble modelview[16];
	GLdouble projection[16];

	GLdouble winStartX = 0.0;
	GLdouble winStartY = 0.0;

	GLdouble winEndX = 100.0;
	GLdouble winEndY = 100.0;

	GLdouble objStartX, objStartY, objStartZ;
	GLdouble objEndX, objEndY, objEndZ;
	//获取视图和模型变换矩阵
	glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
	//获取投影矩阵
	glGetDoublev(GL_PROJECTION_MATRIX, projection);
	//将窗口坐标转化为物体坐标
	gluUnProject(winStartX, winStartY, 0.0, modelview, projection, viewport, &objStartX, &objStartY, &objStartZ);
	gluUnProject(winEndX, winEndY, 0.0, modelview, projection, viewport, &objEndX,&objEndY,&objEndZ);

	//执行绘制
	glBegin(GL_LINES);
	glVertex2f(objStartX, objStartY);
	glVertex2f(objEndX, objEndY);
    glEnd();

效果图如下:

  OpenGL绘图中窗口坐标(0,0)是在窗口的左下角,可以看出我们的代码绘制是正确的。

以上是关于OpenGL学习笔记之坐标变换学习的主要内容,如果未能解决你的问题,请参考以下文章

我的OpenGL学习进阶之旅OpenGL的坐标系的学习笔记

OpenGL学习之路

OpenGl从零开始之坐标变换

OPENGL之矩阵

OpenGL ES总结OpenGL坐标变换之平移及旋转

OpenGL学习脚印: 坐标变换过程(vertex transformation)