OpenGL GLFW实现单个网格三角面独立着色的方案咨询
为网格单个三角面设置独立颜色的实现方法
我当前用以下代码渲染网格三角面:
// draw the same polygons again glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); shader.setVec3("objectColor", obj_color); glDrawElements(GL_TRIANGLES, static_cast<unsigned int>(indices.size()), GL_UNSIGNED_INT, 0);
问题在于这段代码通过着色器给整个网格设置了统一的objectColor,无法实现单个三角面的独立上色。目前我仅了解顶点着色的方法(将顶点颜色传入片段着色器),自己想到的思路是复制网格顶点来避免颜色插值,想知道设置单个三角面颜色的常见方式。
当前着色器代码如下:
顶点着色器
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; out vec3 FragPos; out vec3 Normal; out vec3 LightPos; uniform vec3 lightPos; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { gl_Position = projection * view * model * vec4(aPos, 1.0); FragPos = vec3(view * model * vec4(aPos, 1.0)); Normal = mat3(transpose(inverse(view * model))) * aNormal; LightPos = vec3(vec4(lightPos, 1.0)); // Transform world-space light position to view-space light position // FragPos = vec3(model * vec4(aPos, 1.0)); //Normal = mat3(transpose(inverse(model))) * aNormal; // gl_Position = projection * view * vec4(FragPos, 1.0); }
片段着色器
#version 330 core out vec4 FragColor; in vec3 FragPos; in vec3 Normal; in vec3 LightPos; // extra in variable, since we need the light position in view space we calculate this in the vertex shader uniform vec3 lightColor; uniform vec3 objectColor; uniform float f; uniform float transparency; void main() { //flat shading // vec3 x_ = dFdx(FragPos); // vec3 y_= dFdy(FragPos); // vec3 normal_ = cross(x_, y_); // vec3 norm_ = normalize(normal_); // ambient float ambientStrength = 0.75; vec3 ambient = ambientStrength * lightColor; // diffuse vec3 norm = normalize(Normal); vec3 lightDir = normalize(LightPos - FragPos); float diff = max(dot(norm, lightDir), 0.0);//change "norm_" to "norm" avoid the performance warning and have unwelded view vec3 diffuse = diff * lightColor; // specular float specularStrength = 0.01; vec3 viewDir = normalize(-FragPos); // the viewer is always at (0,0,0) in view-space, so viewDir is (0,0,0) - Position => -Position vec3 reflectDir = reflect(-lightDir, norm); float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); vec3 specular = specularStrength * spec * lightColor; vec3 shading = (ambient + diffuse + specular)*objectColor; //float f = 0.75; float r_interpolated = shading[0] + f * (objectColor[0] - shading[0]); float g_interpolated = shading[1] + f * (objectColor[1] - shading[1]); float b_interpolated = shading[2] + f * (objectColor[2] - shading[2]); vec3 result = vec3(r_interpolated,g_interpolated,b_interpolated); FragColor = vec4(result, transparency); }
常见的单三角面着色方法
- 复制顶点:每个三角面的三个顶点单独存储,不共享顶点数据,给每个面的三个顶点设置相同颜色。光栅化时颜色插值不会跨面,每个面保持纯色。优点是逻辑简单,缺点是增加顶点数据量,适合小网格。
- 面ID索引颜色数组:给每个三角面分配唯一ID,将ID作为顶点属性传入着色器,片段着色器用ID索引存储所有面颜色的uniform数组。无需复制顶点,但uniform数组有大小限制。
- 纹理存储面颜色:把每个面的颜色编码到1D纹理中,用面ID作为纹理坐标采样。适合面数量多的场景,突破uniform数组大小限制。
- 几何着色器生成面颜色:在几何着色器中为整个三角面输出统一颜色,传递给片段着色器。无需修改顶点数据,但会增加性能开销,适合动态生成面颜色的场景。
具体实现方案(以复制顶点+顶点颜色为例)
1. 修改顶点数据结构
在顶点属性中添加颜色字段,每个三角面的三个顶点使用相同颜色:
// 修改后的顶点结构 struct Vertex { glm::vec3 pos; glm::vec3 normal; glm::vec3 color; // 新增颜色属性 }; // 构建网格时,每个三角面的三个顶点单独添加,设置对应面的颜色 vertices.push_back({pos0, normal0, {1.0f, 0.0f, 0.0f}}); vertices.push_back({pos1, normal1, {1.0f, 0.0f, 0.0f}}); vertices.push_back({pos2, normal2, {1.0f, 0.0f, 0.0f}}); vertices.push_back({pos3, normal3, {0.0f, 1.0f, 0.0f}}); vertices.push_back({pos4, normal4, {0.0f, 1.0f, 0.0f}}); vertices.push_back({pos5, normal5, {0.0f, 1.0f, 0.0f}});
2. 更新顶点着色器
添加颜色输入属性,并传递给片段着色器:
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; layout (location = 2) in vec3 aColor; // 新增颜色属性 out vec3 FragPos; out vec3 Normal; out vec3 LightPos; out vec3 VertexColor; // 传递颜色到片段着色器 uniform vec3 lightPos; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { gl_Position = projection * view * model * vec4(aPos, 1.0); FragPos = vec3(view * model * vec4(aPos, 1.0)); Normal = mat3(transpose(inverse(view * model))) * aNormal; LightPos = vec3(vec4(lightPos, 1.0)); VertexColor = aColor; // 赋值输出颜色 }
3. 更新片段着色器
用VertexColor替代原有的objectColor:
#version 330 core out vec4 FragColor; in vec3 FragPos; in vec3 Normal; in vec3 LightPos; in vec3 VertexColor; // 接收顶点颜色 uniform vec3 lightColor; uniform float f; uniform float transparency; // 移除uniform的objectColor void main() { // ambient float ambientStrength = 0.75; vec3 ambient = ambientStrength * lightColor; // diffuse vec3 norm = normalize(Normal); vec3 lightDir = normalize(LightPos - FragPos); float diff = max(dot(norm, lightDir), 0.0); vec3 diffuse = diff * lightColor; // specular float specularStrength = 0.01; vec3 viewDir = normalize(-FragPos); vec3 reflectDir = reflect(-lightDir, norm); float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); vec3 specular = specularStrength * spec * lightColor; vec3 shading = (ambient + diffuse + specular) * VertexColor; float r_interpolated = shading[0] + f * (VertexColor[0] - shading[0]); float g_interpolated = shading[1] + f * (VertexColor[1] - shading[1]); float b_interpolated = shading[2] + f * (VertexColor[2] - shading[2]); vec3 result = vec3(r_interpolated,g_interpolated,b_interpolated); FragColor = vec4(result, transparency); }
4. 配置VAO的颜色属性
添加颜色属性的顶点指针:
// 绑定VAO和VBO后执行 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, color)); glEnableVertexAttribArray(2);
5. 修改渲染代码
移除设置objectColor的代码,直接绘制:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // shader.setVec3("objectColor", obj_color); // 删除该行 glDrawElements(GL_TRIANGLES, static_cast<unsigned int>(indices.size()), GL_UNSIGNED_INT, 0);
内容的提问来源于stack exchange,提问作者PetrasVestartasEPFL
相关产品推荐
相关产品推荐

