视频加载失败

课程

1765 字
约 6 分钟

1.3 OpenGL 直线绘制

计算机图形学labs/lab01-opengl-drawing·更新于 2026-09-15

1.3 OpenGL 直线绘制

1. 任务描述

根据下面要求,在右侧修改代码空间,绘制出预期输出的图片。平台会对你编写的代码进行测试。

本关任务

  1. 理解基本图形元素光栅化的基本原理。
  2. 了解和使用 OpenGL 的生成直线的命令,以验证程序运行结果。

预期输出

预期输出

具体要求

  1. 背景色为黑色,用 glClearColor 来完成。
  2. 绘制一个矩形,颜色为 (1.0f, 0.0f, 0.0f),矩形位置为 (25.0, 25.0)(75.0, 75.0)
  3. 绘制一个直径为 10 的点,颜色为 (0.0f, 1.0f, 0.0f),对应的点坐标为原点 (0, 0)
  4. 利用 GL_LINES 的绘线方式绘制一条线,其中线段的两个顶点颜色分别为 (0.0f, 1.0f, 0.0f)(0.0f, 1.0f, 0.0f),顶点的坐标分别为 (100.0f, 0.0f)(180.0f, 240.0f)
  5. 调用向 glutReshapeFunc 注册的函数。

相关知识

为了完成本关任务,你需要掌握:前面两关的知识点、GL_LINES 的绘线方式、调用向 glutReshapeFunc 注册的函数以及虚拟机的使用。

1. OpenGL 画线

下面介绍下 OpenGL 画线的一些基础知识和 glutReshapeFunc() 函数。

数学上的直线没有宽度,但 OpenGL 的直线则是有宽度的。同时,OpenGL 的直线必须是有限长度,而不是像数学概念那样是无限的。可以认为,OpenGL 的“直线”概念与数学上的“线段”接近,它可以由两个端点来确定。这里的线由一系列顶点顺次连结而成,有闭合和不闭合两种。

前面的实验已经知道如何绘“点”,那么 OpenGL 是如何知道拿这些顶点来做什么呢?是一个一个的画出来,还是连成线?或者构成一个多边形?或是做其它事情呢?为了解决这一问题,OpenGL 要求:指定顶点的命令必须包含在 glBegin 函数之后,glEnd 函数之前(否则指定的顶点将被忽略),并由 glBegin 来指明如何使用这些点。

例如:

glBegin(GL_POINTS);
    glVertex2f(0.0f, 0.0f);
    glVertex2f(0.5f, 0.0f);
glEnd();

则这两个点将分别被画出来。如果将 GL_POINTS 替换成 GL_LINES,则两个点将被认为是直线的两个端点,OpenGL 将会画出一条直线。还可以指定更多的顶点,然后画出更复杂的图形。另一方面,glBegin 支持的方式除了 GL_POINTSGL_LINES,还有 GL_LINE_STRIPGL_LINE_LOOPGL_TRIANGLESGL_TRIANGLE_STRIPGL_TRIANGLE_FAN 等,每种方式的大致效果如图所示:

图1

此外,glShadeModel 函数用于选择平坦或光滑渐变模式。GL_SMOOTH 为缺省值,为光滑渐变模式,GL_FLAT 为平坦渐变模式。

2. glutReshapeFunc() 函数

首次打开窗口、移动窗口和改变窗口大小时,窗口系统都将发送一个事件,以通知程序员。如果使用的是 GLUT,通知将自动完成,并调用向 glutReshapeFunc() 注册的函数。该函数必须完成下列工作:

  • 重新建立用作新渲染画布的矩形区域;
  • 定义绘制物体时使用的坐标系。

例如:

void Reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei) w, (GLsizei) h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0, (GLdouble) w, 0.0, (GLdouble) h);
}

在 GLUT 内部,将给该函数传递两个参数:窗口被移动或修改大小后的宽度和高度,单位为像素。glViewport() 调整像素矩形,用于绘制整个窗口。接下来三个函数调整绘图坐标系,使左下角位置为 (0, 0),右上角为 (w, h)


开始你的任务吧,祝评测通过!

2. 我的回答

文件 step3/test3.cpp:

// 提示:写完代码请保存之后再进行评测
#include <GL/freeglut.h>
#include <stdio.h>

// 评测代码所用头文件-开始
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束

void myDisplay(void)
{
   // 请在此添加你的代码
   /********** Begin ********/
   // 清除颜色缓冲区,背景为黑色(glClearColor已设置为黑色)
   glClear(GL_COLOR_BUFFER_BIT);
   
   // 绘制红色矩形,位置 (25,25) 到 (75,75)
   glColor3f(1.0f, 0.0f, 0.0f);
   glRectf(25.0f, 25.0f, 75.0f, 75.0f);
   
   // 绘制直径为10的绿色点,位于原点 (0,0)
   glPointSize(10.0f);
   glColor3f(0.0f, 1.0f, 0.0f);
   glBegin(GL_POINTS);
   glVertex2f(0.0f, 0.0f);
   glEnd();
   
   // 绘制绿色线段,端点 (100,0) 和 (180,240)
   glBegin(GL_LINES);
   glColor3f(0.0f, 1.0f, 0.0f);
   glVertex2f(100.0f, 0.0f);
   glVertex2f(180.0f, 240.0f);
   glEnd();
   /********** End **********/
 	glFlush();
}
void Init()
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glShadeModel(GL_SMOOTH);
}
void myReshape(int w, int h)
{
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h);
}

int main(int argc, char *argv[])
{
	glutInit(&argc, argv);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("Hello Point!");
    Init();
	glutDisplayFunc(myDisplay);
    glutReshapeFunc(myReshape);
    glutMainLoopEvent();     
     
    /*************以下为评测代码,与本次实验内容无关,请勿修改**************/
	GLubyte* pPixelData = (GLubyte*)malloc(400 * 400 * 3);//分配内存
    GLint viewport[4] = {0};    
    glReadBuffer(GL_FRONT);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glGetIntegerv(GL_VIEWPORT, viewport);
    glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3], GL_RGB, GL_UNSIGNED_BYTE, pPixelData);

	cv::Mat img;
    std::vector<cv::Mat> imgPlanes;
    img.create(400, 400, CV_8UC3);
    cv::split(img, imgPlanes);
 
    for(int i = 0; i < 400; i ++) {
        unsigned char* plane0Ptr = imgPlanes[0].ptr<unsigned char>(i);
        unsigned char* plane1Ptr = imgPlanes[1].ptr<unsigned char>(i);
        unsigned char* plane2Ptr = imgPlanes[2].ptr<unsigned char>(i);
        for(int j = 0; j < 400; j ++) {
            int k = 3 * (i * 400 + j);
            plane2Ptr[j] = pPixelData[k];
            plane1Ptr[j] = pPixelData[k+1];
            plane0Ptr[j] = pPixelData[k+2];
        }
    }
    cv::merge(imgPlanes, img);
    cv::flip(img, img ,0); 
    cv::namedWindow("openglGrab");
    cv::imshow("openglGrab", img);
    //cv::waitKey();
    cv::imwrite("../img_step3/test.jpg", img);
	return 0;
}
Profile Image of the Author
Sonder
好想要技术
这是公告标题
这只是一个公告
分类
标签
站点信息
构建平台
GitHub Actions
博客版本
Firefly v6.16.7
文章许可
CC BY-NC-SA 4.0
文章目录