视频加载失败

课程

1988 字
约 6 分钟

7.2 简单机器人构建

计算机图形学labs/lab07-3d-modeling·更新于 2026-09-15

7.2 简单机器人构建

1. 任务描述

本关任务

  1. 熟悉视点观察函数的设置和使用。
  2. 熟悉 3D 图形变换的设置和使用。
  3. 进一步熟悉基本 3D 图元的绘制。

预期输出

预期输出

具体要求

  1. 背景色为黑色,用 glClearColor 来完成。
  2. glutSolidCube(GLdouble size) 绘制立方体实体模型,要求尺寸大小为 0.5。
  3. 绘制脖子,将立方实体设为白色 glColor3f(1.0, 1.0, 1.0),沿 Y 轴正方向平移 1.4f,调用 glScalef() 缩放函数参数为 glScalef(0.5, 0.7, 0.5)
  4. 绘制头部,将立方实体设为黄色 glColor3f(1.0, 0.5, 0.2),沿 Y 轴正方向平移 1.9f,调用 glScalef() 缩放函数参数为 glScalef(1.5, 1.5, 0.5)
  5. 绘制身体,将立方实体设为红色 glColor3f(1.0, 0.0, 0.0),沿 Y 轴正方向平移 0.25f,调用 glScalef() 函数将立方实体 X 轴方向变为原来的 4 倍,Y 轴方向变为原来的 4 倍,Z 轴方向变为原来的 0.5 倍。
  6. 绘制两个手臂,将立方实体设为 glColor3f(1.0, 1.0, 0.0);将左手臂移动坐标为 glTranslatef(-1.25f, 0.5f, 0.0f),右手臂移动坐标为 glTranslatef(1.25f, 0.5f, 0.0f),调用 glScalef() 函数将立方体 Y 轴方向变为原来的 3 倍,Z 轴方向变为原来的 0.5 倍。
  7. 绘制两个机器人的腿部,将立方实体设为蓝色 glColor3f(0.5, 0.5, 1.5),将左腿移动坐标为 glTranslatef(-0.5f, -1.5f, 0.0f),右腿移动坐标为 glTranslatef(0.5f, -1.5f, 0.0f),调用 glScalef() 函数将立方体 Y 轴方向变为原来的 3 倍,Z 轴方向变为原来的 0.5 倍。
  8. 绘制机器人的双手,用圆球绘制。球体的半径为 0.25,球心在原点,经线和纬线数目为 50。将球体设置为 glColor3f(1.0, 0.5, 0.2)。将小球分别移动 glTranslatef(-1.25f, -0.5f, 0.0f)glTranslatef(1.25f, -0.5f, 0.0f) 作为左手和右手。将两个小球进行放缩 glScalef(1, 1.5, 1),变为椭圆。
  9. 视点改为 (2.0, 2.0, 5.0),观察中心改为 (0.0, 0.0, 0.0),向上矢量改为 (0.0, 1.0, 0.0)

相关知识

1. 视图变换

也称观察变换,指从不同的位置去观察模型。

在载入单位矩阵之后,使用 gluLookAt 函数指定视图变换。如果程序没有调用 gluLookAt(),那么照相机会设定为一个默认的位置和方向,即照相机位于原点,指向 z 轴负方向,朝上向量为 (0, 1, 0)

gluLookAt(0, 0, 5, 0, 0, 0, 0, 1, 0) 函数指把照相机位置放在 (0, 0, 5) 处,镜头瞄准 (0, 0, 0) 点,朝上方向为 (0, 1, 0)

2. glScalef() 函数

glScalef(GLfloat x, GLfloat y, GLfloat z):参数 x, y, z 分别为模型在 x, y, z 轴方向的缩放比。

3. 小球绘制函数

小球绘制函数,其功能为绘制一个半径为 radius 的线框或实心小球,小球的中心点位于原点,slices 为小球的经线数目,stacks 为小球的纬线数目。

gluSphere(GLUquadricObj *obj, GLdouble radius, GLint slices, GLint stacks);

用法实例:

GLUquadricObj *sphere;     // 定义二次曲面对象
sphere = gluNewQuadric();  // 生成二次曲面对象
gluSphere(sphere, 8, 50, 50); // 半径为 8,球心在原点,经线和纬线数目为 50 的小球

4. glPushMatrix() 和 glPopMatrix() 函数

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


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

2. 我的回答

文件 step2/test2.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 = 500, winHeight =500 ; 	      //设置初始化窗口大小

/*观察坐标系参数设置*/
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 ********/
    // (9) 重新设置视点。因为外部已经调用过一次gluLookAt,我们需要用glLoadIdentity()覆盖它
    glLoadIdentity();
    gluLookAt(2.0, 2.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

    // (3) 绘制脖子
    glPushMatrix();
    glColor3f(1.0f, 1.0f, 1.0f);            // 白色
    glTranslatef(0.0f, 1.4f, 0.0f);         // 沿Y轴正方向平移1.4f
    glScalef(0.5f, 0.7f, 0.5f);             // 缩放
    glutSolidCube(0.5);                     // 绘制立方体,尺寸0.5
    glPopMatrix();

    // (4) 绘制头部
    glPushMatrix();
    glColor3f(1.0f, 0.5f, 0.2f);            // 黄色/橘色
    glTranslatef(0.0f, 1.9f, 0.0f);         // 沿Y轴正方向平移1.9f
    glScalef(1.5f, 1.5f, 0.5f);             // 缩放
    glutSolidCube(0.5);
    glPopMatrix();

    // (5) 绘制身体
    glPushMatrix();
    glColor3f(1.0f, 0.0f, 0.0f);            // 红色
    glTranslatef(0.0f, 0.25f, 0.0f);        // 沿Y轴正方向平移0.25f
    glScalef(4.0f, 4.0f, 0.5f);             // 缩放
    glutSolidCube(0.5);
    glPopMatrix();

    // (6) 绘制两个手臂
    // 左手臂
    glPushMatrix();
    glColor3f(1.0f, 1.0f, 0.0f);            // 黄色
    glTranslatef(-1.25f, 0.5f, 0.0f);       // 左移
    glScalef(1.0f, 3.0f, 0.5f);             // Y轴3倍,Z轴0.5倍 (X保持1倍)
    glutSolidCube(0.5);
    glPopMatrix();
    
    // 右手臂
    glPushMatrix();
    glColor3f(1.0f, 1.0f, 0.0f);            // 黄色
    glTranslatef(1.25f, 0.5f, 0.0f);        // 右移
    glScalef(1.0f, 3.0f, 0.5f);             // Y轴3倍,Z轴0.5倍
    glutSolidCube(0.5);
    glPopMatrix();

    // (7) 绘制机器人的腿部
    // 左腿
    glPushMatrix();
    glColor3f(0.5f, 0.5f, 1.5f);            // 蓝色 (按照要求填入参数)
    glTranslatef(-0.5f, -1.5f, 0.0f);       // 左下平移
    glScalef(1.0f, 3.0f, 0.5f);             // Y轴3倍,Z轴0.5倍
    glutSolidCube(0.5);
    glPopMatrix();

    // 右腿
    glPushMatrix();
    glColor3f(0.5f, 0.5f, 1.5f);            // 蓝色
    glTranslatef(0.5f, -1.5f, 0.0f);        // 右下平移
    glScalef(1.0f, 3.0f, 0.5f);             // Y轴3倍,Z轴0.5倍
    glutSolidCube(0.5);
    glPopMatrix();

    // (8) 绘制机器人的双手 (用圆球绘制)
    GLUquadricObj *sphere = gluNewQuadric(); // 生成二次曲面对象用于画球
    
    // 左手
    glPushMatrix();
    glColor3f(1.0f, 0.5f, 0.2f);
    glTranslatef(-1.25f, -0.5f, 0.0f);      // 平移到左手臂下方
    glScalef(1.0f, 1.5f, 1.0f);             // 缩放变为椭圆
    gluSphere(sphere, 0.25, 50, 50);        // 半径0.25,经纬线50
    glPopMatrix();

    // 右手
    glPushMatrix();
    glColor3f(1.0f, 0.5f, 0.2f);
    glTranslatef(1.25f, -0.5f, 0.0f);       // 平移到右手臂下方
    glScalef(1.0f, 1.5f, 1.0f);             // 缩放变为椭圆
    gluSphere(sphere, 0.25, 50, 50);
    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( 500 , 500 );        //设置初始化窗口大小
    glutCreateWindow("三维观察");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoopEvent();





    /*************以下为评测代码,与本次实验内容无关,请勿修改**************/
    GLubyte* pPixelData = (GLubyte*)malloc(500 * 500 * 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(500, 500, CV_8UC3);
    cv::split(img, imgPlanes);

    for (int i = 0; i < 500; 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 < 500; j++) {
            int k = 3 * (i * 500 + 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;
}

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