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

本文探讨了为何初学者在学习OpenGL时遇到困难,重点讲解了GDI、Qt和OpenGL在绘图上的区别,特别是OpenGL中坐标转换的重要性。通过实例展示了如何在OpenGL中正确地将窗口坐标转换为物体坐标,以便绘制从(0,0)到(100,100)的直线。
摘要由CSDN通过智能技术生成

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

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

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

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绘图的效果图如下:
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坐标转换流程
  问题又来了,假使我们要用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绘制直线

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

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

clever101

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值