I’ve taken models from here:
Spot | Blub | Mushroom | Oozey the Slime |
---|---|---|---|
The Vertex shader is straightforward. We compute the relative vertex position and a normal for the current view to pass it to the Fragment shader.
Shader Code:
#version 400
layout(location = 0) in vec3 vPosition;
layout(location = 1) in vec3 vNormal;
uniform mat4 mViewProjection;
uniform mat4 mModel;
out vec3 position;
out vec3 normal;
void main() {
normal = vec3(mModel * vec4(vNormal, 0.0));
position = vec3(mModel * vec4(vPosition, 1.0));
gl_Position = (mViewProjection * mModel) * vec4(vPosition, 1.0);
}
In the Fragment shader, we’re mixing Sky colour and ground colour using a linear interpolation function (mix) and weight equation for hemisphere illumination:
\[weight = \frac{1}{2}(1 + \cos(\theta)) = \frac{1}{2}(1 + \vec{U}\cdot\vec{N})\]Where:
The weighted linear interpolation function for two colours:
\[Color = (1 - weight) \times GroundColor + weight \times SkyColor\]Shader Code:
#version 400
in vec3 position;
in vec3 normal;
uniform vec3 lightPosition;
uniform vec3 skyColor;
uniform vec3 groundColor;
layout(location = 0) out vec4 fragColor;
void main() {
vec3 normalDirection = normalize(normal);
vec3 lightDirection = normalize(lightPosition - position);
float cosTheta = dot(lightDirection, normalDirection);
float w = 0.5 * (1.0 + cosTheta);
vec3 color = mix(groundColor, skyColor, w);
// Alternatively, we may avoid using the mix function:
// vec3 color = groundColor * (1.0 - w) + skyColor * w;
fragColor = vec4(color, 1.0);
}