1#define_import_path bevy_pbr::lighting 3#import bevy_pbr::utils as Utils 4#import bevy_pbr::mesh_view_types as ViewTypes 45fn getDistanceAttenuation(distanceSquare: f32, inverseRangeSquared: f32) -> f32 { 46 let factor = distanceSquare * inverseRangeSquared; 47 let smoothFactor = Utils::saturate(1.0 - factor * factor); 48 let attenuation = smoothFactor * smoothFactor; 49 return attenuation * 1.0 / max(distanceSquare, 0.0001); 59fn D_GGX(roughness: f32, NoH: f32, h: vec3<f32>) -> f32 { 60 let oneMinusNoHSquared = 1.0 - NoH * NoH; 61 let a = NoH * roughness; 62 let k = roughness / (oneMinusNoHSquared + a * a); 63 let d = k * k * (1.0 / Utils::PI); 74fn V_SmithGGXCorrelated(roughness: f32, NoV: f32, NoL: f32) -> f32 { 75 let a2 = roughness * roughness; 76 let lambdaV = NoL * sqrt((NoV - a2 * NoV) * NoV + a2); 77 let lambdaL = NoV * sqrt((NoL - a2 * NoL) * NoL + a2); 78 let v = 0.5 / (lambdaV + lambdaL); 85fn F_Schlick_vec(f0: vec3<f32>, f90: f32, VoH: f32) -> vec3<f32> { 87 return f0 + (f90 - f0) * pow(1.0 - VoH, 5.0); 90fn F_Schlick(f0: f32, f90: f32, VoH: f32) -> f32 { 92 return f0 + (f90 - f0) * pow(1.0 - VoH, 5.0); 95fn fresnel(f0: vec3<f32>, LoH: f32) -> vec3<f32> { 98 let f90 = Utils::saturate(dot(f0, vec3<f32>(50.0 * 0.33))); 99 return F_Schlick_vec(f0, f90, LoH); 107fn specular(f0: vec3<f32>, roughness: f32, h: vec3<f32>, NoV: f32, NoL: f32, 108 NoH: f32, LoH: f32, specularIntensity: f32) -> vec3<f32> { 109 let D = D_GGX(roughness, NoH, h); 110 let V = V_SmithGGXCorrelated(roughness, NoV, NoL); 111 let F = fresnel(f0, LoH); 113 return (specularIntensity * D * V) * F; 130fn Fd_Burley(roughness: f32, NoV: f32, NoL: f32, LoH: f32) -> f32 { 131 let f90 = 0.5 + 2.0 * roughness * LoH * LoH; 132 let lightScatter = F_Schlick(1.0, f90, NoL); 133 let viewScatter = F_Schlick(1.0, f90, NoV); 134 return lightScatter * viewScatter * (1.0 / Utils::PI); 138fn EnvBRDFApprox(f0: vec3<f32>, perceptual_roughness: f32, NoV: f32) -> vec3<f32> { 139 let c0 = vec4<f32>(-1.0, -0.0275, -0.572, 0.022); 140 let c1 = vec4<f32>(1.0, 0.0425, 1.04, -0.04); 141 let r = perceptual_roughness * c0 + c1; 142 let a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y; 143 let AB = vec2<f32>(-1.04, 1.04) * a004 + r.zw; 144 return f0 * AB.x + AB.y; 147fn perceptualRoughnessToRoughness(perceptualRoughness: f32) -> f32 { 151 let clampedPerceptualRoughness = clamp(perceptualRoughness, 0.089, 1.0); 152 return clampedPerceptualRoughness * clampedPerceptualRoughness; 157fn reinhard(color: vec3<f32>) -> vec3<f32> { 158 return color / (1.0 + color); 161fn reinhard_extended(color: vec3<f32>, max_white: f32) -> vec3<f32> { 162 let numerator = color * (1.0 + (color / vec3<f32>(max_white * max_white))); 163 return numerator / (1.0 + color); 168fn luminance(v: vec3<f32>) -> f32 { 169 return dot(v, vec3<f32>(0.2126, 0.7152, 0.0722)); 172fn change_luminance(c_in: vec3<f32>, l_out: f32) -> vec3<f32> { 173 let l_in = luminance(c_in); 174 return c_in * (l_out / l_in); 177fn reinhard_luminance(color: vec3<f32>) -> vec3<f32> { 178 let l_old = luminance(color); 179 let l_new = l_old / (1.0 + l_old); 180 return change_luminance(color, l_new); 183fn reinhard_extended_luminance(color: vec3<f32>, max_white_l: f32) -> vec3<f32> { 184 let l_old = luminance(color); 185 let numerator = l_old * (1.0 + (l_old / (max_white_l * max_white_l))); 186 let l_new = numerator / (1.0 + l_old); 187 return change_luminance(color, l_new); 191 world_position: vec3<f32>, light: ViewTypes::PointLight, roughness: f32, NdotV: f32, N: vec3<f32>, V: vec3<f32>, 192 R: vec3<f32>, F0: vec3<f32>, diffuseColor: vec3<f32> 194 let light_to_frag = light.position_radius.xyz - world_position.xyz; 195 let distance_square = dot(light_to_frag, light_to_frag); 196 let rangeAttenuation = 197 getDistanceAttenuation(distance_square, light.color_inverse_square_range.w); 203 let centerToRay = dot(light_to_frag, R) * R - light_to_frag; 204 let closestPoint = light_to_frag + centerToRay * Utils::saturate(light.position_radius.w * inverseSqrt(dot(centerToRay, centerToRay))); 205 let LspecLengthInverse = inverseSqrt(dot(closestPoint, closestPoint)); 206 let normalizationFactor = a / Utils::saturate(a + (light.position_radius.w * 0.5 * LspecLengthInverse)); 207 let specularIntensity = normalizationFactor * normalizationFactor; 209 var L: vec3<f32> = closestPoint * LspecLengthInverse; 210 var H: vec3<f32> = normalize(L + V); 211 var NoL: f32 = Utils::saturate(dot(N, L)); 212 var NoH: f32 = Utils::saturate(dot(N, H)); 213 var LoH: f32 = Utils::saturate(dot(L, H)); 215 let specular_light = specular(F0, roughness, H, NdotV, NoL, NoH, LoH, specularIntensity); 219 L = normalize(light_to_frag); 220 H = normalize(L + V); 221 NoL = Utils::saturate(dot(N, L)); 222 NoH = Utils::saturate(dot(N, H)); 223 LoH = Utils::saturate(dot(L, H)); 225 let diffuse = diffuseColor * Fd_Burley(roughness, NdotV, NoL, LoH); 242 return ((diffuse + specular_light) * light.color_inverse_square_range.rgb) * (rangeAttenuation * NoL); 246 world_position: vec3<f32>, light: ViewTypes::PointLight, roughness: f32, NdotV: f32, N: vec3<f32>, V: vec3<f32>, 247 R: vec3<f32>, F0: vec3<f32>, diffuseColor: vec3<f32> 250 let point_light = point_light(world_position, light, roughness, NdotV, N, V, R, F0, diffuseColor); 253 var spot_dir = vec3<f32>(light.light_custom_data.x, 0.0, light.light_custom_data.y); 254 spot_dir.y = sqrt(1.0 - spot_dir.x * spot_dir.x - spot_dir.z * spot_dir.z); 255 if ((light.flags & ViewTypes::POINT_LIGHT_FLAGS_SPOT_LIGHT_Y_NEGATIVE) != 0u) { 256 spot_dir.y = -spot_dir.y; 258 let light_to_frag = light.position_radius.xyz - world_position.xyz; 263 let cd = dot(-spot_dir, normalize(light_to_frag)); 264 let attenuation = Utils::saturate(cd * light.light_custom_data.z + light.light_custom_data.w); 265 let spot_attenuation = attenuation * attenuation; 267 return point_light * spot_attenuation; 270fn directional_light(light: ViewTypes::DirectionalLight, roughness: f32, NdotV: f32, normal: vec3<f32>, view: vec3<f32>, R: vec3<f32>, F0: vec3<f32>, diffuseColor: vec3<f32>) -> vec3<f32> { 271 let incident_light = light.direction_to_light.xyz; 273 let half_vector = normalize(incident_light + view); 274 let NoL = Utils::saturate(dot(normal, incident_light)); 275 let NoH = Utils::saturate(dot(normal, half_vector)); 276 let LoH = Utils::saturate(dot(incident_light, half_vector)); 278 let diffuse = diffuseColor * Fd_Burley(roughness, NdotV, NoL, LoH); 279 let specularIntensity = 1.0; 280 let specular_light = specular(F0, roughness, half_vector, NdotV, NoL, NoH, LoH, specularIntensity); 282 return (specular_light + diffuse) * light.color.rgb * NoL;