You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C语言中使用OpenGL初始化投影矩阵?代码改写求助

在C语言中使用vmath库初始化OpenGL投影矩阵(改写spinnycube.cpp)

我帮你梳理下在C环境下用sb7的vmath库初始化投影矩阵的关键点,同时补全你代码里缺失的部分,适配C语言的特性:

首先,sb7的vmath库本身是兼容C语言的,只是不能像C++那样用运算符重载,得用库提供的函数来创建和操作矩阵。下面是完整的修正代码片段,重点看投影矩阵的初始化和传递部分:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <GL/gl.h>
#include "vmath.h"

// Remove this to draw only a single cube!
// #define MANY_CUBES

// keep track of window size for things like the viewport and the mouse cursor
int g_gl_width = 640;
int g_gl_height = 480;
GLuint program;
GLuint vao;

// a call-back function
void glfw_window_size_callback(GLFWwindow* window, int width, int height) {
    g_gl_width = width;
    g_gl_height = height;
    glViewport(0, 0, width, height);
}

// 简单的顶点着色器源码(C语言里用const char数组)
const char* vertex_shader_src = 
    "#version 450 core\n"
    "layout (location = 0) in vec4 position;\n"
    "uniform mat4 proj_matrix;\n"
    "uniform mat4 mv_matrix;\n"
    "void main()\n"
    "{\n"
    "    gl_Position = proj_matrix * mv_matrix * position;\n"
    "}\n";

// 片段着色器源码
const char* fragment_shader_src = 
    "#version 450 core\n"
    "out vec4 color;\n"
    "void main()\n"
    "{\n"
    "    color = vec4(0.8, 0.8, 0.8, 1.0);\n"
    "}\n";

// 创建编译着色器的辅助函数
GLuint create_shader(GLenum type, const char* src) {
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, &src, NULL);
    glCompileShader(shader);
    // 可以加编译错误检查,这里简化了
    return shader;
}

int main() {
    // start GL context and O/S window using the GLFW helper library
    if (!glfwInit()) {
        fprintf(stderr, "ERROR: could not start GLFW3\n");
        return 1;
    }

    GLFWwindow* window = glfwCreateWindow(g_gl_width, g_gl_height, "Spinny Cube (C Version)", NULL, NULL);
    if (!window) {
        fprintf(stderr, "ERROR: could not open window with GLFW3\n");
        glfwTerminate();
        return 1;
    }
    glfwSetWindowSizeCallback(window, glfw_window_size_callback);
    glfwMakeContextCurrent(window);

    // 初始化GLEW
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK) {
        fprintf(stderr, "ERROR: could not initialize GLEW\n");
        return 1;
    }

    // 获取OpenGL版本信息
    const GLubyte* renderer = glGetString(GL_RENDERER);
    const GLubyte* version = glGetString(GL_VERSION);
    printf("Renderer: %s\n", renderer);
    printf("OpenGL version supported: %s\n", version);

    // 启用深度测试
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    // 创建并链接着色器程序
    GLuint vs = create_shader(GL_VERTEX_SHADER, vertex_shader_src);
    GLuint fs = create_shader(GL_FRAGMENT_SHADER, fragment_shader_src);
    program = glCreateProgram();
    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    // 可以加链接错误检查
    glDeleteShader(vs);
    glDeleteShader(fs);

    // 获取uniform位置
    GLint proj_loc = glGetUniformLocation(program, "proj_matrix");
    GLint mv_loc = glGetUniformLocation(program, "mv_matrix");

    // 立方体顶点数据
    float vertices[] = {
        -0.5f, -0.5f, -0.5f,
         0.5f, -0.5f, -0.5f,
         0.5f,  0.5f, -0.5f,
        -0.5f,  0.5f, -0.5f,
        -0.5f, -0.5f,  0.5f,
         0.5f, -0.5f,  0.5f,
         0.5f,  0.5f,  0.5f,
        -0.5f,  0.5f,  0.5f
    };

    // 索引数据
    unsigned int indices[] = {
        0, 1, 2, 2, 3, 0,
        4, 5, 6, 6, 7, 4,
        0, 4, 7, 7, 3, 0,
        1, 5, 6, 6, 2, 1,
        3, 2, 6, 6, 7, 3,
        0, 1, 5, 5, 4, 0
    };

    // 创建VAO和VBO
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    GLuint vbo, ebo;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // 主循环
    while (!glfwWindowShouldClose(window)) {
        // 清屏
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glUseProgram(program);

        // 初始化投影矩阵:用vmath_perspective函数
        vmat4 proj_matrix = vmath_perspective(60.0f, (float)g_gl_width / g_gl_height, 0.1f, 100.0f);
        // 传递投影矩阵给着色器:注意取vmat4内部的m数组
        glUniformMatrix4fv(proj_loc, 1, GL_FALSE, proj_matrix.m);

        // 计算模型视图矩阵(示例:旋转的立方体)
        float time = (float)glfwGetTime();
        vmat4 mv_matrix = vmath_translate(0.0f, 0.0f, -2.0f);
        mv_matrix = vmath_rotate(mv_matrix, time * 90.0f, 0.0f, 1.0f, 0.0f);
        mv_matrix = vmath_rotate(mv_matrix, time * 45.0f, 1.0f, 0.0f, 0.0f);
        // 传递模型视图矩阵
        glUniformMatrix4fv(mv_loc, 1, GL_FALSE, mv_matrix.m);

        // 绘制立方体
        glBindVertexArray(vao);
        glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);

        // 交换缓冲区和处理事件
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 清理资源
    glDeleteVertexArrays(1, &vao);
    glDeleteProgram(program);
    glfwTerminate();
    return 0;
}

关键要点说明:

  • vmath库的C语言用法:sb7的vmath为C提供了函数式的矩阵操作,比如vmath_perspective创建透视投影矩阵,vmath_translate、vmath_rotate来构建模型视图矩阵,这些函数返回vmat4结构体,内部包含一个float m[16]的数组存储矩阵数据。
  • 传递矩阵到着色器:C语言中不能直接把vmat4传给glUniformMatrix4fv,需要传入结构体内部的m数组(矩阵的列主序数据,符合OpenGL的要求),第三个参数传GL_FALSE表示不需要转置。
  • 窗口大小变化时更新:在窗口大小回调里要调用glViewport,同时如果需要的话,可以在这里重新计算投影矩阵(不过示例里是在每一帧计算,也可以优化成窗口变化时才更新)。
  • 着色器处理:C语言里用const char*数组来存储着色器源码,和C++的字符串用法一致,编译链接流程也相同。

内容的提问来源于stack exchange,提问作者Kroka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:16:35