目录
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.输出
程序运行结果为一条直线,具体结果如下图所示:
二.相关知识
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.输出
程序运行结果为一条直线,具体结果如下图所示:
二.相关知识
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.输出
程序运行结果为一条直线,具体结果如下图所示:
二.相关知识
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三维人头模型,具体模型如下图:
3.输出
若编写的任意斜率的Bresenham画线算法代码正确,则程序会将模型转换为线条图片,具体结果如下图所示:
二.相关知识
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. 输出
程序运行结果为一个绿色三角形区域,如下图所示:
#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. 输出
程序运行结果为一个红色三角形区域,如下图所示:
#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.运行前
3.输出
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.运行前
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.运行前
3.输出
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.预期输出
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.预期输出
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.预期输出
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.预期输出
设计如图所示二维图形
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正方体模型,具体模型如下图:
(2) 代码自动将模型投影到二维平面上生成一个边长为1的白色正方形,并且代码会生成红色x轴,绿色y轴,具体图片如下所示:
(3) 将立方体的顶点坐标分别向x,y,z轴正方向平移0.5个单位距离,然后绘制一个红色正方形; (4) 将立方体的顶点坐标分别沿x,y,z轴方向缩放0.5倍,然后绘制一个绿色正方形; (5) 将立方体的顶点坐标沿z轴逆时针方向旋转45度,然后绘制一个黄色正方形。
3. 输出
具体结果如下图所示:
#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正方体模型,具体模型如下图:
(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. 输出
具体结果如下图所示:
#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正方体模型,具体模型如下图:
(2) 将立方体的顶点坐标分别沿x,y,z轴方向缩放0.5倍,然后绘制一个白色正方形; (3) 将立方体的顶点坐标分别向x,y,z轴正方向平移0.5个单位距离,再沿z轴逆时针方向旋转45度,然后绘制一个绿色正方形 (4) 将立方体的顶点坐标分别沿z轴逆时针方向旋转45度,再分别向x,y,z轴正方向平移0.5个单位距离,然后绘制一个红色正方形;
3. 输出
具体结果如下图所示:
#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正方体模型,具体模型如下图:
(2) 将立方体的顶点坐标分别沿x,y,z轴方向缩放0.5倍,然后绘制一个白色正方形; (3) 将立方体的顶点坐标分别向y,z轴缩放0.5倍,x轴保持不变,再沿z轴逆时针方向旋转45度,然后绘制一个绿色矩形; (4) 将立方体的顶点坐标分别沿z轴逆时针方向旋转45度,再分别向y,z轴缩放0.5倍,x轴保持不变,然后绘制一个红菱形。
3. 输出
具体结果如下图所示:
#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正方体模型,具体模型如下图:
(2) 将立方体的顶点坐标分别沿x,y,z轴方向缩放0.5倍; (3) 将立方体的顶点坐标分别沿z轴逆时针方向旋转45度,再分别向y,z轴缩放0.5倍,x轴保持不变,然后绘制一个红菱形; (4) 将红色菱形沿着x轴正方向平移
22
个单位距离,然后将红菱形沿Z轴逆时针旋转90度; (5)绿色和黄色菱形与红色菱形的夹角均为120度。3. 输出
具体结果如下图所示:
#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正方体模型,具体模型如下图:
(2) 代码自动将模型投影到二维平面上生成一个边长为1的白色立方体,具体图片如下所示:
(3) 将白色立方体的顶点坐标向x轴正方向平移1.2个单位距离,然后绘制一个红色立方形; (4) 将白色立方体的顶点坐标沿y轴逆时针方向旋转30度,再向x轴负方向平移1.3个单位距离,然后绘制一个绿色正方形。
3. 输出
具体结果如下图所示:
#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正方体模型,具体模型如下图:
(2) 相机坐标为(0, 1.5, 4),中心点坐标为(0,0,0),向上的矢量为Vec3f(0, 1, 0)
3. 输出
具体结果如下图所示:
#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正方体模型,具体模型如下图:
(2) 视口矩阵中参数x、y的大小为宽度(width)的四分之一,参数w的大小为宽度的一半(width),参数h的大小为高度的一半(height),参数d=255。
3. 输出
具体结果如下图所示:
#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正方体模型,具体模型如下图:
(2) 代码自动将模型投影到二维平面中心生成一个边长为1的立方体,经过模型变换和投影变换后生成三个绿色的方体,三个立方体的投影变换eye的坐标均为(0,0,5),具体图片如下所示:
(3) 参考已有代码,将中心立绿色方体的顶点分别向y轴负方向平移1.2个单位,绘制一个红色立方体。再将红色立方体顶点分别向x轴正,负两个方向平移1.2个单位,绘制两个红色立方体。三个立方体的投影变换eye的坐标均为(0,0,4); (4) 将中心绿色立方体的顶点分别向y轴正方向平移1.2个单位,绘制一个黄色立方体。再将黄色立方体顶点分别向x轴正,负两个方向平移1.2个单位,绘制两个黄色立方体。三个立方体的投影变换eye的坐标均为(0,0,8);
3. 输出
具体结果如下图所示:
#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正方体模型,具体模型如下图:
(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. 输出
具体结果如下图所示:
#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正方体模型,具体模型如下图:
(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. 输出
具体结果如下图所示:
#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正方体模型,具体模型如下图:
(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. 输出
具体结果如下图所示:
#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;
}