如何在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
相关产品推荐
相关产品推荐

