I'm trying to load an .mtl
file to shade an object for OpenGL. The objects I'm loading are coming from Google's Poly library so I know they're valid and I believe something is wrong with my shader script. My starting point was the shader provided on Google ARCore sample object_fragment.shader. Since not all mtls use a texture I added a boolean to tell me whether or not to use the texture map, I also changed the material properties to allow the mtl to pass rgb values instead of a single scalar. Here's the result:
precision mediump float;
uniform bool u_TextureValid;
uniform sampler2D u_Texture;
uniform vec4 u_LightingParameters;
uniform vec2 u_MaterialParameters;
uniform vec3 u_MaterialAmbientLighting;
uniform vec3 u_MaterialDiffuseLighting;
uniform vec3 u_MaterialSpecularLighting;
varying vec3 v_ViewPosition;
varying vec3 v_ViewNormal;
varying vec2 v_TexCoord;
void main() {
// We support approximate sRGB gamma.
const float kGamma = 0.4545454;
const float kInverseGamma = 2.2;
// Unpack lighting and material parameters for better naming.
vec3 viewLightDirection = u_LightingParameters.xyz;
float lightIntensity = u_LightingParameters.w;
float materialSpecularPower = u_MaterialParameters.x;
float materialAlpha = u_MaterialParameters.y;
vec3 materialDiffuse = u_MaterialDiffuseLighting;
vec3 materialSpecular = u_MaterialSpecularLighting;
// Normalize varying parameters, because they are linearly interpolated in the vertex shader.
vec3 viewFragmentDirection = normalize(v_ViewPosition);
vec3 viewNormal = normalize(v_ViewNormal);
// Apply inverse SRGB gamma to the texture before making lighting calculations.
// Flip the y-texture coordinate to address the texture from top-left.
vec4 objectColor;
if (u_TextureValid) {
objectColor = texture2D(u_Texture, vec2(v_TexCoord.x, 1.0 - v_TexCoord.y));
} else {
objectColor = vec4(1.0, 1.0, 1.0, 1.0);
}
objectColor.rgb = pow(objectColor.rgb, vec3(kInverseGamma));
// Ambient light is unaffected by the light intensity.
vec3 ambient = u_MaterialAmbientLighting;
// Approximate a hemisphere light (not a harsh directional light).
vec3 diffuse = lightIntensity * materialDiffuse *
0.5 * (dot(viewNormal, viewLightDirection) + 1.0);
// Compute specular light.
vec3 reflectedLightDirection = reflect(-viewLightDirection, viewNormal);
float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection));
vec3 specular = lightIntensity * materialSpecular *
pow(specularStrength, materialSpecularPower);
// Apply SRGB gamma before writing the fragment color.
gl_FragColor.a = objectColor.a * materialAlpha;
if (u_TextureValid) {
gl_FragColor.rgb = pow(objectColor.rgb + ambient + diffuse + specular, vec3(kGamma));
} else {
gl_FragColor.rgb = pow(objectColor.rgb * (ambient + diffuse) + specular, vec3(kGamma));
}
}
Models with textures appear to look correct, but others with only Ka
and Ks
values look too bright.
This is what it should look like: https://poly.google.com/view/9086wpJW1vO
All the parameters being passed come from the mtl
file except for the u_LightingParameters
which come from the constant light source direction and the light intensity provided by ARCore.
Does anyone know what I might be doing wrong when computing the fragment colors?
UPDATE
I've fixed the computation for the reflection but the color is still too bright, the materials for this model are:
newmtl mat8
Ka 0.96 0.26 0.21
Kd 0.96 0.26 0.21
newmtl mat18
Ka 1.00 0.80 0.53
Kd 1.00 0.80 0.53
newmtl mat19
Ka 0.87 0.60 0.27
Kd 0.87 0.60 0.27
newmtl mat21
Ka 1.00 1.00 1.00
Kd 1.00 1.00 1.00
newmtl mat22
Ka 0.62 0.62 0.62
Kd 0.62 0.62 0.62
newmtl mat23
Ka 0.10 0.10 0.10
Kd 0.10 0.10 0.10
My current theory is that the issue is my choice for base color when no texture mapping is used in the material.
UPDATE
I'm having a hard time explaining it but if I take the u_MaterialDiffuseLighting
value as the gl_FragColor
and nothing else (not even perform gamma correction) then the color looks right... Can anyone explain?