返回

用 OpenGL 构建 3D 图形世界的关键

Android

揭秘 OpenGL 模型加载的奥秘

首先,我们必须将 3D 建模工具构建的物体导出为特定的文件格式,而后才能通过 OpenGL 进行渲染。其中,obj 模型文件因其简单、文本化的特点,成为许多开发者的首选。obj 文件将顶点信息、纹理信息、法线信息等一系列数据按照固定格式组织起来,便于 OpenGL 加载和解析。

// 加载模型
const char* filename = "model.obj";
FILE* file = fopen(filename, "r");
if (file == NULL) {
  printf("Error: cannot open file %s\n", filename);
  return;
}

// 逐行读取模型数据
while (true) {
  char line[256];
  if (fgets(line, sizeof(line), file) == NULL) {
    break;
  }

  // 解析顶点信息
  if (strncmp(line, "v ", 2) == 0) {
    float x, y, z;
    sscanf(line, "v %f %f %f", &x, &y, &z);
    // 将顶点数据存储到数组中
  }

  // 解析纹理信息
  if (strncmp(line, "vt ", 3) == 0) {
    float u, v;
    sscanf(line, "vt %f %f", &u, &v);
    // 将纹理数据存储到数组中
  }

  // 解析法线信息
  if (strncmp(line, "vn ", 3) == 0) {
    float nx, ny, nz;
    sscanf(line, "vn %f %f %f", &nx, &ny, &nz);
    // 将法线数据存储到数组中
  }

  // 解析面信息
  if (strncmp(line, "f ", 2) == 0) {
    int v1, v2, v3;
    sscanf(line, "f %d/%d/%d %d/%d/%d %d/%d/%d", &v1, &v1, &v1, &v2, &v2, &v2, &v3, &v3, &v3);
    // 将面数据存储到数组中
  }
}

// 关闭文件
fclose(file);

掌握 OpenGL 渲染技巧,让 3D 模型栩栩如生

加载模型只是第一步,为了让模型在屏幕上显示出来,我们还需要进行渲染。渲染过程主要包括顶点着色、片元着色和光栅化三个步骤。

顶点着色负责将顶点坐标从模型空间转换到屏幕空间,并计算每个顶点的颜色和纹理坐标。片元着色负责计算每个片元的颜色,并将其写入帧缓冲区。光栅化则将片元信息转化为屏幕上的像素。

// 顶点着色器
const char* vertex_shader_source =
  "attribute vec3 position;"
  "attribute vec2 texcoord;"
  "uniform mat4 modelviewprojection;"
  "varying vec2 v_texcoord;"
  "void main() {"
    "v_texcoord = texcoord;"
    "gl_Position = modelviewprojection * vec4(position, 1.0);"
  "}";

// 片元着色器
const char* fragment_shader_source =
  "uniform sampler2D texture0;"
  "varying vec2 v_texcoord;"
  "void main() {"
    "gl_FragColor = texture2D(texture0, v_texcoord);"
  "}";

// 编译着色器
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
glCompileShader(vertex_shader);

GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
glCompileShader(fragment_shader);

// 创建着色器程序
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);

// 使用着色器程序
glUseProgram(program);

// 设置模型视图投影矩阵
glUniformMatrix4fv(glGetUniformLocation(program, "modelviewprojection"), 1, GL_FALSE, &modelviewprojection[0][0]);

// 设置纹理
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture0);
glUniform1i(glGetUniformLocation(program, "texture0"), 0);

// 渲染模型
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_INT, 0);

结语

通过本文的介绍,相信大家对 OpenGL 模型加载和渲染有了更深入的理解。无论是初学者还是经验丰富的开发者,都可以利用 OpenGL 的强大功能打造出令人惊叹的 3D 图形世界。如果你想了解更多关于 OpenGL 的知识,不妨继续探索相关教程和文档,相信你会有更多收获。