Improve lighting

- No specular on surfaces facing away from the light source
- Transform the light direction to view space to ensure that all
  lighting calculations happen in a consistent coordinate space.
- Other lighting tweaks
This commit is contained in:
reo 2025-12-15 23:34:51 +03:00
parent a51aeb23bd
commit 71e991db77
3 changed files with 28 additions and 15 deletions

View file

@ -6,28 +6,37 @@ in vec3 v_position;
out vec4 frag_color;
uniform vec3 u_light;
uniform vec3 u_light; // direction TO the light (normalized)
uniform sampler2D tex;
uniform vec3 color; // base colour factor (acts as solid colour when no texture)
uniform vec3 color; // base colour factor (acts as solid colour when no texture)
void main() {
// Combine base texture (or constant white) with colour factor supplied by CPU.
vec3 base_col = texture(tex, v_tex).rgb * color;
vec3 ambient_color = base_col * 0.2;
vec3 diffuse_color = base_col * 0.6;
vec3 specular_color = vec3(1.0);
vec3 N = normalize(v_normal);
vec3 L = normalize(u_light);
// u_light is the direction **from the light towards the fragment**.
float diffuse = max(dot(normalize(v_normal), normalize(u_light)), 0.0);
// Classic Blinn-Phong lighting
// Ambient: always present
vec3 ambient = base_col * 0.15;
vec3 camera_dir = normalize(-v_position);
vec3 half_dir = normalize(normalize(u_light) + camera_dir);
float specular = pow(max(dot(half_dir, normalize(v_normal)), 0.0), 16.0);
// Diffuse: N dot L, clamped
float NdotL = max(dot(N, L), 0.0);
vec3 diffuse = base_col * NdotL * 0.7;
vec3 result = ambient_color + diffuse * diffuse_color + specular * specular_color;
// Specular: only on surfaces facing the light (NdotL > 0)
float specular = 0.0;
if (NdotL > 0.0) {
vec3 V = normalize(-v_position); // view direction (camera at origin in view space)
vec3 H = normalize(L + V); // half-vector
float NdotH = max(dot(N, H), 0.0);
specular = pow(NdotH, 32.0) * 0.5; // tighter highlight, moderated intensity
}
// Convert from linear to sRGB for display (approximate γ-correction)
vec3 result = ambient + diffuse + vec3(specular);
// Convert from linear to sRGB for display (approximate gamma correction)
result = pow(result, vec3(1.0 / 2.2));
frag_color = vec4(result, 1.0);