Hello!
I’m writing an app for Android which currently consists of nothing more than a rotating untextured rock. I’ve implemented a per-vertex diffuse ligthing shader, but when I try to convert it to a per-pixel/per-fragment shader something goes awry.
First of all, let’s start with my working per-vertex shader:
#version 300 es
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform vec3 lightPosition;
uniform vec4 vertexColor;
in vec4 vertexPosition;
in vec3 vertexNormal;
out vec4 finalColor;
void main()
{
vec3 cameraSpaceVertex = vec3(mvMatrix * vec4(vertexPosition.xyz, 1.0));
vec3 cameraSpaceNormal = vec3(mvMatrix * vec4(vertexNormal, 0.0));
float distance = length(lightPosition - cameraSpaceVertex);
vec3 lightVector = normalize(lightPosition - cameraSpaceVertex);
float cosTheta = clamp(dot(cameraSpaceNormal, lightVector), 0.0, 1.0);
float lightPower = 60.0;
float ambientLighting = 0.1;
finalColor = ambientLighting + vec4((lightPower * cosTheta / (distance * distance)) * vertexColor.rgb, 1.0);
gl_Position = mvpMatrix * vec4(vertexPosition.xyz, 1.0);
}
#version 300 es
precision mediump float;
in vec4 finalColor;
out vec4 FragColor;
void main()
{
FragColor = finalColor;
}
Next up is my per-pixel diffuse lighting shader:
#version 300 es
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
in vec3 vertexPosition;
in vec4 vertexColor;
in vec3 vertexNormal;
out vec3 fragPosition;
out vec4 fragColor;
out vec3 fragNormal;
void main()
{
fragPosition = vec3(mvMatrix * vec4(vertexPosition, 1.0));
fragColor = vertexColor;
fragNormal = vec3(mvMatrix * vec4(vertexNormal, 0.0));
gl_Position = mvpMatrix * vec4(vertexPosition, 1.0);
}
#version 300 es
precision mediump float;
uniform vec3 lightPosition; // position of the light in camera space
in vec3 fragPosition;
in vec4 fragColor;
in vec3 fragNormal;
out vec4 finalColor;
void main()
{
float distance = length(lightPosition - fragPosition);
vec3 lightVector = normalize(lightPosition - fragPosition); // Calculate the light vector (pointing towards the light)
float cosTheta = clamp(dot(fragNormal, lightVector), 0.0, 1.0); // Calculate the dot product between the normal and the light vector
float lightPower = 60.0;
float ambientLighting = 0.1;
finalColor = ambientLighting + vec4((lightPower * cosTheta / (distance * distance)) * fragColor.rgb, 1.0);
//finalColor = vec4(abs(lightVector.xyz), 1.0);
}
The per-vertex code is working as expected. Here’s an example: https://i.imgur.com/2elCcDm.png
However, when I try to implement the same diffuse lighting per-pixel instead, the diffuse lighting is gone. The rock is lit up by the ambient lighting, but the diffuse light is nowhere to be seen. Here’s an example: https://i.imgur.com/3vtzYVi.png
What am I doing wrong? I’m using the exact same attributes when calling both of my implementations. I’ve spent 12 hours trying to find a solution, but I can’t think of anything any longer.
EDIT:
I just figured out that I can pass the color (the same throughout the entire object) to the fragment shader as a uniform instead of as an “in” to the vertex shader. When it was passed from the vertex shader to the fragment shader it somehow got changed into black. I suppose this doesn’t really allow interpolation, but every vertex of the same model shares color in my app anyway.
Anyhow, I’d be grateful if someone could explain to me why I can’t pass the color to the vertex shader as an “in” instead of passing it directly to the fragment shader as an uniform.