顶点着色器 glsl qt 中的纹理映射

Posted

技术标签:

【中文标题】顶点着色器 glsl qt 中的纹理映射【英文标题】:Texture mapping in vertex shader glsl qt 【发布时间】:2021-05-08 07:26:13 【问题描述】:

我正在尝试使用 QOpenGLWindow 在 opengl 中通过纹理映射实现每个顶点照明。但是渲染的对象是黑色的。如果我在片段着色器中进行相同的纹理映射,它工作正常。

//Vertex Shader        
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec3 tangent;
layout (location = 3) in vec3 bitangent;
layout (location = 4) in vec2 texCoords;

out vec4 afragColor;

vec3 fragPos;
out vec2 fragTexCoords;
mat3 TBN;

uniform sampler2D diffuseMap;
uniform sampler2D specularMap;
uniform sampler2D bumpMap;

vec3 calcAmbientLight(int idx, vec3 color, float ambient) 
    return ambient * color * vec3(ambientLight[idx].color);


vec3 calcDirectionalLight(int idx, vec3 normal, vec3 color, float diff, float spec) 
    vec3 lightDir = normalize(-vec3(directionalLight[idx].direction));
    vec3 viewDir = normalize(vec3(viewPos) - fragPos);
    vec3 reflectDir = reflect(-lightDir, normal);

    vec3 result = vec3(0.0f);
    result += diff * color * max(dot(normal, lightDir), 0.0f);
    result += spec * color * pow(max(dot(viewDir, reflectDir), 0.0f), material.shininess);

    return result * vec3(directionalLight[idx].color);


vec3 calcPointLight(int idx, vec3 normal, vec3 color, float diff, float spec) 
    vec3 lightDir = normalize(vec3(pointLight[idx].pos) - fragPos);
    vec3 viewDir = normalize(vec3(viewPos) - fragPos);
    vec3 reflectDir = reflect(-lightDir, normal);
    float dis = length(vec3(pointLight[idx].pos) - fragPos);

    vec3 result = vec3(0.0f);
    result += diff * color * max(dot(normal, lightDir), 0.0f);
    result += spec * color * pow(max(dot(viewDir, reflectDir), 0.0f), material.shininess);

    float attenuation = 1.0f / (pointLight[idx].attenuation[3]
                            + pointLight[idx].attenuation[2] * dis
                            + pointLight[idx].attenuation[1] * dis * dis);
    result *= attenuation * pointLight[idx].attenuation[0] + (1.0f - pointLight[idx].attenuation[0]);

    return result * vec3(pointLight[idx].color);


vec3 calcSpotLight(int idx, vec3 normal, vec3 color, float diff, float spec) 
    vec3 lightDir = normalize(vec3(spotLight[idx].pos) - fragPos);
    vec3 viewDir = normalize(vec3(viewPos) - fragPos);
    vec3 reflectDir = reflect(-lightDir, normal);
    float dis = length(vec3(spotLight[idx].pos) - fragPos);
    float theta = dot(lightDir, normalize(-vec3(spotLight[idx].direction)));
    float intensity = (theta - spotLight[idx].cutOff[1]) / (spotLight[idx].cutOff[0] - spotLight[idx].cutOff[1]);

    vec3 result = vec3(0.0f);
    result += diff * color * max(dot(normal, lightDir), 0.0f);
    result += spec * color * pow(max(dot(viewDir, reflectDir), 0.0f), material.shininess);

    float attenuation = 1.0f / (spotLight[idx].attenuation[3]
                            + spotLight[idx].attenuation[2] * dis
                            + spotLight[idx].attenuation[1] * dis * dis);
    result *= attenuation * spotLight[idx].attenuation[0] + (1.0f - spotLight[idx].attenuation[0]);

    return result * vec3(spotLight[idx].color) * clamp(intensity, 0.0f, 1.0f);



void main() 
    vec3 T = normalize(mat3(modelMat) * tangent);
    vec3 B = normalize(mat3(modelMat) * bitangent);
    vec3 N = normalize(mat3(normalMat) * normal);
    
    fragPos = vec3(modelMat * vec4(position, 1.0f));
    fragTexCoords = texCoords;
    TBN = mat3(T, B, N);

    mat4 MVP = projMat * viewMat * modelMat;

    vec3 color  = material.useDiffuseMap == 1 ? texture(diffuseMap, fragTexCoords).rgb : vec3(material.color);
    float spec  = material.useSpecularMap == 1 ? texture(specularMap, fragTexCoords).r : material.specular;
    vec3 normal = material.useBumpMap == 1 ? texture(bumpMap, fragTexCoords).rgb * 2 - 1 : vec3(0, 0, 1);
    normal = normalize(TBN * normalize(normal));

    afragColor = vec4(0, 0, 0, 1);

    for (int i = 0; i < ambientLightNum; i++)
        afragColor += vec4(calcAmbientLight(i, color, material.ambient), 1);

    for (int i = 0; i < directionalLightNum; i++)
        afragColor += vec4(calcDirectionalLight(i, normal, color, material.diffuse, spec), 1);

    for (int i = 0; i < pointLightNum; i++)
        afragColor += vec4(calcPointLight(i, normal, color, material.diffuse, spec), 1);

    for (int i = 0; i < spotLightNum; i++)
        afragColor += vec4(calcSpotLight(i, normal, color, material.diffuse, spec), 1);

    if (highlighted == 1)
        afragColor += vec4(0.2, 0.2, 0.2, 0);

    if (selected == 1)
        afragColor += vec4(0, 0, 0.4, 0);

    gl_Position = MVP * vec4(position, 1.0f);
    if (sizeFixed == 1) 
        float w = (MVP * vec4(0.0f, 0.0f, 0.0f, 1.0f)).w / 100;
        gl_Position = MVP * vec4(position * w, 1.0f);
    







//Fragment Shader

out vec4 fragColor;

in vec4 afragColor;
void main() 
    fragColor = afragColor;


我觉得顶点着色器返回一个很暗的颜色,但也不做纹理映射。 谢谢

【问题讨论】:

当顶点着色器在片段着色器中工作时,为什么要尝试在顶点着色器中执行此操作?顶点着色器只针对每个顶点执行。因此,仅查找图元的顶点(角)的纹理。顶点着色器的输出沿片段进行插值。您不能在顶点着色器中执行此算法。您需要在片段着色器中为每个片段执行此操作。 我这样做是为了实现每个顶点照明,所以我们不能在顶点着色器中进行纹理映射。如果不是,那么我们如何在顶点着色器中进行纹理映射? 您必须在片段着色器中进行纹理映射。您不能在顶点着色器中执行此操作。为什么要做“逐顶点照明”? “逐顶点光照”的质量很差,并且会丢失镜面高光。 “per vertex lighting”仅对恒定漫射光有意义。 谢谢,但是在每个顶点光照中,我们通常在顶点着色器中计算光照并在片段着色器中进行纹理映射吗? "per vertex lighting" 只对恒定漫射光敏感。对于镜面高光和纹理映射,您需要一个片段着色器。 Per-vertex Lighting 仅用于非常简单的光照模型,现在一般不使用。 【参考方案1】:

顶点着色器只针对每个顶点执行。因此,仅查找图元的顶点(角)的纹理。顶点着色器的输出沿片段进行插值。您不能在顶点着色器中执行此算法。您需要在片段着色器中为每个片段执行此操作。 “Per Vertex Lighting”仅对恒定漫射光有意义。在镜面高光和纹理贴图的情况下,光分布不是线性的,无法用线性插值计算。 Per-vertex Lighting 仅用于非常简单的光照模型,现在一般不使用。

【讨论】:

以上是关于顶点着色器 glsl qt 中的纹理映射的主要内容,如果未能解决你的问题,请参考以下文章

GLSL索引绘图并设置纹理案例

在GLSL ES中的片段着色器上旋转纹理

为啥我的着色器中的 GLSL 纹理坐标不是线性的?

GLSL 偏移多纹理

GLSL 多纹理 - 混合纹理

手动使用圆柱体中间表面进行纹理映射