Skip to content

Commit

Permalink
pointslights: implement pointlights
Browse files Browse the repository at this point in the history
  • Loading branch information
vlj committed Jan 6, 2024
1 parent be96c72 commit db2e567
Show file tree
Hide file tree
Showing 46 changed files with 961 additions and 181 deletions.
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 - 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;
}
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;

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(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);
#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
10 changes: 10 additions & 0 deletions data/base/shaders/terrain_combined_high.frag
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,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 +79,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 +93,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 +147,10 @@ vec4 doBumpMapping(BumpData b, vec3 lightDir, vec3 halfVec) {

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

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

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;
}
14 changes: 13 additions & 1 deletion data/base/shaders/vk/tcmask_instanced.frag
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,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 +309,14 @@ void main()
float distanceAboveTerrain = uvLightmap.z;
float lightmapFactor = 1.0f - (clamp(distanceAboveTerrain, 0.f, 300.f) / 300.f);

float specularMapValue = 0;
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 +334,15 @@ 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)));

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
11 changes: 11 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,11 @@

#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 +26,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
6 changes: 6 additions & 0 deletions data/base/shaders/vk/terrain_combined_high.frag
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ layout(set = 1, binding = 9) uniform sampler2DArrayShadow shadowMap;

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

layout(location = 0) out vec4 FragColor;

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

vec3 getGroundUv(int i) {
uint groundNo = fragf.grounds[i];
Expand Down Expand Up @@ -83,6 +85,10 @@ vec4 doBumpMapping(BumpData b, vec3 lightDir, vec3 halfVec) {

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

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

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

Expand Down
4 changes: 2 additions & 2 deletions lib/framework/string_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
# endif
# if defined(DEBUG)
# define strdup(s) \
strdup2(s,__FILE__,__LINE__)
static inline char *strdup2(const char *s, char *fileName, int line)
strdup2(static_cast<const char*>(s),__LINE__)
static inline char *strdup2(const char *s, int line)
{
char *result;

Expand Down
Loading

0 comments on commit db2e567

Please sign in to comment.