Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 0 additions & 85 deletions asset/shader/brdf.glsl

This file was deleted.

42 changes: 42 additions & 0 deletions asset/shader/common/brdf.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// PBR (Physically Based Rendering) common functions
// Based on Cook-Torrance BRDF

const float PI = 3.14159265359;

// Fresnel-Schlick (general form, roughness clamps the max reflectance for IBL)
vec3 fresnelSchlick(float cosTheta, vec3 F0, float roughness)
{
vec3 Fmax = max(vec3(1.0 - roughness), F0);
return F0 + (Fmax - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}

// Convenience overload for direct lighting (roughness = 0)
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
return fresnelSchlick(cosTheta, F0, 0.0);
}

// GGX/Trowbridge-Reitz normal distribution function
float DistributionGGX(vec3 N, vec3 H, float roughness)
{
float a = roughness * roughness;
float a2 = a * a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH * NdotH;

float nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;

return nom / max(denom, 0.0001);
}

// Height-Correlated Smith GGX visibility term (Heitz 2014, used by Filament/Unity HDRP)
// Returns V = G / (4 * NdotV * NdotL) — denominator already incorporated
float V_SmithGGXCorrelated(float NdotV, float NdotL, float roughness)
{
float a2 = roughness * roughness * roughness * roughness;
float GGXV = NdotL * sqrt(NdotV * NdotV * (1.0 - a2) + a2);
float GGXL = NdotV * sqrt(NdotL * NdotL * (1.0 - a2) + a2);
return 0.5 / max(GGXV + GGXL, 0.0001);
}
41 changes: 41 additions & 0 deletions asset/shader/common/ibl.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// IBL (Image-Based Lighting) ambient contribution
// Split-sum approximation (Karis 2013)

#include <common/brdf.glsl>

// Calculate IBL ambient contribution (diffuse + specular)
// irradianceMap : convolved diffuse irradiance cubemap
// prefilteredMap : prefiltered specular cubemap (mips = roughness levels)
// brdfLUT : precomputed split-sum BRDF LUT (R=scale, G=bias)
vec3 calculateIBLLighting(
vec3 N,
vec3 V,
vec3 albedo,
float metallic,
float roughness,
float ao,
samplerCube irradianceMap,
samplerCube prefilteredMap,
sampler2D brdfLUT
)
{
float NdotV = max(dot(N, V), 0.0);

vec3 F0 = mix(vec3(0.04), albedo, metallic);
vec3 F = fresnelSchlick(NdotV, F0, roughness);

vec3 kD = (1.0 - F) * (1.0 - metallic);

// Diffuse IBL
vec3 irradiance = texture(irradianceMap, N).rgb;
vec3 diffuse = kD * irradiance * albedo;

// Specular IBL (split-sum)
vec3 R = reflect(-V, N);
const float MAX_LOD = 5.0; // must match prefilter mip count
vec3 prefilteredColor = textureLod(prefilteredMap, R, roughness * MAX_LOD).rgb;
vec2 brdf = texture(brdfLUT, vec2(NdotV, roughness)).rg;
vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);

return (diffuse + specular) * ao;
}
26 changes: 0 additions & 26 deletions asset/shader/common/lighting.glsl

This file was deleted.

41 changes: 40 additions & 1 deletion asset/shader/punctual.glsl → asset/shader/common/punctual.glsl
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Punctual lights support (point lights and spot lights)

#include <common/brdf.glsl>

// Light types
const int LIGHT_TYPE_DIRECTIONAL = 0;
const int LIGHT_TYPE_POINT = 1;
Expand All @@ -16,7 +18,6 @@ struct PunctualLight
float intensity;
float innerConeAngle;
float outerConeAngle;
vec2 _padding;
};

// Calculate attenuation for point lights and spot lights
Expand Down Expand Up @@ -92,3 +93,41 @@ vec3 calculateRadiance(PunctualLight light, vec3 fragPosition, vec3 L)

return vec3(0.0); // Unknown light type
}

// Calculate PBR lighting for a single light source
// Returns the contribution from this light
vec3 calculatePBRLighting(
vec3 N, // Normal
vec3 V, // View direction
vec3 L, // Light direction
vec3 albedo, // Base color
float metallic, // Metallic value
float roughness, // Roughness value
vec3 radiance // Light color/intensity
)
{
vec3 H = normalize(V + L);

// Calculate reflectance at normal incidence
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, metallic);

float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);

// Cook-Torrance BRDF
// V_SmithGGXCorrelated already includes the 4*NdotV*NdotL denominator
float NDF = DistributionGGX(N, H, roughness);
float Vis = V_SmithGGXCorrelated(NdotV, NdotL, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);

vec3 specular = NDF * Vis * F;

// Energy conservation: kS + kD = 1.0
vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - metallic; // Metallic surfaces don't have diffuse

return (kD * albedo / PI + specular) * radiance * NdotL;
}

39 changes: 39 additions & 0 deletions asset/shader/common/sampling.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// IBL precomputation sampling utilities
// Requires: PI (defined in common/brdf.glsl)

// Hammersley quasi-random low-discrepancy sequence
float RadicalInverse_VdC(uint bits) {
bits = (bits << 16u) | (bits >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
return float(bits) * 2.3283064365386963e-10;
}

vec2 Hammersley(uint i, uint N) {
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
}

// GGX importance sampling for IBL precomputation
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) {
float a = roughness * roughness;

float phi = 2.0 * PI * Xi.x;
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
float sinTheta = sqrt(1.0 - cosTheta*cosTheta);

// From spherical coordinates to cartesian coordinates
vec3 H;
H.x = cos(phi) * sinTheta;
H.y = sin(phi) * sinTheta;
H.z = cosTheta;

// From tangent-space vector to world-space sample vector
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 tangent = normalize(cross(up, N));
vec3 bitangent = cross(N, tangent);

vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
return normalize(sampleVec);
}
25 changes: 19 additions & 6 deletions asset/shader/damaged_helmet.frag
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#version 460 core

#include <brdf.glsl>
#include <punctual.glsl>
#include <common/ibl.glsl>
#include <common/punctual.glsl>

in vec3 v_position;
in vec3 v_normal;
Expand All @@ -16,6 +16,11 @@ layout(binding = 2) uniform sampler2D u_normalTexture;
layout(binding = 3) uniform sampler2D u_emissiveTexture;
layout(binding = 4) uniform sampler2D u_occlusionTexture;

// IBL textures
layout(binding = 5) uniform samplerCube u_irradianceMap;
layout(binding = 6) uniform samplerCube u_prefilteredMap;
layout(binding = 7) uniform sampler2D u_brdfLUT;

// UBO for camera
layout(std140, binding = 1) uniform CameraUBO
{
Expand All @@ -31,17 +36,22 @@ layout(std140, binding = 2) uniform MaterialUBO
vec3 emissiveFactor;
float metallicFactor;
float roughnessFactor;
float _padding[3]; // alignment
} u_material;

// UBO for all lighting (fixed maximum size)
layout(std140, binding = 3) uniform LightingUBO
{
int lightCount;
int _padding[3];
PunctualLight lights[32]; // Maximum 32 lights
} u_lighting;

// IBL / tone-mapping parameters
layout(std140, binding = 4) uniform EnvironmentUBO
{
mat4 rotation; // for rotating the environment map
float intensity; // scales IBL contribution
} u_env;

void main()
{
// Sample textures
Expand All @@ -68,8 +78,11 @@ void main()
Lo += calculatePBRLighting(N, V, L, baseColor.rgb, metallic, roughness, radiance);
}

// Ambient lighting (simplified)
vec3 ambient = vec3(0.03) * baseColor.rgb * ao;
// IBL ambient
N = (u_env.rotation * vec4(N, 0.0)).xyz; // Rotate normal for IBL
vec3 ambient = calculateIBLLighting(N, V, baseColor.rgb, metallic, roughness, ao,
u_irradianceMap, u_prefilteredMap, u_brdfLUT)
* u_env.intensity;

vec3 color = ambient + Lo + emissive;

Expand Down
Loading
Loading