目标:OpenGL 中的坐标变换和颜色的使用。
具体任务:利用矩阵操作实现视图变换、模型变换和投影变换;利用函数指定颜色模式。

三种变换

  • 模型变换:改变物体自身的位置、旋转、缩放(比如让立方体向左移动、旋转)。
  • 视图变换:改变观察角度(相机位置和朝向),不改变物体本身,只改变 “从哪里看”。
  • 投影变换:定义画面的透视效果(比如近大远小),而视图变换只决定观察方向。

代码解释

一、主函数

// 主函数
int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("OpenGL 矩阵变换示例");

    init();

    // 注册回调函数
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutTimerFunc(0, timer, 0);
    glutKeyboardFunc(keyboard);

    glutMainLoop();
    return 0;
}

对比上节代码,区别在于

1、glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

开启深度缓存的作用在于:每当绘制新像素时,OpenGL 会自动比较新像素与已有像素的深度值,如果新像素更近(深度值更小),则更新颜色缓冲区和深度缓冲区(显示新像素);如果新像素更远,则忽略该像素(不覆盖已有像素)。

2、glutReshapeFunc(reshape);

当窗口被拉伸、缩放或首次创建时,FreeGLUT 会自动调用这个函数。

由于我们将在该节中使用透视投影,代码如下,透视投影与窗口的宽高比密切相关,若窗口大小改变而不及时去更改width和height的值,可能导致图像投影后失真。

gluPerspective(45.0f, (float)width / (float)height, 0.1f, 100.0f);

可是,问题是,为什么窗口会改变呢?我们并不会在代码中去更改窗口大小,但是用户可以通过拉伸窗口更改其宽高。为了防止图像失真,需要主动调用。

3、glutTimerFunc(0, timer, 0);

如果不注册 glutTimerFunc(0, timer, 0);,就无法自动更新场景状态和触发重绘,动画会静止不动(除非通过用户交互手动触发)。

二、display函数

// 显示回调函数
void display() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // 清除颜色和深度缓冲区

    // 重置模型视图矩阵
    glLoadIdentity();

    // -------------------------- 视图变换 --------------------------
    // 参数:相机位置(x,y,z)、目标点(x,y,z)、上方向向量(x,y,z)
    gluLookAt(0.0f, 1.0f, cameraZ,  // 相机位置(可以通过按键调整z值)
        0.0f, 0.0f, 0.0f,     // 目标点(看向原点)
        0.0f, 1.0f, 0.0f);    // 上方向(Y轴为上)

    // -------------------------- 模型变换 --------------------------
    glRotatef(rotationAngle, 1.0f, 1.0f, 0.0f);  // 绕(1,1,0)轴旋转
    glTranslatef(1.0f, 0.0f, 0.0f);             // 沿X轴平移

    // 绘制第一个立方体
    drawCube();

    // 对第二个立方体应用不同的模型变换
    glPushMatrix();  // 保存当前矩阵状态
    glRotatef(rotationAngle, 0.0f, 1.0f, 0.0f);  // 绕Y轴旋转
    glTranslatef(-2.0f, 0.0f, 0.0f);             // 沿X轴负方向平移
    glScalef(0.5f, 0.5f, 0.5f);                  // 缩小一半
    drawCube();                                   // 绘制第二个立方体
    glPopMatrix();   // 恢复矩阵状态

    glutSwapBuffers();  // 交换缓冲区
}

这里主要介绍三点:

1、glLoadIdentity()

用于矩阵初始化的核心函数,作用是将「当前活跃的矩阵」重置为单位矩阵。

为什么需要重置为单位矩阵:

OpenGL 是一个 “状态机”,矩阵运算具有累积性—— 每次调用变换函数(如 glRotateglTranslateglScale),都是将当前矩阵与新的变换矩阵相乘,并将结果作为新的当前矩阵。如果不重置矩阵,新的变换会叠加在之前的变换上,导致结果不可控。

2、 gluLookAt(0.0f, 1.0f, cameraZ,  // 相机位置(可以通过按键调整z值)
        0.0f, 0.0f, 0.0f,     // 目标点(看向原点)
        0.0f, 1.0f, 0.0f);    // 上方向(Y轴为上)

为什么需要定义上方向:

想象你手里拿着一个相机,镜头对准前方的一棵树(目标点):

  • 当你水平握持相机时(镜头朝前,相机顶部朝上),拍出来的照片是正的(地平线水平,树干垂直);
  • 当你倾斜握持相机时(镜头仍对准树,但相机顶部朝左或朝右),拍出来的照片会是歪的(地平线倾斜,树干歪斜)。

这里的 “相机顶部朝向” 就是现实中的 “上方向”—— 即使镜头对准同一个目标,上方向不同,最终画面的 “正立状态” 也会不同。

3、glutSwapBuffers()

核心作用是交换双缓冲模式下的前后缓冲区,让后台缓冲区中绘制完成的完整画面显示到屏幕上,从而避免绘制过程中的闪烁。当 display 函数中的所有绘制操作(画点、线、立方体等)完成后,glutSwapBuffers() 会执行一次 “缓冲区交换”:

  • 原本的后台缓冲区(已完成当前帧绘制)变成前台缓冲区,直接显示到屏幕上;
  • 原本的前台缓冲区变成新的后台缓冲区,为下一帧绘制做准备。

这个过程瞬间完成,用户看不到中间绘制步骤,只会看到完整的画面,从而消除闪烁。

三、reshape函数

// 窗口大小变化回调函数
void reshape(int width, int height) {
    glViewport(0, 0, width, height);  // 设置视口,占满整个窗口

    // 切换到投影矩阵模式
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();  // 重置投影矩阵

    // -------------------------- 投影变换 --------------------------
    // 使用透视投影
    // 参数:视野角度、宽高比、近平面距离、远平面距离
    float aspectRatio = (float)width / (float)height;
    gluPerspective(45.0f, aspectRatio, 0.1f, 100.0f);

    // 切换回模型视图矩阵模式
    glMatrixMode(GL_MODELVIEW);
}

矩阵模式切换:

  • 投影矩阵(GL_PROJECTION:专门负责 “投影变换”—— 决定 3D 场景如何被 “投影” 到 2D 屏幕上(如透视投影的 “近大远小” 效果)。在 reshape 函数中,我们需要设置透视投影参数(gluPerspective),因此必须先切换到 GL_PROJECTION 模式,否则这些参数会错误地应用到其他矩阵上。

  • 模型视图矩阵(GL_MODELVIEW:专门负责 “模型变换”(物体的旋转、平移、缩放)和 “视图变换”(相机的位置和朝向)。绝大多数绘制逻辑(如 display 函数中的旋转、gluLookAt 视图变换)都需要在这个模式下进行,因此设置完投影矩阵后,必须切换回 GL_MODELVIEW 模式,确保后续的模型 / 视图变换正确生效。

透视投影:

        核心作用是让 3D 场景在 2D 屏幕上呈现出符合人类视觉习惯的真实效果,通过近大远小的规律模拟深度感,完成 3D 到 2D 的坐标转换,限定可见区域优化效率,同时保证画面比例正确。

三、timer函数

// 定时器回调函数,用于动画效果
void timer(int value) {
    rotationAngle += 1.0f;  // 增加旋转角度
    if (rotationAngle >= 360.0f) {
        rotationAngle = 0.0f;
    }

    glutPostRedisplay();  // 标记窗口需要重绘
    glutTimerFunc(16, timer, 0);  // 约60fps
}

四、键盘回调函数

// 键盘回调函数
void keyboard(unsigned char key, int x, int y) {
    switch (key) {
    case 27:  // ESC键退出
        exit(0);
        break;
    case '+':  // 相机靠近
        cameraZ -= 0.5f;
        if (cameraZ < 1.0f) cameraZ = 1.0f;
        break;
    case '-':  // 相机远离
        cameraZ += 0.5f;
        break;
    }
    glutPostRedisplay();  // 重绘
}

代码汇总

#include <GL/glut.h>
#include <GL/glu.h>
#include <math.h>

// 全局变量
float rotationAngle = 0.0f;  // 旋转角度
float cameraZ = 5.0f;        // 相机Z轴位置

// 初始化函数
void init() {
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);  // 背景色:深灰色
    glEnable(GL_DEPTH_TEST);               // 启用深度测试,处理遮挡关系
    glEnable(GL_COLOR_MATERIAL);           // 启用颜色材质,使颜色生效
}

// 绘制彩色立方体
void drawCube() {
    glBegin(GL_QUADS);  // 使用四边形绘制立方体的6个面

    // 前面(红色)
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f(-0.5f, -0.5f, 0.5f);
    glVertex3f(0.5f, -0.5f, 0.5f);
    glVertex3f(0.5f, 0.5f, 0.5f);
    glVertex3f(-0.5f, 0.5f, 0.5f);

    // 后面(绿色)
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(-0.5f, -0.5f, -0.5f);
    glVertex3f(-0.5f, 0.5f, -0.5f);
    glVertex3f(0.5f, 0.5f, -0.5f);
    glVertex3f(0.5f, -0.5f, -0.5f);

    // 右面(蓝色)
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(0.5f, -0.5f, -0.5f);
    glVertex3f(0.5f, 0.5f, -0.5f);
    glVertex3f(0.5f, 0.5f, 0.5f);
    glVertex3f(0.5f, -0.5f, 0.5f);

    // 左面(黄色)
    glColor3f(1.0f, 1.0f, 0.0f);
    glVertex3f(-0.5f, -0.5f, -0.5f);
    glVertex3f(-0.5f, -0.5f, 0.5f);
    glVertex3f(-0.5f, 0.5f, 0.5f);
    glVertex3f(-0.5f, 0.5f, -0.5f);

    // 上面(青色)
    glColor3f(0.0f, 1.0f, 1.0f);
    glVertex3f(-0.5f, 0.5f, -0.5f);
    glVertex3f(-0.5f, 0.5f, 0.5f);
    glVertex3f(0.5f, 0.5f, 0.5f);
    glVertex3f(0.5f, 0.5f, -0.5f);

    // 下面(紫色)
    glColor3f(1.0f, 0.0f, 1.0f);
    glVertex3f(-0.5f, -0.5f, -0.5f);
    glVertex3f(0.5f, -0.5f, -0.5f);
    glVertex3f(0.5f, -0.5f, 0.5f);
    glVertex3f(-0.5f, -0.5f, 0.5f);

    glEnd();
}

// 显示回调函数
void display() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // 清除颜色和深度缓冲区

    // 重置模型视图矩阵
    glLoadIdentity();

    // -------------------------- 视图变换 --------------------------
    // 参数:相机位置(x,y,z)、目标点(x,y,z)、上方向向量(x,y,z)
    gluLookAt(0.0f, 1.0f, cameraZ,  // 相机位置(可以通过按键调整z值)
        0.0f, 0.0f, 0.0f,     // 目标点(看向原点)
        0.0f, 1.0f, 0.0f);    // 上方向(Y轴为上)

    // -------------------------- 模型变换 --------------------------
    glRotatef(rotationAngle, 1.0f, 1.0f, 0.0f);  // 绕(1,1,0)轴旋转
    glTranslatef(1.0f, 0.0f, 0.0f);             // 沿X轴平移

    // 绘制第一个立方体
    drawCube();

    // 对第二个立方体应用不同的模型变换
    glPushMatrix();  // 保存当前矩阵状态
    glRotatef(rotationAngle, 0.0f, 1.0f, 0.0f);  // 绕Y轴旋转
    glTranslatef(-2.0f, 0.0f, 0.0f);             // 沿X轴负方向平移
    glScalef(0.5f, 0.5f, 0.5f);                  // 缩小一半
    drawCube();                                   // 绘制第二个立方体
    glPopMatrix();   // 恢复矩阵状态

    glutSwapBuffers();  // 交换缓冲区
}

// 窗口大小变化回调函数
void reshape(int width, int height) {
    glViewport(0, 0, width, height);  // 设置视口,占满整个窗口

    // 切换到投影矩阵模式
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();  // 重置投影矩阵

    // -------------------------- 投影变换 --------------------------
    // 使用透视投影
    // 参数:视野角度、宽高比、近平面距离、远平面距离
    float aspectRatio = (float)width / (float)height;
    gluPerspective(45.0f, aspectRatio, 0.1f, 100.0f);

    // 切换回模型视图矩阵模式
    glMatrixMode(GL_MODELVIEW);
}

// 定时器回调函数,用于动画效果
void timer(int value) {
    rotationAngle += 1.0f;  // 增加旋转角度
    if (rotationAngle >= 360.0f) {
        rotationAngle = 0.0f;
    }

    glutPostRedisplay();  // 标记窗口需要重绘
    glutTimerFunc(16, timer, 0);  // 约60fps
}

// 键盘回调函数
void keyboard(unsigned char key, int x, int y) {
    switch (key) {
    case 27:  // ESC键退出
        exit(0);
        break;
    case '+':  // 相机靠近
        cameraZ -= 0.5f;
        if (cameraZ < 1.0f) cameraZ = 1.0f;
        break;
    case '-':  // 相机远离
        cameraZ += 0.5f;
        break;
    }
    glutPostRedisplay();  // 重绘
}

// 主函数
int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("OpenGL 矩阵变换示例");

    init();

    // 注册回调函数
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutTimerFunc(0, timer, 0);
    glutKeyboardFunc(keyboard);

    glutMainLoop();
    return 0;
}

第一个任务完成,我们接下来看看第二个任务:利用函数指定颜色模式。

首先我们先定义三种颜色模式。

typedef enum {
    COLOR_MODE_COLORFUL,   // 彩色模式(默认)
    COLOR_MODE_GRAYSCALE,  // 灰度模式(无彩色,仅黑白灰)
    COLOR_MODE_MONO        // 单色模式(所有面用同一种颜色)
} ColorMode;

对具体颜色模式进行处理。

ColorMode currentColorMode = COLOR_MODE_COLORFUL;  // 当前激活的颜色模式
float monoColor[3] = { 1.0f, 0.5f, 0.0f };          // 单色模式的预设颜色(初始为橙色)
void setCurrentColor(float r, float g, float b) {
    float gray = 0.0f;  // 提前初始化,避免case跳过问题
    switch (currentColorMode) {
    case COLOR_MODE_COLORFUL:
        // 彩色模式:直接使用原始颜色
        glColor3f(r, g, b);
        break;

    case COLOR_MODE_GRAYSCALE:
        // 灰度模式:计算并使用灰度值
        gray = 0.299f * r + 0.587f * g + 0.114f * b;
        glColor3f(gray, gray, gray);
        break;

    case COLOR_MODE_MONO:
        // 单色模式:使用统一预设颜色
        glColor3f(monoColor[0], monoColor[1], monoColor[2]);
        break;
    }
}

对键盘函数进行改进,加入颜色按键选择。

    // -------------------------- 新增:颜色模式切换 --------------------------
case '1':  // 1键:切换到彩色模式
    currentColorMode = COLOR_MODE_COLORFUL;
    glutSetWindowTitle("OpenGL 矩阵变换示例 - 彩色模式");
    printf("当前颜色模式:彩色模式\n");
    break;

case '2':  // 2键:切换到灰度模式
    currentColorMode = COLOR_MODE_GRAYSCALE;
    glutSetWindowTitle("OpenGL 矩阵变换示例 - 灰度模式");
    printf("当前颜色模式:灰度模式\n");
    break;

case '3':  // 3键:切换到单色模式
    currentColorMode = COLOR_MODE_MONO;
    glutSetWindowTitle("OpenGL 矩阵变换示例 - 单色模式(橙色)");
    printf("当前颜色模式:单色模式(可按4/5/6调整颜色)\n");
    break;

    // 单色模式下调整颜色(4=加红,5=加绿,6=加蓝)
case '4':
    if (currentColorMode == COLOR_MODE_MONO) {
        monoColor[0] = (monoColor[0] + 0.1f) > 1.0f ? 1.0f : monoColor[0] + 0.1f;
        glutSetWindowTitle("OpenGL 矩阵变换示例 - 单色模式(红+)");
        printf("单色模式:红色分量=%.1f\n", monoColor[0]);
    }
    break;

case '5':
    if (currentColorMode == COLOR_MODE_MONO) {
        monoColor[1] = (monoColor[1] + 0.1f) > 1.0f ? 1.0f : monoColor[1] + 0.1f;
        glutSetWindowTitle("OpenGL 矩阵变换示例 - 单色模式(绿+)");
        printf("单色模式:绿色分量=%.1f\n", monoColor[1]);
    }
    break;

case '6':
    if (currentColorMode == COLOR_MODE_MONO) {
        monoColor[2] = (monoColor[2] + 0.1f) > 1.0f ? 1.0f : monoColor[2] + 0.1f;
        glutSetWindowTitle("OpenGL 矩阵变换示例 - 单色模式(蓝+)");
        printf("单色模式:蓝色分量=%.1f\n", monoColor[2]);
    }
    break;
}

glutMainLoop()调用后, 启动了一个 “无限事件循环”,不断触发回调函数(如 displaytimer、keyboard)重复执行。

代码汇总为

#include <GL/glut.h>
#include <GL/glu.h>
#include <math.h>
#include <stdio.h>
// 全局变量
float rotationAngle = 0.0f;  // 旋转角度
float cameraZ = 5.0f;        // 相机Z轴位置

// -------------------------- 新增:颜色模式相关定义 --------------------------
// 1. 颜色模式枚举(定义可支持的颜色模式)
typedef enum {
    COLOR_MODE_COLORFUL,   // 彩色模式(默认)
    COLOR_MODE_GRAYSCALE,  // 灰度模式(无彩色,仅黑白灰)
    COLOR_MODE_MONO        // 单色模式(所有面用同一种颜色)
} ColorMode;

ColorMode currentColorMode = COLOR_MODE_COLORFUL;  // 当前激活的颜色模式
float monoColor[3] = { 1.0f, 0.5f, 0.0f };          // 单色模式的预设颜色(初始为橙色)

// 2. 统一颜色处理函数(根据当前颜色模式,处理原始颜色并设置)
// 参数:r/g/b - 物体面的原始颜色;返回:根据模式处理后的颜色
void setCurrentColor(float r, float g, float b) {
    float gray = 0.0f;  // 提前初始化,避免case跳过问题
    switch (currentColorMode) {
    case COLOR_MODE_COLORFUL:
        // 彩色模式:直接使用原始颜色
        glColor3f(r, g, b);
        break;

    case COLOR_MODE_GRAYSCALE:
        // 灰度模式:计算并使用灰度值
        gray = 0.299f * r + 0.587f * g + 0.114f * b;
        glColor3f(gray, gray, gray);
        break;

    case COLOR_MODE_MONO:
        // 单色模式:使用统一预设颜色
        glColor3f(monoColor[0], monoColor[1], monoColor[2]);
        break;
    }
}

// 初始化函数(原有逻辑不变,新增颜色模式默认提示)
void init() {
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);  // 背景色:深灰色
    glEnable(GL_DEPTH_TEST);               // 启用深度测试,处理遮挡关系
    glEnable(GL_COLOR_MATERIAL);           // 启用颜色材质,使颜色生效
    printf("初始化完成!当前颜色模式:彩色模式\n");
    printf("操作提示:1=彩色 2=灰度 3=单色 4=单色+红 5=单色+绿 6=单色+蓝 ESC=退出\n");
}

// 绘制立方体(修改:用setCurrentColor替代直接glColor3f)
void drawCube() {
    glBegin(GL_QUADS);  // 使用四边形绘制立方体的6个面

    // 前面(原始红色)
    setCurrentColor(1.0f, 0.0f, 0.0f);
    glVertex3f(-0.5f, -0.5f, 0.5f);
    glVertex3f(0.5f, -0.5f, 0.5f);
    glVertex3f(0.5f, 0.5f, 0.5f);
    glVertex3f(-0.5f, 0.5f, 0.5f);

    // 后面(原始绿色)
    setCurrentColor(0.0f, 1.0f, 0.0f);
    glVertex3f(-0.5f, -0.5f, -0.5f);
    glVertex3f(-0.5f, 0.5f, -0.5f);
    glVertex3f(0.5f, 0.5f, -0.5f);
    glVertex3f(0.5f, -0.5f, -0.5f);

    // 右面(原始蓝色)
    setCurrentColor(0.0f, 0.0f, 1.0f);
    glVertex3f(0.5f, -0.5f, -0.5f);
    glVertex3f(0.5f, 0.5f, -0.5f);
    glVertex3f(0.5f, 0.5f, 0.5f);
    glVertex3f(0.5f, -0.5f, 0.5f);

    // 左面(原始黄色)
    setCurrentColor(1.0f, 1.0f, 0.0f);
    glVertex3f(-0.5f, -0.5f, -0.5f);
    glVertex3f(-0.5f, -0.5f, 0.5f);
    glVertex3f(-0.5f, 0.5f, 0.5f);
    glVertex3f(-0.5f, 0.5f, -0.5f);

    // 上面(原始青色)
    setCurrentColor(0.0f, 1.0f, 1.0f);
    glVertex3f(-0.5f, 0.5f, -0.5f);
    glVertex3f(-0.5f, 0.5f, 0.5f);
    glVertex3f(0.5f, 0.5f, 0.5f);
    glVertex3f(0.5f, 0.5f, -0.5f);

    // 下面(原始紫色)
    setCurrentColor(1.0f, 0.0f, 1.0f);
    glVertex3f(-0.5f, -0.5f, -0.5f);
    glVertex3f(0.5f, -0.5f, -0.5f);
    glVertex3f(0.5f, -0.5f, 0.5f);
    glVertex3f(-0.5f, -0.5f, 0.5f);

    glEnd();
}

// 显示回调函数(原有逻辑不变)
void display() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // 清除颜色和深度缓冲区

    // 重置模型视图矩阵
    glLoadIdentity();

    // -------------------------- 视图变换 --------------------------
    gluLookAt(0.0f, 1.0f, cameraZ,  // 相机位置(可通过+/-调整)
        0.0f, 0.0f, 0.0f,     // 目标点(看向原点)
        0.0f, 1.0f, 0.0f);    // 上方向(Y轴为上)

    // -------------------------- 模型变换 --------------------------
    glRotatef(rotationAngle, 1.0f, 1.0f, 0.0f);  // 绕(1,1,0)轴旋转
    glTranslatef(1.0f, 0.0f, 0.0f);             // 沿X轴平移

    // 绘制第一个立方体
    drawCube();

    // 对第二个立方体应用不同的模型变换
    glPushMatrix();  // 保存当前矩阵状态
    glRotatef(rotationAngle, 0.0f, 1.0f, 0.0f);  // 绕Y轴旋转
    glTranslatef(-2.0f, 0.0f, 0.0f);             // 沿X轴负方向平移
    glScalef(0.5f, 0.5f, 0.5f);                  // 缩小一半
    drawCube();                                   // 绘制第二个立方体
    glPopMatrix();   // 恢复矩阵状态

    glutSwapBuffers();  // 交换缓冲区
}

// 窗口大小变化回调函数(原有逻辑不变)
void reshape(int width, int height) {
    glViewport(0, 0, width, height);  // 设置视口,占满整个窗口

    // 切换到投影矩阵模式
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();  // 重置投影矩阵

    // -------------------------- 投影变换 --------------------------
    float aspectRatio = (float)width / (float)height;
    gluPerspective(45.0f, aspectRatio, 0.1f, 100.0f);  // 透视投影

    // 切换回模型视图矩阵模式
    glMatrixMode(GL_MODELVIEW);
}

// 定时器回调函数(原有逻辑不变)
void timer(int value) {
    rotationAngle += 1.0f;  // 增加旋转角度
    if (rotationAngle >= 360.0f) {
        rotationAngle = 0.0f;
    }

    glutPostRedisplay();  // 标记窗口需要重绘
    glutTimerFunc(16, timer, 0);  // 约60fps
}

// 键盘回调函数(修改:新增颜色模式切换逻辑)
void keyboard(unsigned char key, int x, int y) {
    switch (key) {
    case 27:  // ESC键:退出程序
        exit(0);
        break;

    case '+':  // 相机靠近
        cameraZ -= 0.5f;
        if (cameraZ < 1.0f) cameraZ = 1.0f;
        break;

    case '-':  // 相机远离
        cameraZ += 0.5f;
        break;

        // -------------------------- 新增:颜色模式切换 --------------------------
    case '1':  // 1键:切换到彩色模式
        currentColorMode = COLOR_MODE_COLORFUL;
        glutSetWindowTitle("OpenGL 矩阵变换示例 - 彩色模式");
        printf("当前颜色模式:彩色模式\n");
        break;

    case '2':  // 2键:切换到灰度模式
        currentColorMode = COLOR_MODE_GRAYSCALE;
        glutSetWindowTitle("OpenGL 矩阵变换示例 - 灰度模式");
        printf("当前颜色模式:灰度模式\n");
        break;

    case '3':  // 3键:切换到单色模式
        currentColorMode = COLOR_MODE_MONO;
        glutSetWindowTitle("OpenGL 矩阵变换示例 - 单色模式(橙色)");
        printf("当前颜色模式:单色模式(可按4/5/6调整颜色)\n");
        break;

        // 单色模式下调整颜色(4=加红,5=加绿,6=加蓝)
    case '4':
        if (currentColorMode == COLOR_MODE_MONO) {
            monoColor[0] = (monoColor[0] + 0.1f) > 1.0f ? 1.0f : monoColor[0] + 0.1f;
            glutSetWindowTitle("OpenGL 矩阵变换示例 - 单色模式(红+)");
            printf("单色模式:红色分量=%.1f\n", monoColor[0]);
        }
        break;

    case '5':
        if (currentColorMode == COLOR_MODE_MONO) {
            monoColor[1] = (monoColor[1] + 0.1f) > 1.0f ? 1.0f : monoColor[1] + 0.1f;
            glutSetWindowTitle("OpenGL 矩阵变换示例 - 单色模式(绿+)");
            printf("单色模式:绿色分量=%.1f\n", monoColor[1]);
        }
        break;

    case '6':
        if (currentColorMode == COLOR_MODE_MONO) {
            monoColor[2] = (monoColor[2] + 0.1f) > 1.0f ? 1.0f : monoColor[2] + 0.1f;
            glutSetWindowTitle("OpenGL 矩阵变换示例 - 单色模式(蓝+)");
            printf("单色模式:蓝色分量=%.1f\n", monoColor[2]);
        }
        break;
    }
    glutPostRedisplay();  // 切换后触发重绘
}

// 主函数(原有逻辑不变)
int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("OpenGL 矩阵变换示例 - 彩色模式");

    init();

    // 注册回调函数
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutTimerFunc(0, timer, 0);
    glutKeyboardFunc(keyboard);

    glutMainLoop();
    return 0;
}

结果为:

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐