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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 14:35:57