diff --git a/assets/shaders/gl_textured.frag b/assets/shaders/gl_textured.frag index b264f77..abfa702 100644 --- a/assets/shaders/gl_textured.frag +++ b/assets/shaders/gl_textured.frag @@ -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); diff --git a/glium_platform/src/render/basic.rs b/glium_platform/src/render/basic.rs index a55d865..3ed144b 100644 --- a/glium_platform/src/render/basic.rs +++ b/glium_platform/src/render/basic.rs @@ -59,7 +59,11 @@ impl RenderingSystem for BasicMeshRenderingSystem { }; // Use HDR-derived environment light direction if provided, otherwise default to downward - let light_dir: Vec3 = if ctx.env_light_dir.length_squared() > 0.0 { ctx.env_light_dir.normalize() } else { Vec3::new(0.0, -1.0, 0.0) }; + let light_dir_world: Vec3 = if ctx.env_light_dir.length_squared() > 0.0 { ctx.env_light_dir.normalize() } else { Vec3::new(0.0, -1.0, 0.0) }; + + // Transform light direction to view space (normals/positions are in view space) + let view_mat3 = glam::Mat3::from_mat4(cam.view()); + let light_dir_view = (view_mat3 * light_dir_world).normalize(); let asset_manager = ctx.asset_manager.borrow(); @@ -90,7 +94,7 @@ impl RenderingSystem for BasicMeshRenderingSystem { model: tr.matrix().to_cols_array_2d(), view: cam.view().to_cols_array_2d(), projection: cam.projection().to_cols_array_2d(), - u_light: [light_dir.x, light_dir.y, light_dir.z], + u_light: [light_dir_view.x, light_dir_view.y, light_dir_view.z], tex: sampler, color: [c[0], c[1], c[2]], uv_offset: [mat.uv_offset.x, mat.uv_offset.y], diff --git a/glium_platform/src/render/skybox.rs b/glium_platform/src/render/skybox.rs index 2c9b9d9..d11683b 100644 --- a/glium_platform/src/render/skybox.rs +++ b/glium_platform/src/render/skybox.rs @@ -119,7 +119,7 @@ impl RenderingSystem for SkyboxRenderingSystem { // Load EXR from assets/exr let manifest_dir = env!("CARGO_MANIFEST_DIR"); - let path = std::path::Path::new(manifest_dir).join("../assets/exr/qwantani_sunset_puresky_2k.exr"); + let path = std::path::Path::new(manifest_dir).join("../assets/exr/citrus_orchard_road_puresky_4k.exr"); let (equirect_srgb, light_dir) = Self::load_hdr_equirect_and_analyze(display, &path); Self { program, quad_vb, quad_ib, equirect_srgb, light_dir } }