PDA

View Full Version : Diffuse lighting working per-vertex but not per-pixel



WizardOfUs
11-04-2015, 09:10 AM
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.

Alfonse Reinheart
11-04-2015, 09:26 AM
Well, I see one thing right off the bat. You didn't renormalize your per-fragment normal in the fragment shader.

WizardOfUs
11-04-2015, 09:42 AM
My bad. I've been editing the code back and forth, forgot to put that back in there. Still made no difference though.

EDIT:
I'll be damned! I managed to get it to work, see the OP for info.

GClements
11-04-2015, 09:28 PM
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.
Given that there doesn't appear to be anything wrong with the GLSL code, I'd check for errors related to the vertexColor attribute in the client code.