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

使用两个VAO/VBO渲染不同对象时,顶点着色器该如何编写?

问题解决:双VAO/VBO渲染对象的顶点着色器修正

你的核心错误是把两个对象的渲染逻辑都塞进了同一个顶点着色器main函数,顶点着色器是针对单次绘制调用的每个顶点执行的,最后一行的gl_Position赋值会完全覆盖前面的,导致只有第二个对象的计算逻辑生效,而第一个对象的VAO并没有提供vertexPositionMotorcycle这类属性,自然无法正确渲染。

下面是两种可行的修正方案:


方案1:共用同一套着色器(推荐)

这是最常用的方式,因为两个对象的渲染逻辑本质是一致的,只是模型矩阵、纹理等参数不同。

修改后的顶点着色器

只保留一套通用变量,不要给变量加对象后缀:

#version 330 core
layout (location = 0) in vec3 vertexPosition;
layout (location = 1) in vec3 vertexNormal;
layout (location = 2) in vec3 vertexColor;
layout (location = 3) in vec2 vertexTexCoord;

uniform mat4 model_matrix;
uniform mat4 normal_matrix;
uniform mat4 projection_view_matrix;

out vec3 worldSpacePosition;
out vec3 worldSpaceNormal;
out vec3 objectColor;
out vec2 shaderTexCoord;

void main()
{
    worldSpacePosition = (model_matrix * vec4(vertexPosition, 1.0f)).xyz;
    worldSpaceNormal = (normal_matrix * vec4(vertexNormal, 0.0f)).xyz; // 法线用0.0f避免平移影响
    objectColor = vertexColor;
    shaderTexCoord = vertexTexCoord;
    gl_Position = projection_view_matrix * vec4(worldSpacePosition, 1.0f);
}

对应Render代码调整

每次绘制前更新Uniform参数,绑定对应纹理和VAO:

// 绘制第一个对象(卡车)
// 1. 设置纹理:绑定卡车纹理到纹理单元0,传递给着色器的sampler
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, truckTexture);
glUniform1i(glGetUniformLocation(shaderProgram, "objectTexture"), 0);

// 2. 更新Uniform参数为卡车的矩阵
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model_matrix"), 1, GL_FALSE, &truckModelMatrix[0][0]);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "normal_matrix"), 1, GL_FALSE, &truckNormalMatrix[0][0]);
// 投影视图矩阵如果两个对象共用,只需要设置一次,不用重复设置
// glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection_view_matrix"), 1, GL_FALSE, &projViewMatrix[0][0]);

// 3. 绑定VAO并绘制
glBindVertexArray(vao1);
glDrawArrays(GL_TRIANGLES, 0, indicesNo1);


// 绘制第二个对象(摩托车)
// 1. 设置纹理:绑定摩托车纹理到纹理单元0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, motorcycleTexture);
glUniform1i(glGetUniformLocation(shaderProgram, "objectTexture"), 0);

// 2. 更新Uniform参数为摩托车的矩阵
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model_matrix"), 1, GL_FALSE, &motorcycleModelMatrix[0][0]);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "normal_matrix"), 1, GL_FALSE, &motorcycleNormalMatrix[0][0]);

// 3. 绑定VAO并绘制
glBindVertexArray(vao2);
glDrawArrays(GL_TRIANGLES, 0, indicesNo2);

方案2:使用两套独立的着色器程序

如果两个对象的渲染逻辑差异极大(比如一个是卡通渲染,一个是PBR),可以为每个对象单独编写着色器程序。

  • 为卡车编写一套顶点/片段着色器,编译链接成truckShaderProgram
  • 为摩托车编写另一套顶点/片段着色器,编译链接成motorcycleShaderProgram

Render代码调整为:

// 绘制卡车
glUseProgram(truckShaderProgram);
// 设置卡车的纹理、矩阵Uniform
glBindVertexArray(vao1);
glDrawArrays(GL_TRIANGLES, 0, indicesNo1);

// 绘制摩托车
glUseProgram(motorcycleShaderProgram);
// 设置摩托车的纹理、矩阵Uniform
glBindVertexArray(vao2);
glDrawArrays(GL_TRIANGLES, 0, indicesNo2);

关于gl_InstanceID的说明

gl_InstanceID是用于实例化绘制(比如glDrawArraysInstanced)的,当你需要一次性绘制大量相同模型(比如一片树林)时,用它来区分不同实例的参数。而你现在是两次独立的glDrawArrays调用,每次调用都是处理单个对象,完全不需要用到gl_InstanceID。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 01:47:17