Where is surface "shininess" specified in these shaders?

  • I have little experience with OpenGL shader programs - can someone please help me understand some GLSL shader code?

    I have source code for Qt 5.14.2, including DataVisualization, and would like to modify the source to reduce specular “shininess” from Surface3D. This screenshot shows a Surface3D that depicts topography, and it has a very “shiny” look to it. Debugging with gdb I’ve determined that the following shaders are generating this surface. Could someone please comment on how this shader code affects the shininess of the surface? The code doesn't look like it's directly based on the Phong reflection model, e.g. I don't see an exponential "shininess" term in the code.

    vertex shader:

    #version 120
    uniform highp mat4 MVP;
    uniform highp mat4 V;
    uniform highp mat4 M;
    uniform highp mat4 itM;
    uniform highp mat4 depthMVP;
    uniform highp vec3 lightPosition_wrld;
    attribute highp vec3 vertexPosition_mdl;
    attribute highp vec3 vertexNormal_mdl;
    attribute highp vec2 vertexUV;
    varying highp vec2 UV;
    varying highp vec3 position_wrld;
    varying highp vec3 normal_cmr;
    varying highp vec3 eyeDirection_cmr;
    varying highp vec3 lightDirection_cmr;
    varying highp vec4 shadowCoord;
    varying highp vec2 coords_mdl;
    const highp mat4 bias = mat4(0.5, 0.0, 0.0, 0.0,
                                 0.0, 0.5, 0.0, 0.0,
                                 0.0, 0.0, 0.5, 0.0,
                                 0.5, 0.5, 0.5, 1.0);
    void main() {
        gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
        coords_mdl = vertexPosition_mdl.xy;
        shadowCoord = bias * depthMVP * vec4(vertexPosition_mdl, 1.0);
        position_wrld = vec4(M * vec4(vertexPosition_mdl, 1.0)).xyz;
        vec3 vertexPosition_cmr = vec4(V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
        eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
       lightDirection_cmr = vec4(V * vec4(lightPosition_wrld, 0.0)).xyz;
        normal_cmr = vec4(V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
        UV = vertexUV;

    fragment shader:

    #version 120
    varying highp vec2 coords_mdl;
    varying highp vec3 position_wrld;
    varying highp vec3 normal_cmr;
    varying highp vec3 eyeDirection_cmr;
    varying highp vec3 lightDirection_cmr;
    varying highp vec4 shadowCoord;
    uniform highp sampler2DShadow shadowMap;
    uniform sampler2D textureSampler;
    uniform highp vec3 lightPosition_wrld;
    uniform highp float lightStrength;
    uniform highp float ambientStrength;
    uniform highp float shadowQuality;
    uniform highp vec4 lightColor;
    uniform highp float gradMin;
    uniform highp float gradHeight;
    highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216),
                                          vec2(0.94558609, -0.76890725),
                                          vec2(-0.094184101, -0.92938870),
                                          vec2(0.34495938, 0.29387760),
                                          vec2(-0.91588581, 0.45771432),
                                          vec2(-0.81544232, -0.87912464),
                                          vec2(-0.38277543, 0.27676845),
                                          vec2(0.97484398, 0.75648379),
                                          vec2(0.44323325, -0.97511554),
                                          vec2(0.53742981, -0.47373420),
                                          vec2(-0.26496911, -0.41893023),
                                          vec2(0.79197514, 0.19090188),
                                          vec2(-0.24188840, 0.99706507),
                                          vec2(-0.81409955, 0.91437590),
                                          vec2(0.19984126, 0.78641367),
                                          vec2(0.14383161, -0.14100790));
    void main() {
        highp vec2 gradientUV = vec2(0.0, gradMin + coords_mdl.y * gradHeight);
        highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz;
        highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
        highp vec3 materialSpecularColor = lightColor.rgb;
        highp vec3 n = normalize(normal_cmr);
        highp vec3 l = normalize(lightDirection_cmr);
        highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
        highp vec3 E = normalize(eyeDirection_cmr);
        highp vec3 R = reflect(-l, n);
        highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
        highp float bias = 0.005 * tan(acos(cosTheta));
        bias = clamp(bias, 0.001, 0.01);
        vec4 shadCoords = shadowCoord;
        shadCoords.z -= bias;
        highp float visibility = 0.6;
        for (int i = 0; i < 15; i++) {
            vec4 shadCoordsPD = shadCoords;
            shadCoordsPD.x += cos(poissonDisk[i].x) / shadowQuality;
            shadCoordsPD.y += sin(poissonDisk[i].y) / shadowQuality;
            visibility += 0.025 * shadow2DProj(shadowMap, shadCoordsPD).r;
        gl_FragColor.rgb =
            (materialAmbientColor +
            materialDiffuseColor * lightStrength * cosTheta +
            materialSpecularColor * lightStrength * pow(cosAlpha, 10));
        gl_FragColor.a = 1.0;
        gl_FragColor.rgb = visibility * clamp(gl_FragColor.rgb, 0.0, 1.0);


  • In fact the fragment shader I posted does seem to implement the Phong reflection model, with a fixed shininess factor of 10, in this line:

     gl_FragColor.rgb =
            (materialAmbientColor +
            materialDiffuseColor * lightStrength * cosTheta +
            materialSpecularColor * lightStrength * pow(cosAlpha, 10));

    If I increase 10 to 20, I see the "shiny" areas decrease, if I decrease 10 to 1, the shiny areas increase, consistent with the Phong model.

  • Yup, looks like you've spotted it -- in particular, the specular term is

    materialSpecularColor * lightStrength * pow(cosAlpha, 10)

    That's the part that will contribute to the shininess of the material. And, materialSpecularColor comes from highp vec3 materialSpecularColor = lightColor.rgb; which is to say that the materialSpecularColor in that shader is not really a property of the material since the value is just from the lighting. Not really the clearest name if you are trying to pick it apart. This type of look is traditionally used for a plastic type material which has white highlights for white lights regardless of the color of the material. If you want something a bit more metallic looking, you can multiply the lightcolor.rgb by some actual material color. This lighting model is a bit of an old school aphysical hack, so you may want to look into to more modern physically based lighting models if you are looking for more realism. But the classic specular + diffuse model is way simpler to understand even if it isn't super accurate to the real world.