base
This commit is contained in:
+23
-67
@@ -63,65 +63,23 @@ uniform float envIntensity = 0.8;
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float rough)
|
||||
// Plain Blinn-Phong: ambient, Lambert diffuse and a half vector highlight.
|
||||
// Roughness sets how tight and strong the highlight is, metallic tints it and takes away the diffuse.
|
||||
|
||||
// Close enough to the 2.2 curve and much cheaper than pow
|
||||
vec3 ToLinear(vec3 c)
|
||||
{
|
||||
float a = rough * rough;
|
||||
float a2 = a * a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH * NdotH;
|
||||
float denom = NdotH2 * (a2 - 1.0) + 1.0;
|
||||
return a2 / max(PI * denom * denom, 1e-5);
|
||||
return c * c;
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float rough)
|
||||
{
|
||||
float r = rough + 1.0;
|
||||
float k = (r * r) / 8.0;
|
||||
return NdotV / (NdotV * (1.0 - k) + k);
|
||||
}
|
||||
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float rough)
|
||||
{
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
return GeometrySchlickGGX(NdotV, rough) * GeometrySchlickGGX(NdotL, rough);
|
||||
}
|
||||
|
||||
vec3 FresnelSchlick(float cosTheta, vec3 F0)
|
||||
{
|
||||
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
|
||||
}
|
||||
|
||||
vec3 FresnelSchlickRoughness(float cosTheta, vec3 F0, float rough)
|
||||
{
|
||||
vec3 f = max(vec3(1.0 - rough), F0);
|
||||
return F0 + (f - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
|
||||
}
|
||||
|
||||
vec3 EnvironmentBRDF(vec3 F0, float rough, float NdotV)
|
||||
{
|
||||
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
|
||||
const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
|
||||
vec4 r = rough * c0 + c1;
|
||||
float a004 = min(r.x * r.x, exp2(-9.28 * NdotV)) * r.x + r.y;
|
||||
vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;
|
||||
return F0 * AB.x + AB.y;
|
||||
}
|
||||
|
||||
// Light from one direction, L points from the surface toward the light
|
||||
vec3 ShadeLight(vec3 L, vec3 radiance, vec3 N, vec3 V, vec3 albedo, float metal, float rough, vec3 F0, float NdotV)
|
||||
// Light from one direction, L points from the surface toward the light.
|
||||
// diffuse and specular are already scaled for this pixel, see main.
|
||||
vec3 ShadeLight(vec3 L, vec3 radiance, vec3 N, vec3 V, vec3 diffuse, vec3 specular, float power)
|
||||
{
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
if (NdotL <= 0.0)
|
||||
return vec3(0.0);
|
||||
|
||||
vec3 H = normalize(V + L);
|
||||
vec3 F = FresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||
float NDF = DistributionGGX(N, H, rough);
|
||||
float G = GeometrySmith(N, V, L, rough);
|
||||
vec3 specular = (NDF * G * F) / max(4.0 * NdotV * NdotL, 1e-4);
|
||||
vec3 kD = (vec3(1.0) - F) * (1.0 - metal);
|
||||
return (kD * albedo / PI + specular) * radiance * NdotL;
|
||||
float highlight = pow(max(dot(N, H), 0.0), power);
|
||||
return (diffuse + specular * highlight) * radiance * NdotL;
|
||||
}
|
||||
|
||||
// Inverse square falloff, windowed so it reaches exactly zero at the radius
|
||||
@@ -196,7 +154,7 @@ void main()
|
||||
albedoSample = texture(tex, texCoord);
|
||||
if (albedoSample.a < 0.1)
|
||||
discard;
|
||||
albedoSample.rgb = pow(albedoSample.rgb, vec3(2.2));
|
||||
albedoSample.rgb = ToLinear(albedoSample.rgb);
|
||||
}
|
||||
|
||||
albedoSample.rgb = mix(albedoSample.rgb, colorOverride.rgb, colorOverride.w);
|
||||
@@ -207,22 +165,25 @@ void main()
|
||||
|
||||
vec3 N = normalize(normal);
|
||||
vec3 V = normalize(viewPos - FragPos);
|
||||
float NdotV = max(dot(N, V), 1e-4);
|
||||
|
||||
vec3 F0 = mix(vec3(0.04), albedo, metal);
|
||||
float smoothness = 1.0 - clamp(rough, 0.0, 1.0);
|
||||
float power = exp2(10.0 * smoothness + 1.0); // 2 when fully rough, 2048 when mirror smooth
|
||||
vec3 specularColor = mix(vec3(0.5 * smoothness * smoothness), albedo * (0.25 + 0.75 * smoothness), metal);
|
||||
vec3 diffuseBRDF = albedo * (1.0 - metal) / PI; // the light intensities were tuned with the 1/PI in
|
||||
vec3 specularBRDF = specularColor / PI;
|
||||
vec3 direct = vec3(0.0);
|
||||
|
||||
// Facing away from the sun has no direct light, so skip the BRDF and the 9 shadow samples
|
||||
vec3 sunL = normalize(-dirLight.direction);
|
||||
if (dot(N, sunL) > 0.0) {
|
||||
float shadow = ShadowCalculation(fragposlightspace, N, sunL);
|
||||
direct += ShadeLight(sunL, dirLight.color * dirLight.intensity, N, V, albedo, metal, rough, F0, NdotV) * shadow;
|
||||
direct += ShadeLight(sunL, dirLight.color * dirLight.intensity, N, V, diffuseBRDF, specularBRDF, power) * shadow;
|
||||
}
|
||||
|
||||
for (int i = 0; i < directionalLightCount; i++) {
|
||||
vec3 L = normalize(-directionalLights[i].direction);
|
||||
vec3 radiance = directionalLights[i].color * directionalLights[i].intensity;
|
||||
direct += ShadeLight(L, radiance, N, V, albedo, metal, rough, F0, NdotV);
|
||||
direct += ShadeLight(L, radiance, N, V, diffuseBRDF, specularBRDF, power);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pointLightCount; i++) {
|
||||
@@ -237,7 +198,7 @@ void main()
|
||||
if (dot(N, L) <= 0.0)
|
||||
continue;
|
||||
|
||||
vec3 lit = ShadeLight(L, radiance, N, V, albedo, metal, rough, F0, NdotV);
|
||||
vec3 lit = ShadeLight(L, radiance, N, V, diffuseBRDF, specularBRDF, power);
|
||||
if (pointLights[i].shadowTile >= 0)
|
||||
lit *= LocalShadow(pointLights[i].shadowTile + PointShadowFace(-toLight), FragPos, N);
|
||||
direct += lit;
|
||||
@@ -259,19 +220,14 @@ void main()
|
||||
continue;
|
||||
|
||||
vec3 radiance = spotLights[i].color * spotLights[i].intensity * PointAttenuation(distanceSquared, radius) * cone;
|
||||
vec3 lit = ShadeLight(L, radiance, N, V, albedo, metal, rough, F0, NdotV);
|
||||
vec3 lit = ShadeLight(L, radiance, N, V, diffuseBRDF, specularBRDF, power);
|
||||
if (spotLights[i].shadowTile >= 0)
|
||||
lit *= LocalShadow(spotLights[i].shadowTile, FragPos, N);
|
||||
direct += lit;
|
||||
}
|
||||
|
||||
vec3 ambientF = FresnelSchlickRoughness(NdotV, F0, rough);
|
||||
vec3 ambientKD = (vec3(1.0) - ambientF) * (1.0 - metal);
|
||||
vec3 irradiance = pow(textureLod(environmentMap, N, 7.0).rgb, vec3(2.2)) * envIntensity;
|
||||
vec3 R = reflect(-V, N);
|
||||
vec3 prefiltered = pow(textureLod(environmentMap, R, rough * 7.0).rgb, vec3(2.2)) * envIntensity;
|
||||
vec3 specularIBL = prefiltered * EnvironmentBRDF(F0, rough, NdotV);
|
||||
vec3 ambient = (ambientKD * irradiance * albedo + specularIBL) * ao;
|
||||
// Ambient is the sky's blurred colour in the direction the surface faces
|
||||
vec3 ambient = ToLinear(textureLod(environmentMap, N, 7.0).rgb) * envIntensity * albedo * ao;
|
||||
|
||||
FragColor = vec4(direct + ambient + albedo * emissive * 4.0, albedoSample.a);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ vec2 SurfaceUV()
|
||||
{
|
||||
if (uvMode == 0) return aTex + uvOffset;
|
||||
|
||||
vec3 n = abs(aNormal);
|
||||
// Unscale the normal first, so a stretched mesh picks the axis it faces in the world
|
||||
vec3 n = abs(aNormal / max(tileScale, vec3(1e-4)));
|
||||
vec3 p = aPos * tileScale;
|
||||
if (n.y >= n.x && n.y >= n.z) return p.xz + uvOffset;
|
||||
if (n.x >= n.z) return p.zy + uvOffset;
|
||||
|
||||
@@ -58,65 +58,23 @@ uniform float envIntensity = 0.8;
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float rough)
|
||||
// Plain Blinn-Phong: ambient, Lambert diffuse and a half vector highlight.
|
||||
// Roughness sets how tight and strong the highlight is, metallic tints it and takes away the diffuse.
|
||||
|
||||
// Close enough to the 2.2 curve and much cheaper than pow
|
||||
vec3 ToLinear(vec3 c)
|
||||
{
|
||||
float a = rough * rough;
|
||||
float a2 = a * a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH * NdotH;
|
||||
float denom = NdotH2 * (a2 - 1.0) + 1.0;
|
||||
return a2 / max(PI * denom * denom, 1e-5);
|
||||
return c * c;
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float rough)
|
||||
{
|
||||
float r = rough + 1.0;
|
||||
float k = (r * r) / 8.0;
|
||||
return NdotV / (NdotV * (1.0 - k) + k);
|
||||
}
|
||||
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float rough)
|
||||
{
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
return GeometrySchlickGGX(NdotV, rough) * GeometrySchlickGGX(NdotL, rough);
|
||||
}
|
||||
|
||||
vec3 FresnelSchlick(float cosTheta, vec3 F0)
|
||||
{
|
||||
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
|
||||
}
|
||||
|
||||
vec3 FresnelSchlickRoughness(float cosTheta, vec3 F0, float rough)
|
||||
{
|
||||
vec3 f = max(vec3(1.0 - rough), F0);
|
||||
return F0 + (f - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
|
||||
}
|
||||
|
||||
vec3 EnvironmentBRDF(vec3 F0, float rough, float NdotV)
|
||||
{
|
||||
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
|
||||
const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
|
||||
vec4 r = rough * c0 + c1;
|
||||
float a004 = min(r.x * r.x, exp2(-9.28 * NdotV)) * r.x + r.y;
|
||||
vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;
|
||||
return F0 * AB.x + AB.y;
|
||||
}
|
||||
|
||||
// Light from one direction, L points from the surface toward the light
|
||||
vec3 ShadeLight(vec3 L, vec3 radiance, vec3 N, vec3 V, vec3 albedo, float metal, float rough, vec3 F0, float NdotV)
|
||||
// Light from one direction, L points from the surface toward the light.
|
||||
// diffuse and specular are already scaled for this pixel, see main.
|
||||
vec3 ShadeLight(vec3 L, vec3 radiance, vec3 N, vec3 V, vec3 diffuse, vec3 specular, float power)
|
||||
{
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
if (NdotL <= 0.0)
|
||||
return vec3(0.0);
|
||||
|
||||
vec3 H = normalize(V + L);
|
||||
vec3 F = FresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||
float NDF = DistributionGGX(N, H, rough);
|
||||
float G = GeometrySmith(N, V, L, rough);
|
||||
vec3 specular = (NDF * G * F) / max(4.0 * NdotV * NdotL, 1e-4);
|
||||
vec3 kD = (vec3(1.0) - F) * (1.0 - metal);
|
||||
return (kD * albedo / PI + specular) * radiance * NdotL;
|
||||
float highlight = pow(max(dot(N, H), 0.0), power);
|
||||
return (diffuse + specular * highlight) * radiance * NdotL;
|
||||
}
|
||||
|
||||
// Inverse square falloff, windowed so it reaches exactly zero at the radius
|
||||
@@ -203,22 +161,25 @@ void main()
|
||||
|
||||
vec3 N = normalize(normal);
|
||||
vec3 V = normalize(viewPos - FragPos);
|
||||
float NdotV = max(dot(N, V), 1e-4);
|
||||
|
||||
vec3 F0 = mix(vec3(0.04), albedo, metal);
|
||||
float smoothness = 1.0 - clamp(rough, 0.0, 1.0);
|
||||
float power = exp2(10.0 * smoothness + 1.0); // 2 when fully rough, 2048 when mirror smooth
|
||||
vec3 specularColor = mix(vec3(0.5 * smoothness * smoothness), albedo * (0.25 + 0.75 * smoothness), metal);
|
||||
vec3 diffuseBRDF = albedo * (1.0 - metal) / PI; // the light intensities were tuned with the 1/PI in
|
||||
vec3 specularBRDF = specularColor / PI;
|
||||
vec3 direct = vec3(0.0);
|
||||
|
||||
// Facing away from the sun has no direct light, so skip the BRDF and the 9 shadow samples
|
||||
vec3 sunL = normalize(-dirLight.direction);
|
||||
if (dot(N, sunL) > 0.0) {
|
||||
float shadow = ShadowCalculation(lightSpaceMatrix * vec4(FragPos, 1.0), N, sunL);
|
||||
direct += ShadeLight(sunL, dirLight.color * dirLight.intensity, N, V, albedo, metal, rough, F0, NdotV) * shadow;
|
||||
direct += ShadeLight(sunL, dirLight.color * dirLight.intensity, N, V, diffuseBRDF, specularBRDF, power) * shadow;
|
||||
}
|
||||
|
||||
for (int i = 0; i < directionalLightCount; i++) {
|
||||
vec3 L = normalize(-directionalLights[i].direction);
|
||||
vec3 radiance = directionalLights[i].color * directionalLights[i].intensity;
|
||||
direct += ShadeLight(L, radiance, N, V, albedo, metal, rough, F0, NdotV);
|
||||
direct += ShadeLight(L, radiance, N, V, diffuseBRDF, specularBRDF, power);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pointLightCount; i++) {
|
||||
@@ -233,7 +194,7 @@ void main()
|
||||
if (dot(N, L) <= 0.0)
|
||||
continue;
|
||||
|
||||
vec3 lit = ShadeLight(L, radiance, N, V, albedo, metal, rough, F0, NdotV);
|
||||
vec3 lit = ShadeLight(L, radiance, N, V, diffuseBRDF, specularBRDF, power);
|
||||
if (pointLights[i].shadowTile >= 0)
|
||||
lit *= LocalShadow(pointLights[i].shadowTile + PointShadowFace(-toLight), FragPos, N);
|
||||
direct += lit;
|
||||
@@ -255,19 +216,14 @@ void main()
|
||||
continue;
|
||||
|
||||
vec3 radiance = spotLights[i].color * spotLights[i].intensity * PointAttenuation(distanceSquared, radius) * cone;
|
||||
vec3 lit = ShadeLight(L, radiance, N, V, albedo, metal, rough, F0, NdotV);
|
||||
vec3 lit = ShadeLight(L, radiance, N, V, diffuseBRDF, specularBRDF, power);
|
||||
if (spotLights[i].shadowTile >= 0)
|
||||
lit *= LocalShadow(spotLights[i].shadowTile, FragPos, N);
|
||||
direct += lit;
|
||||
}
|
||||
|
||||
vec3 ambientF = FresnelSchlickRoughness(NdotV, F0, rough);
|
||||
vec3 ambientKD = (vec3(1.0) - ambientF) * (1.0 - metal);
|
||||
vec3 irradiance = pow(textureLod(environmentMap, N, 7.0).rgb, vec3(2.2)) * envIntensity;
|
||||
vec3 R = reflect(-V, N);
|
||||
vec3 prefiltered = pow(textureLod(environmentMap, R, rough * 7.0).rgb, vec3(2.2)) * envIntensity;
|
||||
vec3 specularIBL = prefiltered * EnvironmentBRDF(F0, rough, NdotV);
|
||||
vec3 ambient = (ambientKD * irradiance * albedo + specularIBL) * ao;
|
||||
// Ambient is the sky's blurred colour in the direction the surface faces
|
||||
vec3 ambient = ToLinear(textureLod(environmentMap, N, 7.0).rgb) * envIntensity * albedo * ao;
|
||||
|
||||
vec3 emission = albedo * material.a * 4.0;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ void main()
|
||||
albedo = texture(tex, TexCoord);
|
||||
if (albedo.a < 0.1)
|
||||
discard;
|
||||
albedo.rgb = pow(albedo.rgb, vec3(2.2));
|
||||
albedo.rgb = albedo.rgb * albedo.rgb; // same cheap 2.2 stand-in as the lighting shaders
|
||||
}
|
||||
|
||||
albedo.rgb = mix(albedo.rgb, colorOverride.rgb, colorOverride.w);
|
||||
|
||||
@@ -27,7 +27,8 @@ vec2 SurfaceUV()
|
||||
{
|
||||
if (uvMode == 0) return aTexCoord + uvOffset;
|
||||
|
||||
vec3 n = abs(aNormal);
|
||||
// Unscale the normal first, so a stretched mesh picks the axis it faces in the world
|
||||
vec3 n = abs(aNormal / max(tileScale, vec3(1e-4)));
|
||||
vec3 p = aPos * tileScale;
|
||||
if (n.y >= n.x && n.y >= n.z) return p.xz + uvOffset;
|
||||
if (n.x >= n.z) return p.zy + uvOffset;
|
||||
|
||||
Reference in New Issue
Block a user