视频加载失败

课程

1152 字
约 4 分钟

6.1 立方体透视投影

计算机图形学labs/lab06-projection-transformations·更新于 2026-09-15

6.1 立方体透视投影

1. 任务描述

本关任务

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

预期输出

预期输出

具体要求

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

相关知识

  1. 实验内容
    • 阅读教材有关三维图形变换原理,运行示范实验代码,掌握 OpenGL 程序三维图形变换的方法。
    • 阅读实验原理,运行示范实验代码,理解掌握 OpenGL 程序的模型视图变换。
    • 请分别调整观察变换矩阵、模型变换矩阵和投影变换矩阵的参数,观察变换结果。
    • 掌握三维观察流程、观察坐标系的确定、世界坐标系与观察坐标系之间的转换、平行投影和透视投影的特点,观察空间与规范化观察空间的概念。理解 OpenGL 图形库下视点函数、正交投影函数、透视投影函数。理解三维图形显示与观察代码实例。
  2. 模型变换
    • 设置模型的位置和方向,通过移动、旋转或缩放变换,让模型具有合适的位置和大小。

开始你的任务吧,祝你成功!

2. 我的回答

文件 step4/test4.cpp:

// 提示:在合适的地方修改或添加代码
#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 **/

    // 1. 绘制中间红色立方体线框(一点透视)
    glPushMatrix();
    glColor3f(1.0, 0.0, 0.0);       // 设置前景色为红色
    glutWireCube(1.0);              // 绘制单位立方体线框
    glPopMatrix();

    // 2. 绘制右边绿色立方体线框并旋转(三点透视)
    glPushMatrix();
    glColor3f(0.0, 1.0, 0.0);       // 设置前景色为绿色 (题目说黑色但给了绿色的RGB值)
    glLineWidth(2.0);               // 设置线宽为2.0
    glTranslatef(2.0, 0.0, 0.0);    // 沿X轴正方向平移2.0
    glRotatef(30.0, 1.0, 0.0, 0.0); // 绕X轴旋转+30度
    glutWireCube(1.0);              // 绘制单位立方体线框
    glPopMatrix();

    // 3. 绘制左边蓝色立方体实体(两点透视)
    glPushMatrix();
    glColor3f(0.0, 0.0, 1.0);       // 设置前景色为蓝色
    glTranslatef(-2.0, 0.0, 0.0);   // 沿X轴负方向平移2.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;
}

Profile Image of the Author
Sonder
好想要技术
这是公告标题
这只是一个公告
分类
标签
站点信息
构建平台
GitHub Actions
博客版本
Firefly v6.16.7
文章许可
CC BY-NC-SA 4.0
文章目录