Skip to content

Commit

Permalink
volumetric: start gl implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
vlj committed Jan 28, 2024
1 parent e702003 commit 732f1bf
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 12 deletions.
131 changes: 123 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 1

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,115 @@ 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;
}



float getShadowVisibilityWithoutPCF(vec3 fragPos)
{
if (WZ_SHADOW_MODE == 0 || WZ_SHADOW_FILTER_SIZE == 0)
{
// no shadow-mapping
return 1.0;
}
else
{
// Shadow Mapping

vec4 fragPosViewSpace = ViewMatrix * vec4(fragPos, 1.0);
float depthValue = abs(fragPosViewSpace.z);

int cascadeIndex = 0;

// unrolled loop, using vec4 swizzles
if (WZ_SHADOW_CASCADES_COUNT > 1)
{
if (depthValue >= ShadowMapCascadeSplits.x)
{
cascadeIndex = 1;
}
}
if (WZ_SHADOW_CASCADES_COUNT > 2)
{
if (depthValue >= ShadowMapCascadeSplits.y)
{
cascadeIndex = 2;
}
}
if (WZ_SHADOW_CASCADES_COUNT > 3)
{
if (depthValue >= ShadowMapCascadeSplits.z)
{
cascadeIndex = 3;
}
}

vec4 shadowPos = ShadowMapMVPMatrix[cascadeIndex] * vec4(fragPos, 1.0);
vec3 pos = shadowPos.xyz / shadowPos.w;

if (pos.z > 1.0f)
{
return 1.0;
}

float bias = 0.0002f;

return texture( shadowMap, vec4(pos.xy, cascadeIndex, (pos.z+bias)) );
}
}


// 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 64
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;

float sunLightEnergy = getShadowVisibilityWithoutPCF(posOnViewLine) ;
vec3 scatteredLight = vec3(sunLightEnergy) * sunLightColor * od;

for (int i = 0; i < bucketOffsetAndSize[bucketId].y; i++)
{
int entryInLightList = bucketOffsetAndSize[bucketId].x + i;
int lightIndex = PointLightsIndex[entryInLightList / 4][entryInLightList % 4];
vec4 position = PointLightsPosition[lightIndex];
vec4 colorAndEnergy = PointLightsColorAndEnergy[lightIndex];
scatteredLight += colorAndEnergy.xyz * pointLightEnergyAtPosition(posOnViewLine, position.xyz, colorAndEnergy.w) * 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 == 1) {
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);
}
else if (fogEnabled > 0)
{
// Calculate linear fog
float fogFactor = (fogEnd - vertexDistance) / (fogEnd - fogStart);
Expand Down
13 changes: 11 additions & 2 deletions data/base/shaders/terrain_combined_high.frag
Original file line number Diff line number Diff line change
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,12 @@ void main()
{
vec4 fragColor = main_bumpMapping();

if (fogEnabled > 0)
if (WZ_VOLUMETRIC_LIGHTING_ENABLED == 1) {
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);
}
else if (fogEnabled > 0)
{
// Calculate linear fog
float fogFactor = (fogEnd - vertexDistance) / (fogEnd - fogStart);
Expand Down

0 comments on commit 732f1bf

Please sign in to comment.