计算机图形学头歌合集(题集附解)

发布时间:2023年12月18日

目录

CG1-v1.0-点和直线的绘制?

第1关:OpenGL点的绘制

?第2关:OpenGL简单图形绘制

?第3关:OpenGL直线绘制

第4关:0<1直线绘制-dda算法<>

?第5关:0<1直线绘制-中点算法<>

?第6关:一般直线绘制

CG1-v2.0-直线绘制

第1关:直线光栅化-DDA画线算法

第2关:直线光栅化-中点画线算法?

第3关:直线光栅化-Bresenham画线算法

第4关:直线光栅化-任意斜率的Bresenham画线算法

CG2-v2.0-三角形填充

第1关:扫描线填充法

?第2关:重心坐标填充法

?第3关:同侧判断填充法

?直线裁剪v1.0

第1关:Cohen-Sutherland编码裁剪算法

?第2关:中点分割裁剪算法

?第3关:Liang-Barsky参数化裁剪算法

CG2-v1.0-二维几何变换

第1关:正方形的平移与缩放

?第2关:正方形的平移和旋转

?第3关:正方形的变换组合

?第4关:三菱形状

CG3-v2.0-图形几何变换

第1关:平移、缩放、旋转正方体

?第2关:图形的平移与缩放

第3关:图形的平移与旋转

?第4关:图形的旋转与缩放

?第5关:绘制三菱形状

模型、观察及视口变换v1.0

第1关:立方体模型变换

?第2关:立方体观察变换

?第3关:立方体视口变换

模型、观察及视口变换v2.0

第1关:模型变换-左右两个立方体

第2关:观察变换

?第3关:视口变换

投影变换v1.0

第1关:立方体透视投影

第2关:立方体平行投影

投影变换v2.0

第1关:一点透视

第2关:两点透视

?第3关:三视图与正等测投影

?第4关:视口变换与三视图

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)。

// 提示:写完代码请保存之后再进行评测
#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);
   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;
}

?第2关:OpenGL简单图形绘制

一.任务描述

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

1.本关任务

利用 OpenGL 作为开发平台设计程序,生成一个光栅图。

2.预期输出

3.具体要求

(1).使用黑色作为背景,采用 glClearColor 来实现;

(2).绘制一个矩形,颜色为(1.0f,1.0f,1.0f),矩阵位置(-0.5f,-0.5f,0.5f,0.5f);

(3).绘制一个三角形,三个顶点颜色分别为(1.0f, 0.0f, 0.0f), (0.0f,1.0f,0.0f), (0.0f,0.0f,1.0f),对应的顶点坐标分别为(0.0f,1.0f), (0.8f,-0.5f), (-0.8f,-0.5f);

(4).绘制三个直径为3的点,颜色为(1.0f, 0.0f, 0.0f), (0.0f,1.0f,0.0f), (0.0f,0.0f,1.0f),对应的顶点坐标分别为(-0.4f,-0.4f), (0.0f,0.0f),(0.4f,0.4f)。

// 提示:写完代码请保存之后再进行评测
#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);
   glColor3f(1.0,1.0,1.0);
   glRectf(-0.5,-0.5,0.5,0.5);
 
   glBegin(GL_TRIANGLES);
   glColor3f(1.0,0.0,0.0);
   glVertex2f(0.0,1.0);
   glColor3f(0.0,1.0,0.0);
   glVertex2f(0.8,-0.5);
   glColor3f(0.0,0.0,1.0);
   glVertex2f(-0.8,-0.5);
   glEnd();
   
   glPointSize(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_step2/test.jpg", img);
	return 0;
}

?第3关:OpenGL直线绘制

一.任务描述

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

1.本关任务

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

2.预期输出

3.具体要求

(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),对应的点坐标为原点;

(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注册的函数。

// 提示:写完代码请保存之后再进行评测
#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);
    glColor3f(1.0,0.0f,0.0f);
    glRectf(25.0,25.0,75.0,75.0);
 
    glPointSize(10);
    glBegin(GL_POINTS);
    glColor3f(0.0f,1.0f,0.0f);
    glVertex2f(0.0f,0.0f);
    glEnd();
 
    glBegin(GL_LINES);
    glColor3f(0.0f,1.0f,0.0f);
    glVertex2f(100.0f,0.0f);
    glColor3f(0.0f,1.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;
}

第4关:0<k<1直线绘制-DDA算法

一.任务描述

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

1.本关任务

掌握一种基本图形元素光栅化算法,利用OpenGL实现直线光栅化的DDA算法。

2.预期输出

3.具体要求

(1).背景色为黑色,用 glclearcolor 来完成;

(2).利用DDA算法生成一条直线,线粗为1,直线颜色为(1.0f,1.0f,0.0f),直线两端点坐标为(0,0,200,200)。

// 提示:写完代码请保存之后再进行评测
#include <GL/freeglut.h>
#include<stdio.h>
 
// 评测代码所用头文件-开始
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
 
void LineDDA(int x0, int y0, int x1, int y1)
{
 // 请在此添加你的代码
   /********** Begin ********/
  int x;
	int dy, dx;
	int y;
	float k;
	dx = x1 - x0, dy = y1 - y0;
	k = dy / dx;
	y = y0;
        glColor3f(1.0f, 1.0f, 0.0f);
	glPointSize(1);
	for (x = x0; x <= x1; x++)
	{
		glBegin(GL_POINTS);
		glVertex2i(x, (int)(y + 0.5)); 
		glEnd();
		y += k;
	}
 
 
 
   /********** End **********/
 	glFlush();
}
 
void myDisplay(void)
{
   // 请在此添加你的代码
   /********** Begin ********/
glClearColor(0.0, 0.0, 0.0, 0.0);
   LineDDA( 0, 0, 200, 200);
 
 
   /********** 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_step4/test.jpg", img);
	return 0;
}

?第5关:0<k<1直线绘制-中点算法

一.任务描述

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

1.本关任务

掌握一种基本图形元素光栅化算法,利用OpenGL实现直线光栅化的中点画线算法。

2.预期输出

3.具体要求

(1).背景色为黑色,用 glclearcolor 来完成;

(2).利用中点画线算法生成一条直线,线粗为1,直线颜色为(0.0f,1.0f,0.0f),直线两端点坐标为(10,50,300,260)。

// 提示:写完代码请保存之后再进行评测
#include <GL/freeglut.h>
#include<stdio.h>
 
// 评测代码所用头文件-开始
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
 
void MidPLine(int x0, int y0, int x1, int y1)
{
 // 请在此添加你的代码
   /********** Begin ********/
 
int dx, dy, dt, db, d, x, y;
    dx = x1- x0;
    dy = y1 - y0;
    d = dx - 2*dy;          
    dt = 2*dx - 2*dy;       
    db = -2*dy;            
    x = x0; y = y0;
    glColor3f(0.0f, 1.0f, 0.0f);
   glPointSize(1);
   glBegin(GL_POINTS);
   glVertex2i(x, y);
   glEnd();
    while (x < x1)
    {
        if (d < 0)
        {
            x++;
            y++;
            d += dt;
        }
        else
        {
            x++;
            d += db;
        }
        
		
	 glBegin(GL_POINTS);
   glVertex2i(x, y);
   glEnd();
    }
 
 
   /********** End **********/
 	glFlush();
}
 
void myDisplay(void)
{
   // 请在此添加你的代码
   /********** Begin ********/
    glClear(GL_COLOR_BUFFER_BIT);
   MidPLine(10,50,300,260);
 
 
   /********** 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_step5/test.jpg", img);
	return 0;
}

?第6关:一般直线绘制

一.任务描述

1.本关任务

在前面关卡的基础上,根据下面具体要求,利用OpenGL画点函数来实现一般直线(所有斜率情况)的绘制算法。

2.预期输出

五角星

3.具体要求

根据下面要求,在右侧修改代码,绘制出预期输出的图片,并进行评测。

(1) 直线颜色为红色(1.0f,0.0f,0.0f), 线粗为1;

(2) 实现一般直线(所有斜率情况)的绘制算法,并将代码填写在函数void Line(int x0, int y0, int x1, int y1)中;

(3) 绘制一个五角星来测试上述直线绘制算法,并将代码填写在函数void myDisplay(void)中指定位置。五角星的顶点坐标分别为:(261, 215), (344, 275),(429, 213), (398, 319), (477, 384), (378, 385), (344, 491), (310, 384), (209, 382), (292, 319).?

// 提示:写完代码请保存之后再进行评测
#include <GL/freeglut.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
 
// 评测代码所用头文件-开始
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
 
void Line(int x0, int y0, int x1, int y1)
{
 // 请在此添加你的代码
   /********** Begin ********/
    glColor3f(1.0f, 0.0f, 0.0f);
    glBegin(GL_POINTS);
    glPointSize(1);
 
    int dx = abs(x1 - x0);
    int dy = abs(y1 - y0);
    if (dx > dy) // x方向为步进方向
    {
        if (x0 > x1) //确保x0<x1,这样循环中x=x+1
        {
            swap(x0, x1);
            swap(y0, y1);
        }
 
        int d = dx - 2 * dy;
        int d1 = 2 * dx - 2 * dy;
        int d2 = -2 * dy;
        int x = x0;
        int y = y0;
        int yIncr = (y1 > y0) ? 1 : -1; // 比较两端点y值大小决定y的增量值
        glVertex2i(x, y);
        for (int x = x0 + 1; x <= x1; x++)
        {
            if (d < 0)
            {
                y = y + yIncr;
                d = d + d1;
            }
            else
                d = d + d2;
 
            glVertex2i(x, y);
        }
    }
    else
    {
        if (y0 > y1)
        {
            swap(x0, x1);
            swap(y0, y1);
        }
 
        int d = dy - 2 * dx;
        int d1 = 2 * dy - 2 * dx;
        int d2 = -2 * dx;
        int x = x0;
        int y = y0;
        int xIncr = (x1 > x0) ? 1 : -1;
        glVertex2i(x, y);
        for (int y = y0 + 1; y <= y1; y++)
        {
            if (d < 0)
            {
                x = x + xIncr;
                d = d + d1;
            }
            else
                d = d + d2;
 
            glVertex2i(x, y);
        }
    }
    glEnd();
   /********** End **********/
}
 
void myDisplay(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
   // 请在此添加你的代码用来测试直线绘制代码
   /********** Begin ********/
    Line(261, 215, 344, 275);
    Line(344, 275, 429, 213);
    Line(429, 213, 398, 319);
    Line(398, 319, 477, 384);
    Line(477, 384, 378, 385);
    Line(378, 385, 344, 491);
    Line(344, 491, 310, 384);
    Line(310, 384, 209, 382);
    Line(209, 382, 292, 319);
    Line(292, 319, 261, 215);
   /********** 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[])
{
    int width = 800;
    int height = 600;
    
    glutInit(&argc, argv);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(width, height);
    glutCreateWindow("Hello Line!");
    Init();
    glutDisplayFunc(myDisplay);
    glutReshapeFunc(myReshape);
    glutMainLoopEvent();    
   
     
    /*************以下为评测代码,与本次实验内容无关,请勿修改**************/
    GLubyte* pPixelData = (GLubyte*)malloc(width * height * 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(height, width, CV_8UC3);
    cv::split(img, imgPlanes);
 
    for(int i = 0; i < height; 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 < width; j ++) {
            int k = 3 * (i * width + 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_step6/test.jpg", img);
    return 0;
}

CG1-v2.0-直线绘制

第1关:直线光栅化-DDA画线算法

一.任务描述

1.本关任务

(1)根据直线DDA算法补全line函数,其中直线斜率0<k<1; (2)当直线方程恰好经过P(x,y)和T(x,y+1)的中点M时,统一选取直线上方的T点为显示的像素点。

2.输入

(1)直线两端点坐标:(13, 20)和(180,140); (2)直线颜色为白色。

3.输出

程序运行结果为一条直线,具体结果如下图所示:

test

二.相关知识

1.绘制点函数

image.set(x, y, color)函数是绘制点的函数,参数包括x、y和color。参数x为绘制点的x坐标,参数y为绘制点的y坐标,参数color为绘制点的颜色。

2.DDA算法

DDA算法相关知识点,请参考教材与课件或有关资料。

三.操作说明

(1)按要求补全line函数;

(2)点击窗口右下角"测评"按钮,等待测评结果,如果通过后可进行下一关任务。

#include "tgaimage.h"

const TGAColor white = TGAColor(255, 255, 255, 255);
const TGAColor red = TGAColor(255, 0, 0, 255);

void line(int x0, int y0, int x1, int y1, TGAImage &image, TGAColor color)
{
    // Please add the code here
    /********** Begin ********/
    int x;
    float y, k;
    k = (float)(y1 - y0) / (float)(x1 - x0);
    y = y0;
    for (x = x0;x <= x1;x++)
    {
        image.set(x, int(y + 0.5f),color);
        y = y + k;
    }
    /********** End *********/
}

int main(int argc, char** argv)
{
	TGAImage image(640,480, TGAImage::RGB);
	line(13, 20, 180, 140, image, white);
	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_tga_file("../img_step1/test.tga");

	return 0;
}

第2关:直线光栅化-中点画线算法?

一.任务描述

1.本关任务

(1)根据直线中点画线算法补全line函数,其中直线斜率0<k<1,并将main函数中的line函数参数补充完整; (2)当直线方程恰好经过P(x,y)和T(x,y+1)的中点M时,统一选取直线上方的T点为显示的像素点。

2.输入

(1)直线两端点坐标:(100, 100)和(520,300); (2)直线颜色为红色。

3.输出

程序运行结果为一条直线,具体结果如下图所示:

test

二.相关知识

1.绘制点函数

image.set(x, y, color)函数是绘制点的函数,参数包括x、y和color。参数x为绘制点的x坐标,参数y为绘制点的y坐标,参数color为绘制点的颜色。

2.中点画线算法

中点画线算法相关知识点,请参考教材与课件或有关资料。

三.操作说明

(1)按要求补全line函数;

(2)点击窗口右下角"测评"按钮,等待测评结果,如果通过后可进行下一关任务。

#include "tgaimage.h"
 
const TGAColor white = TGAColor(255, 255, 255, 255);
const TGAColor red = TGAColor(255, 0, 0, 255);
 
void line(int x0, int y0, int x1, int y1, TGAImage &image, TGAColor color)
{
    // Please add the code here
    /********** Begin ********/
    int dx,dy,dt,db,d,x,y;
    dx = x1 - x0;
    dy = y1 - y0;
    d = dx - 2*dy;
    dt = 2*dx - 2*dy;
    db = -2*dy;
    x = x0;
    y = y0;
    image.set(x,y,color);
    while (x < x1)
    {
        if (d <= 0)
        {    x++;
            y++;
            d += dt;
            }
    else
    {
        x++;
        d += db;
    }
    image.set(x,y,color);
    }
    /********** End *********/
}
 
int main(int argc, char** argv)
{
	TGAImage image(640,480, TGAImage::RGB);
    // Please add the code here
    /********** Begin ********/
	line( 100, 100 , 520 , 300 , image, red );
    /********** End *********/
	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_tga_file("../img_step4/test.tga");
	return 0;
}

第3关:直线光栅化-Bresenham画线算法

一.任务描述

1.本关任务

(1)根据直线Bresenham算法补全line函数,其中直线斜率0<k<1,并将main函数中的line函数参数补充完整; (2)当直线方程恰好经过P(x,y)和T(x,y+1)的中点M时,统一选取直线上方的T点为显示的像素点。

2.输入

(1)直线两端点坐标:(20, 20)和(180,140); (2)直线颜色为白色。

3.输出

程序运行结果为一条直线,具体结果如下图所示:

test

二.相关知识

1.绘制点函数

image.set(x, y, color)函数是绘制点的函数,参数包括x、y和color。参数x为绘制点的x坐标,参数y为绘制点的y坐标,参数color为绘制点的颜色。

2.Bresenham算法

Bresenham算法相关知识点,请参考教材与课件或有关资料。

三.操作说明

(1)按要求补全line函数;

(2)点击窗口右下角"测评"按钮,等待测评结果,如果通过后可进行下一关任务。

#include "tgaimage.h"
 
const TGAColor white = TGAColor(255, 255, 255, 255);
const TGAColor red = TGAColor(255, 0, 0, 255);
 
void line(int x0, int y0, int x1, int y1, TGAImage &image, TGAColor color)
{
    // Please add the code here
    /********** Begin ********/
    int Dx=x1-x0,Dy=y1-y0,y=y0,D=-Dx;
    for(int x = x0;x <=x1;x++)
    {
        image.set(x,y,color);
        D = D + 2*Dy;
        if(D >= 0)
        {
            y++;
            D = D - 2*Dx;
        }
    }
    /********** End *********/
}
 
int main(int argc, char** argv)
{
	TGAImage image(640,480, TGAImage::RGB);
    // Please add the code here
    /********** Begin ********/
	line( 20, 20 , 180 , 140 , image, white);
    /********** End *********/
	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_tga_file("../img_step2/test.tga");
	return 0;
}

第4关:直线光栅化-任意斜率的Bresenham画线算法

一.任务描述

1.本关任务

(1)根据直线Bresenham算法补全line函数以绘制白色直线,其中直线斜率为任意情况。 (2)当直线方程恰好经过P(x,y)和T(x,y+1)的中点M时,统一选取直线上方的T点为显示的像素点。

2.输入

代码将自动输入一个OBJ三维人头模型,具体模型如下图:

test

3.输出

若编写的任意斜率的Bresenham画线算法代码正确,则程序会将模型转换为线条图片,具体结果如下图所示:

test

二.相关知识

1.绘制点函数

image.set(x, y, color)函数是绘制点的函数,参数包括x、y和color。参数x为绘制点的x坐标,参数y为绘制点的y坐标,参数color为绘制点的颜色。

2.Bresenham算法

Bresenham算法相关知识点,请参考教材与课件或有关资料。

三.操作说明

(1)按要求补全line函数;

(2)点击窗口右下角"测评"按钮,等待测评结果,如果通过后可进行下一关任务。

CG2-v2.0-三角形填充

第1关:扫描线填充法

一. 任务描述

1. 本关任务

了解和掌握扫描线填充法,实现对三角形区域进行填充,具体要求如下: (1) 补全triangle函数; (2) 将main函数中的三角形顶点坐标和triangle函数参数补充完整。

2. 输入

(1) 三角形的三个顶点的坐标:
t0 = {125,50}, t1 = {300,200}, t2 ={200,350};
(2) 三角形区域为蓝色。

3. 输出

程序运行结果为一个蓝色三角形区域,如下图所示:

实验图片

#include "pngimage.h"
#include<stdio.h>
#include <iostream>
 
struct Vec2i
{
	int x, y;
};
 
void triangle(Vec2i t0, Vec2i t1, Vec2i t2, PNGImage& image, PNGColor color) {
    // Please add your code here
    /********** Begin ********/ 
    if (t0.y>t1.y) std::swap(t0, t1); 
    if (t0.y>t2.y) std::swap(t0, t2); 
    if (t1.y>t2.y) std::swap(t1, t2);
    int total_height = t2.y-t0.y;
        for (int y=t0.y; y<=t1.y; y++) { 
        int segment_height = t1.y-t0.y+1;    //be careful with divisions by zero
        float alpha = (float)(y-t0.y)/total_height,beta  = (float)(y-t0.y)/segment_height;   
        Vec2i A,B;
        A.y=B.y=y;
        A.x = t0.x + (t2.x-t0.x)*alpha; 
        B.x = t0.x + (t1.x-t0.x)*beta; 
        if (A.x>B.x) std::swap(A.x, B.x); 
        for (int x=A.x; x<=B.x; x++) { 
            image.set(x, y, color);  
        } 
    }
    for (int y = t1.y; y <= t2.y; y++)
    {
        int segment_height = t2.y-t1.y+1;    
        float alpha2=(float)(y-t0.y)/total_height,beta2 =(float)(y-t1.y)/segment_height;    
        Vec2i A2,B2;
        A2.y=B2.y=y;
        A2.x = t0.x + (t2.x-t0.x)*alpha2; 
        B2.x = t1.x - (t1.x-t2.x)*beta2; 
        if (A2.x>B2.x) std::swap(A2.x, B2.x); 
        for (int x=A2.x; x<=B2.x; x++) { 
            image.set(x, y, color);  
        } 
    }
}
    /********** End **********/
int main(int argc, char** argv) {
	PNGColor white = PNGColor(255, 255, 255, 255);
	PNGColor black = PNGColor(0, 0, 0, 255);
	PNGColor red = PNGColor(255, 0, 0, 255);
    PNGColor blue = PNGColor(0, 255, 255, 255);
 
	int width = 400;
	int height = 400;
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
    // Please add your code here
    /********** Begin ********/
    Vec2i t0 = {125 ,50 }, t1 = {300 , 200}, t2 = {200 ,350 };
	triangle( t0,t1 ,t2, image,PNGColor(0, 255, 255, 255)  );
    /********** End **********/
	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step3/test.png");
	return 0;
}

?第2关:重心坐标填充法

一. 任务描述

1. 本关任务

了解和掌握重心坐标法,以便能够对三角形区域进行填充,具体要求如下: (1) 补全Triangle和Barycenter函数; (2) 将main函数中的三角形顶点坐标和Triangle函数参数补充完整。

2. 输入

(1) 三角形的三个顶点的坐标:
t0 = {50,50}, t1 = {300,200}, t2 ={200,350};
(2) 三角形颜色区域为绿色。

3. 输出

程序运行结果为一个绿色三角形区域,如下图所示: test

#include "pngimage.h"
#include<stdio.h>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <stdlib.h>
struct Vec2i
{
	int x, y;
};
struct Vec3f
{
	float x, y, z;
};
//cross Product
Vec3f cross(const Vec3f& v1, const Vec3f& v2)
{
    Vec3f v3;
    v3.x = v1.y * v2.z - v1.z * v2.y;
    v3.y = v1.z * v2.x - v1.x * v2.z;
    v3.z = v1.x * v2.y - v1.y * v2.x;
    return v3;
}
//Determine the point p coordinates are in the triangle abc
Vec3f Barycentre(Vec2i p, Vec2i a, Vec2i b, Vec2i c)
{
    // Please add your code here
    /********** Begin ********/
    Vec3f s[2];
    s[0].x = c.x-a.x;
    s[0].y = b.x-a.x;
    s[0].z = a.x-p.x;
    s[1].x = c.y-a.y;
    s[1].y = b.y-a.y;
    s[1].z = a.y-p.y;
    Vec3f u = cross(s[0], s[1]);
    Vec3f v;
    if (abs(u.z) > 1e-2) 
    {
        v.x = 1.0-(u.x+u.y)/u.z;
        v.y = u.y/u.z;
        v.z = u.x/u.z;
    } 
    else 
    {
        v.x = -1;
        v.y = 1;
        v.z = 1;
    }
    return v;
    /********** End ********/
}
// Please draw point to make a triangle in bounding box
void Triangle(Vec2i t0, Vec2i t1, Vec2i t2, PNGImage& image, PNGColor color)
{
    // Please add your code here
    /********** Begin ********/
    int xmax,ymax,x,y;
    xmax=400,ymax=400;
    Vec2i A;
    Vec3f v;
    for(x=0;x<=xmax;x++)
    {
        for(y=0;y<=ymax;y++)
        {
            A.x=x;
            A.y=y;
            v=Barycentre(A, t0, t1, t2);
            if(v.x>=0&&v.y>=0&&v.z>=0)
            {
                image.set(x,y,color);
            }
        }
    }
}
   /********** End **********/
int main(int argc, char** argv) {
	PNGColor white = PNGColor(255, 255, 255, 255);
	PNGColor black = PNGColor(0, 0, 0, 255);
	PNGColor red = PNGColor(255, 0, 0, 255);
    PNGColor green = PNGColor(0, 255, 0, 255);    
	PNGColor blue = PNGColor(0, 255, 255, 255);
	int width = 400;
	int height = 400;
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
    // Please add your code here
    /********** Begin ********/
    Vec2i t0={50,50},t1={300,200 },t2={200,350};
    Triangle(t0,t1,t2,image, PNGColor(0,255,0,255));
    /********** End **********/
	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step2/test.png");
	return 0;
}
 

?第3关:同侧判断填充法

一. 任务描述

1. 本关任务

了解和掌握同侧判断算法,以便能够对三角形区域进行填充,具体要求如下: (1) 并补全Triangle、SameSide和PointInTriangle函数; (2) 将main函数中的三角形顶点坐标和Triangle函数参数补充完整。

2. 输入

(1) 三角形的三个顶点的坐标:
t0 = {50,50}, t1 = {300,200}, t2 ={200,350};
(2) 三角形区域为红色。

3. 输出

程序运行结果为一个红色三角形区域,如下图所示:

test

#include "pngimage.h"
#include<stdio.h>
#include <iostream>
#include <algorithm>
using namespace std;
struct Vec2i
{
	int x, y;
};
 
//Cross product 
float CrossProduct(Vec2i a,Vec2i b)
{
    return a.x * b.y - b.x * a.y;
}
//DotProduct
float DotProduct(float cp1,float cp2)
{
    return cp1*cp2;
}
//Determine if P1 and P2 are on the same side
bool SameSide( Vec2i p,Vec2i a, Vec2i b, Vec2i c )
{
    // Please add your code here
    /********** Begin ********/
    Vec2i AB = {b.x - a.x, b.y - a.y};
    Vec2i AC = {c.x - a.x, c.y - a.y};
    Vec2i AP = {p.x - a.x, p.y - a.y};
    float v1 = CrossProduct(AB, AC);
    float v2 = CrossProduct(AB, AP);
    if (DotProduct(v1, v2) >= 0) 
    return 1;
    else return 0;
    /********** End **********/
}
//Determine the point coordinates are in the triangle
float PointInTriangle(Vec2i p,Vec2i a, Vec2i b, Vec2i c)
{
    // Please add your code here
    /********** Begin ********/
     return SameSide(a, b, c, p) && SameSide(b, c, a, p) && SameSide(c, a, b, p); 
    /********** End **********/
}
 
// Please draw point in bounding box
void Triangle(Vec2i t0, Vec2i t1, Vec2i t2, PNGImage& image, PNGColor color)
{
    // Please add your code here
    /********** Begin ********/
    int xmax,ymax,x,y;
    Vec2i A;
    xmax=300,ymax=350;
    for(x=0;x<=xmax;x++)
    {
        for(y=0;y<=ymax;y++)
        {
            A.x=x;
            A.y=y;
            if(PointInTriangle(A,t0,t1 ,t2 ))
            image.set(x,y,color);
        }
    }

    /********** End **********/
}
 
int main(int argc, char** argv) {
	PNGColor white = PNGColor(255, 255, 255, 255);
	PNGColor black = PNGColor(0, 0, 0, 255);
	PNGColor red = PNGColor(255, 0, 0, 255);
    PNGColor green = PNGColor(0, 255, 0, 255);    
	PNGColor blue = PNGColor(0, 255, 255, 255);
	int width = 400;
	int height = 400;
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
    // Please add your code here
    /********** Begin ********/
    Vec2i t0 = { 50 , 50 }, t1 = {300  ,200  }, t2 = {200  ,350  };
    Triangle(t0 ,t1  , t2 , image, PNGColor(255, 0, 0, 255));
    /********** End **********/
	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step1/test.png");
	return 0;
}

?直线裁剪v1.0

第1关:Cohen-Sutherland编码裁剪算法

一. 任务描述

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

1.本关任务

(1)理解直线裁剪的原理(Cohen-Surtherland算法、中点分割算法、梁友栋算法); (2)利用VC+OpenGL实现直线的编码裁剪算法,在屏幕上用一个封闭矩形裁剪任意一条直线; (3)调试、编译、修改程序;

2.运行前

123

3.输出

213

4.具体要求

(1)对CompCode(Point node, MyRect rect)函数进行补全; (2)对LineClipCohenSurtherland(MyRect rect, Point& node1, Point& node2)函数进行补全,最终实现裁剪后的图片。

// 评测代码所用头文件-开始
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
// 提示:写完代码请保存之后再进行评测
#include <GL/freeglut.h>
#include <stdio.h>
 
#define LEFT   1
#define RIGHT  2
#define BOTTOM 4
#define TOP    8
 
struct MyRect
{
	int xmin, xmax, ymin, ymax;
    MyRect() : xmin(), xmax(), ymin(), ymax(){};
    MyRect(int a, int b, int c, int d) : xmin(a), xmax(b), ymin(c), ymax(d){};
};
 
struct Point
{
	int x, y;
	Point() : x(), y() {};
	Point(int a, int b) :x(a), y(b) {};
};
 
MyRect  rect;
Point vPoint[6];
 
void LineGL(Point node1, Point node2)
{
	glBegin(GL_LINES);
	glColor3f(0.0f, 1.0f, 0.0f);   
    glVertex2f(node1.x, node1.y);
	glVertex2f(node2.x, node2.y);
	glEnd();
}
 
int CompCode(Point node, MyRect rect)
{
	// 请在此添加你的代码
   /********** Begin ********/
int code = 0;
    if (node.x < rect.xmin)
        code |= LEFT;
    else if (node.x > rect.xmax)
        code |= RIGHT;
 
    if (node.y < rect.ymin)
        code |= BOTTOM;
    else if (node.y > rect.ymax)
        code |= TOP;
    
    return code;
   /********** End **********/
}
 
void LineClipCohenSurtherland(MyRect rect, Point& node1, Point& node2)
{
	bool accept = false;
	// 请在此添加你的代码
   /********** Begin ********/
    int code1 = CompCode(node1, rect);
    int code2 = CompCode(node2, rect);
 
    while (true)
    {
        if ((code1 | code2) == 0)
        {
            accept = true;
            break;
        }
        else if (code1 & code2)
        {
            break;
        }
        else
        {
            int code = (code1 != 0) ? code1 : code2;
            Point node;
            if (code & LEFT)
            {
                node.x = rect.xmin;
                node.y = node1.y + (node2.y - node1.y) * (rect.xmin - node1.x) / (node2.x - node1.x);
            }
            else if (code & RIGHT)
            {
                node.x = rect.xmax;
                node.y = node1.y + (node2.y - node1.y) * (rect.xmax - node1.x) / (node2.x - node1.x);
            }
            else if (code & BOTTOM)
            {
                node.y = rect.ymin;
                node.x = node1.x + (node2.x - node1.x) * (rect.ymin - node1.y) / (node2.y - node1.y);
            }
            else if (code & TOP)
            {
                node.y = rect.ymax;
                node.x = node1.x + (node2.x - node1.x) * (rect.ymax - node1.y) / (node2.y - node1.y);
            }
 
            if (code == code1)
            {
                node1 = node;
                code1 = CompCode(node1, rect);
            }
            else
            {
                node2 = node;
                code2 = CompCode(node2, rect);
            }
        }
    }
   /********** End **********/
	if (accept)
        LineGL(node1, node2);
}
 
void MyDisplay()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0f, 1.0f, 1.0f);
	glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
 
  	for (int i = 0; i < 5; i+=2) 
		LineClipCohenSurtherland(rect, vPoint[i], vPoint[i+1]);
	
	
	glFlush();
}
 
void Init()
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glShadeModel(GL_FLAT);
 
    rect = MyRect(100, 300, 100, 300);
 
	vPoint[0] = Point(200, 50); vPoint[1] = Point(350, 250);
	vPoint[2] = Point(125, 205); vPoint[3] = Point(250, 255);
	vPoint[4] = Point(40, 150); vPoint[5] = Point(150, 40);
}
 
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);
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("Hello World!");
 
	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::imwrite("../img_step1/test.jpg", img);
	return 0;
}

?第2关:中点分割裁剪算法

一. 任务描述

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

1.本关任务

(1)理解直线裁剪的原理(Cohen-Surtherland算法、中点分割算法、梁友栋算法); (2)利用VC+OpenGL实现直线的编码裁剪算法,在屏幕上用一个封闭矩形裁剪任意一条直线; (3)调试、编译、修改程序;

2.运行前

123

3.输出

// 评测代码所用头文件-开始
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
// 提示:写完代码请保存之后再进行评测
#include <GL/freeglut.h>
#include <stdio.h>
 
#define LEFT   1
#define RIGHT  2
#define BOTTOM 4
#define TOP    8
 
struct MyRect
{
	int xmin, xmax, ymin, ymax;
    MyRect() : xmin(), xmax(), ymin(), ymax(){};
    MyRect(int a, int b, int c, int d) : xmin(a), xmax(b), ymin(c), ymax(d){};
};
 
 
struct Point
{
	int x, y;
	Point() : x(), y() {};
	Point(int a, int b) :x(a), y(b) {};
};
 
MyRect  rect;
Point vPoint[6];
 
void LineGL(Point node1, Point node2)
{
	glBegin(GL_LINES);
	glColor3f(0.0f, 1.0f, 0.0f);   
    glVertex2f(node1.x, node1.y);
	glVertex2f(node2.x, node2.y);
	glEnd();
}
 
 int CompCode(Point node, MyRect rect)
{
    int code = 0x00;
    if (node.y < rect.ymin)
        code = code | BOTTOM;
    if (node.y > rect.ymax)
        code = code | TOP;
    if (node.x > rect.xmax)
        code = code | RIGHT;
    if (node.x < rect.xmin)
        code = code | LEFT;
    return code;
}
 
 void LineClipMidPoint(MyRect rect, Point& node1, Point& node2)
{
    bool accept = true;
    Point start, end, mid;//分别代表起点,终点和中点
    int code1, code2, codemid;
    code1 = CompCode(node1, rect);
    code2 = CompCode(node2, rect);
    if(code1 == 0 && code2 == 0)
        accept = true;
    else if(code1 & code2)
        accept = false;
    else {
        if(code2!=0){
            start = node1; end = node2;
            mid = Point((float)(start.x + end.x)/(float)2 + 0.5, (float)(start.y + end.y)/(float)2 + 0.5);
            while(abs(start.x - mid.x)>1 || abs(start.y - mid.y)>1){
                codemid = CompCode(mid, rect);
                if(codemid==0){
                     start = mid;
                } 
                else{
                    end = mid;
                }
                mid = Point((float)(start.x + end.x)/(float)2 + 0.5, (float)(start.y + end.y)/(float)2 + 0.5);
            }
            node2 = mid;
        }
        if(code1!=0){
               start = node1; end = node2;
            mid = Point((float)(start.x + end.x)/(float)2 + 0.5, (float)(start.y + end.y)/(float)2 + 0.5);
            while(abs(start.x - mid.x)>1 || abs(start.y - mid.y)>1){
                codemid = CompCode(mid, rect);
                if(codemid==0){
                     end = mid;
                }
                else{
                     start = mid;
                }
                mid = Point((float)(start.x + end.x)/(float)2 + 0.5, (float)(start.y + end.y)/(float)2 + 0.5);
            }
            node1 = mid;
        }
    }
    if (accept)
        LineGL(node1, node2);
}
 
void MyDisplay()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0f, 1.0f, 1.0f);
	glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
 
   for (int i = 0; i < 5; i+=2) 
		LineClipMidPoint(rect, vPoint[i], vPoint[i+1]);
	 
	
	glFlush();
}
 
void Init()
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glShadeModel(GL_FLAT);
 
	rect = MyRect(100, 300, 100, 300);
 
	vPoint[0] = Point(200, 50); vPoint[1] = Point(350, 250);
	vPoint[2] = Point(125, 205); vPoint[3] = Point(250, 255);
	vPoint[4] = Point(40, 150); vPoint[5] = Point(150, 40);
}
 
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);
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("Hello World!");
 
	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::imwrite("../img_step3/test.jpg", img);
	return 0;
}

4.具体要求

对LineClipMidPoint(MyRect rect, Point& node1, Point& node2)函数进行补全,最终实现裁剪后的图片。

?第3关:Liang-Barsky参数化裁剪算法

一. 任务描述

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

1.本关任务

(1)理解直线裁剪的原理(Cohen-Surtherland算法、中点分割算法、梁友栋算法); (2)利用VC+OpenGL实现直线的编码裁剪算法,在屏幕上用一个封闭矩形裁剪任意一条直线; (3)调试、编译、修改程序;

2.运行前

123

3.输出

213

4.具体要求

(1)对ClipTest(float p, float q, float* u1, float* u2)函数进行补全; (2)对LineClipLiangBarsky(MyRect rect, Point& node1, Point& node2)函数进行补全,最终实现裁剪后的图片。

// 评测代码所用头文件-开始
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
// 提示:写完代码请保存之后再进行评测
#include <GL/freeglut.h>
#include <stdio.h>
 
struct MyRect
{
	int xmin, xmax, ymin, ymax;
    MyRect() : xmin(), xmax(), ymin(), ymax(){};
    MyRect(int a, int b, int c, int d) : xmin(a), xmax(b), ymin(c), ymax(d){};
};
 
struct Point
{
	int x, y;
	Point() : x(), y() {};
	Point(int a, int b) :x(a), y(b) {};
};
 
MyRect  rect;
Point vPoint[6];
 
void LineGL(Point node1, Point node2)
{
	glBegin(GL_LINES);
	glColor3f(0.0f, 1.0f, 0.0f);   
    glVertex2f(node1.x, node1.y);
	glVertex2f(node2.x, node2.y);
	glEnd();
}
 
int ClipTest(float p, float q, float* u1, float* u2)
{
    if (p < 0.0)
    {
        float r = q / p;
        if (r > *u2)
        {
            return 0;
        }
        else if (r > *u1)
        {
            *u1 = r;
        }
    }
    else if (p > 0.0)
    {
        float r = q / p;
        if (r < *u1)
        {
            return 0;
        }
        else if (r < *u2)
        {
            *u2 = r;
        }
    }
    else if (q < 0.0)
    {
        return 0;
    }
    return 1;
}
 
bool LineClipLiangBarsky(MyRect rect, Point& node1, Point& node2)
{
    float u1 = 0.0, u2 = 1.0;
    int dx = node2.x - node1.x;
    int dy = node2.y - node1.y;
 
    if (ClipTest(-dx, node1.x - rect.xmin, &u1, &u2))
    {
        if (ClipTest(dx, rect.xmax - node1.x, &u1, &u2))
        {
            if (ClipTest(-dy, node1.y - rect.ymin, &u1, &u2))
            {
                if (ClipTest(dy, rect.ymax - node1.y, &u1, &u2))
                {
                    if (u2 < 1.0)
                    {
                        node2.x = node1.x + u2*dx;
                        node2.y = node1.y + u2*dy;
                    }
                    if (u1 > 0.0)
                    {
                        node1.x = node1.x + u1*dx;
                        node1.y = node1.y + u1*dy;
                    }
                    return true;
                }
            }
        }
    }
    return false;
}
 
void MyDisplay()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0f, 1.0f, 1.0f);
	glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
 
	for(int i = 0; i < 5; i+=2){
        bool bAccept = LineClipLiangBarsky(rect, vPoint[i], vPoint[i+1]);
		if(bAccept)
            LineGL(vPoint[i], vPoint[i+1]);
	}
	
	glFlush();
}
 
void Init()
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glShadeModel(GL_FLAT);
 
	rect = MyRect(100, 300, 100, 300);
 
	vPoint[0] = Point(200, 50); vPoint[1] = Point(350, 250);
	vPoint[2] = Point(125, 205); vPoint[3] = Point(250, 255);
	vPoint[4] = Point(40, 150); vPoint[5] = Point(150, 40);
}
 
 
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);
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("Hello World!");
 
	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::imwrite("../img_step2/test.jpg", img);
	return 0;
}

CG2-v1.0-二维几何变换

第1关:正方形的平移与缩放

一.任务描述

根据提示,在右侧修改代码,并自己绘制出图形。平台会对你编写的代码进行测试。

1.本关任务

理解并掌握OpenGL二维平移、旋转、缩放变换的方法; 阅读实验原理,掌握OpenGL程序平移、旋转、缩放变换的方法。

2.预期输出

1

3.具体要求

(1).背景色为黑色,用 glClearColor() 来完成; (2).以中心为绘制原点,设计一个边长为2的正方形将正方形设置为红色glColor3f(1.0, 0.0, 0.0); (3).将原正方形保留下来并以正方形为基础,然后进行二维几何变换。将正方形向上平移2.0,同时将正方形沿X方向放大3倍,沿Y方向缩小成原来的0.5倍。新生成的矩形颜色为白色glColor3f (1.0, 1.0, 1.0)。

4.本关提示

(1).用glRectf()函数来绘制正方形; (2).每进行一个矩阵操作时,需要先保存这个矩阵,调用glPushMatrix()函数,把当前矩阵压入堆栈。当需要恢复最近一次的保存时,调用glPopMatrix()函数,它相当于从堆栈栈顶弹出一个矩阵为当前矩阵(后边的三关都会用到)。

// 提示:写完代码请保存之后再进行评测
#include <GL/freeglut.h>
#include<stdio.h>
 
// 评测代码所用头文件-开始
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
void init(void)
{  
    glClearColor(0.0, 0.0, 0.0, 0.0);       //设置背景颜色
    glMatrixMode(GL_PROJECTION);
    gluOrtho2D(-5.0, 5.0, -5.0, 5.0);       //设置显示的范围是X:-5.0~5.0, Y:-5.0~5.0
    glMatrixMode(GL_MODELVIEW);
}
 
void myDraw(void)                           //二维几何变换
{
   // 请在此添加你的代码
   /********** Begin ********/
    glPushMatrix();
    glColor3f(1.0, 0.0, 0.0);
    glRectf(-1.0f, - 1.0f,1.0f,1.0f);
    glPopMatrix();
    glPushMatrix();
    glTranslatef(0.0f,2.0f,0.0f);
    glPushMatrix();
    glScalef(3.0,0.5,1.0);
    glColor3f (1.0, 1.0, 1.0);
    glRectf(-1.0f, - 1.0f,1.0f,1.0f);
    glFlush();
   /********** End **********/                          
    glFlush();
}
 
int main(int argc, char *argv[])
{
 
    glutInit(&argc, argv);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(400, 400);
    glutCreateWindow("几何变换示例");
    
    init();
    glutDisplayFunc(&myDraw);
    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;
}

?第2关:正方形的平移和旋转

一.任务描述

根据提示,在右侧修改代码,并自己绘制出图形。平台会对你编写的代码进行测试。

1.本关任务

理解并掌握OpenGL二维平移、旋转、缩放变换的方法; 阅读实验原理,掌握OpenGL程序平移、旋转、缩放变换的方法。

2.预期输出

1

3.具体要求

(1).背景色为黑色,用 glclearcolor 来完成; (2).以中心为绘制原点,设计一个边长为2的正方形将正方形设置为红色glColor3f(1.0, 0.0, 0.0); (3).将原正方形保留下来并以正方形为基础,然后进行二维几何变换。将正方形向左平移3.0,同时将正方形沿X轴逆时针旋转45度,生成新的图形颜色为glColor3f (0.0, 1.0, 0.0); (4).再进行二维几何变换,将原正方形向右平移3.0,同时将正方形沿X轴逆时针旋转45度,生成新的图形颜色为glColor3f (0.0, 0.7, 0.0);

4.本关提示

(1).用glRectf()函数来绘制正方形; (2).每进行一个矩阵操作时,需要先保存这个矩阵,调用glPushMatrix()函数,把当前矩阵压入堆栈。当需要恢复最近一次的保存时,调用glPopMatrix()函数,它相当于从堆栈栈顶弹出一个矩阵为当前矩阵。

// 提示:写完代码请保存之后再进行评测
#include <GL/freeglut.h>
#include<stdio.h>
 
// 评测代码所用头文件-开始
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
void init(void)
{  
    glClearColor(0.0, 0.0, 0.0, 0.0);       //设置背景颜色
    glMatrixMode(GL_PROJECTION);
    gluOrtho2D(-5.0, 5.0, -5.0, 5.0);       //设置显示的范围是X:-5.0~5.0, Y:-5.0~5.0
    glMatrixMode(GL_MODELVIEW);
}
 
void myDraw(void)                           //二维几何变换
{
   // 请在此添加你的代码
    glPushMatrix();
    glColor3f(1.0, 0.0, 0.0);
    glRectf(-1.0f, - 1.0f,1.0f,1.0f);
    glPopMatrix();
    //glPushMatrix();
 
    glTranslatef(-3.0f,0.0f,0.0f);
 
    glPushMatrix();
    glRotatef(45.0,0.0,0.0,1.0);
    glColor3f (0.0, 1.0, 0.0);
    glRectf(-1.0f, - 1.0f,1.0f,1.0f);
    glPopMatrix();
 
    glTranslatef(6.0f,0.0f,0.0f);
 
    glPushMatrix();
    glRotatef(45.0,0.0,0.0,1.0);
    glColor3f (0.0, 0.7, 0.0);
    glRectf(-1.0f, - 1.0f,1.0f,1.0f);
    glPopMatrix();
    glFlush();
 
   /********** End **********/                          
    glFlush();
}
 
int main(int argc, char *argv[])
{
 
    glutInit(&argc, argv);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(400, 400);
    glutCreateWindow("几何变换示例");
    
    init();
    glutDisplayFunc(&myDraw);
    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_step2/test.jpg", img);
    return 0;
}

?第3关:正方形的变换组合

一.任务描述

根据提示,在右侧修改代码,并自己绘制出图形。平台会对你编写的代码进行测试。

1.本关任务

理解并掌握OpenGL二维平移、旋转、缩放变换的方法; 阅读实验原理,掌握OpenGL程序平移、旋转、缩放变换的方法。

2.预期输出

1

3.具体要求

(1).背景色为黑色,用 glclearcolor 来完成; (2).以中心为绘制原点,设计一个边长为2的正方形将正方形设置为红色glColor3f(1.0, 0.0, 0.0); (3).完成前两关的内容; (4).将原正方形进行二维几何变换。将正方形向下平移3.0,同时将正方形沿X方向放大4倍,沿Y方向扩大成原来的1.5倍。新生成的矩形颜色为蓝色glColor3f (0.0, 0.0, 1.0)。

4.本关提示

(1).用glRectf()函数来绘制正方形; (2).每进行一个矩阵操作时,需要先保存这个矩阵,调用glPushMatrix()函数,把当前矩阵压入堆栈。当需要恢复最近一次的保存时,调用glPopMatrix()函数,它相当于从堆栈栈顶弹出一个矩阵为当前矩阵。

// 提示:写完代码请保存之后再进行评测
#include <GL/freeglut.h>
#include<stdio.h>
 
// 评测代码所用头文件-开始
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
void init(void)
{  
    glClearColor(0.0, 0.0, 0.0, 0.0);       //设置背景颜色
    glMatrixMode(GL_PROJECTION);
    gluOrtho2D(-5.0, 5.0, -5.0, 5.0);       //设置显示的范围是X:-5.0~5.0, Y:-5.0~5.0
    glMatrixMode(GL_MODELVIEW);
}
 
void myDraw(void)                           //二维几何变换
{
   // 请在此添加你的代码
   /********** Begin ********/
    glClear (GL_COLOR_BUFFER_BIT); //清空
    glLoadIdentity(); //将当前矩阵设为单位矩阵
 
    glPushMatrix();
    glTranslatef(0.0f,2.0f,0.0f);
    glScalef(3.0,0.5,1.0);
    glColor3f (1.0, 1.0, 1.0);
    glRectf(-1.0f, -1.0f, 1.0f, 1.0f); //上面白色矩形
    glPopMatrix();
 
    glPushMatrix();
 
    glTranslatef(-3.0,0.0,0.0);
 
    glPushMatrix();
    glRotatef(45.0,0.0,0.0,1.0);
    glColor3f (0.0, 1.0, 0.0);
    glRectf(-1.0f, -1.0f, 1.0f, 1.0f); //中间左菱形
    glPopMatrix();
 
    glTranslatef(3.0,0.0,0.0);
 
    glPushMatrix();
    glColor3f (1.0, 0.0, 0.0);
    glRectf(-1.0f, -1.0f, 1.0f, 1.0f); //中间中菱形
    glPopMatrix();
 
    glTranslatef(3.0,0.0,0.0);
 
    glPushMatrix();
    glRotatef(45.0,0.0,0.0,1.0);
    glColor3f (0.0, 0.7, 0.0);
    glRectf(-1.0f, -1.0f, 1.0f, 1.0f); //中间右菱形
    glPopMatrix();
 
    glPopMatrix();
 
    glTranslatef(0.0,-3.0,0.0);
    glScalef(4.0,1.5,1.0);
    glColor3f (0.0, 0.0, 1.0);
    glRectf(-1.0f, -1.0f, 1.0f, 1.0f); //下面蓝色矩形
 
    glFlush ( );
 
   /********** End **********/                          
    glFlush();
}
 
int main(int argc, char *argv[])
{
 
    glutInit(&argc, argv);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(400, 400);
    glutCreateWindow("几何变换示例");
    
    init();
    glutDisplayFunc(&myDraw);
    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;
}

?第4关:三菱形状

一.任务描述

根据提示,在右侧修改代码,并自己绘制出图形。平台会对你编写的代码进行测试。

1.本关任务

理解并掌握OpenGL二维平移、旋转、缩放变换的方法; 阅读实验原理,掌握OpenGL程序平移、旋转、缩放变换的方法; 利用虚拟机进行编程,以OpenGL为开发平台设计程序,设计二维几何变换图形。

2.预期输出

设计如图所示二维图形

1

3.具体要求

(1).背景色为黑色,用 glclearcolor 来完成; (2).三个菱形图形通过二维平移和旋转完成。颜色分别为红色(1.0, 0.0, 0.0)、蓝色(0.0, 0.0, 1.0)和绿色(0.0, 1.0, 0.0); (3).三个菱形的长对角线长度为4.0,短对角线长度为2.0,三个菱形的交点为原点(0.0,0.0); (4).红色菱形的长对角线与Y轴重合,每个菱形的长对角线夹角为120度。

4.本关提示

(1).可将绘制原始的图形设置成一个单独的函数便于调用,这样可以省去反复绘制原始图形的步骤; (2).画一个凸多边形可以调用glBegin(GL_POLYGON),后边用glVertex2f( , )指定顶点坐标,需要注意凸多边形的顶点指定需要按逆时针方向; (3).保留原始图形可以看做调用平移函数并且平移的距离为(0.0,0.0,0.0); (4).每进行一个矩阵操作时,需要先保存这个矩阵,调用glPushMatrix()函数,把当前矩阵压入堆栈。当需要恢复最近一次的保存时,调用glPopMatrix()函数,它相当于从堆栈栈顶弹出一个矩阵为当前矩阵。

// 提示:写完代码请保存之后再进行评测
#include <GL/freeglut.h>
#include<stdio.h>
 
// 评测代码所用头文件-开始
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
void init(void)
{  
    glClearColor(0.0, 0.0, 0.0, 0.0);       //设置背景颜色
    glMatrixMode(GL_PROJECTION);
    gluOrtho2D(-5.0, 5.0, -5.0, 5.0);       //设置显示的范围是X:-5.0~5.0, Y:-5.0~5.0
    glMatrixMode(GL_MODELVIEW);
}
void drawDiamond(void)                        //绘制一个菱形
{
   // 请在此添加你的代码
   /********** Begin ********/
    glBegin (GL_POLYGON); //顶点指定需要按逆时针方向
    glVertex2f (0.0f,-1.0f);//下点
    glVertex2f (2.0f,0.0f);//右点
    glVertex2f (0.0f, 1.0f);//上点
    glVertex2f (-2.0f,0.0f);//左点
    glEnd ( );
   /********** End **********/
}
 
void myDraw(void)                           //二维几何变换
{
   // 请在此添加你的代码
   /********** Begin ********/
    glClear(GL_COLOR_BUFFER_BIT); //清空
    glLoadIdentity(); //将当前矩阵设为单位矩阵
 
    glPushMatrix();
    glRotatef(30.0, 0.0, 0.0, 1.0);
    glTranslatef(-2.0, 0.0, 0.0);
    glColor3f(0.0, 1.0, 0.0);
    drawDiamond();
    glPopMatrix();
 
    glPushMatrix();
    glRotatef(150.0, 0.0, 0.0, 1.0);
    glTranslatef(-2.0, 0.0, 0.0);
    glColor3f(0.0, 0.0, 1.0);
    drawDiamond();
    glPopMatrix();
 
    glPushMatrix();
    glRotatef(270.0, 0.0, 0.0, 1.0);
    glTranslatef(-2.0, 0.0, 0.0);
    glColor3f(1.0, 0.0, 0.0);
    drawDiamond();
   /********** End **********/                          
    glFlush();
}
 
int main(int argc, char *argv[])
{
 
    glutInit(&argc, argv);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(400, 400);
    glutCreateWindow("几何变换示例");
    
    init();
    glutDisplayFunc(&myDraw);
    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_step4/test.jpg", img);
    return 0;
}

CG3-v2.0-图形几何变换

第1关:平移、缩放、旋转正方体

一. 任务描述

1. 本关任务

(1) 理解几何变换基本原理, 掌握平移、旋转、缩放变换的方法; (2) 根据平移算法原理补全translation、scale、rotation_x、rotation_y和rotation_z函数; (3) 根据几何变换基本原理,将main函数中的translation、scale、rotation_z参数补充完整。

2. 输入

(1) 代码将自动输入一个边长为2的obj正方体模型,具体模型如下图:

test

(2) 代码自动将模型投影到二维平面上生成一个边长为1的白色正方形,并且代码会生成红色x轴,绿色y轴,具体图片如下所示:

test

(3) 将立方体的顶点坐标分别向x,y,z轴正方向平移0.5个单位距离,然后绘制一个红色正方形; (4) 将立方体的顶点坐标分别沿x,y,z轴方向缩放0.5倍,然后绘制一个绿色正方形; (5) 将立方体的顶点坐标沿z轴逆时针方向旋转45度,然后绘制一个黄色正方形。

3. 输出

具体结果如下图所示:

test

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"

using namespace std;
const double PI = acos(-1.0);

void line(Vec3i p0, Vec3i p1, PNGImage  &image, PNGColor color)
{
	bool steep = false;
	if (std::abs(p0.x - p1.x) < std::abs(p0.y - p1.y))
	{
		std::swap(p0.x, p0.y);
		std::swap(p1.x, p1.y);
		steep = true;
	}
	if (p0.x > p1.x)
	{
		std::swap(p0.x, p1.x);
		std::swap(p0.y, p1.y);
	}

	int dx = p1.x - p0.x;
	int dy = std::abs(p1.y - p0.y);

	int y = p0.y;
	int d = -dx;
	for (int x = p0.x; x <= p1.x; x++)
	{
		if (steep)
			image.set(y, x, color);
		else
			image.set(x, y, color);

		d = d + 2 * dy;
		if (d > 0)
		{
			y += (p1.y > p0.y ? 1 : -1);
			d = d - 2 * dx;
		}
	}
}

Matrix viewport(int x, int y, int w, int h, int depth) {
	Matrix m = Matrix::identity(4);
	m[0][3] = x + w / 2.f;
	m[1][3] = y + h / 2.f;
	m[2][3] = depth / 2.f;

	m[0][0] = w / 2.f;
	m[1][1] = h / 2.f;
	m[2][2] = depth / 2.f;
	return m;
}

Matrix translation(Vec3f v) {
	Matrix Tr = Matrix::identity(4);
    // Please add the code here
    /********** Begin ********/
    Tr[0][3] = v.x;
    Tr[1][3] = v.y;
    Tr[2][3] = v.z;
    /********** End *********/
	return Tr;
}

Matrix scale(float factorX, float factorY, float factorZ)
{
	Matrix Z = Matrix::identity(4);
    /********** Begin ********/
    Z[0][0] = factorX;
    Z[1][1] = factorY;
    Z[2][2] = factorZ;
    /********** End *********/
	return Z;
}

Matrix rotation_x(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);
	Matrix R = Matrix::identity(4);
    /********** Begin ********/
    R[1][1] = R[2][2] = cosangle;
    R[1][2] = -sinangle;
    R[2][1] = sinangle;
    /********** End *********/
	return R;
}

Matrix rotation_y(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
    /********** Begin ********/
    R[0][0] = R[2][2] = cosangle;
    R[0][2] = sinangle;
    R[2][0] = -sinangle;
    /********** End *********/
	return R;
}

Matrix rotation_z(float angle) {
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
    /********** Begin ********/
    R[0][0] = R[1][1] = cosangle;
    R[0][1] = -sinangle;
    R[1][0] = sinangle;
    /********** End *********/
	return R;
}

int main(int argc, char** argv)
{
	const PNGColor white = PNGColor(255, 255, 255, 255);
	const PNGColor black = PNGColor(0, 0, 0, 255);
	const PNGColor red = PNGColor(255, 0, 0, 255);
	const PNGColor green = PNGColor(0, 255, 0, 255);
	const PNGColor blue = PNGColor(0, 0, 255, 255);
	const PNGColor yellow = PNGColor(255, 255, 0, 255);

	Model *model = NULL;
	const int width = 500;
	const int height = 500;
	const int depth = 255;

	//generate some image
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
	model = new Model("../step3/cube.obj");
	Matrix VP = viewport(width / 4, width / 4, width / 2, height / 2, depth);

	{ // draw the axes
		Vec3f x(1.f, 0.f, 0.f), y(0.f, 1.f, 0.f), o(0.f, 0.f, 0.f);
		o = VP*o;
		x = VP*x;
		y = VP*y;
		line(o, x, image, red);
		line(o, y, image, green);
	}

	for (int i = 0; i < model->nfaces(); i++) {
		std::vector<int> face = model->face(i);
		for (int j = 0; j < (int)face.size(); j++) {
			Vec3f wp0 = model->vert(face[j]);
			Vec3f wp1 = model->vert(face[(j + 1) % face.size()]);
       
			// draw the original model
			Vec3f op0 = VP*wp0;
			Vec3f op1 = VP*wp1;
			line(op0, op1, image, white);

			// draw the translated model
            // Please add the code here
            /********** Begin ********/
			Matrix T = translation(Vec3f(0.5, 0.5, 0.5));
            /********** End *********/
			Vec3f tp0 = VP*T*wp0;
			Vec3f tp1 = VP*T*wp1;
			line(tp0, tp1, image, red);

			// draw the scaled model
            // Please add the code here
            /********** Begin ********/            
			Matrix S = scale(0.5, 0.5, 0.5);
            /********** End *********/
			Vec3f sp0 = VP*S*wp0;
			Vec3f sp1 = VP*S*wp1;
			line(sp0, sp1, image, green);

			// draw the rotated model
            // Please add the code here
            /********** Begin ********/   
			Matrix R = rotation_z(45);
            /********** End *********/
			Vec3f rp0 = VP*R*wp0;
			Vec3f rp1 = VP*R*wp1;
			line(rp0, rp1, image, yellow);
		}
	}
	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step3/test.png");
	delete model;
	return 0;
}

?第2关:图形的平移与缩放

一. 任务描述

1. 本关任务

(1) 理解几何变换基本原理, 掌握平移和缩放变换的方法; (2) 根据几何变换基本原理,将main函数中的空白部分补充完整。

2. 输入

(1) 代码将自动输入一个边长为2的obj正方体模型,具体模型如下图:

test

(2) 将立方体的顶点坐标分别沿x,y,z轴方向缩放0.5倍,然后绘制一个白色正方形; (3) 将立方体的顶点坐标分别沿x,y,z轴方向缩放0.5倍,再分别向x,y,z轴正方向平移0.5个单位距离,然后绘制一个红色正方形; (4) 将立方体的顶点坐标分别向x,y,z轴正方向平移0.5个单位距离,再分别沿x,y,z轴方向缩放0.5倍,然后绘制一个绿色正方形。

3. 输出

具体结果如下图所示:

test

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"

using namespace std;
const double PI = acos(-1.0);

void line(Vec3i p0, Vec3i p1, PNGImage  &image, PNGColor color)
{
	bool steep = false;
	if (std::abs(p0.x - p1.x) < std::abs(p0.y - p1.y))
	{
		std::swap(p0.x, p0.y);
		std::swap(p1.x, p1.y);
		steep = true;
	}
	if (p0.x > p1.x)
	{
		std::swap(p0.x, p1.x);
		std::swap(p0.y, p1.y);
	}

	int dx = p1.x - p0.x;
	int dy = std::abs(p1.y - p0.y);

	int y = p0.y;
	int d = -dx;
	for (int x = p0.x; x <= p1.x; x++)
	{
		if (steep)
			image.set(y, x, color);
		else
			image.set(x, y, color);

		d = d + 2 * dy;
		if (d > 0)
		{
			y += (p1.y > p0.y ? 1 : -1);
			d = d - 2 * dx;
		}
	}
}

Matrix viewport(int x, int y, int w, int h, int depth) {
	Matrix m = Matrix::identity(4);
	m[0][3] = x + w / 2.f;
	m[1][3] = y + h / 2.f;
	m[2][3] = depth / 2.f;

	m[0][0] = w / 2.f;
	m[1][1] = h / 2.f;
	m[2][2] = depth / 2.f;
	return m;
}

Matrix translation(Vec3f v) {
	Matrix Tr = Matrix::identity(4);
	Tr[0][3] = v.x;
	Tr[1][3] = v.y;
	Tr[2][3] = v.z;
	return Tr;
}

Matrix scale(float factorX, float factorY, float factorZ)
{
	Matrix Z = Matrix::identity(4);
	Z[0][0] = factorX;
	Z[1][1] = factorY;
	Z[2][2] = factorZ;
	return Z;
}

Matrix rotation_x(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[1][1] = R[2][2] = cosangle;
	R[1][2] = -sinangle;
	R[2][1] = sinangle;
	return R;
}

Matrix rotation_y(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[2][2] = cosangle;
	R[0][2] = sinangle;
	R[2][0] = -sinangle;
	return R;
}

Matrix rotation_z(float angle) {
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[1][1] = cosangle;
	R[0][1] = -sinangle;
	R[1][0] = sinangle;
	return R;
}

int main(int argc, char** argv)
{
	const PNGColor white = PNGColor(255, 255, 255, 255);
	const PNGColor black = PNGColor(0, 0, 0, 255);
	const PNGColor red = PNGColor(255, 0, 0, 255);
	const PNGColor green = PNGColor(0, 255, 0, 255);
	const PNGColor blue = PNGColor(0, 0, 255, 255);
	const PNGColor yellow = PNGColor(255, 255, 0, 255);

	Model *model = NULL;
	const int width = 500;
	const int height = 500;
	const int depth = 255;

	//generate some image
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
	model = new Model("cube.obj");
	Matrix VP = viewport(width / 4, width / 4, width / 2, height / 2, depth);

	for (int i = 0; i < model->nfaces(); i++)
	{
		std::vector<int> face = model->face(i);
		for (int j = 0; j < (int)face.size(); j++)
		{
			Vec3f wp0 = model->vert(face[j]);
			Vec3f wp1 = model->vert(face[(j + 1) % face.size()]);
            // Please add the code here
            /********** Begin ********/
            Matrix S0 = scale(0.5, 0.5, 0.5);
            Vec3f swp0 = S0 * wp0;
            Vec3f swp1 = S0 * wp1;
			// draw the model after scaled
            Vec3f op0 = VP * swp0;
            Vec3f op1 = VP * swp1;
            line(op0, op1, image, white);
            Matrix T = translation(Vec3f(0.5, 0.5, 0.5));
            Matrix S = scale(0.5, 0.5, 0.5);
			// scaled then translated
            Vec3f tsp0 = VP*T*S*swp0;
            Vec3f tsp1 = VP*T*S*swp1;
            line(tsp0, tsp1, image, red);
			// translated then scaled
            Vec3f stp0 = VP*S*T*swp0;
            Vec3f stp1 = VP*S*T*swp1;
            line(stp0, stp1, image, green);
            /********** End *********/
		}
	}

	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step2/test.png");
	delete model;
	return 0;
}

第3关:图形的平移与旋转

一. 任务描述

1. 本关任务

(1) 理解几何变换基本原理, 掌握平移和旋转变换的方法; (2) 根据几何变换基本原理,将main函数中的空白部分补充完整。

2. 输入

(1) 代码将自动输入一个边长为2的obj正方体模型,具体模型如下图:

test

(2) 将立方体的顶点坐标分别沿x,y,z轴方向缩放0.5倍,然后绘制一个白色正方形; (3) 将立方体的顶点坐标分别向x,y,z轴正方向平移0.5个单位距离,再沿z轴逆时针方向旋转45度,然后绘制一个绿色正方形 (4) 将立方体的顶点坐标分别沿z轴逆时针方向旋转45度,再分别向x,y,z轴正方向平移0.5个单位距离,然后绘制一个红色正方形;

3. 输出

具体结果如下图所示:

test

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"

using namespace std;
const double PI = acos(-1.0);

void line(Vec3i p0, Vec3i p1, PNGImage  &image, PNGColor color)
{
	bool steep = false;
	if (std::abs(p0.x - p1.x) < std::abs(p0.y - p1.y))
	{
		std::swap(p0.x, p0.y);
		std::swap(p1.x, p1.y);
		steep = true;
	}
	if (p0.x > p1.x)
	{
		std::swap(p0.x, p1.x);
		std::swap(p0.y, p1.y);
	}

	int dx = p1.x - p0.x;
	int dy = std::abs(p1.y - p0.y);

	int y = p0.y;
	int d = -dx;
	for (int x = p0.x; x <= p1.x; x++)
	{
		if (steep)
			image.set(y, x, color);
		else
			image.set(x, y, color);

		d = d + 2 * dy;
		if (d > 0)
		{
			y += (p1.y > p0.y ? 1 : -1);
			d = d - 2 * dx;
		}
	}
}

Matrix viewport(int x, int y, int w, int h, int depth) {
	Matrix m = Matrix::identity(4);
	m[0][3] = x + w / 2.f;
	m[1][3] = y + h / 2.f;
	m[2][3] = depth / 2.f;

	m[0][0] = w / 2.f;
	m[1][1] = h / 2.f;
	m[2][2] = depth / 2.f;
	return m;
}

Matrix translation(Vec3f v) {
	Matrix Tr = Matrix::identity(4);
	Tr[0][3] = v.x;
	Tr[1][3] = v.y;
	Tr[2][3] = v.z;
	return Tr;
}

Matrix scale(float factorX, float factorY, float factorZ)
{
	Matrix Z = Matrix::identity(4);
	Z[0][0] = factorX;
	Z[1][1] = factorY;
	Z[2][2] = factorZ;
	return Z;
}

Matrix rotation_x(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[1][1] = R[2][2] = cosangle;
	R[1][2] = -sinangle;
	R[2][1] = sinangle;
	return R;
}

Matrix rotation_y(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[2][2] = cosangle;
	R[0][2] = sinangle;
	R[2][0] = -sinangle;
	return R;
}

Matrix rotation_z(float angle) {
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[1][1] = cosangle;
	R[0][1] = -sinangle;
	R[1][0] = sinangle;
	return R;
}

int main(int argc, char** argv)
{
	const PNGColor white = PNGColor(255, 255, 255, 255);
	const PNGColor black = PNGColor(0, 0, 0, 255);
	const PNGColor red = PNGColor(255, 0, 0, 255);
	const PNGColor green = PNGColor(0, 255, 0, 255);
	const PNGColor blue = PNGColor(0, 0, 255, 255);
	const PNGColor yellow = PNGColor(255, 255, 0, 255);

	Model *model = NULL;
	const int width = 500;
	const int height = 500;
	const int depth = 255;

	//generate some image
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
	model = new Model("cube.obj");
	Matrix VP = viewport(width / 4, width / 4, width / 2, height / 2, depth);

	for (int i = 0; i < model->nfaces(); i++)
	{
		std::vector<int> face = model->face(i);
		for (int j = 0; j < (int)face.size(); j++)
		{
			Vec3f wp0 = model->vert(face[j]);
			Vec3f wp1 = model->vert(face[(j + 1) % face.size()]);

            // Please add the code here
            /********** Begin ********/
			Matrix S = scale(0.5,0.5,0.5);
			Vec3f sp0 = VP*S*wp0;
			Vec3f sp1 = VP*S*wp1;
			line(sp0,sp1,image,white);

			Matrix P = rotation_z(45)*translation(Vec3f(0.5,0.5,0.5))*S;
			Vec3f pp0 = VP*P*wp0;
			Vec3f pp1 = VP*P*wp1;
			line(pp0,pp1,image,green);

			Matrix Q = translation(Vec3f(0.5,0.5,0.5))*rotation_z(45)*S;
			Vec3f qp0 = VP*Q*wp0;
			Vec3f qp1 = VP*Q*wp1;
			line(qp0,qp1,image,red);
            /********** End *********/

		}
	}

	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step1/test.png");
	delete model;
	return 0;
}

?第4关:图形的旋转与缩放

一. 任务描述

1. 本关任务

(1) 理解几何变换基本原理, 掌握旋转和缩放变换的方法; (2) 根据几何变换基本原理,将main函数中的空白部分补充完整。

2. 输入

(1) 代码将自动输入一个边长为2的obj正方体模型,具体模型如下图:

test

(2) 将立方体的顶点坐标分别沿x,y,z轴方向缩放0.5倍,然后绘制一个白色正方形; (3) 将立方体的顶点坐标分别向y,z轴缩放0.5倍,x轴保持不变,再沿z轴逆时针方向旋转45度,然后绘制一个绿色矩形; (4) 将立方体的顶点坐标分别沿z轴逆时针方向旋转45度,再分别向y,z轴缩放0.5倍,x轴保持不变,然后绘制一个红菱形。

3. 输出

具体结果如下图所示:

test

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"

using namespace std;
const double PI = acos(-1.0);

void line(Vec3i p0, Vec3i p1, PNGImage  &image, PNGColor color)
{
	bool steep = false;
	if (std::abs(p0.x - p1.x) < std::abs(p0.y - p1.y))
	{
		std::swap(p0.x, p0.y);
		std::swap(p1.x, p1.y);
		steep = true;
	}
	if (p0.x > p1.x)
	{
		std::swap(p0.x, p1.x);
		std::swap(p0.y, p1.y);
	}

	int dx = p1.x - p0.x;
	int dy = std::abs(p1.y - p0.y);

	int y = p0.y;
	int d = -dx;
	for (int x = p0.x; x <= p1.x; x++)
	{
		if (steep)
			image.set(y, x, color);
		else
			image.set(x, y, color);

		d = d + 2 * dy;
		if (d > 0)
		{
			y += (p1.y > p0.y ? 1 : -1);
			d = d - 2 * dx;
		}
	}
}

Matrix viewport(int x, int y, int w, int h, int depth) {
	Matrix m = Matrix::identity(4);
	m[0][3] = x + w / 2.f;
	m[1][3] = y + h / 2.f;
	m[2][3] = depth / 2.f;

	m[0][0] = w / 2.f;
	m[1][1] = h / 2.f;
	m[2][2] = depth / 2.f;
	return m;
}

Matrix translation(Vec3f v) {
	Matrix Tr = Matrix::identity(4);
	Tr[0][3] = v.x;
	Tr[1][3] = v.y;
	Tr[2][3] = v.z;
	return Tr;
}

Matrix scale(float factorX, float factorY, float factorZ)
{
	Matrix Z = Matrix::identity(4);
	Z[0][0] = factorX;
	Z[1][1] = factorY;
	Z[2][2] = factorZ;
	return Z;
}

Matrix rotation_x(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[1][1] = R[2][2] = cosangle;
	R[1][2] = -sinangle;
	R[2][1] = sinangle;
	return R;
}

Matrix rotation_y(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[2][2] = cosangle;
	R[0][2] = sinangle;
	R[2][0] = -sinangle;
	return R;
}

Matrix rotation_z(float angle) {
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[1][1] = cosangle;
	R[0][1] = -sinangle;
	R[1][0] = sinangle;
	return R;
}

int main(int argc, char** argv)
{
	const PNGColor white = PNGColor(255, 255, 255, 255);
	const PNGColor black = PNGColor(0, 0, 0, 255);
	const PNGColor red = PNGColor(255, 0, 0, 255);
	const PNGColor green = PNGColor(0, 255, 0, 255);
	const PNGColor blue = PNGColor(0, 0, 255, 255);
	const PNGColor yellow = PNGColor(255, 255, 0, 255);

	Model *model = NULL;
	const int width = 500;
	const int height = 500;
	const int depth = 255;

	//generate some image
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
	model = new Model("cube.obj");
	Matrix VP = viewport(width / 4, width / 4, width / 2, height / 2, depth);

	for (int i = 0; i < model->nfaces(); i++)
	{
		std::vector<int> face = model->face(i);
		for (int j = 0; j < (int)face.size(); j++)
		{
			Vec3f wp0 = model->vert(face[j]);
			Vec3f wp1 = model->vert(face[(j + 1) % face.size()]);
            // Please add the code here
            /********** Begin ********/
						Matrix S = scale(0.5,0.5,0.5);
			Vec3f sp0 = VP*S*wp0;
			Vec3f sp1 = VP*S*wp1;
			line(sp0,sp1,image,white);

			Matrix P = rotation_z(45)*scale(1,0.5,0.5)*S;
			Vec3f pp0 = VP*P*wp0;
			Vec3f pp1 = VP*P*wp1;
			line(pp0,pp1,image,green);

			Matrix Q = scale(1,0.5,0.5)*rotation_z(45)*S;
			Vec3f qp0 = VP*Q*wp0;
			Vec3f qp1 = VP*Q*wp1;
			line(qp0,qp1,image,red);
            /********** End *********/
		}
	}

	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step4/test.png");
	delete model;
	return 0;
}

?第5关:绘制三菱形状

一. 任务描述

1. 本关任务

(1) 理解几何变换基本原理, 掌握平移、旋转和缩放变换的方法; (2) 根据几何变换基本原理,将main函数中的空白部分补充完整来绘制三菱形状。

2. 输入

(1) 代码将自动输入一个边长为2的obj正方体模型,具体模型如下图:

test

(2) 将立方体的顶点坐标分别沿x,y,z轴方向缩放0.5倍; (3) 将立方体的顶点坐标分别沿z轴逆时针方向旋转45度,再分别向y,z轴缩放0.5倍,x轴保持不变,然后绘制一个红菱形; (4) 将红色菱形沿着x轴正方向平移22?? 个单位距离,然后将红菱形沿Z轴逆时针旋转90度; (5)绿色和黄色菱形与红色菱形的夹角均为120度。

3. 输出

具体结果如下图所示:

test

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"

using namespace std;
const double PI = acos(-1.0);

void line(Vec3i p0, Vec3i p1, PNGImage  &image, PNGColor color)
{
	bool steep = false;
	if (std::abs(p0.x - p1.x) < std::abs(p0.y - p1.y))
	{
		std::swap(p0.x, p0.y);
		std::swap(p1.x, p1.y);
		steep = true;
	}
	if (p0.x > p1.x)
	{
		std::swap(p0.x, p1.x);
		std::swap(p0.y, p1.y);
	}

	int dx = p1.x - p0.x;
	int dy = std::abs(p1.y - p0.y);

	int y = p0.y;
	int d = -dx;
	for (int x = p0.x; x <= p1.x; x++)
	{
		if (steep)
			image.set(y, x, color);
		else
			image.set(x, y, color);

		d = d + 2 * dy;
		if (d > 0)
		{
			y += (p1.y > p0.y ? 1 : -1);
			d = d - 2 * dx;
		}
	}
}

Matrix viewport(int x, int y, int w, int h, int depth) {
	Matrix m = Matrix::identity(4);
	m[0][3] = x + w / 2.f;
	m[1][3] = y + h / 2.f;
	m[2][3] = depth / 2.f;

	m[0][0] = w / 2.f;
	m[1][1] = h / 2.f;
	m[2][2] = depth / 2.f;
	return m;
}

Matrix translation(Vec3f v) {
	Matrix Tr = Matrix::identity(4);
	Tr[0][3] = v.x;
	Tr[1][3] = v.y;
	Tr[2][3] = v.z;
	return Tr;
}

Matrix scale(float factorX, float factorY, float factorZ)
{
	Matrix Z = Matrix::identity(4);
	Z[0][0] = factorX;
	Z[1][1] = factorY;
	Z[2][2] = factorZ;
	return Z;
}

Matrix rotation_x(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[1][1] = R[2][2] = cosangle;
	R[1][2] = -sinangle;
	R[2][1] = sinangle;
	return R;
}

Matrix rotation_y(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[2][2] = cosangle;
	R[0][2] = sinangle;
	R[2][0] = -sinangle;
	return R;
}

Matrix rotation_z(float angle) {
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[1][1] = cosangle;
	R[0][1] = -sinangle;
	R[1][0] = sinangle;
	return R;
}

int main(int argc, char** argv)
{
	const PNGColor white = PNGColor(255, 255, 255, 255);
	const PNGColor black = PNGColor(0, 0, 0, 255);
	const PNGColor red = PNGColor(255, 0, 0, 255);
	const PNGColor green = PNGColor(0, 255, 0, 255);
	const PNGColor blue = PNGColor(0, 0, 255, 255);
	const PNGColor yellow = PNGColor(255, 255, 0, 255);

	Model *model = NULL;
	const int width = 800;
	const int height = 800;
	const int depth = 255;

	//generate some image
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
	model = new Model("cube.obj");
	Matrix VP = viewport(width / 4, width / 4, width / 2, height / 2, depth);

	for (int i = 0; i < model->nfaces(); i++)
	{
		std::vector<int> face = model->face(i);
		for (int j = 0; j < (int)face.size(); j++)
		{
			Vec3f wp0 = model->vert(face[j]);
			Vec3f wp1 = model->vert(face[(j + 1) % face.size()]);

			Matrix T = translation(Vec3f(sqrt(2)/2, 0, 0));
			// Please add the code here
            /********** Begin ********/
			Matrix S = scale(0.5f,0.5f  ,0.5f  );
			Matrix S1 = scale(1.f,0.5f  ,0.5f  );
			Matrix R = rotation_z(45.f);
			Matrix R3 = rotation_z(90.f);
			Matrix R2 = rotation_z(120.f);
			Matrix R1 = rotation_z(-120.f);
			
			Vec3f sp0 = VP*R3*T*S1*R*S*wp0;
			Vec3f sp1 = VP*R3*T*S1*R*S*wp1;
			line(sp0, sp1, image, red);
			
			Vec3f op0 = VP*R2*R3*T*S1*R*S*wp0;
			Vec3f op1 = VP*R2*R3*T*S1*R*S*wp1;
			line(op0, op1, image,green );
            
            Vec3f Sp0 = VP*R1*R3*T*S1*R*S*wp0;
			Vec3f Sp1 = VP*R1*R3*T*S1*R*S*wp1;
			line(Sp0, Sp1, image,yellow );
            /********** End *********/
		}		
	}

	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step5/test.png");
	delete model;
	return 0;
}

模型、观察及视口变换v1.0

第1关:立方体模型变换

一.任务描述

根据提示,在右侧修改代码,并自己绘制出图形。平台会对你编写的代码进行测试。

1.本关任务

学习了解三维图形几何变换原理。 理解掌握OpenGL三维图形几何变换的方法。 理解掌握OpenGL程序的模型视图变换。 掌握OpenGL三维图形显示与观察的原理与实现。

2.预期输出

参考图片

3.具体要求

(1).背景色为黑色,用 glclearcolor 来完成;

(2).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,以中心为绘制原点,设置前景色为红色glColor3f(1.0, 0.0, 0.0),绘制单位立方体线框,用glutWireCube(1.0)完成;

(3).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,设置前景色为黑色glColor3f(0.0, 1.0, 0.0),设置线宽为2.0用glLineWidth(2.0)完成,将原单位立方体线框沿X轴正方向平移2.0;
(4).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,沿X轴负方向平移2.0,设置前景色为蓝色glColor3f(0.0, 0.0, 1.0),绘制单位立方体实体用glutSolidCube(1.0)完成;

// 提示:在合适的地方修改或添加代码
#include <GL/freeglut.h>
#include<stdio.h>
 
// 评测代码所用头文件-开始
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
GLint winWidth = 400, winHeight =400 ; 	      //设置初始化窗口大小
 
/*观察坐标系参数设置*/
GLfloat x0 = 0.0, yy = 0.0, z0 = 5.0;	   //设置观察坐标系原点 
GLfloat xref = 0.0, yref = 0.0, zref = 0.0;	//设置观察坐标系参考点(视点) 
GLfloat Vx = 0.0, Vy = 1.0, Vz = 0.0;	   //设置观察坐标系向上向量(y轴) 
 
/*观察体参数设置 */
GLfloat xwMin = -1.0, ywMin = -1.0, xwMax = 1.0, ywMax = 1.0;//设置裁剪窗口坐标范围
GLfloat dnear = 1.5, dfar = 20.0;	      //设置远、近裁剪面深度范围
 
void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
}
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
 
    glLoadIdentity();
    /*观察变换*/
    gluLookAt(x0, yy, z0, xref, yref, zref, Vx, Vy, Vz);        //指定三维观察参数
 
    // 请在此添加你的代码
    /********** Begin ********/
  //
 
    glColor3f(1.0, 0.0, 0.0);
    glPushMatrix();
    
    glutWireCube(1.0);
     glPopMatrix();
//
 
    glColor3f(0.0, 1.0, 0.0);
    glLineWidth(2.0);
     glPushMatrix();
    glTranslatef(2.0f,0.0f,0.0f);
    glutWireCube(1.0);
     glPopMatrix();
//
   glColor3f(0.0, 0.0, 1.0);
     glPushMatrix();
    glTranslatef(-2.0f,0.0f,0.0f);
    glutSolidCube(1.0);
     glPopMatrix();
 
 
    /********** End **********/
    glFlush();
}
 
void reshape(GLint newWidth, GLint newHeight)
{
    /*视口变换*/
    glViewport(0, 0, newWidth, newHeight);	//定义视口大小
 
    /*投影变换*/
    glMatrixMode(GL_PROJECTION);
 
    glLoadIdentity();
 
    /*透视投影,设置透视观察体*/
	glFrustum(xwMin, xwMax, ywMin, ywMax, dnear, dfar);
 
    /*模型变换*/
    glMatrixMode(GL_MODELVIEW);
    
    winWidth = newWidth;
    winHeight = newHeight;
}
int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize( 400 , 400 );        //设置初始化窗口大小
    glutCreateWindow("三维观察");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoopEvent();
 
    /*************以下为评测代码,与本次实验内容无关,请勿修改**************/
    GLubyte* pPixelData = (GLubyte*)malloc(800 * 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;
}

?第2关:立方体观察变换

一.任务描述

根据提示,在右侧修改代码,并自己绘制出图形。平台会对你编写的代码进行测试。

1.本关任务

学习了解三维图形几何变换原理。 理解掌握OpenGL三维图形几何变换的方法。 理解掌握OpenGL程序的模型视图变换。 掌握OpenGL三维图形显示与观察的原理与实现。

2.预期输出

参考图片

3.具体要求

(1).背景色为黑色,用 glclearcolor 来完成;

(2).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,以中心为绘制原点,设置前景色为红色glColor3f(1.0, 0.0, 0.0),绘制单位立方体线框,用glutWireCube(1.0)完成;

(3).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,设置前景色为黑色glColor3f(0.0, 1.0, 0.0),设置线宽为2.0用glLineWidth(2.0)完成,将原单位立方体线框沿X轴正方向平移2.0;
(4).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,沿X轴负方向平移2.0,设置前景色为蓝色glColor3f(0.0, 0.0, 1.0),绘制单位立方体实体用glutSolidCube(1.0)完成;

(5).视点改为(1.0,1.5,8.0),观察中心改为在(0, 0 ,0),向上矢量改为(0, 1, 0);

(6).将glFrustum(xwMin, xwMax, ywMin, ywMax, dnear, dfar);换为透视投影gluPerspective (fovy,aspect,zNear,zFar)函数,参数分别为(视角,宽高比,近处,远处)。要求参数为gluPerspective(45, 1, 1, 100)。

// 提示:在合适的地方修改或添加代码
#include <GL/freeglut.h>
#include<stdio.h>
 
// 评测代码所用头文件-开始
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
GLint winWidth = 400, winHeight =400 ;           //设置初始化窗口大小
 
/*观察坐标系参数设置*/
GLfloat x0 = 1.0, yy = 1.5, z0 = 8.0;       //设置观察坐标系原点 
GLfloat xref = 0.0, yref = 0.0, zref = 0.0;    //设置观察坐标系参考点(视点) 
GLfloat Vx = 0.0, Vy = 1.0, Vz = 0.0;       //设置观察坐标系向上向量(y轴) 
 
/*观察体参数设置 */
GLfloat xwMin = -1.0, ywMin = -1.0, xwMax = 1.0, ywMax = 1.0;//设置裁剪窗口坐标范围
GLfloat dnear = 1.5, dfar = 20.0;          //设置远、近裁剪面深度范围
 
void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
}
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
 
    glLoadIdentity();
    /*观察变换*/
    gluLookAt(x0, yy, z0, xref, yref, zref, Vx, Vy, Vz);        //指定三维观察参数
 
    // 请在此添加你的代码
    /********** Begin ********/
    glPushMatrix();
    glColor3f(1.0, 0.0, 0.0);
    glutWireCube(1.0);
    glPopMatrix();
 
    glPushMatrix();
    glColor3f(0.0, 1.0, 0.0);
    glLineWidth(2.0);
    glTranslatef(2.0f,0.0f,0.0f);
    glutWireCube(1.0);
    glPopMatrix();
 
    glPushMatrix();
    glColor3f(0.0, 0.0, 1.0);
    glLineWidth(2.0);
    glTranslatef(-2.0f,0.0f,0.0f);
    glutSolidCube(1.0);
    glPopMatrix();
    /********** End **********/
    glFlush();
}
void reshape(GLint newWidth, GLint newHeight)
{
    /*视口变换*/
    glViewport(0, 0, newWidth, newHeight);    //定义视口大小
 
    /*投影变换*/
    glMatrixMode(GL_PROJECTION);
 
    glLoadIdentity();
 
    /*透视投影,设置透视观察体*/
    gluPerspective( 45,1,1,100 );
 
    /*模型变换*/
    glMatrixMode(GL_MODELVIEW);
    
    winWidth = newWidth;
    winHeight = newHeight;
}
int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize( 400 , 400 );        //设置初始化窗口大小
    glutCreateWindow("三维观察");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoopEvent();
    /*************以下为评测代码,与本次实验内容无关,请勿修改**************/
    GLubyte* pPixelData = (GLubyte*)malloc(800 * 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_step2/test.jpg", img);
    return 0;
}

?第3关:立方体视口变换

一.任务描述

根据提示,在右侧修改代码,并自己绘制出图形。平台会对你编写的代码进行测试。

1.本关任务

学习了解三维图形几何变换原理。 理解掌握OpenGL三维图形几何变换的方法。 理解掌握OpenGL程序的模型视图变换。 掌握OpenGL三维图形显示与观察的原理与实现。

2.预期输出

参考图片

3.具体要求

(1).背景色为黑色,用 glclearcolor 来完成;

(2).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,以中心为绘制原点,设置前景色为红色glColor3f(1.0, 0.0, 0.0),绘制单位立方体线框,用glutWireCube(1.0)完成;

(3).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,设置前景色为黑色glColor3f(0.0, 1.0, 0.0),设置线宽为2.0用glLineWidth(2.0)完成,将原单位立方体线框沿X轴正方向平移2.0;
(4).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,沿X轴负方向右平移2.0,设置前景色为蓝色glColor3f(0.0, 0.0, 1.0),绘制单位立方体实体用glutSolidCube(1.0)完成; (5).进行视口变换视口宽为800,高为400。实验内调整winWidth和winHeight 来设置初始化窗口大小;

(6).调用透视投影gluperspective()函数,参数为gluPerspective(45, 2, 1, 100)要求宽高比为2;

(7).在main函数中用glutInitWindowSize()调整视口窗口大小。

// 提示:在合适的地方修改或添加代码
#include <GL/freeglut.h>
#include<stdio.h>
 
// 评测代码所用头文件-开始
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
GLint winWidth =800 , winHeight =400 ; 	      //设置初始化窗口大小
 
/*观察坐标系参数设置*/
GLfloat x0 = 0.0, yy = 0.0, z0 = 5.0;	   //设置观察坐标系原点 
GLfloat xref = 0.0, yref = 0.0, zref = 0.0;	//设置观察坐标系参考点(视点) 
GLfloat Vx = 0.0, Vy = 1.0, Vz = 0.0;	   //设置观察坐标系向上向量(y轴) 
 
/*观察体参数设置 */
GLfloat xwMin = -1.0, ywMin = -1.0, xwMax = 1.0, ywMax = 1.0;//设置裁剪窗口坐标范围
GLfloat dnear = 1.5, dfar = 20.0;	      //设置远、近裁剪面深度范围
 
void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
}
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
 
    glLoadIdentity();
    /*观察变换*/
    gluLookAt(x0, yy, z0, xref, yref, zref, Vx, Vy, Vz);        //指定三维观察参数
    // 请在此添加你的代码
    /********** Begin ********/
    glColor3f(1.0, 0.0, 0.0);
    glPushMatrix();
    
    glutWireCube(1.0);
     glPopMatrix();

    glColor3f(0.0, 1.0, 0.0);
    glLineWidth(2.0);
     glPushMatrix();
    glTranslatef(2.0f,0.0f,0.0f);
    glutWireCube(1.0);
     glPopMatrix();

   glColor3f(0.0, 0.0, 1.0);
     glPushMatrix();
    glTranslatef(-2.0f,0.0f,0.0f);
    glutSolidCube(1.0);
     glPopMatrix();
    /********** End **********/
    glFlush();
}
 
void reshape(GLint newWidth, GLint newHeight)
{
    /*视口变换*/
    glViewport(0, 0, newWidth, newHeight);	//定义视口大小
 
    /*投影变换*/
    glMatrixMode(GL_PROJECTION);
 
    glLoadIdentity();
 
    /*透视投影,设置透视观察体*/
    gluPerspective( 45,2 ,1 ,100 );
 
    /*模型变换*/
    glMatrixMode(GL_MODELVIEW);
    
    winWidth = newWidth;
    winHeight = newHeight;
}
int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize( 800 ,400  );        //设置初始化窗口大小
    glutCreateWindow("三维观察");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoopEvent();
    /*************以下为评测代码,与本次实验内容无关,请勿修改**************/
    GLubyte* pPixelData = (GLubyte*)malloc(800 * 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, 800, 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 < 800; j++) {
            int k = 3 * (i * 800 + 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_step5/test.jpg", img);
    return 0;
}

模型、观察及视口变换v2.0

第1关:模型变换-左右两个立方体

一. 任务描述

1. 本关任务

(1) 理解模型变换基本原理,掌握平移和旋转变换的方法; (2) 根据模型变换基本原理,将main函数中的空白部分补充完整。

2. 输入

(1) 代码将自动输入一个边长为1的obj正方体模型,具体模型如下图:

test

(2) 代码自动将模型投影到二维平面上生成一个边长为1的白色立方体,具体图片如下所示:

test

(3) 将白色立方体的顶点坐标向x轴正方向平移1.2个单位距离,然后绘制一个红色立方形; (4) 将白色立方体的顶点坐标沿y轴逆时针方向旋转30度,再向x轴负方向平移1.3个单位距离,然后绘制一个绿色正方形。

3. 输出

具体结果如下图所示:

test

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"
 
using namespace std;
const double PI = acos(-1.0);
 
void line(Vec3i p0, Vec3i p1, PNGImage  &image, PNGColor color)
{
	bool steep = false;
	if (std::abs(p0.x - p1.x) < std::abs(p0.y - p1.y))
	{
		std::swap(p0.x, p0.y);
		std::swap(p1.x, p1.y);
		steep = true;
	}
	if (p0.x > p1.x)
	{
		std::swap(p0.x, p1.x);
		std::swap(p0.y, p1.y);
	}
 
	int dx = p1.x - p0.x;
	int dy = std::abs(p1.y - p0.y);
 
	int y = p0.y;
	int d = -dx;
	for (int x = p0.x; x <= p1.x; x++)
	{
		if (steep)
			image.set(y, x, color);
		else
			image.set(x, y, color);
 
		d = d + 2 * dy;
		if (d > 0)
		{
			y += (p1.y > p0.y ? 1 : -1);
			d = d - 2 * dx;
		}
	}
}
 
Matrix translation(Vec3f v) {//平移
	Matrix Tr = Matrix::identity(4);
	Tr[0][3] = v.x;
	Tr[1][3] = v.y;
	Tr[2][3] = v.z;
	return Tr;
}
 
Matrix scale(float factorX, float factorY, float factorZ)
{
	Matrix Z = Matrix::identity(4);
	Z[0][0] = factorX;
	Z[1][1] = factorY;
	Z[2][2] = factorZ;
	return Z;
}
 
Matrix rotation_x(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);
 
	Matrix R = Matrix::identity(4);
	R[1][1] = R[2][2] = cosangle;
	R[1][2] = -sinangle;
	R[2][1] = sinangle;
	return R;
}
 
Matrix rotation_y(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);
 
	Matrix R = Matrix::identity(4);
	R[0][0] = R[2][2] = cosangle;
	R[0][2] = sinangle;
	R[2][0] = -sinangle;
	return R;
}
 
Matrix rotation_z(float angle) {
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);
 
	Matrix R = Matrix::identity(4);
	R[0][0] = R[1][1] = cosangle;
	R[0][1] = -sinangle;
	R[1][0] = sinangle;
	return R;
}
 
int main(int argc, char** argv)
{
	const PNGColor white = PNGColor(255, 255, 255, 255);
	const PNGColor black = PNGColor(0, 0, 0, 255);
	const PNGColor red = PNGColor(255, 0, 0, 255);
	const PNGColor green = PNGColor(0, 255, 0, 255);
	const PNGColor blue = PNGColor(0, 0, 255, 255);
	const PNGColor yellow = PNGColor(255, 255, 0, 255);
 
	Model *model = NULL;
	const int width = 500;
	const int height = 500;
	const int depth = 255;
	Vec3f eye(0.5, 1.5, 4);
	Vec3f center(0, 0, 0);
 
	Matrix Projection = Matrix::projection(eye, center);
	Matrix ViewPort = Matrix::viewport(width / 4, width / 4, width / 2, height / 2, depth);
 
 
	//generate some image
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
	model = new Model("cube.obj");
 
 
	for (int i = 0; i < model->nfaces(); i++)
	{
		std::vector<int> face = model->face(i);
		for (int j = 0; j < (int)face.size(); j++)
		{
			Vec3f wp0 = model->vert(face[j]);
			Vec3f wp1 = model->vert(face[(j + 1) % face.size()]);
 
			Matrix S0 = scale(0.5, 0.5, 0.5);
			Vec3f swp0 = S0 * wp0;
			Vec3f swp1 = S0 * wp1;
 
			// for comparing - draw the model after scaled 
			Vec3f op0 = ViewPort * Projection * swp0;
			Vec3f op1 = ViewPort * Projection * swp1;
			line(op0, op1, image, white);
 
			// Please add the code here
            /********** Begin ********/
            //3) 将白色立方体的顶点坐标向x轴正方向平移1.2个单位距离,然后绘制一个红色立方形
            Matrix S1 = translation(Vec3f(1.2,0.0,0.0));
 
            op0 = ViewPort * Projection *S1 * swp0;
			 op1 = ViewPort * Projection *S1 * swp1;
			line(op0, op1, image, red);
            // (4) 将白色立方体的顶点坐标沿y轴逆时针方向旋转30度,再向x轴负方向平移1.3个单位距离,然后绘制一个绿色正方形
        //    Matrix rotation_y(float angle)
             Matrix S3 = rotation_y(30.0);
             Matrix S4 = translation(Vec3f(-1.3,0.0,0.0));
             op0 = ViewPort * Projection *S4 *S3 * swp0;
             op1 = ViewPort * Projection *S4 *S3 * swp1;
             line(op0, op1, image,green );
            /********** End *********/
		}
	}
	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step1/test.png");
	delete model;
	return 0;
}

第2关:观察变换

一. 任务描述

1. 本关任务

(1) 理解观察变换基本原理,将lookat函数中空白部分补充完整; (2) 将main函数中的参数补充完整。

2. 输入

(1) 代码将自动输入一个边长为1的obj正方体模型,具体模型如下图:

test

(2) 相机坐标为(0, 1.5, 4),中心点坐标为(0,0,0),向上的矢量为Vec3f(0, 1, 0)

3. 输出

具体结果如下图所示:

test

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"
 
using namespace std;
const double PI = acos(-1.0);
 
void line(Vec3i p0, Vec3i p1, PNGImage  &image, PNGColor color)
{
	bool steep = false;
	if (std::abs(p0.x - p1.x) < std::abs(p0.y - p1.y))
	{
		std::swap(p0.x, p0.y);
		std::swap(p1.x, p1.y);
		steep = true;
	}
	if (p0.x > p1.x)
	{
		std::swap(p0.x, p1.x);
		std::swap(p0.y, p1.y);
	}
 
	int dx = p1.x - p0.x;
	int dy = std::abs(p1.y - p0.y);
 
	int y = p0.y;
	int d = -dx;
	for (int x = p0.x; x <= p1.x; x++)
	{
		if (steep)
			image.set(y, x, color);
		else
			image.set(x, y, color);
 
		d = d + 2 * dy;
		if (d > 0)
		{
			y += (p1.y > p0.y ? 1 : -1);
			d = d - 2 * dx;
		}
	}
}
 
 
Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) {
    Matrix res = Matrix::identity(4);
	// Please add the code here
    /********** Begin ********/
    Vec3f z = (eye - center).normalize();
	Vec3f x = (up^z).normalize();
	Vec3f y = (z^x).normalize();
	for (int i = 0; i < 3; i++) {
		res[0][i] = x[i];
		res[1][i] = y[i];
		res[2][i] = z[i];
		res[i][3] = -center[i];
	}
 
 
	/********** End ********/
	return res;
}
 
Matrix translation(Vec3f v) {
	Matrix Tr = Matrix::identity(4);
	Tr[0][3] = v.x;
	Tr[1][3] = v.y;
	Tr[2][3] = v.z;
	return Tr;
}
 
Matrix scale(float factorX, float factorY, float factorZ)
{
	Matrix Z = Matrix::identity(4);
	Z[0][0] = factorX;
	Z[1][1] = factorY;
	Z[2][2] = factorZ;
	return Z;
}
 
Matrix rotation_x(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);
 
	Matrix R = Matrix::identity(4);
	R[1][1] = R[2][2] = cosangle;
	R[1][2] = -sinangle;
	R[2][1] = sinangle;
	return R;
}
 
Matrix rotation_y(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);
 
	Matrix R = Matrix::identity(4);
	R[0][0] = R[2][2] = cosangle;
	R[0][2] = sinangle;
	R[2][0] = -sinangle;
	return R;
}
 
Matrix rotation_z(float angle) {
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);
 
	Matrix R = Matrix::identity(4);
	R[0][0] = R[1][1] = cosangle;
	R[0][1] = -sinangle;
	R[1][0] = sinangle;
	return R;
}
 
int main(int argc, char** argv)
{
	const PNGColor white = PNGColor(255, 255, 255, 255);
	const PNGColor black = PNGColor(0, 0, 0, 255);
	const PNGColor red = PNGColor(255, 0, 0, 255);
	const PNGColor green = PNGColor(0, 255, 0, 255);
	const PNGColor blue = PNGColor(0, 0, 255, 255);
	const PNGColor yellow = PNGColor(255, 255, 0, 255);
 
	Model *model = NULL;
	const int width = 500;
	const int height = 500;
	const int depth = 255;
 
	// Please add the code here
    /********** Begin ********/
    Vec3f eye(0 ,1.5  ,4  );
	Vec3f center( 0, 0 ,0  );
	Matrix ModelView = lookat(eye, center, Vec3f( 0, 1 ,0  ));
	// Please add the code here
    /********** Begin ********/
 
	Matrix Projection = Matrix::projection(eye, center);
	Matrix ViewPort = Matrix::viewport(width / 4, width / 4, width / 2, height / 2, depth);
 
 
	//generate some image
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
	model = new Model("cube.obj");
 
	for (int i = 0; i < model->nfaces(); i++)
	{
		std::vector<int> face = model->face(i);
		for (int j = 0; j < (int)face.size(); j++)
		{
			Vec3f wp0 = model->vert(face[j]);
			Vec3f wp1 = model->vert(face[(j + 1) % face.size()]);
 
			Matrix S0 = scale(0.5, 0.5, 0.5);
			Vec3f swp0 = S0 * wp0;
			Vec3f swp1 = S0 * wp1;
 
			Vec3f sp0 = ViewPort*Projection*ModelView*swp0;
			Vec3f sp1 = ViewPort*Projection*ModelView*swp1;
			line(sp0, sp1, image, red);
		}
	}
 
	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step2/test.png");
	delete model;
	return 0;
}

?第3关:视口变换

一. 任务描述

1. 本关任务

(1) 理解视口变换的方法; (3) 根据视口变换的方法将viewport函数中的空白部分补充完整,并将main函数中的参数补充完整。

2. 输入

(1) 代码将自动输入一个边长为1的obj正方体模型,具体模型如下图:

test

(2) 视口矩阵中参数x、y的大小为宽度(width)的四分之一,参数w的大小为宽度的一半(width),参数h的大小为高度的一半(height),参数d=255。

3. 输出

具体结果如下图所示:

test

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"
 
using namespace std;
const double PI = acos(-1.0);
 
void line(Vec3i p0, Vec3i p1, PNGImage  &image, PNGColor color)
{
	bool steep = false;
	if (std::abs(p0.x - p1.x) < std::abs(p0.y - p1.y))
	{
		std::swap(p0.x, p0.y);
		std::swap(p1.x, p1.y);
		steep = true;
	}
	if (p0.x > p1.x)
	{
		std::swap(p0.x, p1.x);
		std::swap(p0.y, p1.y);
	}
 
	int dx = p1.x - p0.x;
	int dy = std::abs(p1.y - p0.y);
 
	int y = p0.y;
	int d = -dx;
	for (int x = p0.x; x <= p1.x; x++)
	{
		if (steep)
			image.set(y, x, color);
		else
			image.set(x, y, color);
 
		d = d + 2 * dy;
		if (d > 0)
		{
			y += (p1.y > p0.y ? 1 : -1);
			d = d - 2 * dx;
		}
	}
}
 
Matrix viewport(int x, int y, int w, int h, int depth) {
	Matrix m = Matrix::identity(4);
	// Please add the code here
    /********** Begin ********/
    m[0][0]=w/2;
    m[0][3]=x+(w/2);
    m[1][1]=h/2;
    m[1][3]=y+h/2;
    m[2][2]=255/2;
    m[2][3]=255/2;
    m[3][3]=1;
	/********** End **********/
	return m;
}
 
Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) {
	Vec3f z = (eye - center).normalize();
	Vec3f x = (up^z).normalize();
	Vec3f y = (z^x).normalize();
	Matrix res = Matrix::identity(4);
	for (int i = 0; i < 3; i++) {
		res[0][i] = x[i];
		res[1][i] = y[i];
		res[2][i] = z[i];
		res[i][3] = -center[i];
	}
	return res;
}
 
Matrix translation(Vec3f v) {
	Matrix Tr = Matrix::identity(4);
	Tr[0][3] = v.x;
	Tr[1][3] = v.y;
	Tr[2][3] = v.z;
	return Tr;
}
 
Matrix scale(float factorX, float factorY, float factorZ)
{
	Matrix Z = Matrix::identity(4);
	Z[0][0] = factorX;
	Z[1][1] = factorY;
	Z[2][2] = factorZ;
	return Z;
}
 
Matrix rotation_x(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);
 
	Matrix R = Matrix::identity(4);
	R[1][1] = R[2][2] = cosangle;
	R[1][2] = -sinangle;
	R[2][1] = sinangle;
	return R;
}
 
Matrix rotation_y(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);
 
	Matrix R = Matrix::identity(4);
	R[0][0] = R[2][2] = cosangle;
	R[0][2] = sinangle;
	R[2][0] = -sinangle;
	return R;
}
 
Matrix rotation_z(float angle) {
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);
 
	Matrix R = Matrix::identity(4);
	R[0][0] = R[1][1] = cosangle;
	R[0][1] = -sinangle;
	R[1][0] = sinangle;
	return R;
}
 
int main(int argc, char** argv)
{
	const PNGColor white = PNGColor(255, 255, 255, 255);
	const PNGColor black = PNGColor(0, 0, 0, 255);
	const PNGColor red = PNGColor(255, 0, 0, 255);
	const PNGColor green = PNGColor(0, 255, 0, 255);
	const PNGColor blue = PNGColor(0, 0, 255, 255);
	const PNGColor yellow = PNGColor(255, 255, 0, 255);
 
	Model *model = NULL;
 
	Vec3f eye(0, 1.5, 4);
	Vec3f center(0, 0, 0);
 
	Matrix ModelView = lookat(eye, center, Vec3f(0, 1, 0));
	Matrix Projection = Matrix::projection(eye, center);
 
 
	const int width = 500;
	const int height = 500;
	const int depth = 255;
	// Please add the code here
    /********** Begin ********/
	Matrix ViewPort = viewport(width/4,width/4,width/2,height/2,depth);
	/********** End **********/
 
	//generate some image
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
	model = new Model("cube.obj");
 
	for (int i = 0; i < model->nfaces(); i++)
	{
		std::vector<int> face = model->face(i);
		for (int j = 0; j < (int)face.size(); j++)
		{
			Vec3f wp0 = model->vert(face[j]);
			Vec3f wp1 = model->vert(face[(j + 1) % face.size()]);
 
			Matrix S0 = scale(0.5, 0.5, 0.5);
			Vec3f swp0 = S0 * wp0;
			Vec3f swp1 = S0 * wp1;
 
			Vec3f sp0 = ViewPort*Projection*ModelView*swp0;
			Vec3f sp1 = ViewPort*Projection*ModelView*swp1;
			line(sp0, sp1, image, red);
		}
	}
 
	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step3/test.png");
	delete model;
	return 0;
}

投影变换v1.0

第1关:立方体透视投影

一.任务描述

根据提示,在右侧修改代码,并自己绘制出图形。平台会对你编写的代码进行测试。

1.本关任务

学习了解三维图形几何变换原理。 理解掌握OpenGL三维图形几何变换的方法。 理解掌握OpenGL程序的模型视图变换。 掌握OpenGL三维图形显示与观察的原理与实现。

2.预期输出

参考图片

3.具体要求

(1).背景色为黑色,用 glclearcolor 来完成; (2).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,以中心为绘制原点,设置前景色为红色glColor3f(1.0, 0.0, 0.0),绘制单位立方体线框,用glutWireCube(1.0)完成; (3).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,设置前景色为黑色glColor3f(0.0, 1.0, 0.0),设置线宽为2.0用glLineWidth(2.0)完成,将原单位立方体线框沿X轴正方向平移2.0;
(4).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,沿X轴负方向平移2.0,设置前景色为蓝色glColor3f(0.0, 0.0, 1.0),绘制单位立方体实体用glutSolidCube(1.0)完成; (5).由图可知,中间红色为一点透视。右边绿色和左边蓝色为两点透视。通过glRotatef()旋转绿色立方体来,完成蓝色立方体的三点透视。将绿色立方体绕X轴旋转+30度。

// 提示:在合适的地方修改或添加代码
#include <GL/freeglut.h>
#include<stdio.h>

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

GLint winWidth = 400, winHeight =400 ; 	      //设置初始化窗口大小

/*观察坐标系参数设置*/
GLfloat x0 = 0.0, yy = 0.0, z0 = 5.0;	   //设置观察坐标系原点 
GLfloat xref = 0.0, yref = 0.0, zref = 0.0;	//设置观察坐标系参考点(视点) 
GLfloat Vx = 0.0, Vy = 1.0, Vz = 0.0;	   //设置观察坐标系向上向量(y轴) 

/*观察体参数设置 */
GLfloat xwMin = -1.0, ywMin = -1.0, xwMax = 1.0, ywMax = 1.0;//设置裁剪窗口坐标范围
GLfloat dnear = 1.5, dfar = 20.0;	      //设置远、近裁剪面深度范围

void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
}
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    /*观察变换*/
    gluLookAt(x0, yy, z0, xref, yref, zref, Vx, Vy, Vz);        //指定三维观察参数
    // 请在此添加你的代码
    /********** Begin ********/
    glPushMatrix();
    glColor3f(1.0, 0.0, 0.0);    //设置前景色为红色
    glutWireCube(1.0);   //绘制单位立方体线框
    glPopMatrix();
    glPushMatrix();
    glColor3f(0.0, 1.0, 0.0);    //设置前景色为黑色
    glLineWidth(2.0);             //设置线宽
    glRotatef(30,1,0,0);
    glTranslatef(2.0f, 0.0f, 0.0f);
    glutWireCube(1.0);   //绘制单位立方体线框
    glPopMatrix();
    glPushMatrix();
    glTranslatef(-2.0f, 0.0f, 0.0f);
    glColor3f(0.0, 0.0, 1.0);
    glutSolidCube(1.0);    //绘制单位立方体实体
    glPopMatrix();
    /********** End **********/
    glFlush();
}


void reshape(GLint newWidth, GLint newHeight)
{
    /*视口变换*/
    glViewport(0, 0, newWidth, newHeight);	//定义视口大小

    /*投影变换*/
    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    /*透视投影,设置透视观察体*/
	glFrustum(xwMin, xwMax, ywMin, ywMax, dnear, dfar);

    /*模型变换*/
    glMatrixMode(GL_MODELVIEW);
    
    winWidth = newWidth;
    winHeight = newHeight;
}
int main(int argc, char* argv[])
{

    glutInit(&argc, argv);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize( 400 , 400 );        //设置初始化窗口大小
    glutCreateWindow("三维观察");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoopEvent();


    /*************以下为评测代码,与本次实验内容无关,请勿修改**************/
    GLubyte* pPixelData = (GLubyte*)malloc(800 * 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_step4/test.jpg", img);
    return 0;
}

第2关:立方体平行投影

一.任务描述

根据提示,在右侧修改代码,并自己绘制出图形。平台会对你编写的代码进行测试。

1.本关任务

学习了解三维图形几何变换原理。 理解掌握OpenGL三维图形几何变换的方法。 理解掌握OpenGL程序的模型视图变换。 掌握OpenGL三维图形显示与观察的原理与实现。

2.预期输出

参考图片

3.具体要求

(1).背景色为黑色,用 glclearcolor 来完成;

(2).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,以中心为绘制原点,设置前景色为红色glColor3f(1.0, 0.0, 0.0),绘制单位立方体线框,用glutWireCube(1.0)完成;

(3).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,设置前景色为黑色glColor3f(0.0, 1.0, 0.0),设置线宽为2.0用glLineWidth(2.0)完成,将原单位立方体线框沿X轴正方向平移2.0;
(4).运用glPushMatrix()函数和glPopMatrix()函数进行矩阵操作,沿X轴负方向平移2.0,设置前景色为蓝色glColor3f(0.0, 0.0, 1.0),绘制单位立方体实体用glutSolidCube(1.0)完成;

(5).进行平行投影调用glOrtho()函数,坐标为(左,右,下,上,近,远),坐标为glOrtho(-3.0, 3.0, -3.0, 3.0,-100.0, 100.0);

// 提示:在合适的地方修改或添加代码
#include <GL/freeglut.h>
#include<stdio.h>
 
// 评测代码所用头文件-开始
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
// 评测代码所用头文件-结束
 
GLint winWidth = 400, winHeight =400 ; 	      //设置初始化窗口大小
 
/*观察坐标系参数设置*/
GLfloat x0 = 0.0, yy = 0.0, z0 = 5.0;	   //设置观察坐标系原点 
GLfloat xref = 0.0, yref = 0.0, zref = 0.0;	//设置观察坐标系参考点(视点) 
GLfloat Vx = 0.0, Vy = 1.0, Vz = 0.0;	   //设置观察坐标系向上向量(y轴) 
 
/*观察体参数设置 */
GLfloat xwMin = -1.0, ywMin = -1.0, xwMax = 1.0, ywMax = 1.0;//设置裁剪窗口坐标范围
GLfloat dnear = 1.5, dfar = 20.0;	      //设置远、近裁剪面深度范围
 
void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
}
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
 
    glLoadIdentity();
    /*观察变换*/
    gluLookAt(x0, yy, z0, xref, yref, zref, Vx, Vy, Vz);        //指定三维观察参数
 
    // 请在此添加你的代码
    /********** Begin ********/
     glPushMatrix();
    glColor3f(1.0, 0.0, 0.0);    //设置前景色为红色
    glutWireCube(1.0);   //绘制单位立方体线框
    glPopMatrix();
    glPushMatrix();
    glColor3f(0.0, 1.0, 0.0);    //设置前景色为黑色
    glLineWidth(2.0);             //设置线宽
    glTranslatef(2.0f, 0.0f, 0.0f);
    glutWireCube(1.0);   //绘制单位立方体线框
    glPopMatrix();
    glPushMatrix();
    glTranslatef(-2.0f, 0.0f, 0.0f);
    glColor3f(0.0, 0.0, 1.0);
    glutSolidCube(1.0);    //绘制单位立方体实体
    glPopMatrix();
 
    /********** End **********/
    glFlush();
}
 
void reshape(GLint newWidth, GLint newHeight)
{
    /*视口变换*/
    glViewport(0, 0, newWidth, newHeight);	//定义视口大小
 
    /*投影变换*/
    glMatrixMode(GL_PROJECTION);
 
    glLoadIdentity();
 
    /*平行投影*/
    glOrtho( -3,3 ,-3 ,3 ,-100 ,100 );
 
    /*模型变换*/
    glMatrixMode(GL_MODELVIEW);
    
    winWidth = newWidth;
    winHeight = newHeight;
}
int main(int argc, char* argv[])
{
 
    glutInit(&argc, argv);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize( 400 , 400 );        //设置初始化窗口大小
    glutCreateWindow("三维观察");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoopEvent();
 
 
 
 
 
    /*************以下为评测代码,与本次实验内容无关,请勿修改**************/
    GLubyte* pPixelData = (GLubyte*)malloc(800 * 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;
}

投影变换v2.0

第1关:一点透视

一. 任务描述

1. 本关任务

(1) 理解透视投影变换的方法; (2) 将projection函数和main函数中的空白部分补充完整。

2. 输入

(1) 代码将自动输入一个边长为1的obj正方体模型,具体模型如下图:

test

(2) 代码自动将模型投影到二维平面中心生成一个边长为1的立方体,经过模型变换和投影变换后生成三个绿色的方体,三个立方体的投影变换eye的坐标均为(0,0,5),具体图片如下所示:

test

(3) 参考已有代码,将中心立绿色方体的顶点分别向y轴负方向平移1.2个单位,绘制一个红色立方体。再将红色立方体顶点分别向x轴正,负两个方向平移1.2个单位,绘制两个红色立方体。三个立方体的投影变换eye的坐标均为(0,0,4); (4) 将中心绿色立方体的顶点分别向y轴正方向平移1.2个单位,绘制一个黄色立方体。再将黄色立方体顶点分别向x轴正,负两个方向平移1.2个单位,绘制两个黄色立方体。三个立方体的投影变换eye的坐标均为(0,0,8);

3. 输出

具体结果如下图所示:

test

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"
using namespace std;
const double PI = acos(-1.0);
void line(Vec3i p0, Vec3i p1, PNGImage  &image, PNGColor color)
{
    bool steep = false;
    if (std::abs(p0.x - p1.x) < std::abs(p0.y - p1.y))
    {
        std::swap(p0.x, p0.y);
        std::swap(p1.x, p1.y);
        steep = true;
    }
    if (p0.x > p1.x)
    {
        std::swap(p0.x, p1.x);
        std::swap(p0.y, p1.y);
    }
    int dx = p1.x - p0.x;
    int dy = std::abs(p1.y - p0.y);
    int y = p0.y;
    int d = -dx;
    for (int x = p0.x; x <= p1.x; x++)
    {
        if (steep)
            image.set(y, x, color);
        else
            image.set(x, y, color);
        d = d + 2 * dy;
        if (d > 0)
        {
            y += (p1.y > p0.y ? 1 : -1);
            d = d - 2 * dx;
        }
    }
}
Matrix projection(Vec3f eye, Vec3f center)
{
    Matrix m = Matrix::identity(4);
    // Please add the code here
    /********** Begin ********/
    m[3][2] = -1.f / (eye - center).norm();
    /********** End **********/
    return m;
}
Matrix viewport(int x, int y, int w, int h, int depth) {
    Matrix m = Matrix::identity(4);
    m[0][3] = x + w / 2.f;
    m[1][3] = y + h / 2.f;
    m[2][3] = depth / 2.f;
    m[0][0] = w / 2.f;
    m[1][1] = h / 2.f;
    m[2][2] = depth / 2.f;
    return m;
}
Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) {
    Vec3f z = (eye - center).normalize();
    Vec3f x = (up^z).normalize();
    Vec3f y = (z^x).normalize();
    Matrix res = Matrix::identity(4);
    for (int i = 0; i < 3; i++) {
        res[0][i] = x[i];
        res[1][i] = y[i];
        res[2][i] = z[i];
        res[i][3] = -center[i];
    }
    return res;
}
Matrix translation(Vec3f v) {
    Matrix Tr = Matrix::identity(4);
    Tr[0][3] = v.x;
    Tr[1][3] = v.y;
    Tr[2][3] = v.z;
    return Tr;
}
Matrix scale(float factorX, float factorY, float factorZ)
{
    Matrix Z = Matrix::identity(4);
    Z[0][0] = factorX;
    Z[1][1] = factorY;
    Z[2][2] = factorZ;
    return Z;
}
Matrix rotation_x(float angle)
{
    angle = angle * PI / 180;
    float sinangle = sin(angle);
    float cosangle = cos(angle);
    Matrix R = Matrix::identity(4);
    R[1][1] = R[2][2] = cosangle;
    R[1][2] = -sinangle;
    R[2][1] = sinangle;
    return R;
}
Matrix rotation_y(float angle)
{
    angle = angle * PI / 180;
    float sinangle = sin(angle);
    float cosangle = cos(angle);
    Matrix R = Matrix::identity(4);
    R[0][0] = R[2][2] = cosangle;
    R[0][2] = sinangle;
    R[2][0] = -sinangle;
    return R;
}
Matrix rotation_z(float angle) {
    angle = angle * PI / 180;
    float sinangle = sin(angle);
    float cosangle = cos(angle);
    Matrix R = Matrix::identity(4);
    R[0][0] = R[1][1] = cosangle;
    R[0][1] = -sinangle;
    R[1][0] = sinangle;
    return R;
}
int main(int argc, char** argv)
{
    const PNGColor white = PNGColor(255, 255, 255, 255);
    const PNGColor black = PNGColor(0, 0, 0, 255);
    const PNGColor red = PNGColor(255, 0, 0, 255);
    const PNGColor green = PNGColor(0, 255, 0, 255);
    const PNGColor blue = PNGColor(0, 0, 255, 255);
    const PNGColor yellow = PNGColor(255, 255, 0, 255);
    Model *model = NULL;
    const int width = 800;
    const int height = 800;
    const int depth = 255;
    Vec3f center(0, 0, 0);
    Matrix ViewPort = viewport(width / 4, width / 4, width / 2, height / 2, depth);
    //generate some image
    PNGImage image(width, height, PNGImage::RGBA); 
    image.init(black);
    model = new Model("cube.obj");
    for (int i = 0; i < model->nfaces(); i++)
    {
        std::vector<int> face = model->face(i);
        for (int j = 0; j < (int)face.size(); j++)
        {
            Vec3f wp0 = model->vert(face[j]);
            Vec3f wp1 = model->vert(face[(j + 1) % face.size()]);
            Matrix S0 = scale(0.5, 0.5, 0.5);
            Vec3f swp0 = S0 * wp0;
            Vec3f swp1 = S0 * wp1;
            // 一点透视 
            float t[3] = { -1.2, 0, 1.2 };
            Matrix ModelView = Matrix::identity(4);
            PNGColor clr[3] = { red, green, yellow };
            
            Vec3f eye2(0, 0, 5);
            Matrix Projection2 = projection(eye2, center);
            for (int j = 0; j < 3; j++)
            {
                ModelView = translation(Vec3f(t[j], t[1], 0));
                Vec3f op0 = ViewPort * Projection2 * ModelView * swp0;
                Vec3f op1 = ViewPort * Projection2 * ModelView *swp1;
                line(op0, op1, image, green);
            }
            // Please add the code here
            /********** Begin ********/
            Vec3f eye1(0, 0, 4);
            Matrix Projection1 = projection(eye1, center);
            for (int j = 0; j < 3; j++)
            {
                ModelView = translation(Vec3f(t[j], t[0], 0));
                Vec3f op0 = ViewPort * Projection1 * ModelView * swp0;
                Vec3f op1 = ViewPort * Projection1 * ModelView *swp1;
                line(op0, op1, image, red);
            }
            Vec3f eye3(0, 0, 8);
            Matrix Projection3 = projection(eye3, center);
            for (int j = 0; j < 3; j++)
            {
                ModelView = translation(Vec3f(t[j], t[2], 0));
                Vec3f op0 = ViewPort * Projection3 * ModelView * swp0;
                Vec3f op1 = ViewPort * Projection3 * ModelView *swp1;
                line(op0, op1, image, yellow);
            }
            /********** End **********/
        }
    }
    image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
    image.write_png_file("../img_step1/test.png");
    delete model;
    return 0;
}

第2关:两点透视

一. 任务描述

1. 本关任务

(1) 理解透视投影变换的方法; (2) 将main函数中的空白部分补充完整。

2. 输入

(1) 代码将自动输入一个边长为1的obj正方体模型,具体模型如下图:

test

(2) 代码自动将模型投影到二维平面中心生成一个边长为1的绿色立方体; (3) 改变模型位置,产生两点透视: 将绿色立方体顶点分别沿z轴逆时针旋转45度,向y轴正方向平移1.2个单位,绘制一个红色立方体。再将红色立方体顶点分别向x轴正,负两个方向平移1.2个单位,绘制两个红色立方体。最后对三个红立方体进行投影变换,变换矩阵Projection已给出; (4) 改变视点与模型位置,产生两点透视(先模型变换再观察变换): 首先将立绿色方体的顶点分别向x轴正,负两个方向平移1.2个单位,绘制两个绿色立方体。然后对三个绿色立方体分别进行观察变换,将参数eye沿y轴顺时针旋转45度作为相机坐标,中心点坐标为center,向上矢量为Vec3f(0, 1, 0)。最后对三个绿立方体进行投影变换,变换矩阵Projection已给出; (5) 改变视点与模型位置,产生两点透视(先观察变换再模型变换): 首先对绿色立方体分别进行观察变换,将参数eye沿y轴顺时针旋转45度作为相机坐标,中心点坐标为center,向上矢量为Vec3f(0, 1, 0)。将绿色立方体向y轴负方向平移1.2个单位,绘制一个黄色立方体。再将黄色立方体顶点分别向x轴正,负两个方向平移1.2个单位,绘制两个黄色立方体。最后对三个黄立方体进行投影变换,变换矩阵Projection已给出。

3. 输出

具体结果如下图所示:

test

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"

using namespace std;
const double PI = acos(-1.0);

void line(Vec3i p0, Vec3i p1, PNGImage  &image, PNGColor color)
{
	bool steep = false;
	if (std::abs(p0.x - p1.x) < std::abs(p0.y - p1.y))
	{
		std::swap(p0.x, p0.y);
		std::swap(p1.x, p1.y);
		steep = true;
	}
	if (p0.x > p1.x)
	{
		std::swap(p0.x, p1.x);
		std::swap(p0.y, p1.y);
	}

	int dx = p1.x - p0.x;
	int dy = std::abs(p1.y - p0.y);

	int y = p0.y;
	int d = -dx;
	for (int x = p0.x; x <= p1.x; x++)
	{
		if (steep)
			image.set(y, x, color);
		else
			image.set(x, y, color);

		d = d + 2 * dy;
		if (d > 0)
		{
			y += (p1.y > p0.y ? 1 : -1);
			d = d - 2 * dx;
		}
	}
}

Matrix projection(Vec3f eye, Vec3f center)
{
	Matrix m = Matrix::identity(4);
	m[3][2] = -1.f / (eye - center).norm();
	return m;
}

Matrix viewport(int x, int y, int w, int h, int depth) {
	Matrix m = Matrix::identity(4);
	m[0][3] = x + w / 2.f;
	m[1][3] = y + h / 2.f;
	m[2][3] = depth / 2.f;

	m[0][0] = w / 2.f;
	m[1][1] = h / 2.f;
	m[2][2] = depth / 2.f;
	return m;
}

Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) {
	Vec3f z = (eye - center).normalize();
	Vec3f x = (up^z).normalize();
	Vec3f y = (z^x).normalize();
	Matrix res = Matrix::identity(4);
	for (int i = 0; i < 3; i++) {
		res[0][i] = x[i];
		res[1][i] = y[i];
		res[2][i] = z[i];
		res[i][3] = -center[i];
	}
	return res;
}

Matrix translation(Vec3f v) {
	Matrix Tr = Matrix::identity(4);
	Tr[0][3] = v.x;
	Tr[1][3] = v.y;
	Tr[2][3] = v.z;
	return Tr;
}

Matrix scale(float factorX, float factorY, float factorZ)
{
	Matrix Z = Matrix::identity(4);
	Z[0][0] = factorX;
	Z[1][1] = factorY;
	Z[2][2] = factorZ;
	return Z;
}

Matrix rotation_x(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[1][1] = R[2][2] = cosangle;
	R[1][2] = -sinangle;
	R[2][1] = sinangle;
	return R;
}

Matrix rotation_y(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[2][2] = cosangle;
	R[0][2] = sinangle;
	R[2][0] = -sinangle;
	return R;
}

Matrix rotation_z(float angle) {
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[1][1] = cosangle;
	R[0][1] = -sinangle;
	R[1][0] = sinangle;
	return R;
}

int main(int argc, char** argv)
{
	const PNGColor white = PNGColor(255, 255, 255, 255);
	const PNGColor black = PNGColor(0, 0, 0, 255);
	const PNGColor red = PNGColor(255, 0, 0, 255);
	const PNGColor green = PNGColor(0, 255, 0, 255);
	const PNGColor blue = PNGColor(0, 0, 255, 255);
	const PNGColor yellow = PNGColor(255, 255, 0, 255);

	Model *model = NULL;
	const int width = 800;
	const int height = 800;
	const int depth = 255;


	//generate some image
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
	model = new Model("cube.obj");

	Vec3f eye(0, 0, 4);
	Vec3f center(0, 0, 0);
	Matrix ModelView = Matrix::identity(4);
	Matrix Projection = projection(eye, center);
	Matrix ViewPort = viewport(width / 4, width / 4, width / 2, height / 2, depth);

	for (int i = 0; i < model->nfaces(); i++)
	{
		std::vector<int> face = model->face(i);
		for (int j = 0; j < (int)face.size(); j++)
		{
			Vec3f wp0 = model->vert(face[j]);
			Vec3f wp1 = model->vert(face[(j + 1) % face.size()]);

			Matrix S0 = scale(0.4, 0.4, 0.4);
			Vec3f swp0 = S0 * wp0;
			Vec3f swp1 = S0 * wp1;
            // Please add the code here
            /********** Begin ********/
             float tx[3] = { -1.2, 0, 1.2 };
            for (int i = 0; i < 3; i++)
            {
                ModelView = translation(Vec3f(tx[i], 1.2, 0)) * rotation_y(45);
                Vec3f op0 = ViewPort * Projection * ModelView * swp0;
                Vec3f op1 = ViewPort * Projection * ModelView * swp1;
                line(op0, op1, image, red);
            }
            // 改变视点与模型位置,产生两点透视 
            // 先模型变换,再视点变换
            Vec3f eye1 = rotation_y(-45) * eye;
            for (int j = 0; j < 3; j++)
            {
                Matrix ModelView1 = lookat(eye1, center, Vec3f(0, 1, 0)) * translation(Vec3f(tx[j], 0, 0));
                Vec3f vp0 = ViewPort * Projection * ModelView1 * swp0;
                Vec3f vp1 = ViewPort * Projection * ModelView1 *swp1;
                line(vp0, vp1, image, green);
            }
            // 改变视点与模型位置,产生两点透视 
            // 先视点变换,再模型变换
            for (int k = 0; k < 3; k++)
            {    
                Matrix ModelView1 = translation(Vec3f(tx[k], -1.2, 0)) * lookat(eye1, center, Vec3f(0, 1, 0));
                Vec3f vp0 = ViewPort * Projection * ModelView1 * swp0;
                Vec3f vp1 = ViewPort * Projection * ModelView1 *swp1;
                line(vp0, vp1, image, yellow);
            }    
            /********** End ********/
		}
	}

	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step2/test.png");
	delete model;
	return 0;
}

?第3关:三视图与正等测投影

一. 任务描述

1. 本关任务

(1) 理解投影变换的方法; (2) 将main函数中的空白部分补充完整。

2. 输入

(1) 代码将自动输入一个边长为1的obj正方体模型,具体模型如下图:

test

(2) 代码自动将模型投影到二维平面,经过模型变换,生成一个长宽高不等的立方体; (3) 将立方体沿Z轴向XOY平面正投影,并绘制出一个白色矩形; (4) 将立方体沿Y轴向XOZ平面正投影,然后沿X轴逆时针旋转90度,最后沿着Y轴负方向平移1.2个单位长度,绘制一个红色矩形; (5) 将立方体沿X轴向YOZ平面正投影,然后沿Y轴顺时针旋转90度,最后沿着X轴负方向平移1.2个单位长度,绘制一个绿色矩形; (6) 绘制正等测投影图,将立方体沿Z轴逆时针旋转45度,再沿X轴逆时针旋转35.25度,然后沿Z轴向XOY平面正投影。最后沿着Y轴正方向平移1.2个单位长度,绘制一个黄色立方体;

3. 输出

具体结果如下图所示:

test

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"

using namespace std;
const double PI = acos(-1.0);

void line(Vec3i p0, Vec3i p1, PNGImage  &image, PNGColor color)
{
	bool steep = false;
	if (std::abs(p0.x - p1.x) < std::abs(p0.y - p1.y))
	{
		std::swap(p0.x, p0.y);
		std::swap(p1.x, p1.y);
		steep = true;
	}
	if (p0.x > p1.x)
	{
		std::swap(p0.x, p1.x);
		std::swap(p0.y, p1.y);
	}

	int dx = p1.x - p0.x;
	int dy = std::abs(p1.y - p0.y);

	int y = p0.y;
	int d = -dx;
	for (int x = p0.x; x <= p1.x; x++)
	{
		if (steep)
			image.set(y, x, color);
		else
			image.set(x, y, color);

		d = d + 2 * dy;
		if (d > 0)
		{
			y += (p1.y > p0.y ? 1 : -1);
			d = d - 2 * dx;
		}
	}
}

Matrix projection(Vec3f eye, Vec3f center)
{
	Matrix m = Matrix::identity(4);
	m[3][2] = -1.f / (eye - center).norm();
	return m;
}

Matrix viewport(int x, int y, int w, int h, int depth) {
	Matrix m = Matrix::identity(4);
	m[0][3] = x + w / 2.f;
	m[1][3] = y + h / 2.f;
	m[2][3] = depth / 2.f;

	m[0][0] = w / 2.f;
	m[1][1] = h / 2.f;
	m[2][2] = depth / 2.f;
	return m;
}

Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) {
	Vec3f z = (eye - center).normalize();
	Vec3f x = (up^z).normalize();
	Vec3f y = (z^x).normalize();
	Matrix res = Matrix::identity(4);
	for (int i = 0; i < 3; i++) {
		res[0][i] = x[i];
		res[1][i] = y[i];
		res[2][i] = z[i];
		res[i][3] = -center[i];
	}
	return res;
}

Matrix translation(Vec3f v) {
	Matrix Tr = Matrix::identity(4);
	Tr[0][3] = v.x;
	Tr[1][3] = v.y;
	Tr[2][3] = v.z;
	return Tr;
}

Matrix scale(float factorX, float factorY, float factorZ)
{
	Matrix Z = Matrix::identity(4);
	Z[0][0] = factorX;
	Z[1][1] = factorY;
	Z[2][2] = factorZ;
	return Z;
}

Matrix rotation_x(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[1][1] = R[2][2] = cosangle;
	R[1][2] = -sinangle;
	R[2][1] = sinangle;
	return R;
}

Matrix rotation_y(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[2][2] = cosangle;
	R[0][2] = sinangle;
	R[2][0] = -sinangle;
	return R;
}

Matrix rotation_z(float angle) {
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[1][1] = cosangle;
	R[0][1] = -sinangle;
	R[1][0] = sinangle;
	return R;
}

int main(int argc, char** argv)
{
	const PNGColor white = PNGColor(255, 255, 255, 255);
	const PNGColor black = PNGColor(0, 0, 0, 255);
	const PNGColor red = PNGColor(255, 0, 0, 255);
	const PNGColor green = PNGColor(0, 255, 0, 255);
	const PNGColor blue = PNGColor(0, 0, 255, 255);
	const PNGColor yellow = PNGColor(255, 255, 0, 255);

	Model *model = NULL;
	const int width = 800;
	const int height = 800;
	const int depth = 255;


	//generate some image
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(black);
	model = new Model("cube.obj");
	Matrix ViewPort = viewport(width / 4, width / 4, width / 2, height / 2, depth);

	for (int i = 0; i < model->nfaces(); i++)
	{
		std::vector<int> face = model->face(i);
		for (int j = 0; j < (int)face.size(); j++)
		{
			Vec3f wp0 = model->vert(face[j]);
			Vec3f wp1 = model->vert(face[(j + 1) % face.size()]);

			Matrix S0 = scale(0.5, 0.4, 0.3);
			Vec3f swp0 = S0 * wp0;
			Vec3f swp1 = S0 * wp1;
  /********** Begin ********/
            Matrix ProjectionX = Matrix::identity(4);
            ProjectionX[0][0] = 0.0f;
            Matrix ProjectionY = Matrix::identity(4);
            ProjectionY[1][1] = 0.0f;
            Matrix ProjectionZ = Matrix::identity(4);
            ProjectionZ[2][2] = 0.0f;
            //沿Z轴向XOY平面投影 
            Vec3f zp0 = ViewPort * ProjectionZ * swp0;
            Vec3f zp1 = ViewPort * ProjectionZ * swp1;
            line(zp0, zp1, image, white);
            //沿Y轴向XOZ平面投影,再旋转与平移
            Matrix rx = rotation_x(90);
            Matrix ty = translation(Vec3f(0, -1.2f, 0));
            Vec3f yp0 = ViewPort * ty * rx * ProjectionY * swp0;
            Vec3f yp1 = ViewPort * ty * rx * ProjectionY * swp1;
            line(yp0, yp1, image, red);
            //沿X轴向YOZ平面投影,再旋转与平移
            Matrix ry = rotation_y(-90);
            Matrix tx = translation(Vec3f(-1.2f, 0, 0));
            Vec3f xp0 = ViewPort * tx * ry * ProjectionX * swp0;
            Vec3f xp1 = ViewPort * tx * ry * ProjectionX * swp1;
            line(xp0, xp1, image, green);
            //正等测投影图
            Matrix rz = rotation_z(45);
            Matrix rx1 = rotation_x(35.25);
            Matrix ty1 = translation(Vec3f(0, 1.2f, 0));
            Vec3f rp0 = ViewPort * ty1 * ProjectionZ * rx1 * rz *swp0;
            Vec3f rp1 = ViewPort * ty1 * ProjectionZ * rx1 * rz *swp1;
            line(rp0, rp1, image, yellow);
            /********** end ********/
		}
	}

	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step3/test.png");
	delete model;
	return 0;
}

?第4关:视口变换与三视图

一. 任务描述

1. 本关任务

(1) 理解投影变换的方法; (2) 将main函数中的空白部分补充完整。

2. 输入

(1) 代码将自动输入一个边长为1的obj正方体模型,具体模型如下图:

test

(2) 代码自动将模型投影到二维平面,经过模型变换,生成一个长宽高不等的立方体,并将显示窗口一分为四,分为四个视口,每个视口大小均为原窗口大小的一半。红绿两线为四个视口的分隔线; (3) 在第一视口ViewPort中,首先将立方体沿Z轴向XOY平面投影。然后进行视口变换ViewPort,并绘制出一个白色矩形; (4) 在第二视口ViewPort1中,首先将立方体沿X轴向YOZ平面投影。然后沿Y轴顺时针旋转90度,最后进行视口变换ViewPort1,绘制一个绿色矩形; (5) 在第三视口ViewPort2中,首先将立方体沿Y轴向XOZ平面投影。然后沿X轴逆时针旋转90度,最后进行视口变换ViewPort2,绘制一个红矩形; (6) 在第四视口ViewPort3中,首先将立方体沿Y轴顺时针旋转45度,然后进行投影变换,投影变换参数eye和center已给出。最后进行视口变换ViewPort3,绘制一个黄色立方体。

3. 输出

具体结果如下图所示:

test

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"
using namespace std;
const double PI = acos(-1.0);
void line(Vec3i p0, Vec3i p1, PNGImage  &image, PNGColor color)
{
    bool steep = false;
    if (std::abs(p0.x - p1.x) < std::abs(p0.y - p1.y))
    {
        std::swap(p0.x, p0.y);
        std::swap(p1.x, p1.y);
        steep = true;
    }
    if (p0.x > p1.x)
    {
        std::swap(p0.x, p1.x);
        std::swap(p0.y, p1.y);
    }
    int dx = p1.x - p0.x;
    int dy = std::abs(p1.y - p0.y);
    int y = p0.y;
    int d = -dx;
    for (int x = p0.x; x <= p1.x; x++)
    {
        if (steep)
            image.set(y, x, color);
        else
            image.set(x, y, color);
        d = d + 2 * dy;
        if (d > 0)
        {
            y += (p1.y > p0.y ? 1 : -1);
            d = d - 2 * dx;
        }
    }
}
Matrix projection(Vec3f eye, Vec3f center)
{
    Matrix m = Matrix::identity(4);
    m[3][2] = -1.f / (eye - center).norm();
    return m;
}
Matrix viewport(int x, int y, int w, int h, int depth) {
    Matrix m = Matrix::identity(4);
    m[0][3] = x + w / 2.f;
    m[1][3] = y + h / 2.f;
    m[2][3] = depth / 2.f;
    m[0][0] = w / 2.f;
    m[1][1] = h / 2.f;
    m[2][2] = depth / 2.f;
    return m;
}
Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) {
    Vec3f z = (eye - center).normalize();
    Vec3f x = (up^z).normalize();
    Vec3f y = (z^x).normalize();
    Matrix res = Matrix::identity(4);
    for (int i = 0; i < 3; i++) {
        res[0][i] = x[i];
        res[1][i] = y[i];
        res[2][i] = z[i];
        res[i][3] = -center[i];
    }
    return res;
}
Matrix translation(Vec3f v) {
    Matrix Tr = Matrix::identity(4);
    Tr[0][3] = v.x;
    Tr[1][3] = v.y;
    Tr[2][3] = v.z;
    return Tr;
}
Matrix scale(float factorX, float factorY, float factorZ)
{
    Matrix Z = Matrix::identity(4);
    Z[0][0] = factorX;
    Z[1][1] = factorY;
    Z[2][2] = factorZ;
    return Z;
}
Matrix rotation_x(float angle)
{
    angle = angle * PI / 180;
    float sinangle = sin(angle);
    float cosangle = cos(angle);
    Matrix R = Matrix::identity(4);
    R[1][1] = R[2][2] = cosangle;
    R[1][2] = -sinangle;
    R[2][1] = sinangle;
    return R;
}
Matrix rotation_y(float angle)
{
    angle = angle * PI / 180;
    float sinangle = sin(angle);
    float cosangle = cos(angle);
    Matrix R = Matrix::identity(4);
    R[0][0] = R[2][2] = cosangle;
    R[0][2] = sinangle;
    R[2][0] = -sinangle;
    return R;
}
Matrix rotation_z(float angle) {
    angle = angle * PI / 180;
    float sinangle = sin(angle);
    float cosangle = cos(angle);
    Matrix R = Matrix::identity(4);
    R[0][0] = R[1][1] = cosangle;
    R[0][1] = -sinangle;
    R[1][0] = sinangle;
    return R;
}
int main(int argc, char** argv)
{
    const PNGColor white = PNGColor(255, 255, 255, 255);
    const PNGColor black = PNGColor(0, 0, 0, 255);
    const PNGColor red = PNGColor(255, 0, 0, 255);
    const PNGColor green = PNGColor(0, 255, 0, 255);
    const PNGColor blue = PNGColor(0, 0, 255, 255);
    const PNGColor yellow = PNGColor(255, 255, 0, 255);
    Model *model = NULL;
    const int width = 800;
    const int height = 800;
    const int depth = 255;
    //generate some image
    PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
    image.init(black);
    model = new Model("cube.obj");
    Vec3f eye(0, 0, 4);
    Vec3f center(0, 0, 0);
    Matrix ProjectionX = Matrix::identity(4);
    ProjectionX[0][0] = 0.0f;
    Matrix ProjectionY = Matrix::identity(4);
    ProjectionY[1][1] = 0.0f;
    Matrix ProjectionZ = Matrix::identity(4);
    ProjectionZ[2][2] = 0.0f;
    Matrix ViewPort = viewport(0, height / 2, width / 2, height / 2, depth);
    Matrix ViewPort1 = viewport(width / 2, height / 2, width / 2, height / 2, depth);
    Matrix ViewPort2 = viewport(0, 0, width / 2, height / 2, depth);
    Matrix ViewPort3 = viewport(width / 2, 0, width / 2, height / 2, depth);
    // 绘制视口分隔线
    Vec3f x1(0.f, height / 2, 0.f), x2(width, height / 2, 0.f);
    Vec3f y1(width / 2, 0.f, 0.f), y2(width / 2, height, 0.f);
    line(x1, x2, image, red);
    line(y1, y2, image, green);
    for (int i = 0; i < model->nfaces(); i++)
    {
        std::vector<int> face = model->face(i);
        for (int j = 0; j < (int)face.size(); j++)
        {
            Vec3f wp0 = model->vert(face[j]);
            Vec3f wp1 = model->vert(face[(j + 1) % face.size()]);
            Matrix S0 = scale(0.5, 0.4, 0.3);
            Vec3f swp0 = S0 * wp0;
            Vec3f swp1 = S0 * wp1;
            // Please add the code here
            /********** Begin ********/
            //沿Z轴向XOY平面投影 
            Vec3f zp0 = ViewPort * ProjectionZ * swp0;
            Vec3f zp1 = ViewPort * ProjectionZ * swp1;
            line(zp0, zp1, image, white);
            //沿X轴向YOZ平面投影,再旋转与平移
            Matrix ry = rotation_y(-90);
            Vec3f xp0 = ViewPort1 * ry * ProjectionX * swp0;
            Vec3f xp1 = ViewPort1 * ry * ProjectionX * swp1;
            line(xp0, xp1, image, green);
            //沿Y轴向XOZ平面投影,再旋转与平移
            Matrix rx = rotation_x(90);
            Vec3f yp0 = ViewPort2 * rx * ProjectionY * swp0;
            Vec3f yp1 = ViewPort2 * rx * ProjectionY * swp1;
            line(yp0, yp1, image, red);
            //两点透视图
            Matrix ModelView = rotation_y(-45);
            Matrix Projection = projection(eye, center);            
            Vec3f vp0 = ViewPort3 * Projection * ModelView * swp0;
            Vec3f vp1 = ViewPort3 * Projection * ModelView * swp1;
            line(vp0, vp1, image, yellow);
            /************End**********/
        }
    }
    image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
    image.write_png_file("../img_step4/test.png");
    delete model;
    return 0;
}

文章来源:https://blog.csdn.net/m0_63794226/article/details/135057080
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。