Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

volumetric: Add volumetric lighting #3668

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
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
65 changes: 57 additions & 8 deletions data/base/shaders/pointlights.frag
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
#define WZ_MAX_POINT_LIGHTS 0
#define WZ_MAX_INDEXED_POINT_LIGHTS 0
#define WZ_BUCKET_DIMENSION 0
#define WZ_VOLUMETRIC_LIGHTING_ENABLED 0

uniform vec4 PointLightsPosition[WZ_MAX_POINT_LIGHTS];
uniform vec4 PointLightsColorAndEnergy[WZ_MAX_POINT_LIGHTS];
uniform ivec4 bucketOffsetAndSize[WZ_BUCKET_DIMENSION * WZ_BUCKET_DIMENSION];
uniform ivec4 PointLightsIndex[WZ_MAX_INDEXED_POINT_LIGHTS];
uniform int viewportWidth;
uniform int viewportHeight;
uniform vec4 cameraPos; // in modelSpace

// See https://lisyarus.github.io/blog/graphics/2022/07/30/point-light-attenuation.html for explanation
// we want something that looks somewhat physically correct, but must absolutely be 0 past range
Expand All @@ -21,22 +23,29 @@ float pointLightEnergyAtPosition(vec3 position, vec3 pointLightWorldPosition, fl
return numerator * numerator / ( 1.f + 2.f * sqNormDist);
}

vec4 processPointLight(vec3 WorldFragPos, vec3 fragNormal, vec3 viewVector, vec4 albedo, float gloss, vec3 pointLightWorldPosition, float pointLightEnergy, vec3 pointLightColor, mat3 normalWorldSpaceToLocalSpace)
struct MaterialInfo
{
vec4 albedo;
float gloss;
};

vec4 processPointLight(vec3 WorldFragPos, vec3 fragNormal, vec3 viewVector, MaterialInfo material, vec3 pointLightWorldPosition, float pointLightEnergy, vec3 pointLightColor, mat3 normalWorldSpaceToLocalSpace)
{
vec3 pointLightVector = WorldFragPos - pointLightWorldPosition;
vec3 pointLightDir = -normalize(pointLightVector * normalWorldSpaceToLocalSpace);

float energy = pointLightEnergyAtPosition(WorldFragPos, pointLightWorldPosition, pointLightEnergy);
vec4 lightColor = vec4(pointLightColor * energy, 1.f);
vec4 lightColor = vec4(pointLightColor * energy, 1);

float pointLightLambert = max(dot(fragNormal, pointLightDir), 0.f);
float pointLightLambert = max(dot(fragNormal, pointLightDir), 0.0);

vec3 pointLightHalfVec = normalize(viewVector + pointLightDir);

float pointLightBlinn = pow(clamp(dot(fragNormal, pointLightHalfVec), 0.f, 1.f), 16.f);
return lightColor * pointLightLambert * (albedo + pointLightBlinn * (gloss * gloss));
return lightColor * pointLightLambert * (material.albedo + pointLightBlinn * (material.gloss * material.gloss));
}


// This function expects that we have :
// - a uniforms named bucketOffsetAndSize of ivec4[]
// - a uniforms named PointLightsPosition of vec4[]
Expand All @@ -48,8 +57,7 @@ vec4 iterateOverAllPointLights(
vec3 WorldFragPos,
vec3 fragNormal,
vec3 viewVector,
vec4 albedo,
float gloss,
MaterialInfo material,
mat3 normalWorldSpaceToLocalSpace
) {
vec4 light = vec4(0.f);
Expand All @@ -62,8 +70,49 @@ vec4 iterateOverAllPointLights(
int lightIndex = PointLightsIndex[entryInLightList / 4][entryInLightList % 4];
vec4 position = PointLightsPosition[lightIndex];
vec4 colorAndEnergy = PointLightsColorAndEnergy[lightIndex];
vec3 tmp = position.xyz * vec3(1.f, 1.f, -1.f);
light += processPointLight(WorldFragPos, fragNormal, viewVector, albedo, gloss, tmp, colorAndEnergy.w, colorAndEnergy.xyz, normalWorldSpaceToLocalSpace);
light += processPointLight(WorldFragPos, fragNormal, viewVector, material, position.xyz, colorAndEnergy.w, colorAndEnergy.xyz, normalWorldSpaceToLocalSpace);
}
return light;
}


// based on equations found here : https://www.shadertoy.com/view/lstfR7
vec4 volumetricLights(
vec2 clipSpaceCoord,
vec3 cameraPosition,
vec3 WorldFragPos,
vec3 sunLightColor
) {
vec3 result = vec3(0);
ivec2 bucket = ivec2(WZ_BUCKET_DIMENSION * clipSpaceCoord);
int bucketId = min(bucket.y + bucket.x * WZ_BUCKET_DIMENSION, WZ_BUCKET_DIMENSION * WZ_BUCKET_DIMENSION - 1);


vec3 viewLine = cameraPosition.xyz - WorldFragPos;
vec3 currentTransmittence = vec3(1);
vec3 transMittance = vec3(1);


#define STEPS (WZ_VOLUMETRIC_LIGHTING_ENABLED * 4)
for (int i = 0; i < STEPS; i++)
{

vec3 posOnViewLine = WorldFragPos + viewLine * i / STEPS;
// fog is thicker near 0
float thickness = exp(-posOnViewLine.y / 300);

vec3 od = fogColor.xyz * thickness * length(viewLine / STEPS) / 1000;

vec3 scatteredLight = sunLightColor * od;
result += scatteredLight * currentTransmittence;

currentTransmittence *= exp2(od);
transMittance *= exp2(-od);
}
return vec4(result * transMittance, transMittance);
}

vec3 toneMap(vec3 x)
{
return x;
}
13 changes: 11 additions & 2 deletions data/base/shaders/tcmask_instanced.frag
Original file line number Diff line number Diff line change
Expand Up @@ -376,9 +376,13 @@ void main()
0., 1., 0.,
0., 0., 1.
);
MaterialInfo materialInfo;
materialInfo.albedo = diffuse;
materialInfo.gloss = specularMapValue;
// Normals are in view space, we need to get back to world space
vec3 worldSpaceNormal = -(inverse(ViewMatrix) * vec4(N, 0.f)).xyz;
light += iterateOverAllPointLights(clipSpaceCoord, fragPos, worldSpaceNormal, normalize(halfVec - lightDir), diffuse, specularMapValue, identityMat);

light += iterateOverAllPointLights(clipSpaceCoord, fragPos, worldSpaceNormal, normalize(halfVec - lightDir), materialInfo, identityMat);
#endif

light.rgb *= visibility;
Expand All @@ -403,7 +407,12 @@ void main()
fragColour.a = 0.66 + 0.66 * graphicsCycle;
}

if (fogEnabled > 0)
if (WZ_VOLUMETRIC_LIGHTING_ENABLED != 0) {
vec2 clipSpaceCoord = gl_FragCoord.xy / vec2(viewportWidth, viewportHeight);
vec4 volumetric = volumetricLights(clipSpaceCoord, cameraPos.xyz, fragPos, diffuse.xyz);
fragColour.xyz = toneMap(fragColour.xyz * volumetric.a + volumetric.xyz) * lightmap_vec4.a;
}
else if (fogEnabled > 0)
{
// Calculate linear fog
float fogFactor = (fogEnd - vertexDistance) / (fogEnd - fogStart);
Expand Down
16 changes: 13 additions & 3 deletions data/base/shaders/terrain_combined_high.frag
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ uniform vec4 diffuseLight;
uniform vec4 specularLight;


uniform vec4 cameraPos; // in modelSpace
//uniform vec4 cameraPos; // in modelSpace
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to keep commented code. We can always bring it back via git, if needed.

uniform vec4 sunPos; // in modelSpace, normalized

// fog
Expand Down Expand Up @@ -148,10 +148,14 @@ vec4 doBumpMapping(BumpData b, vec3 lightDir, vec3 halfVec) {

vec4 res = (b.color*light) + light_spec;

MaterialInfo materialInfo;
materialInfo.albedo = b.color;
materialInfo.gloss = b.gloss;

#if WZ_POINT_LIGHT_ENABLED == 1
// point lights
vec2 clipSpaceCoord = gl_FragCoord.xy / vec2(float(viewportWidth), float(viewportHeight));
res += iterateOverAllPointLights(clipSpaceCoord, fragPos, b.N, normalize(halfVec - lightDir), b.color, b.gloss, ModelTangentMatrix);
res += iterateOverAllPointLights(clipSpaceCoord, fragPos, b.N, normalize(halfVec - lightDir), materialInfo, ModelTangentMatrix);
#endif

return vec4(res.rgb, b.color.a);
Expand Down Expand Up @@ -186,7 +190,13 @@ void main()
{
vec4 fragColor = main_bumpMapping();

if (fogEnabled > 0)
if (WZ_VOLUMETRIC_LIGHTING_ENABLED != 1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please elaborate why in this particular place the condition is != 1, when in other places (e.g. tcmask_instanced.frag) it's != 0? If this is expected, a comment about this would be really helpful.

vec4 lightmap_vec4 = texture(lightmap_tex, uvLightmap, 0.f);
vec2 clipSpaceCoord = gl_FragCoord.xy / vec2(viewportWidth, viewportHeight);
vec4 volumetric = volumetricLights(clipSpaceCoord, cameraPos.xyz, fragPos, diffuseLight.xyz);
fragColor.xyz = toneMap(fragColor.xyz * volumetric.a + volumetric.xyz) * lightmap_vec4.a;
}
else if (fogEnabled > 0)
{
// Calculate linear fog
float fogFactor = (fogEnd - vertexDistance) / (fogEnd - fogStart);
Expand Down
58 changes: 52 additions & 6 deletions data/base/shaders/vk/pointlights.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ float pointLightEnergyAtPosition(vec3 position, vec3 pointLightWorldPosition, fl
return numerator * numerator / ( 1 + 2 * sqNormDist);
}

vec4 processPointLight(vec3 WorldFragPos, vec3 fragNormal, vec3 viewVector, vec4 albedo, float gloss, vec3 pointLightWorldPosition, float pointLightEnergy, vec3 pointLightColor, mat3 normalWorldSpaceToLocalSpace)
struct MaterialInfo
{
vec4 albedo;
float gloss;
};

vec4 processPointLight(vec3 WorldFragPos, vec3 fragNormal, vec3 viewVector, MaterialInfo material, vec3 pointLightWorldPosition, float pointLightEnergy, vec3 pointLightColor, mat3 normalWorldSpaceToLocalSpace)
{
vec3 pointLightVector = WorldFragPos - pointLightWorldPosition;
vec3 pointLightDir = -normalize(pointLightVector * normalWorldSpaceToLocalSpace);
Expand All @@ -23,9 +29,10 @@ vec4 processPointLight(vec3 WorldFragPos, vec3 fragNormal, vec3 viewVector, vec4
vec3 pointLightHalfVec = normalize(viewVector + pointLightDir);

float pointLightBlinn = pow(clamp(dot(fragNormal, pointLightHalfVec), 0.f, 1.f), 16.f);
return lightColor * pointLightLambert * (albedo + pointLightBlinn * (gloss * gloss));
return lightColor * pointLightLambert * (material.albedo + pointLightBlinn * (material.gloss * material.gloss));
}


// This function expects that we have :
// - a uniforms named bucketOffsetAndSize of ivec4[]
// - a uniforms named PointLightsPosition of vec4[]
Expand All @@ -37,8 +44,7 @@ vec4 iterateOverAllPointLights(
vec3 WorldFragPos,
vec3 fragNormal,
vec3 viewVector,
vec4 albedo,
float gloss,
MaterialInfo material,
mat3 normalWorldSpaceToLocalSpace
) {
vec4 light = vec4(0);
Expand All @@ -51,8 +57,48 @@ vec4 iterateOverAllPointLights(
int lightIndex = PointLightsIndex[entryInLightList / 4][entryInLightList % 4];
vec4 position = PointLightsPosition[lightIndex];
vec4 colorAndEnergy = PointLightsColorAndEnergy[lightIndex];
vec3 tmp = position.xyz * vec3(1., 1., -1.);
light += processPointLight(WorldFragPos, fragNormal, viewVector, albedo, gloss, tmp, colorAndEnergy.w, colorAndEnergy.xyz, normalWorldSpaceToLocalSpace);
light += processPointLight(WorldFragPos, fragNormal, viewVector, material, position.xyz, colorAndEnergy.w, colorAndEnergy.xyz, normalWorldSpaceToLocalSpace);
}
return light;
}


// based on equations found here : https://www.shadertoy.com/view/lstfR7
vec4 volumetricLights(
vec2 clipSpaceCoord,
vec3 cameraPosition,
vec3 WorldFragPos,
vec3 sunLightColor
) {
vec3 result = vec3(0);
ivec2 bucket = ivec2(WZ_BUCKET_DIMENSION * clipSpaceCoord);
int bucketId = min(bucket.y + bucket.x * WZ_BUCKET_DIMENSION, WZ_BUCKET_DIMENSION * WZ_BUCKET_DIMENSION - 1);


vec3 viewLine = cameraPosition.xyz - WorldFragPos;
vec3 currentTransmittence = vec3(1);
vec3 transMittance = vec3(1);


#define STEPS (WZ_VOLUMETRIC_LIGHTING_ENABLED * 4)
for (int i = 0; i < STEPS; i++)
{

vec3 posOnViewLine = WorldFragPos + viewLine * i / STEPS;
// fog is thicker near 0
float thickness = exp(-posOnViewLine.y / 300);

vec3 od = fogColor.xyz * thickness * length(viewLine / STEPS) / 1000;
vec3 scatteredLight = sunLightColor * od;
result += scatteredLight * currentTransmittence;

currentTransmittence *= exp2(od);
transMittance *= exp2(-od);
}
return vec4(result * transMittance, transMittance);
}

vec3 toneMap(vec3 x)
{
return x;
}
20 changes: 15 additions & 5 deletions data/base/shaders/vk/tcmask_instanced.frag
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ layout (constant_id = 1) const uint WZ_SHADOW_MODE = 1;
layout (constant_id = 2) const uint WZ_SHADOW_FILTER_SIZE = 5;
layout (constant_id = 3) const uint WZ_SHADOW_CASCADES_COUNT = 3;
layout (constant_id = 4) const uint WZ_POINT_LIGHT_ENABLED = 0;
layout (constant_id = 5) const uint WZ_VOLUMETRIC_LIGHTING_ENABLED = 0;

layout(set = 2, binding = 0) uniform sampler2D Texture; // diffuse
layout(set = 2, binding = 1) uniform sampler2D TextureTcmask; // tcmask
Expand All @@ -31,8 +32,6 @@ layout(location = 12) in vec3 fragPos;

layout(location = 0) out vec4 FragColor;

#include "pointlights.glsl"

float getShadowMapDepthComp(vec2 base_uv, float u, float v, vec2 shadowMapSizeInv, int cascadeIndex, float z)
{
vec2 uv = base_uv + vec2(u, v) * shadowMapSizeInv;
Expand Down Expand Up @@ -264,6 +263,9 @@ float getShadowVisibility()
}
}


#include "pointlights.glsl"

vec3 blendAddEffectLighting(vec3 a, vec3 b) {
return min(a + b, vec3(1.0));
}
Expand Down Expand Up @@ -346,7 +348,10 @@ void main()
);
// Normals are in view space, we need to get back to world space
vec3 worldSpaceNormal = -(inverse(ViewMatrix) * vec4(N, 0.f)).xyz;
light += iterateOverAllPointLights(clipSpaceCoord, fragPos, worldSpaceNormal, normalize(halfVec - lightDir), diffuse, specularMapValue, identityMat);
MaterialInfo materialInfo;
materialInfo.albedo = diffuse;
materialInfo.gloss = specularMapValue;
light += iterateOverAllPointLights(clipSpaceCoord, fragPos, worldSpaceNormal, normalize(halfVec - lightDir), materialInfo, identityMat);
}

light.rgb *= visibility;
Expand All @@ -370,8 +375,13 @@ void main()
{
fragColour.a = 0.66 + 0.66 * graphicsCycle;
}

if (fogEnabled > 0)

if (WZ_VOLUMETRIC_LIGHTING_ENABLED != 0) {
vec2 clipSpaceCoord = gl_FragCoord.xy / vec2(viewportWidth, viewportHeight);
vec4 volumetric = volumetricLights(clipSpaceCoord, cameraPos.xyz, fragPos, diffuse.xyz);
fragColour.xyz = toneMap(fragColour.xyz * volumetric.a + volumetric.xyz) * lightmap_vec4.a;
}
else if (fogEnabled > 0)
{
// Calculate linear fog
float fogFactor = (fogEnd - vertexDistance) / (fogEnd - fogStart);
Expand Down
1 change: 1 addition & 0 deletions data/base/shaders/vk/tcmask_instanced.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ layout(std140, set = 0, binding = 0) uniform globaluniforms
vec4 PointLightsColorAndEnergy[WZ_MAX_POINT_LIGHTS];
ivec4 bucketOffsetAndSize[WZ_BUCKET_DIMENSION * WZ_BUCKET_DIMENSION];
ivec4 PointLightsIndex[WZ_MAX_INDEXED_POINT_LIGHTS];
vec4 cameraPos; // in modelSpace
};

layout(std140, set = 1, binding = 0) uniform meshuniforms
Expand Down
15 changes: 13 additions & 2 deletions data/base/shaders/vk/terrain_combined_high.frag
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ layout (constant_id = 1) const uint WZ_SHADOW_MODE = 1;
layout (constant_id = 2) const uint WZ_SHADOW_FILTER_SIZE = 5;
layout (constant_id = 3) const uint WZ_SHADOW_CASCADES_COUNT = 3;
layout (constant_id = 4) const uint WZ_POINT_LIGHT_ENABLED = 0;
layout (constant_id = 5) const uint WZ_VOLUMETRIC_LIGHTING_ENABLED = 0;

layout(set = 1, binding = 0) uniform sampler2D lightmap_tex;

Expand Down Expand Up @@ -64,6 +65,10 @@ vec3 blendAddEffectLighting(vec3 a, vec3 b) {
}

vec4 doBumpMapping(BumpData b, vec3 lightDir, vec3 halfVec) {
MaterialInfo materialInfo;
materialInfo.albedo = b.color;
materialInfo.gloss = b.gloss;

vec3 L = normalize(lightDir);
float lambertTerm = max(dot(b.N, L), 0.0); // diffuse lighting
// Gaussian specular term computation
Expand All @@ -90,7 +95,7 @@ vec4 doBumpMapping(BumpData b, vec3 lightDir, vec3 halfVec) {
{
// point lights
vec2 clipSpaceCoord = gl_FragCoord.xy / vec2(viewportWidth, viewportHeight);
res += iterateOverAllPointLights(clipSpaceCoord, frag.fragPos, b.N, normalize(halfVec - lightDir), b.color, b.gloss, ModelTangentMatrix);
res += iterateOverAllPointLights(clipSpaceCoord, frag.fragPos, b.N, normalize(halfVec - lightDir), materialInfo, ModelTangentMatrix);
}

return vec4(res.rgb, b.color.a);
Expand Down Expand Up @@ -125,7 +130,13 @@ void main()
{
vec4 fragColor = main_bumpMapping();

if (fogEnabled > 0)
if (WZ_VOLUMETRIC_LIGHTING_ENABLED != 1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

vec4 lightmap_vec4 = texture(lightmap_tex, frag.uvLightmap, 0.f);
vec2 clipSpaceCoord = gl_FragCoord.xy / vec2(viewportWidth, viewportHeight);
vec4 volumetric = volumetricLights(clipSpaceCoord, cameraPos.xyz, frag.fragPos, diffuseLight.xyz);
fragColor.xyz = toneMap(fragColor.xyz * volumetric.a + volumetric.xyz) * lightmap_vec4.a;
}
else if (fogEnabled > 0)
{
// Calculate linear fog
float fogFactor = (fogEnd - frag.vertexDistance) / (fogEnd - fogStart);
Expand Down
Loading