头歌实践教学平台:CG1-v1.0-点和直线的绘制

第1关:OpenGL点的绘制

一. 任务描述

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

1.本关任务

熟悉编程环境; 了解光栅图形显示器的特点; 了解计算机绘图的特点; 进行编程,以OpenGL为开发平台设计程序,以能够在屏幕上生成三个坐标、颜色和尺寸一定的点。

2.预期输出

实验图片

3.具体要求

(1) 背景色为黑色,用 glClearColor()来完成; (2) 渲染的点的直径设置为 3; (3) 选用 GL_POINTS 作为图形类型; (4) 三个点的颜色分别为(1.0f, 0.0f, 0.0f), (0.0f,1.0f,0.0f), (0.0f,0.0f,1.0f); (5) 三个点对应的顶点坐标分别为(-0.4f,-0.4f), (0.0f,0.0f), (0.4f,0.4f)。

二. 相关知识

为了完成本关任务,你需要掌握:Freeglut 库的基本用法与虚拟机代码的使用方法。

1.FreeGlut简介

先介绍下Glut库。GLUT最初由MarkKilgard编写,从OpenGL Redbook(红宝书)第二版起就用来作为示例程序的支持环境,直到第八版为止(注:第九版开始改为GLFW)。从那时起,GLUT因为其简单、可用性广、可移植性强,被广泛应用于各种OpenGL实际应用中。Glut最新版本为3.7版,大致在1998年8月停止维护和更新,同时其代码也没有开源。Freeglut是Glut库(OpenGL Utility Toolkit,OpenGL实用工具包)的免费开源替代品。它是由Pawel W. Olszta在1999年12月创建,最新版本为2015年3月的3.0版本。

2.基本语法

常用的程序设计语言,如C、C++、Pascal、Fortran和Java等,都支持OpenGL的开发。这里只讨论C版本下OpenGL的语法。

OpenGL基本函数均使用gl作为函数名的前缀,如glClearColor();实用函数则使用glu作为函数名的前缀,如gluSphere()。

OpenGL基本常量的名字以GL_开头,如GL_LINE_LOOP;实用常量的名字以GLU_开头,如GLU_FILL。

一些函数如glColor*()(定义颜色值),函数名后可以接不同的后缀以支持不同的数据类型和格式。如glColor3b(…)、glColor3d(…)、glColor3f(…)和glColor3bv(…)等,这几个函数在功能上是相似的,只是适用于不同的数据类型和格式,其中3表示该函数带有三个参数,b、d、f分别表示参数的类型是字节型、双精度浮点型和单精度浮点型,v则表示这些参数是以向量形式出现的。

为便于移植,OpenGL定义了一些自己的数据类型,如GLfloat、GLvoid,它们其实就是C语言中的float和void。在gl.h文件中可以看到以下定义:


  
  1. typedef float GLfloat;
  2. typedef void GLvoid;
3.freeglut库的基本函数

(1) 初始化函数


  
  1. glutInit(int*argc,char**argv)

参数

  • Argc:一个指针,指向从 main()函数传递过来的没更改的 argc 变量。
  • Argv:一个指针,指向从 main()函数传递过来的没更改的 argv 变量。

(2) 初始化窗口位置 glutInitWindowPosition(int x, int y)

(3) 初始化窗口大小 glutInitWindowSize(int x, int y)

(4) 创建窗口 glutCreateWindow(char *title) 参数 title:窗口标题 (5) 绘图函数 display(void) (6) 窗口重绘函数 glutDisplayFunc(&display) 参数 display:调用的函数名称 (7) 指定刷新颜色缓冲区时所用的颜色 glClearColor(float x1, float x2, float x3, float x4) (8) 刷新颜色缓冲区 glClear(GL_COLOR_BUFFER_BIT) (9) 指定栅格化点的直径 glPointSize(int x) (10) 指定绘制图形的类型 glBegin((GLenum mode) 参数: mode:图形类型 (11) 设置颜色 glColor3f(float x, float y, float z) (12) 设置顶点坐标 glVertex2f(float x, float y) (13) 指定的类型结束,与 glBegin 相对 glEnd() (14) 清空缓冲区 glFlush() (15) 所有的与“事件”有关的函数调用无限循环 glutMainLoop()

4.状态机制

OpenGL的工作方式是一种状态机制,它可以进行各种状态或模式设置,这些状态或模式在重新改变它们之前一直有效。例如,当前颜色就是一个状态变量,在这个状态改变之前,绘制的每个像素都将使用该颜色,直到当前颜色被设置为其他颜色为止。

OpenGL中大量使用了这种状态机制,如颜色模式、投影模式、单双显示缓存区的设置、背景色的设置、光源的位置和特性等。许多状态变量可以通过glEnable()、glDisable()这两个函数来设置成有效或无效状态,如是否设置光照、是否进行深度检测等;在被设置成有效状态之后,绝大部分状态变量都有一个默认值。

通常情况下,可以用下列四个函数来获取某个状态变量的值:glGetBooleanv、glGetDouble、glGetFloatv和glGetIntegerv。究竟选择哪个函数应该根据所要获得的返回值的数据类型来决定。还有些状态变量有特殊的查询函数,如glGetLight*、glGetError和glPolygonStipple等。另外,使用glPushAttrib和glPopAttrib函数,可以存储和恢复最近的状态变量的值。只要有可能,都应该使用这些函数,因为它们比其他查询函数的效率更高。

5.OpenGL的坐标系统

如下图,所示OpengGL坐标与绘图区坐标关系如下, 绘图区的中心点:(0.0,0.0,0.0); 绘图区的右上角点:(1.0,1.0,0.0); 绘图区的左下角点:(-1.0, 1.0,0.0)。

图1 OpengGL绘图区对应坐标


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

三、实验代码

// 提示:写完代码请保存之后再进行评测
#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(0.0,0.0,0.0,0.0);//清除颜色,并设为黑色
    glPointSize(3);//一个点占据三个像素,直径为3
    glBegin(GL_POINTS);//开始绘制点

    glColor3f(1.0,0.0,0.0);//红色
    glVertex2f(-0.4,-0.4);//设置点坐标
    glColor3f(0.0,1.0,0.0);//绿色
    glVertex2f(0.0,0.0);//
    glColor3f(0.0,0.0,1.0);//蓝色
    glVertex2f(0.4,0.4);//

    glEnd();//指定的类型结束
   /********** End **********/

 	glFlush();
}

int main(int argc, char *argv[])
{

	glutInit(&argc, argv);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("Hello Point!");
	glutDisplayFunc(&myDisplay);
    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_step1/test.jpg", img);
	return 0;
}

相关推荐

最近更新

  1. Eureka应用场景和优势

    2024-05-12 06:12:13       0 阅读
  2. ESP32-C3模组上跑通AES-GCM(5)

    2024-05-12 06:12:13       0 阅读
  3. 如何在电子文件上加盖印章

    2024-05-12 06:12:13       1 阅读
  4. github 下载提速的几种方法

    2024-05-12 06:12:13       1 阅读
  5. 交替打印-GO

    2024-05-12 06:12:13       1 阅读
  6. 秒验 iOS端如何修改授权页背景

    2024-05-12 06:12:13       1 阅读

热门阅读

  1. C++:移动语义(std::move)

    2024-05-12 06:12:13       11 阅读
  2. mysql字段乱序 information_schema

    2024-05-12 06:12:13       11 阅读
  3. MySQL 事务的隔离级别

    2024-05-12 06:12:13       11 阅读