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

Implement pointlights #3587

Merged
merged 12 commits into from
Jan 14, 2024
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
69 changes: 69 additions & 0 deletions data/base/shaders/pointlights.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#define WZ_MAX_POINT_LIGHTS 0
#define WZ_MAX_INDEXED_POINT_LIGHTS 0
#define WZ_BUCKET_DIMENSION 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;

// 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
float pointLightEnergyAtPosition(vec3 position, vec3 pointLightWorldPosition, float range)
{
vec3 pointLightVector = position - pointLightWorldPosition;
float normalizedDistance = length(pointLightVector) / range;

float sqNormDist = normalizedDistance * normalizedDistance;
float numerator = max(1.f - sqNormDist, 0.f);
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)
{
vec3 pointLightVector = WorldFragPos - pointLightWorldPosition;
vec3 pointLightDir = -normalize(pointLightVector * normalWorldSpaceToLocalSpace);

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

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

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));
}

// This function expects that we have :
// - a uniforms named bucketOffsetAndSize of ivec4[]
// - a uniforms named PointLightsPosition of vec4[]
// - a uniforms named colorAndEnergy of vec4[]
// fragNormal and view vector are expected to be in the same local space
// normalWorldSpaceToLocalSpace is used to move from world space to local space
vec4 iterateOverAllPointLights(
vec2 clipSpaceCoord,
vec3 WorldFragPos,
vec3 fragNormal,
vec3 viewVector,
vec4 albedo,
float gloss,
mat3 normalWorldSpaceToLocalSpace
) {
vec4 light = vec4(0.f);
ivec2 bucket = ivec2(float(WZ_BUCKET_DIMENSION) * clipSpaceCoord);
int bucketId = min(bucket.y + bucket.x * WZ_BUCKET_DIMENSION, WZ_BUCKET_DIMENSION * WZ_BUCKET_DIMENSION - 1);

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];
vec3 tmp = position.xyz * vec3(1.f, 1.f, -1.f);
light += processPointLight(WorldFragPos, fragNormal, viewVector, albedo, gloss, tmp, colorAndEnergy.w, colorAndEnergy.xyz, normalWorldSpaceToLocalSpace);
}
return light;
}
20 changes: 19 additions & 1 deletion data/base/shaders/tcmask_instanced.frag
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define WZ_SHADOW_MODE 1
#define WZ_SHADOW_FILTER_SIZE 3
#define WZ_SHADOW_CASCADES_COUNT 3
#define WZ_POINT_LIGHT_ENABLED 0
//

#define WZ_MAX_SHADOW_CASCADES 3
Expand Down Expand Up @@ -69,6 +70,10 @@ out vec4 FragColor;
// Uses gl_FragColor
#endif

#if WZ_POINT_LIGHT_ENABLED == 1
#include "pointlights.frag"
#endif

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 @@ -337,13 +342,15 @@ void main()
float distanceAboveTerrain = uvLightmap.z;
float lightmapFactor = 1.0f - (clamp(distanceAboveTerrain, 0.f, 300.f) / 300.f);

float specularMapValue = 0.f;

if (lambertTerm > 0.0)
{
float vanillaFactor = 0.0; // Classic models shouldn't use diffuse light

if (specularmap != 0)
{
float specularMapValue = texture(TextureSpecular, texCoord, WZ_MIP_LOAD_BIAS).r;
specularMapValue = texture(TextureSpecular, texCoord, WZ_MIP_LOAD_BIAS).r;
vec4 specularFromMap = vec4(specularMapValue, specularMapValue, specularMapValue, 1.0);

// Gaussian specular term computation
Expand All @@ -361,6 +368,17 @@ void main()
// ambient light maxed for classic models to keep results similar to original
light += vec4(blendAddEffectLighting(ambient.rgb, ((lightmap_vec4.rgb * lightmapFactor) / 3.f)), ambient.a) * diffuseMap * (1.0 + (1.0 - float(specularmap)));

#if WZ_POINT_LIGHT_ENABLED == 1
vec2 clipSpaceCoord = gl_FragCoord.xy / vec2(float(viewportWidth), float(viewportHeight));

mat3 identityMat = mat3(
1., 0., 0.,
0., 1., 0.,
0., 0., 1.
);
light += iterateOverAllPointLights(clipSpaceCoord, fragPos, -N, normalize(halfVec - lightDir), diffuse, specularMapValue, identityMat);
#endif

light.rgb *= visibility;
light.a = 1.0f;

Expand Down
4 changes: 3 additions & 1 deletion data/base/shaders/terrain_combined.vert
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ out vec4 fgroundWeights;
out vec3 groundLightDir;
out vec3 groundHalfVec;
out mat2 decal2groundMat2;

out mat3 ModelTangentMatrix;
// for Shadows
out vec3 fragPos;
out vec3 fragNormal;
Expand All @@ -55,7 +57,7 @@ void main()
vec3 vaxis = vec3(1,0,0); // v ~ vertex.x, see uv_ground
vec3 tangent = normalize(cross(vertexNormal, vaxis));
vec3 bitangent = cross(vertexNormal, tangent);
mat3 ModelTangentMatrix = mat3(tangent, bitangent, vertexNormal); // aka TBN-matrix
ModelTangentMatrix = mat3(tangent, bitangent, vertexNormal); // aka TBN-matrix
// transform light to TangentSpace:
vec3 eyeVec = normalize((cameraPos.xyz - vertex.xyz) * ModelTangentMatrix);
groundLightDir = sunPos.xyz * ModelTangentMatrix; // already normalized
Expand Down
13 changes: 13 additions & 0 deletions data/base/shaders/terrain_combined_high.frag
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define WZ_SHADOW_MODE 1
#define WZ_SHADOW_FILTER_SIZE 3
#define WZ_SHADOW_CASCADES_COUNT 3
#define WZ_POINT_LIGHT_ENABLED 0
//

#define WZ_MAX_SHADOW_CASCADES 3
Expand Down Expand Up @@ -58,6 +59,8 @@ uniform vec4 ambientLight;
uniform vec4 diffuseLight;
uniform vec4 specularLight;


uniform vec4 cameraPos; // in modelSpace
uniform vec4 sunPos; // in modelSpace, normalized

// fog
Expand All @@ -77,6 +80,9 @@ in vec4 fgroundWeights;
in vec3 groundLightDir;
in vec3 groundHalfVec;
in mat2 decal2groundMat2;


in mat3 ModelTangentMatrix;
// For Shadows
in vec3 fragPos;
in vec3 fragNormal;
Expand All @@ -88,6 +94,7 @@ out vec4 FragColor;
#endif

#include "terrain_combined_frag.glsl"
#include "pointlights.frag"

vec3 getGroundUv(int i) {
uint groundNo = fgrounds[i];
Expand Down Expand Up @@ -141,6 +148,12 @@ vec4 doBumpMapping(BumpData b, vec3 lightDir, vec3 halfVec) {

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

#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);
#endif

return vec4(res.rgb, b.color.a);
}

Expand Down
58 changes: 58 additions & 0 deletions data/base/shaders/vk/pointlights.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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
float pointLightEnergyAtPosition(vec3 position, vec3 pointLightWorldPosition, float range)
{
vec3 pointLightVector = position - pointLightWorldPosition;
float normalizedDistance = length(pointLightVector) / range;

float sqNormDist = normalizedDistance * normalizedDistance;
float numerator = max(1 - sqNormDist, 0);
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)
{
vec3 pointLightVector = WorldFragPos - pointLightWorldPosition;
vec3 pointLightDir = -normalize(pointLightVector * normalWorldSpaceToLocalSpace);

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

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));
}

// This function expects that we have :
// - a uniforms named bucketOffsetAndSize of ivec4[]
// - a uniforms named PointLightsPosition of vec4[]
// - a uniforms named colorAndEnergy of vec4[]
// fragNormal and view vector are expected to be in the same local space
// normalWorldSpaceToLocalSpace is used to move from world space to local space
vec4 iterateOverAllPointLights(
vec2 clipSpaceCoord,
vec3 WorldFragPos,
vec3 fragNormal,
vec3 viewVector,
vec4 albedo,
float gloss,
mat3 normalWorldSpaceToLocalSpace
) {
vec4 light = vec4(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);

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];
vec3 tmp = position.xyz * vec3(1., 1., -1.);
light += processPointLight(WorldFragPos, fragNormal, viewVector, albedo, gloss, tmp, colorAndEnergy.w, colorAndEnergy.xyz, normalWorldSpaceToLocalSpace);
}
return light;
}
18 changes: 17 additions & 1 deletion data/base/shaders/vk/tcmask_instanced.frag
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ layout (constant_id = 0) const float WZ_MIP_LOAD_BIAS = 0.f;
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(set = 2, binding = 0) uniform sampler2D Texture; // diffuse
layout(set = 2, binding = 1) uniform sampler2D TextureTcmask; // tcmask
Expand All @@ -30,6 +31,8 @@ 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 @@ -307,13 +310,14 @@ void main()
float distanceAboveTerrain = uvLightmap.z;
float lightmapFactor = 1.0f - (clamp(distanceAboveTerrain, 0.f, 300.f) / 300.f);

float specularMapValue = 0.f;
if (lambertTerm > 0.0)
{
float vanillaFactor = 0.0; // Classic models shouldn't use diffuse light

if (specularmap != 0)
{
float specularMapValue = texture(TextureSpecular, texCoord, WZ_MIP_LOAD_BIAS).r;
specularMapValue = texture(TextureSpecular, texCoord, WZ_MIP_LOAD_BIAS).r;
vec4 specularFromMap = vec4(specularMapValue, specularMapValue, specularMapValue, 1.0);

// Gaussian specular term computation
Expand All @@ -331,6 +335,18 @@ void main()
// ambient light maxed for classic models to keep results similar to original
light += vec4(blendAddEffectLighting(ambient.rgb, ((lightmap_vec4.rgb * lightmapFactor) / 3.f)), ambient.a) * diffuseMap * (1.0 + (1.0 - float(specularmap)));

if (WZ_POINT_LIGHT_ENABLED == 1)
{
vec2 clipSpaceCoord = gl_FragCoord.xy / vec2(viewportWidth, viewportHeight);

mat3 identityMat = mat3(
1., 0., 0.,
0., 1., 0.,
0., 0., 1.
);
light += iterateOverAllPointLights(clipSpaceCoord, fragPos, -N, normalize(halfVec - lightDir), diffuse, specularMapValue, identityMat);
}

light.rgb *= visibility;
light.a = 1.0f;

Expand Down
11 changes: 11 additions & 0 deletions data/base/shaders/vk/tcmask_instanced.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

#define WZ_MAX_SHADOW_CASCADES 3

#define WZ_MAX_POINT_LIGHTS 128
#define WZ_MAX_INDEXED_POINT_LIGHTS 512
#define WZ_BUCKET_DIMENSION 8

layout(std140, set = 0, binding = 0) uniform globaluniforms
{
mat4 ProjectionMatrix;
Expand All @@ -20,6 +24,13 @@ layout(std140, set = 0, binding = 0) uniform globaluniforms
float fogStart;
float graphicsCycle;
int fogEnabled;
int viewportWidth;
int viewportHeight;

vec4 PointLightsPosition[WZ_MAX_POINT_LIGHTS];
vec4 PointLightsColorAndEnergy[WZ_MAX_POINT_LIGHTS];
ivec4 bucketOffsetAndSize[WZ_BUCKET_DIMENSION * WZ_BUCKET_DIMENSION];
ivec4 PointLightsIndex[WZ_MAX_INDEXED_POINT_LIGHTS];
};

layout(std140, set = 1, binding = 0) uniform meshuniforms
Expand Down
10 changes: 10 additions & 0 deletions data/base/shaders/vk/terrain_combined.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

#define WZ_MAX_SHADOW_CASCADES 3

#define WZ_MAX_POINT_LIGHTS 128
#define WZ_MAX_INDEXED_POINT_LIGHTS 512
#define WZ_BUCKET_DIMENSION 8

layout(std140, set = 0, binding = 0) uniform cbuffer {
mat4 ModelViewProjectionMatrix;
mat4 ViewMatrix;
Expand All @@ -21,6 +25,12 @@ layout(std140, set = 0, binding = 0) uniform cbuffer {
float fogEnd;
float fogStart;
int quality;
int viewportWidth;
int viewportHeight;
vec4 PointLightsPosition[WZ_MAX_POINT_LIGHTS];
vec4 PointLightsColorAndEnergy[WZ_MAX_POINT_LIGHTS];
ivec4 bucketOffsetAndSize[WZ_BUCKET_DIMENSION * WZ_BUCKET_DIMENSION];
ivec4 PointLightsIndex[WZ_MAX_INDEXED_POINT_LIGHTS];
};

// interpolated data. location count = 11
Expand Down
3 changes: 2 additions & 1 deletion data/base/shaders/vk/terrain_combined.vert
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ layout(location = 7) in vec4 groundWeights; // ground weights for splatting

layout(location = 0) out FragData frag;
layout(location = 11) out flat FragFlatData fragf;
layout(location = 14) out mat3 ModelTangentMatrix;

void main()
{
Expand All @@ -33,7 +34,7 @@ void main()
vec3 vaxis = vec3(1,0,0); // v ~ vertex.x, see uv_ground
vec3 tangent = normalize(cross(vertexNormal, vaxis));
vec3 bitangent = cross(vertexNormal, tangent);
mat3 ModelTangentMatrix = mat3(tangent, bitangent, vertexNormal); // aka TBN-matrix
ModelTangentMatrix = mat3(tangent, bitangent, vertexNormal); // aka TBN-matrix
// transform light to TangentSpace:
vec3 eyeVec = normalize((cameraPos.xyz - vertex.xyz) * ModelTangentMatrix);
frag.groundLightDir = sunPos.xyz * ModelTangentMatrix; // already normalized
Expand Down
Loading
Loading