OpenGL 蓝书学习(第四版)第三章

OpenGL 蓝书学习(第四版)第三章

欢迎来到第三章!

绘制一个点

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;

void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    glPointSize(5.0F); // 设置点的大小
    glBegin(GL_POINTS);
        glVertex2f(0.0F, 0.0F); // 绘制一个点
    glEnd();
    glutSwapBuffers(); // 交换缓冲区
}

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        default:
            break;
    }
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, 1.0, -1.0);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, 1.0, -1.0);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutKeyboardFunc(keyboard);     // 键盘事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持点大小
    GLfloat pointSizeRange[2];
    glGetFloatv(GL_POINT_SIZE_RANGE, pointSizeRange);
    // 获取支持的点大小精度
    GLfloat pointSizeGranularity;
    glGetFloatv(GL_POINT_SIZE_GRANULARITY, &pointSizeGranularity);
    std::cout << std::format("pointSizeRange: [{}, {}], pointSizeGranularity: {}", pointSizeRange[0], pointSizeRange[1], pointSizeGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

绘制一个圆

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;

void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    glPointSize(5.0F); // 设置点的大小 // 使用 std::numbers::pi
    glBegin(GL_POINTS);
        glVertex2f(0.0F, 0.0F); // 绘制一个圆点
        // 绘制一个圆
        for (GLfloat angle = 0.0F; angle < std::numbers::pi_v<GLfloat> * 2.0F; angle += 0.1F) {
            const GLfloat x = 50.0F * std::cos(angle);
            const GLfloat y = 50.0F * std::sin(angle);
            glVertex2f(x, y);
        }
    glEnd();
    glutSwapBuffers(); // 交换缓冲区
}

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        default:
            break;
    }
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, 1.0, -1.0);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, 1.0, -1.0);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutKeyboardFunc(keyboard);     // 键盘事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持点大小
    GLfloat pointSizeRange[2];
    glGetFloatv(GL_POINT_SIZE_RANGE, pointSizeRange);
    // 获取支持的点大小精度
    GLfloat pointSizeGranularity;
    glGetFloatv(GL_POINT_SIZE_GRANULARITY, &pointSizeGranularity);
    std::cout << std::format("pointSizeRange: [{}, {}], pointSizeGranularity: {}", pointSizeRange[0], pointSizeRange[1], pointSizeGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

绘制立体弹簧

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度

void renderScene(){
    std::cout << std::format("renderScene xRot={}, yRot={}", xRot, yRot) << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    glPointSize(5.0F); // 设置点的大小 // 使用 std::numbers::pi

    glPushMatrix();
    glRotatef(xRot, 1.0F, 0.0F, 0.0F);  // 绕 X 轴倾斜,看到螺旋侧面
    glRotatef(yRot, 0.0F, 1.0F, 0.0F); // 绕 Y 轴,顶部朝左
    glRotatef(zRot, 0.0F, 0.0F, 1.0F); // 绕 Z 轴旋转

    glBegin(GL_POINTS);
        glVertex2f(0.0F, 0.0F); // 绘制一个圆点
        // 绘制一个圆
        for (GLfloat angle = 0.0F, z = -RADIUS; angle < PI * 2.0F * 3.0F; angle += 0.1F) {
            const GLfloat x = RADIUS * std::cos(angle);
            const GLfloat y = RADIUS * std::sin(angle);
            if(angle > PI * 2.0F * 2.0F) {
                glColor3f(1.0F, 1.0F, 0.0F); // 黄色
            } else {
                glColor3f(1.0F, 0.0F, 0.0F); // 红色
            }
            glVertex3f(x, y, z);
            z += 0.5F; // z 轴增加,形成螺旋
        }
    glEnd();
    glPopMatrix();
    glutSwapBuffers(); // 交换缓冲区
}

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        case 'a':
        case 'A':
            zRot -= 5.0F; // 绕 Z 轴逆时针旋转
            glutPostRedisplay();
            break;
        case 'd':
        case 'D':
            zRot += 5.0F; // 绕 Z 轴顺时针旋转
            glutPostRedisplay();
            break;
        default:
            break;
    }
}

void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case GLUT_KEY_UP:
            xRot -= 5.0F;
            break;
        case GLUT_KEY_DOWN:
            xRot += 5.0F;
            break;
        case GLUT_KEY_LEFT:
            yRot -= 5.0F;
            break;
        case GLUT_KEY_RIGHT:
            yRot += 5.0F;
            break;
        default:
            break;
    }
    // Refresh the Window
    glutPostRedisplay();
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE, -COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys);   // 特殊键事件
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持点大小
    GLfloat pointSizeRange[2];
    glGetFloatv(GL_POINT_SIZE_RANGE, pointSizeRange);
    // 获取支持的点大小精度
    GLfloat pointSizeGranularity;
    glGetFloatv(GL_POINT_SIZE_GRANULARITY, &pointSizeGranularity);
    std::cout << std::format("pointSizeRange: [{}, {}], pointSizeGranularity: {}", pointSizeRange[0], pointSizeRange[1], pointSizeGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

绘制立体变粗的弹簧

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度

void renderScene(){
    std::cout << std::format("renderScene xRot={}, yRot={}", xRot, yRot) << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);

    // 点大小
    GLfloat pointSize = 1.0F;
    glPointSize(pointSize);

    glPushMatrix();
    glRotatef(xRot, 1.0F, 0.0F, 0.0F);  // 绕 X 轴倾斜,看到螺旋侧面
    glRotatef(yRot, 0.0F, 1.0F, 0.0F); // 绕 Y 轴,顶部朝左

    // 原点
    glPointSize(5.0F); // glPointSize必须在 glBegin 之前设置,否则无效,但是会影响性能 
    glBegin(GL_POINTS);
        glVertex2f(0.0F, 0.0F);
    glEnd();

    // 绘制螺旋:每个点单独 begin/end,才能在 glBegin 前设置不同的大小
    for (GLfloat angle = 0.0F, z = -RADIUS; angle < PI * 2.0F * 3.0F; angle += 0.1F) {
        const GLfloat x = RADIUS * std::cos(angle);
        const GLfloat y = RADIUS * std::sin(angle);
        if(angle > PI * 2.0F * 2.0F) {
            glColor3f(1.0F, 1.0F, 0.0F); // 黄色
        } else {
            glColor3f(1.0F, 0.0F, 0.0F); // 红色
        }
        glPointSize(pointSize); // 必须在 glBegin 之前设置
        glBegin(GL_POINTS);
            glVertex3f(x, y, z);
        glEnd();
        pointSize += 0.1F;
        z += 0.5F;
    }
    glPopMatrix();
    glutSwapBuffers(); // 交换缓冲区
}

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        default:
            break;
    }
}

void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case GLUT_KEY_UP:
            xRot -= 5.0F;
            break;
        case GLUT_KEY_DOWN:
            xRot += 5.0F;
            break;
        case GLUT_KEY_LEFT:
            yRot -= 5.0F;
            break;
        case GLUT_KEY_RIGHT:
            yRot += 5.0F;
            break;
        default:
            break;
    }
    // Refresh the Window
    glutPostRedisplay();
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE, -COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys);   // 特殊键事件
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持点大小
    GLfloat pointSizeRange[2];
    glGetFloatv(GL_POINT_SIZE_RANGE, pointSizeRange);
    // 获取支持的点大小精度
    GLfloat pointSizeGranularity;
    glGetFloatv(GL_POINT_SIZE_GRANULARITY, &pointSizeGranularity);
    std::cout << std::format("pointSizeRange: [{}, {}], pointSizeGranularity: {}", pointSizeRange[0], pointSizeRange[1], pointSizeGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

画一条直线

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>

// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;

void renderScene(){
    std::cout << std::format("renderScene...") << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_LINES);
        glVertex3f(0.0F, 0.0F, 0.0F);
        glVertex3f(50.0F, 50.0F, 0.0F);
        glVertex3f(60.0F, 60.0F, 0.0F);
        glVertex3f(70.0F, 70.0F, 0.0F);
    glEnd();
    glutSwapBuffers(); // 交换缓冲区
}

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        default:
            break;
    }
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE, -COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持点大小
    GLfloat pointSizeRange[2];
    glGetFloatv(GL_POINT_SIZE_RANGE, pointSizeRange);
    // 获取支持的点大小精度
    GLfloat pointSizeGranularity;
    glGetFloatv(GL_POINT_SIZE_GRANULARITY, &pointSizeGranularity);
    std::cout << std::format("pointSizeRange: [{}, {}], pointSizeGranularity: {}", pointSizeRange[0], pointSizeRange[1], pointSizeGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

画一个轮毂

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>

// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

void renderScene(){
    std::cout << std::format("renderScene...") << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_LINES);
        const GLfloat step = PI / 45.0F * 2.0F;
        for (GLfloat angle = 0.0F; angle < 2 * PI; angle += step) {
            const GLfloat x = RADIUS * std::cos(angle);
            const GLfloat y = RADIUS * std::sin(angle);
            glVertex2f(0.0F, 0.0F);
            glVertex2f(x, y);
        }
    glEnd();
    glutSwapBuffers(); // 交换缓冲区
}

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        default:
            break;
    }
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE, -COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持点大小
    GLfloat pointSizeRange[2];
    glGetFloatv(GL_POINT_SIZE_RANGE, pointSizeRange);
    // 获取支持的点大小精度
    GLfloat pointSizeGranularity;
    glGetFloatv(GL_POINT_SIZE_GRANULARITY, &pointSizeGranularity);
    std::cout << std::format("pointSizeRange: [{}, {}], pointSizeGranularity: {}", pointSizeRange[0], pointSizeRange[1], pointSizeGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

画一个厂

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>

// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

void renderScene(){
    std::cout << std::format("renderScene...") << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_LINE_STRIP);
        glVertex2f(0.0F, 0.0F);
        glVertex2f(50.0F, 50.0F);
        glVertex2f(80.0F, 50.0F);
    glEnd();
    glutSwapBuffers(); // 交换缓冲区
}

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        default:
            break;
    }
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE, -COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持点大小
    GLfloat pointSizeRange[2];
    glGetFloatv(GL_POINT_SIZE_RANGE, pointSizeRange);
    // 获取支持的点大小精度
    GLfloat pointSizeGranularity;
    glGetFloatv(GL_POINT_SIZE_GRANULARITY, &pointSizeGranularity);
    std::cout << std::format("pointSizeRange: [{}, {}], pointSizeGranularity: {}", pointSizeRange[0], pointSizeRange[1], pointSizeGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

GL_LINE_STRIP会绘制经过所有点集的一条线。GL_LINE_LOOP会自闭和。

绘制圆滑弹簧

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度

void renderScene(){
    std::cout << std::format("renderScene xRot={}, yRot={}", xRot, yRot) << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    glPointSize(5.0F); // 设置点的大小 // 使用 std::numbers::pi

    glPushMatrix();
    glRotatef(xRot, 1.0F, 0.0F, 0.0F);  // 绕 X 轴倾斜,看到螺旋侧面
    glRotatef(yRot, 0.0F, 1.0F, 0.0F); // 绕 Y 轴,顶部朝左

    glBegin(GL_POINTS);
        glVertex2f(0.0F, 0.0F); // 绘制一个圆点
    glEnd();

    glBegin(GL_LINE_STRIP);
        // 绘制一个圆
        for (GLfloat angle = 0.0F, z = -RADIUS; angle < PI * 2.0F * 3.0F; angle += 0.1F) {
            const GLfloat x = RADIUS * std::cos(angle);
            const GLfloat y = RADIUS * std::sin(angle);
            if(angle > PI * 2.0F * 2.0F) {
                glColor3f(1.0F, 1.0F, 0.0F); // 黄色
            } else {
                glColor3f(1.0F, 0.0F, 0.0F); // 红色
            }
            glVertex3f(x, y, z);
            z += 0.5F; // z 轴增加,形成螺旋
        }
    glEnd();
    glPopMatrix();
    glutSwapBuffers(); // 交换缓冲区
}

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        default:
            break;
    }
}

void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case GLUT_KEY_UP:
            xRot -= 5.0F;
            break;
        case GLUT_KEY_DOWN:
            xRot += 5.0F;
            break;
        case GLUT_KEY_LEFT:
            yRot -= 5.0F;
            break;
        case GLUT_KEY_RIGHT:
            yRot += 5.0F;
            break;
        default:
            break;
    }
    // Refresh the Window
    glutPostRedisplay();
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE, -COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys);   // 特殊键事件
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持点大小
    GLfloat pointSizeRange[2];
    glGetFloatv(GL_POINT_SIZE_RANGE, pointSizeRange);
    // 获取支持的点大小精度
    GLfloat pointSizeGranularity;
    glGetFloatv(GL_POINT_SIZE_GRANULARITY, &pointSizeGranularity);
    std::cout << std::format("pointSizeRange: [{}, {}], pointSizeGranularity: {}", pointSizeRange[0], pointSizeRange[1], pointSizeGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

绘制递增线条宽度的线条

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;


void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);

    for (GLfloat lineWidth = lineWidthRange[0], y = -80.0; lineWidth <= lineWidthRange[1]; lineWidth += 1.0F, y += 10.0F) {
        glLineWidth(lineWidth);
        glBegin(GL_LINES);
        glVertex2f(-80.0F, y);
        glVertex2f(80.0F, y);
        glEnd();
    }
    
    glutSwapBuffers(); // 交换缓冲区
}

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        default:
            break;
    }
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE, -COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format("lineWidthRange: [{}, {}], lineWidthGranularity: {}", lineWidthRange[0], lineWidthRange[1], lineWidthGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

绘制虚线

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;


void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    
    glEnable(GL_LINE_SMOOTH); // 开启线条抗锯齿
    glEnable(GL_LINE_STIPPLE); // 开启线条虚线
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // 设置抗锯齿质量

    // const GLushort pattern = 0x5555; // 线条虚线模式
    const GLushort pattern = 0x00FF; // 线条虚线模式
    GLint factor = 1; // 线条虚线重复因子
    for(GLfloat y = -80.0F; y <= 80.0F; y += 10.0F){
        glLineStipple(factor, pattern);
        glBegin(GL_LINES);
            glVertex2f(-80.0F, y);
            glVertex2f(80.0F, y);
        glEnd();
        factor++;
    }
    
    glutSwapBuffers(); // 交换缓冲区
}

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        default:
            break;
    }
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE, -COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format("lineWidthRange: [{}, {}], lineWidthGranularity: {}", lineWidthRange[0], lineWidthRange[1], lineWidthGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

绘制三角形

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;


void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    
    glBegin(GL_TRIANGLES);
        // 绘制第一个三角形
        glVertex2f(0.0F, 0.0F);
        glVertex2f(25.0F, 25.0F);
        glVertex2f(50.0F, 0.0F);
        // 绘制第二个三角形
        glVertex2f(-50.0F, 0.0F);
        glVertex2f(-75.0F, 50.0F);
        glVertex2f(-25.0F, 0.0F);
    glEnd();
    
    glutSwapBuffers(); // 交换缓冲区
}

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        default:
            break;
    }
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE, -COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format("lineWidthRange: [{}, {}], lineWidthGranularity: {}", lineWidthRange[0], lineWidthRange[1], lineWidthGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

绘制三角形并开启背面剔除

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度

void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    
    glPushMatrix();
    
    glRotatef(xRot, 1.0F, 0.0F, 0.0F);  // 绕 X 轴旋转
    glRotatef(yRot, 0.0F, 1.0F, 0.0F); // 绕 Y 轴旋转
    glRotatef(zRot, 0.0F, 0.0F, 1.0F); // 绕 Z 轴旋转

    glBegin(GL_TRIANGLES);
        // 绘制第一个三角形
        glVertex2f(0.0F, 0.0F);
        glVertex2f(25.0F, 25.0F);
        glVertex2f(50.0F, 0.0F);
        // 绘制第二个三角形
        glVertex2f(-50.0F, 0.0F);
        glVertex2f(-75.0F, 50.0F);
        glVertex2f(-25.0F, 0.0F);
    glEnd();
    
    glPopMatrix();

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

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
    glEnable(GL_CULL_FACE);   // 开启面剔除
    glCullFace(GL_BACK);      // 剔除背面(默认就是 BACK)
    glFrontFace(GL_CCW);      // 逆时针为正面(默认值)
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        case 'a':
        case 'A':
            zRot -= 5.0F; // 绕 Z 轴逆时针旋转
            glutPostRedisplay();
            break;
        case 'd':
        case 'D':
            zRot += 5.0F; // 绕 Z 轴顺时针旋转
            glutPostRedisplay();
            break;
        default:
            break;
    }
}

void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case GLUT_KEY_UP:
            xRot -= 5.0F;
            break;
        case GLUT_KEY_DOWN:
            xRot += 5.0F;
            break;
        case GLUT_KEY_LEFT:
            yRot -= 5.0F;
            break;
        case GLUT_KEY_RIGHT:
            yRot += 5.0F;
            break;
        default:
            break;
    }
    // Refresh the Window
    glutPostRedisplay();
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE, -COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys); // 特殊键事件
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format("lineWidthRange: [{}, {}], lineWidthGranularity: {}", lineWidthRange[0], lineWidthRange[1], lineWidthGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

默认情况下GL_TRIANGLES、GL_TRIANGLE_FAN使用的是顺时针环绕,满足右手定则,大拇指指定方向为正面,反之为背面。面剔除默认剔除背面。
GL_TRIANGLE_STRIP使用的是逆时针环绕。

使用GL_TRIANGLE_FAN绘制菱形

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度

void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    
    glPushMatrix();
    
    glRotatef(xRot, 1.0F, 0.0F, 0.0F);  // 绕 X 轴旋转
    glRotatef(yRot, 0.0F, 1.0F, 0.0F); // 绕 Y 轴旋转
    glRotatef(zRot, 0.0F, 0.0F, 1.0F); // 绕 Z 轴旋转

    glBegin(GL_TRIANGLE_FAN);       // 绘制三角形扇(菱形)
        glVertex2f(0.0F, 0.0F);     // 中心点
        glVertex2f(0.0F, 50.0F);    // 上顶点
        glVertex2f(25.0F, 0.0F);    // 右顶点
        glVertex2f(0.0F, -50.0F);   // 下顶点
        glVertex2f(-25.0F, 0.0F);   // 左顶点
        glVertex2f(0.0F, 50.0F);    // 闭合回到上顶点
    glEnd();
    
    glPopMatrix();

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

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
    glEnable(GL_CULL_FACE);   // 开启面剔除
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        case 'a':
        case 'A':
            zRot -= 5.0F; // 绕 Z 轴逆时针旋转
            glutPostRedisplay();
            break;
        case 'd':
        case 'D':
            zRot += 5.0F; // 绕 Z 轴顺时针旋转
            glutPostRedisplay();
            break;
        default:
            break;
    }
}

void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case GLUT_KEY_UP:
            xRot -= 5.0F;
            break;
        case GLUT_KEY_DOWN:
            xRot += 5.0F;
            break;
        case GLUT_KEY_LEFT:
            yRot -= 5.0F;
            break;
        case GLUT_KEY_RIGHT:
            yRot += 5.0F;
            break;
        default:
            break;
    }
    // Refresh the Window
    glutPostRedisplay();
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE, -COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys); // 特殊键事件
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format("lineWidthRange: [{}, {}], lineWidthGranularity: {}", lineWidthRange[0], lineWidthRange[1], lineWidthGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

绘制一个菱形

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度

void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);
    
    glPushMatrix();
    
    glRotatef(xRot, 1.0F, 0.0F, 0.0F);  // 绕 X 轴旋转
    glRotatef(yRot, 0.0F, 1.0F, 0.0F); // 绕 Y 轴旋转
    glRotatef(zRot, 0.0F, 0.0F, 1.0F); // 绕 Z 轴旋转

    glBegin(GL_TRIANGLE_STRIP);                                     // 使用三角形条带绘制菱形
        // GL_TRIANGLE_STRIP 顶点顺序:
        // Triangle 0 (even): v0 → v1 → v2
        // Triangle 1 (odd):  v2 → v1 → v3  (OpenGL自动交换前两个顶点以保持一致的缠绕)
        //
        // 菱形四个顶点:
        //   v0( 0,  50)  ← 上
        //   v1(-25,  0)  ← 左
        //   v2( 25,  0)  ← 右
        //   v3( 0, -50)  ← 下
        //
        // Triangle 0: 上→左→右 (CCW, 上半菱形)
        // Triangle 1: 右→左→下 → 经GL交换后: 左→右→下 (CCW, 下半菱形)

        std::cout << "v0: top   (0, 50)"    << "\n";
        glVertex2f(0.0F, 50.0F);    // v0: 上顶点

        std::cout << "v1: left  (-25, 0)"  << "\n";
        glVertex2f(-25.0F, 0.0F);   // v1: 左顶点

        std::cout << "v2: right (25, 0)"   << "\n";
        glVertex2f(25.0F, 0.0F);    // v2: 右顶点

        std::cout << "v3: bottom(0, -50)"  << "\n";
        glVertex2f(0.0F, -50.0F);   // v3: 下顶点
    glEnd();
    
    glPopMatrix();

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

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
    glEnable(GL_CULL_FACE);   // 开启面剔除
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        case 'a':
        case 'A':
            zRot -= 5.0F; // 绕 Z 轴逆时针旋转
            glutPostRedisplay();
            break;
        case 'd':
        case 'D':
            zRot += 5.0F; // 绕 Z 轴顺时针旋转
            glutPostRedisplay();
            break;
        default:
            break;
    }
}

void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case GLUT_KEY_UP:
            xRot -= 5.0F;
            break;
        case GLUT_KEY_DOWN:
            xRot += 5.0F;
            break;
        case GLUT_KEY_LEFT:
            yRot -= 5.0F;
            break;
        case GLUT_KEY_RIGHT:
            yRot += 5.0F;
            break;
        default:
            break;
    }
    // Refresh the Window
    glutPostRedisplay();
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE, -COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys); // 特殊键事件
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format("lineWidthRange: [{}, {}], lineWidthGranularity: {}", lineWidthRange[0], lineWidthRange[1], lineWidthGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

GL_TRIANGLE_STRIP

画一个圆锥体

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度

void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT);

    GLboolean isGreen = false;

    glPushMatrix();
    
    glRotatef(xRot, 1.0F, 0.0F, 0.0F);  // 绕 X 轴旋转
    glRotatef(yRot, 0.0F, 1.0F, 0.0F); // 绕 Y 轴旋转
    glRotatef(zRot, 0.0F, 0.0F, 1.0F); // 绕 Z 轴旋转

    glBegin(GL_TRIANGLE_FAN);
        glVertex3f(0.0F, 0.0F, 80.0F); // 圆锥顶点
        for (GLfloat angle = 0.0F, i = 0; angle < 2.0F * PI; angle += PI / 8.0F, ++i) {
            glVertex3f(RADIUS * std::cos(angle), RADIUS * std::sin(angle), 0.0F);
            if (isGreen) {
                glColor3f(0.0F, 1.0F, 0.0F); // 绿色
            } else {
                glColor3f(1.0F, 0.0F, 0.0F); // 红色
            }
            isGreen = !isGreen;
        }
        glVertex3f(RADIUS, 0.0F, 0.0F); // 闭合圆锥底面
    glEnd();

    // 底盖
    glBegin(GL_TRIANGLE_FAN);
        glVertex3f(0.0F, 0.0F, 0.0F); // 圆锥底面中心点
        for (GLfloat angle = 0.0F; angle < 2.0F * PI; angle += PI / 8.0F) {
            glVertex3f(RADIUS * std::cos(angle), RADIUS * std::sin(angle), 0.0F);
            if (isGreen) {
                glColor3f(0.0F, 1.0F, 0.0F); // 绿色
            } else {
                glColor3f(1.0F, 0.0F, 0.0F); // 红色
            }
            isGreen = !isGreen;
        }
        glVertex3f(RADIUS, 0.0F, 0.0F); // 闭合圆锥底面
    glEnd();

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

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
    glShadeModel(GL_FLAT); // 设置为平面着色
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        case 'a':
        case 'A':
            zRot -= 5.0F; // 绕 Z 轴逆时针旋转
            glutPostRedisplay();
            break;
        case 'd':
        case 'D':
            zRot += 5.0F; // 绕 Z 轴顺时针旋转
            glutPostRedisplay();
            break;
        default:
            break;
    }
}

void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case GLUT_KEY_UP:
            xRot -= 5.0F;
            break;
        case GLUT_KEY_DOWN:
            xRot += 5.0F;
            break;
        case GLUT_KEY_LEFT:
            yRot -= 5.0F;
            break;
        case GLUT_KEY_RIGHT:
            yRot += 5.0F;
            break;
        default:
            break;
    }
    // Refresh the Window
    glutPostRedisplay();
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE, -COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys);   // 特殊键事件
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format("lineWidthRange: [{}, {}], lineWidthGranularity: {}", lineWidthRange[0], lineWidthRange[1], lineWidthGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

开启深度测试的圆锥体

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度

void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    GLboolean isGreen = false;

    glPushMatrix();
    
    glRotatef(xRot, 1.0F, 0.0F, 0.0F);  // 绕 X 轴旋转
    glRotatef(yRot, 0.0F, 1.0F, 0.0F); // 绕 Y 轴旋转
    glRotatef(zRot, 0.0F, 0.0F, 1.0F); // 绕 Z 轴旋转

    glBegin(GL_TRIANGLE_FAN);
        glVertex3f(0.0F, 0.0F, 80.0F); // 圆锥顶点,指向屏幕外
        for (GLfloat angle = 0.0F, i = 0; angle < 2.0F * PI; angle += PI / 8.0F, ++i) {
            glVertex3f(RADIUS * std::cos(angle), RADIUS * std::sin(angle), 0.0F);
            if (isGreen) {
                glColor3f(0.0F, 1.0F, 0.0F); // 绿色
            } else {
                glColor3f(1.0F, 0.0F, 0.0F); // 红色
            }
            isGreen = !isGreen;
        }
        glVertex3f(RADIUS, 0.0F, 0.0F); // 闭合圆锥底面
    glEnd();

    // 底盖
    glBegin(GL_TRIANGLE_FAN);
        glVertex3f(0.0F, 0.0F, 0.0F); // 圆锥底面中心点
        for (GLfloat angle = 0.0F; angle < 2.0F * PI; angle += PI / 8.0F) {
            glVertex3f(RADIUS * std::cos(angle), RADIUS * std::sin(angle), 0.0F);
            if (isGreen) {
                glColor3f(0.0F, 1.0F, 0.0F); // 绿色
            } else {
                glColor3f(1.0F, 0.0F, 0.0F); // 红色
            }
            isGreen = !isGreen;
        }
        glVertex3f(RADIUS, 0.0F, 0.0F); // 闭合圆锥底面
    glEnd();

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

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
    glShadeModel(GL_FLAT); // 设置为平面着色
    glEnable(GL_DEPTH_TEST); // 启用深度测试
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        case 'a':
        case 'A':
            zRot -= 5.0F; // 绕 Z 轴逆时针旋转
            glutPostRedisplay();
            break;
        case 'd':
        case 'D':
            zRot += 5.0F; // 绕 Z 轴顺时针旋转
            glutPostRedisplay();
            break;
        default:
            break;
    }
}

void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case GLUT_KEY_UP:
            xRot -= 5.0F;
            break;
        case GLUT_KEY_DOWN:
            xRot += 5.0F;
            break;
        case GLUT_KEY_LEFT:
            yRot -= 5.0F;
            break;
        case GLUT_KEY_RIGHT:
            yRot += 5.0F;
            break;
        default:
            break;
    }
    // Refresh the Window
    glutPostRedisplay();
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE, COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys);   // 特殊键事件
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format("lineWidthRange: [{}, {}], lineWidthGranularity: {}", lineWidthRange[0], lineWidthRange[1], lineWidthGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

深度测试+背面剔除

// mac 特有的头文件
#include <GLUT/glut.h>
 
// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>
 
 
// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;
 
// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度
 
void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    GLboolean isGreen = false;
 
    glPushMatrix();
    
    glRotatef(xRot, 1.0F, 0.0F, 0.0F);  // 绕 X 轴旋转
    glRotatef(yRot, 0.0F, 1.0F, 0.0F); // 绕 Y 轴旋转
    glRotatef(zRot, 0.0F, 0.0F, 1.0F); // 绕 Z 轴旋转
 
    glBegin(GL_TRIANGLE_FAN);
        glVertex3f(0.0F, 0.0F, 80.0F); // 圆锥顶点,指向屏幕外
        for (GLfloat angle = 0.0F, i = 0; angle < 2.0F * PI; angle += PI / 8.0F, ++i) {
            glVertex3f(RADIUS * std::cos(angle), RADIUS * std::sin(angle), 0.0F);
            if (isGreen) {
                glColor3f(0.0F, 1.0F, 0.0F); // 绿色
            } else {
                glColor3f(1.0F, 0.0F, 0.0F); // 红色
            }
            isGreen = !isGreen;
        }
        glVertex3f(RADIUS, 0.0F, 0.0F); // 闭合圆锥底面
    glEnd();
 
    // 底盖
    glFrontFace(GL_CW); // 底面从外部看是顺时针,临时翻转
    glBegin(GL_TRIANGLE_FAN);
        glVertex3f(0.0F, 0.0F, 0.0F); // 圆锥底面中心点
        for (GLfloat angle = 0.0F; angle < 2.0F * PI; angle += PI / 8.0F) { // 或者顺时针绘制无需 修改 环绕
            glVertex3f(RADIUS * std::cos(angle), RADIUS * std::sin(angle), 0.0F);
            if (isGreen) {
                glColor3f(0.0F, 1.0F, 0.0F); // 绿色
            } else {
                glColor3f(1.0F, 0.0F, 0.0F); // 红色
            }
            isGreen = !isGreen;
        }
        glVertex3f(RADIUS, 0.0F, 0.0F); // 闭合圆锥底面
    glEnd();
    glFrontFace(GL_CCW); // 恢复默认 为下一帧 渲染恢复默认CCW
 
    glPopMatrix();
    glutSwapBuffers(); // 交换缓冲区
}
 
// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
    glShadeModel(GL_FLAT); // 设置为平面着色
    glEnable(GL_DEPTH_TEST); // 启用深度测试
    glEnable(GL_CULL_FACE); // 启用面剔除
}
 
// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        case 'a':
        case 'A':
            zRot -= 5.0F; // 绕 Z 轴逆时针旋转
            glutPostRedisplay();
            break;
        case 'd':
        case 'D':
            zRot += 5.0F; // 绕 Z 轴顺时针旋转
            glutPostRedisplay();
            break;
        default:
            break;
    }
}
 
void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case GLUT_KEY_UP:
            xRot -= 5.0F;
            break;
        case GLUT_KEY_DOWN:
            xRot += 5.0F;
            break;
        case GLUT_KEY_LEFT:
            yRot -= 5.0F;
            break;
        case GLUT_KEY_RIGHT:
            yRot += 5.0F;
            break;
        default:
            break;
    }
    // Refresh the Window
    glutPostRedisplay();
}
 
// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}
 
 
void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE, COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
 
int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);
 
    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
 
    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");
 
    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys);   // 特殊键事件
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();
 
    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format("lineWidthRange: [{}, {}], lineWidthGranularity: {}", lineWidthRange[0], lineWidthRange[1], lineWidthGranularity) << "\n";
 
    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

线条形状的圆锥体

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>


// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度

void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    GLboolean isGreen = false;

    glPushMatrix();
    
    glRotatef(xRot, 1.0F, 0.0F, 0.0F);  // 绕 X 轴旋转
    glRotatef(yRot, 0.0F, 1.0F, 0.0F); // 绕 Y 轴旋转
    glRotatef(zRot, 0.0F, 0.0F, 1.0F); // 绕 Z 轴旋转

    glBegin(GL_TRIANGLE_FAN);
        glVertex3f(0.0F, 0.0F, 80.0F); // 圆锥顶点,指向屏幕外
        for (GLfloat angle = 0.0F, i = 0; angle < 2.0F * PI; angle += PI / 8.0F, ++i) {
            glVertex3f(RADIUS * std::cos(angle), RADIUS * std::sin(angle), 0.0F);
            if (isGreen) {
                glColor3f(0.0F, 1.0F, 0.0F); // 绿色
            } else {
                glColor3f(1.0F, 0.0F, 0.0F); // 红色
            }
            isGreen = !isGreen;
        }
        glVertex3f(RADIUS, 0.0F, 0.0F); // 闭合圆锥底面
    glEnd();

    // 底盖
    glBegin(GL_TRIANGLE_FAN);
        glVertex3f(0.0F, 0.0F, 0.0F); // 圆锥底面中心点
        for (GLfloat angle = 0.0F; angle < 2.0F * PI; angle += PI / 8.0F) {
            glVertex3f(RADIUS * std::cos(angle), RADIUS * std::sin(angle), 0.0F);
            if (isGreen) {
                glColor3f(0.0F, 1.0F, 0.0F); // 绿色
            } else {
                glColor3f(1.0F, 0.0F, 0.0F); // 红色
            }
            isGreen = !isGreen;
        }
        glVertex3f(RADIUS, 0.0F, 0.0F); // 闭合圆锥底面
    glEnd();

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

// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
    glShadeModel(GL_FLAT); // 设置为平面着色
    glEnable(GL_DEPTH_TEST); // 启用深度测试
    // glEnable(GL_CULL_FACE);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // 设置为线框模式
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        case 'a':
        case 'A':
            zRot -= 5.0F; // 绕 Z 轴逆时针旋转
            glutPostRedisplay();
            break;
        case 'd':
        case 'D':
            zRot += 5.0F; // 绕 Z 轴顺时针旋转
            glutPostRedisplay();
            break;
        default:
            break;
    }
}

void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case GLUT_KEY_UP:
            xRot -= 5.0F;
            break;
        case GLUT_KEY_DOWN:
            xRot += 5.0F;
            break;
        case GLUT_KEY_LEFT:
            yRot -= 5.0F;
            break;
        case GLUT_KEY_RIGHT:
            yRot += 5.0F;
            break;
        default:
            break;
    }
    // Refresh the Window
    glutPostRedisplay();
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}


void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE, COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys);   // 特殊键事件
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format("lineWidthRange: [{}, {}], lineWidthGranularity: {}", lineWidthRange[0], lineWidthRange[1], lineWidthGranularity) << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

绘制四边形

// mac 特有的头文件
#include <GLUT/glut.h>
 
// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>
 
 
// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;
 
// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度
 
void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    GLboolean isGreen = false;
 
    glPushMatrix();
    
    glRotatef(xRot, 1.0F, 0.0F, 0.0F);  // 绕 X 轴旋转
    glRotatef(yRot, 0.0F, 1.0F, 0.0F); // 绕 Y 轴旋转
    glRotatef(zRot, 0.0F, 0.0F, 1.0F); // 绕 Z 轴旋转
 
    glBegin(GL_QUADS);
        glVertex3f(-RADIUS, -RADIUS, 0.0F);
        glVertex3f(RADIUS, -RADIUS, 0.0F);
        glVertex3f(RADIUS, RADIUS, 0.0F);
        glVertex3f(-RADIUS, RADIUS, 0.0F);
    glEnd();
 
    glPopMatrix();
    glutSwapBuffers(); // 交换缓冲区
}
 
// 首先调用
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.6F, 0.4F, 0.7F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
}
 
// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        case 'a':
        case 'A':
            zRot -= 5.0F; // 绕 Z 轴逆时针旋转
            glutPostRedisplay();
            break;
        case 'd':
        case 'D':
            zRot += 5.0F; // 绕 Z 轴顺时针旋转
            glutPostRedisplay();
            break;
        default:
            break;
    }
}
 
void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case GLUT_KEY_UP:
            xRot -= 5.0F;
            break;
        case GLUT_KEY_DOWN:
            xRot += 5.0F;
            break;
        case GLUT_KEY_LEFT:
            yRot -= 5.0F;
            break;
        case GLUT_KEY_RIGHT:
            yRot += 5.0F;
            break;
        default:
            break;
    }
    // Refresh the Window
    glutPostRedisplay();
}
 
// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}
 
 
void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE, COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
 
int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);
 
    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
 
    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");
 
    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys);   // 特殊键事件
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();
 
    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format("lineWidthRange: [{}, {}], lineWidthGranularity: {}", lineWidthRange[0], lineWidthRange[1], lineWidthGranularity) << "\n";
 
    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

点画模式

// mac 特有的头文件
#include <GLUT/glut.h>
 
// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <iostream>
#include <format>
#include <numbers>
 
 
// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;
 
// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度
 
void renderScene(){
    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    GLboolean isGreen = false;
 
    glPushMatrix();
    
    glRotatef(xRot, 1.0F, 0.0F, 0.0F);  // 绕 X 轴旋转
    glRotatef(yRot, 0.0F, 1.0F, 0.0F); // 绕 Y 轴旋转
    glRotatef(zRot, 0.0F, 0.0F, 1.0F); // 绕 Z 轴旋转
 
    glBegin(GL_QUAD_STRIP);
        glVertex3f(-RADIUS, -RADIUS, 0.0F);
        glVertex3f(-RADIUS, RADIUS, 0.0F);
        glVertex3f(RADIUS, -RADIUS, 0.0F);
        glVertex3f(RADIUS, RADIUS, 0.0F);
    glEnd();
 
    glPopMatrix();
    glutSwapBuffers(); // 交换缓冲区
}
 
/**
 * 首先调用
 * 0000 0000 0x00
 * 0000 0001 0x01
 * 0000 0010 0x02
 * 0000 0011 0x03
 * 0000 0100 0x04
 * 0000 0101 0x05
 * 0000 0110 0x06
 * 0000 0111 0x07
 * 0000 1000 0x08
 * 0000 1001 0x09
 * 0000 1010 0x0A
 * 0000 1011 0x0B
 * 0000 1100 0x0C
 * 0000 1101 0x0D
 * 0000 1110 0x0E
 * 0000 1111 0x0F
 */
void setupRc(){
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.0F, 0.0F, 0.0F, 1.0F);
    // 使用红色画笔
    glColor3f(1.0F, 0.0F, 0.0F);
    glEnable(GL_POLYGON_SMOOTH); // 开启多边形抗锯齿
    glEnable(GL_POLYGON_STIPPLE); // 开启多边形点画功能
    const GLubyte pattern[] = {
        0x00, 0x00, 0x00, 0x00,        // 1
        0x00, 0x00, 0x00, 0x00,        // 2
        0x00, 0x00, 0x00, 0x00,      // 3    
        0x00, 0x00, 0x00, 0x00,    // 4
        0x00, 0x00, 0x00, 0x00,    // 5
        0x00, 0x00, 0x00, 0x00,    // 6
        0x00, 0x00, 0x00, 0xC0,    // 7
        0x00, 0x00, 0x01, 0xF0,    // 8
        0x00, 0x00, 0x07, 0xF0,    // 9 
        0x00, 0x00, 0x1F, 0xE0,    // 10
        0x1F, 0x80, 0x1F, 0xC0,    // 11
        0x0F, 0xC0, 0x3F, 0x80,    // 12
        0x07, 0xE0, 0x7E, 0x00,    // 13
        0x03, 0xF0, 0xFF, 0x80,    // 14
        0x03, 0xF5, 0xFF, 0xE0,    // 15
        0x1F, 0xFC, 0xFF, 0xE8,    // 16
        0xE0, 0x03, 0xF0, 0x01,    // 17
        0xC0, 0x07, 0xE0, 0x03,    // 18
        0x80, 0x0F, 0xC0, 0x07,    // 19
        0x00, 0x1F, 0x80, 0x0F,    // 20
        0x00, 0x3F, 0x00, 0x1F,    // 21
        0x00, 0x7E, 0x00, 0x3F,    // 22            
        0x55, 0x55, 0x55, 0x55,    // 23
        0x55, 0x55, 0x55, 0x55,    // 24
        0x55, 0x55, 0x55, 0x55,    // 25
        0x55, 0x55, 0x55, 0x55,    // 26
        0x55, 0x55, 0x55, 0x55,    // 27
        0x55, 0x55, 0x55, 0x55,    // 28
        0x55, 0x55, 0x55, 0x55,    // 29
        0x55, 0x55, 0x55, 0x55,    // 30
        0x55, 0x55, 0x55, 0x55,    // 31
        0x55, 0x55, 0x55, 0x55,    // 32
    };
    glPolygonStipple(pattern);
}
 
// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case 27:    // ESC 键
        case 'q':
        case 'Q':
            std::cout << "keyboard close..." << "\n";
            exit(0);
            break;
        case 'a':
        case 'A':
            zRot -= 5.0F; // 绕 Z 轴逆时针旋转
            glutPostRedisplay();
            break;
        case 'd':
        case 'D':
            zRot += 5.0F; // 绕 Z 轴顺时针旋转
            glutPostRedisplay();
            break;
        default:
            break;
    }
}
 
void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
        case GLUT_KEY_UP:
            xRot -= 5.0F;
            break;
        case GLUT_KEY_DOWN:
            xRot += 5.0F;
            break;
        case GLUT_KEY_LEFT:
            yRot -= 5.0F;
            break;
        case GLUT_KEY_RIGHT:
            yRot += 5.0F;
            break;
        default:
            break;
    }
    // Refresh the Window
    glutPostRedisplay();
}
 
// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}
 
 
void changeSize(const GLsizei w, const GLsizei h){
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio = static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio, -COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE, COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
 
int main(int argc, char** argv){
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);
 
    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
 
    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");
 
    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys);   // 特殊键事件
    glutKeyboardFunc(keyboard);  // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose); 
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();
 
    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format("lineWidthRange: [{}, {}], lineWidthGranularity: {}", lineWidthRange[0], lineWidthRange[1], lineWidthGranularity) << "\n";
 
    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

画一个四角星

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <format>
#include <iostream>
#include <numbers>

// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度

void renderScene() {

    std::cout << "renderScene..." << "\n";
    // 使用紫色 清除颜色缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glPushMatrix();

    glRotatef(xRot, 1.0F, 0.0F, 0.0F); // 绕 X 轴旋转
    glRotatef(yRot, 0.0F, 1.0F, 0.0F); // 绕 Y 轴旋转
    glRotatef(zRot, 0.0F, 0.0F, 1.0F); // 绕 Z 轴旋转

    // constexpr GLboolean isGreen = false;

    // glBegin(GL_LINE_LOOP);
    //     // 逆时针绘制外轮廓
    //     glVertex2f(0.0F, 40.0F);      // 上顶点
    //     glVertex2f(20.0F, 0.0F);      // 内右
    //     glVertex2f(60.0F, -20.0F);    // 外右
    //     glVertex2f(20.0F, -40.0F);    // 内右下
    //     glVertex2f(0.0F, -80.0F);     // 下顶点
    //     glVertex2f(-20.0F, -40.0F);   // 内左下
    //     glVertex2f(-60.0F, -20.0F);   // 外左
    //     glVertex2f(-20.0F, 0.0F);     // 内左上
    // glEnd();

    glBegin(GL_TRIANGLES);
        // 上三角: v0=(-20,0), v1=(20,0), v2=(0,40)
        //         v0→v1 内部边(FALSE), v1→v2 外轮廓(TRUE), v2→v0 外轮廓(TRUE)
        glEdgeFlag(GL_FALSE);  // v0→v1: 内部横线 不画
        glVertex2f(-20.0F, 0.0F);
        glEdgeFlag(GL_TRUE);   // v1→v2: 外轮廓
        glVertex2f(20.0F, 0.0F);
        // glEdgeFlag(GL_TRUE);   // v2→v0: 外轮廓
        glVertex2f(0.0F, 40.0F);

        // 左三角: v0=(-20,0), v1=(-60,-20), v2=(-20,-40)
        //         v0→v1 外轮廓(TRUE), v1→v2 外轮廓(TRUE), v2→v0 内部边(FALSE)
        glVertex2f(-20.0F, 0.0F);
        glVertex2f(-60.0F, -20.0F);
        glEdgeFlag(GL_FALSE);  // v2→v0: 内部竖线 不画
        glVertex2f(-20.0F, -40.0F);

        // 下三角: v0=(-20,-40), v1=(0,-80), v2=(20,-40)
        //         v0→v1 外轮廓(TRUE), v1→v2 外轮廓(TRUE), v2→v0 内部边(FALSE)
        glEdgeFlag(GL_TRUE);   // v0→v1: 外轮廓
        glVertex2f(-20.0F, -40.0F);
        glVertex2f(0.0F, -80.0F);
        glEdgeFlag(GL_FALSE);  // v2→v0: 内部横线 不画
        glVertex2f(20.0F, -40.0F);

        // 右三角: v0=(20,0), v1=(60,-20), v2=(20,-40)
        //         v0→v1 外轮廓(TRUE), v1→v2 外轮廓(TRUE), v2→v0 内部边(FALSE)
        glEdgeFlag(GL_TRUE);   // v0→v1: 外轮廓
        glVertex2f(20.0F, 0.0F);
        glVertex2f(60.0F, -20.0F);
        glEdgeFlag(GL_FALSE);  // v2→v0: 内部竖线 不画
        glVertex2f(20.0F, -40.0F);
        glEdgeFlag(GL_TRUE);
    glEnd();

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

/**
 * 首先调用
 * 0000 0000 0x00
 * 0000 0001 0x01
 * 0000 0010 0x02
 * 0000 0011 0x03
 * 0000 0100 0x04
 * 0000 0101 0x05
 * 0000 0110 0x06
 * 0000 0111 0x07
 * 0000 1000 0x08
 * 0000 1001 0x09
 * 0000 1010 0x0A
 * 0000 1011 0x0B
 * 0000 1100 0x0C
 * 0000 1101 0x0D
 * 0000 1110 0x0E
 * 0000 1111 0x0F
 */
void setupRc() {
    std::cout << "setupRc..." << "\n";
    // 使用紫色清除窗口
    glClearColor(0.0F, 0.0F, 0.0F, 1.0F);
    // 使用白色画笔
    glColor3f(1.0F, 1.0F, 1.0F);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // 线框模式
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
    case 27: // ESC 键
    case 'q':
    case 'Q':
        std::cout << "keyboard close..." << "\n";
        exit(0);
        break;
    case 'a':
    case 'A':
        zRot -= 5.0F; // 绕 Z 轴逆时针旋转
        glutPostRedisplay();
        break;
    case 'd':
    case 'D':
        zRot += 5.0F; // 绕 Z 轴顺时针旋转
        glutPostRedisplay();
        break;
    default:
        break;
    }
}

void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y)
              << "\n";
    switch (key) {
    case GLUT_KEY_UP:
        xRot -= 5.0F;
        break;
    case GLUT_KEY_DOWN:
        xRot += 5.0F;
        break;
    case GLUT_KEY_LEFT:
        yRot -= 5.0F;
        break;
    case GLUT_KEY_RIGHT:
        yRot += 5.0F;
        break;
    default:
        break;
    }
    // Refresh the Window
    glutPostRedisplay();
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}

void changeSize(const GLsizei w, const GLsizei h) {
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio =
        static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE,
                -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio,
                -COORDINATE_SIZE, COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio,
                -COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE,
                COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char **argv) {
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:双缓冲 + RGBA
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys); // 特殊键事件
    glutKeyboardFunc(keyboard);   // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose);
    glutReshapeFunc(changeSize); // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format(
                     "lineWidthRange: [{}, {}], lineWidthGranularity: {}",
                     lineWidthRange[0], lineWidthRange[1], lineWidthGranularity)
              << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

螺旋丸

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <format>
#include <iostream>
#include <numbers>

// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度

void renderScene() {

    std::cout << "renderScene..." << "\n";

    static GLdouble radius = 5.0;
    static GLdouble angle = 0.0;

    if (angle == 0.0) {
        glClear(GL_COLOR_BUFFER_BIT); // 清空屏幕
    }

    glBegin(GL_POINTS);
        glVertex2d(radius * std::cos(angle), radius * std::sin(angle));
    glEnd();

    radius *= 1.01;
    angle += 0.1;

    if(angle > 30.0){
        std::cout << "reset angle and radius..." << std::endl;
        angle = 0.0;
        radius = 5.0;
    }

    glFlush(); // 强制执行所有OpenGL命令
}
// 更好看
void renderScene1() {

    std::cout << "renderScene..." << "\n";

    static GLdouble radius = 1.0;
    static GLdouble angle = 0.0;

    if (angle == 0.0) {
        glClear(GL_COLOR_BUFFER_BIT); // 清空屏幕
    }

    glBegin(GL_POINTS);
        glVertex2d(radius * std::cos(angle), radius * std::sin(angle));
    glEnd();

    radius += 0.3; // 阿基米德螺线:每圈间距均匀
    angle += 0.1;

    if(angle > 30.0){
        std::cout << "reset angle and radius..." << std::endl;
        angle = 0.0;
        radius = 1.0;
    }

    glFlush(); // 强制执行所有OpenGL命令
}

void setupRc() {
    std::cout << "setupRc..." << "\n";
    // 使用蓝色清除窗口
    glClearColor(0.0F, 0.0F, 1.0F, 1.0F);
    glColor3f(0.0F, 1.0F, 0.0F);
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
    case 27: // ESC 键
    case 'q':
    case 'Q':
        std::cout << "keyboard close..." << "\n";
        exit(0);
        break;
    case 'a':
    case 'A':
        zRot -= 5.0F; // 绕 Z 轴逆时针旋转
        glutPostRedisplay();
        break;
    case 'd':
    case 'D':
        zRot += 5.0F; // 绕 Z 轴顺时针旋转
        glutPostRedisplay();
        break;
    default:
        break;
    }
}

void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y)
              << "\n";
    switch (key) {
    case GLUT_KEY_UP:
        xRot -= 5.0F;
        break;
    case GLUT_KEY_DOWN:
        xRot += 5.0F;
        break;
    case GLUT_KEY_LEFT:
        yRot -= 5.0F;
        break;
    case GLUT_KEY_RIGHT:
        yRot += 5.0F;
        break;
    default:
        break;
    }
    // Refresh the Window
    glutPostRedisplay();
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}

void changeSize(const GLsizei w, const GLsizei h) {
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio =
        static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE,
                -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio,
                -COORDINATE_SIZE, COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio,
                -COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE,
                COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void timerFunc(int value) {
    std::cout << std::format("timerFunc: value={}", value) << "\n";
    // 重新绘制窗口
    glutPostRedisplay();
    // 再次注册定时器
    glutTimerFunc(33, timerFunc, 1);
}

int main(int argc, char **argv) {
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:单缓冲 + RGB
    glutInitDisplayMode(GLUT_RGB);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys); // 特殊键事件
    glutKeyboardFunc(keyboard);   // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose);
    glutReshapeFunc(changeSize);     // 窗口变化事件
    glutTimerFunc(33, timerFunc, 1); // 每隔 33 毫秒调用一次,约 30 FPS
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format(
                     "lineWidthRange: [{}, {}], lineWidthGranularity: {}",
                     lineWidthRange[0], lineWidthRange[1], lineWidthGranularity)
              << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

剪刀裁剪

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <format>
#include <iostream>
#include <numbers>

// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度

void renderScene() {

    std::cout << "renderScene..." << "\n";

    glClearColor(0.0F, 0.0F, 1.0F, 1.0F); // 设置背景色为黑色
    glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区

    glClearColor(1.0F, 0.0F, 0.0F, 1.0F); // 设置背景色为黑色
    glScissor(100, 100, 600, 400);
    glEnable(GL_SCISSOR_TEST);
    glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区

    glClearColor(0.0F, 1.0F, 0.0F, 1.0F); // 设置背景色为黑色
    glScissor(200, 200, 400, 200);
    glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区

    glDisable(GL_SCISSOR_TEST);

    glFlush(); // 强制执行所有OpenGL命令
}

void setupRc() {
    std::cout << "setupRc..." << "\n";
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
    case 27: // ESC 键
    case 'q':
    case 'Q':
        std::cout << "keyboard close..." << "\n";
        exit(0);
        break;
    case 'a':
    case 'A':
        zRot -= 5.0F; // 绕 Z 轴逆时针旋转
        glutPostRedisplay();
        break;
    case 'd':
    case 'D':
        zRot += 5.0F; // 绕 Z 轴顺时针旋转
        glutPostRedisplay();
        break;
    default:
        break;
    }
}

void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y)
              << "\n";
    switch (key) {
    case GLUT_KEY_UP:
        xRot -= 5.0F;
        break;
    case GLUT_KEY_DOWN:
        xRot += 5.0F;
        break;
    case GLUT_KEY_LEFT:
        yRot -= 5.0F;
        break;
    case GLUT_KEY_RIGHT:
        yRot += 5.0F;
        break;
    default:
        break;
    }
    // Refresh the Window
    glutPostRedisplay();
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}

void changeSize(const GLsizei w, const GLsizei h) {
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio =
        static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE,
                -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio,
                -COORDINATE_SIZE, COORDINATE_SIZE);
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio,
                -COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE,
                COORDINATE_SIZE);
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char **argv) {
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:单缓冲 + RGB
    glutInitDisplayMode(GLUT_RGB);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys); // 特殊键事件
    glutKeyboardFunc(keyboard);   // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose);
    glutReshapeFunc(changeSize);     // 窗口变化事件
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format(
                     "lineWidthRange: [{}, {}], lineWidthGranularity: {}",
                     lineWidthRange[0], lineWidthRange[1], lineWidthGranularity)
              << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}

螺旋模版图案

// mac 特有的头文件
#include <GLUT/glut.h>

// exit
#include <OpenGL/gl.h>
#include <cstdlib>
#include <format>
#include <iostream>
#include <numbers>

// 可视坐标大小
static constexpr GLfloat COORDINATE_SIZE = 100.0F;
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat RADIUS = 50.0F;

// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度

// 正方形的大小
static constexpr GLfloat RECT_SIZE = 25.0F;
 
// 变量
static GLfloat xPos = 0.0F, yPos = 0.0F; // 正方形的初始位置
static GLfloat windowWidthHalf = 0.0F, windowHeightHalf = 0.0F; // 窗口的宽度和高度
// 步进的大小
static GLfloat xStep = 1.0F, yStep = 1.0F;

void renderScene() {

    std::cout << "renderScene..." << "\n";

    glClearStencil(0x0);
    glEnable(GL_STENCIL_TEST);

    glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    glStencilFunc(GL_NEVER, 0x0, 0x0);
    glStencilOp(GL_INCR, GL_INCR, GL_INCR);
    GLdouble radius = 0.1;
    glBegin(GL_LINE_STRIP);
        for (GLfloat angle = 0.0F; angle <= 2 * PI * 65; angle += 0.1F) {
            glVertex2f(radius * cos(angle), radius * sin(angle));
            radius += 0.1;
        }
    glEnd();

    glStencilFunc(GL_NOTEQUAL, 0x1, 0x1);
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

    glColor3f(1.0F, 0.0F, 0.0F);

    glRectf(xPos, yPos, xPos + RECT_SIZE, yPos - RECT_SIZE);

    glutSwapBuffers();
}

void setupRc() {
    std::cout << "setupRc..." << "\n";
    glClearColor(0.0F, 0.0F, 1.0F, 1.0F); // 设置背景色为蓝色
    glColor3f(1.0F, 1.0F, 1.0F);          // 设置绘制颜色为白色
}

// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
    std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
    switch (key) {
    case 27: // ESC 键
    case 'q':
    case 'Q':
        std::cout << "keyboard close..." << "\n";
        exit(0);
        break;
    case 'a':
    case 'A':
        zRot -= 5.0F; // 绕 Z 轴逆时针旋转
        glutPostRedisplay();
        break;
    case 'd':
    case 'D':
        zRot += 5.0F; // 绕 Z 轴顺时针旋转
        glutPostRedisplay();
        break;
    default:
        break;
    }
}

void specialKeys(const int key, const int x, const int y) {
    std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y)
              << "\n";
    switch (key) {
    case GLUT_KEY_UP:
        xRot -= 5.0F;
        break;
    case GLUT_KEY_DOWN:
        xRot += 5.0F;
        break;
    case GLUT_KEY_LEFT:
        yRot -= 5.0F;
        break;
    case GLUT_KEY_RIGHT:
        yRot += 5.0F;
        break;
    default:
        break;
    }
    // Refresh the Window
    glutPostRedisplay();
}

// 窗口关闭回调(点击红色关闭按钮)
void onClose() {
    std::cout << "window close..." << "\n";
    exit(0);
}

void changeSize(const GLsizei w, const GLsizei h) {
    std::cout << std::format("changeSize: w={}, h={}", w, h) << "\n";
    // 防止除以 0
    if (h == 0) {
        throw std::runtime_error("h == 0");
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); // 投影
    glLoadIdentity();
    const GLfloat aspectRatio =
        static_cast<GLfloat>(w) / static_cast<GLfloat>(h);
    if (w < h) {
        glOrtho(-COORDINATE_SIZE, COORDINATE_SIZE,
                -COORDINATE_SIZE / aspectRatio, COORDINATE_SIZE / aspectRatio,
                -COORDINATE_SIZE, COORDINATE_SIZE);
        windowWidthHalf = 100.0F;
        windowHeightHalf = 100.0F / aspectRatio;
    } else {
        glOrtho(-COORDINATE_SIZE * aspectRatio, COORDINATE_SIZE * aspectRatio,
                -COORDINATE_SIZE, COORDINATE_SIZE, -COORDINATE_SIZE,
                COORDINATE_SIZE);
        windowWidthHalf = 100.0F * aspectRatio;
        windowHeightHalf = 100.0F;
    }
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void timerFunc(const int value) {
    std::cout << std::format("timerFunc: value={}, windowWidthHalf={}, windowHeightHalf={}", value, windowWidthHalf, windowHeightHalf) << "\n";
    if (xPos + RECT_SIZE >= windowWidthHalf || xPos <= -windowWidthHalf) {
        xStep = -xStep;
    }
    if(yPos - RECT_SIZE <= -windowHeightHalf || yPos >= windowHeightHalf){
        yStep = -yStep;
    }
    xPos += xStep;
    yPos += yStep;
    // 窗口变小了,正方形可能会超出窗口范围,需要重新计算位置
    if (xPos + RECT_SIZE > windowWidthHalf) {
        xPos = windowWidthHalf - RECT_SIZE;
    } else if (xPos < -windowWidthHalf) {
        xPos = -windowWidthHalf;
    }
    if (yPos > windowHeightHalf) {
        yPos = windowHeightHalf;
    } else if (yPos - RECT_SIZE < -windowHeightHalf) {
        yPos = -windowHeightHalf + RECT_SIZE;
    }
    glutPostRedisplay(); // 重新绘制窗口
    glutTimerFunc(33, timerFunc, 1); // 每隔 33 毫秒调用一次,约 30 FPS
}

int main(int argc, char **argv) {
    // 初始化 glut 必须在 main() 中调用,且必须在创建窗口之前调用
    glutInit(&argc, argv);

    // 设置显示模式:单缓冲 + RGB + 模板缓冲区
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_STENCIL);

    // 设置窗口大小
    glutInitWindowSize(800, 600);
    glutCreateWindow("Hello World");

    // 注册 窗口变化 回调
    glutDisplayFunc(renderScene);
    // 注册 键盘事件 回调
    glutSpecialFunc(specialKeys); // 特殊键事件
    glutKeyboardFunc(keyboard);   // 普通键事件
    // 注册 窗口关闭 回调(mac已经移除对其支持)
    glutWMCloseFunc(onClose);
    glutReshapeFunc(changeSize);     // 窗口变化事件
    glutTimerFunc(33, timerFunc, 1); // 每隔 33 毫秒调用一次,约 30 FPS
    // 设置 OpenGL 环境
    setupRc();

    // 获取支持的线宽范围
    GLfloat lineWidthRange[2];
    glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidthRange);
    // 获取支持的线宽精度
    GLfloat lineWidthGranularity;
    glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &lineWidthGranularity);
    std::cout << std::format(
                     "lineWidthRange: [{}, {}], lineWidthGranularity: {}",
                     lineWidthRange[0], lineWidthRange[1], lineWidthGranularity)
              << "\n";

    // 进入 GLUT 事件处理循环
    glutMainLoop();
    std::cout << "hello world\n";
    return 0;
}
posted @ 2026-08-01 20:07  爱情丶眨眼而去  阅读(28)  评论(0)    收藏  举报