Skip to content

Commit

Permalink
Initial attempt: use lightmap in the object shader
Browse files Browse the repository at this point in the history
To apply terrain lightmap additive color (from environmental point lights / effects) to objects. For appearances, decrease how much this is applied based on the height above the terrain.
  • Loading branch information
past-due committed Sep 13, 2023
1 parent 06cdbae commit 06283eb
Show file tree
Hide file tree
Showing 19 changed files with 188 additions and 68 deletions.
9 changes: 8 additions & 1 deletion data/base/shaders/tcmask_depth_instanced.vert
Expand Up @@ -35,6 +35,10 @@ VERTEX_INPUT vec4 instancePackedValues; // shaderStretch_ecmState_alphaTest_anim
VERTEX_INPUT vec4 instanceColour;
VERTEX_INPUT vec4 instanceTeamColour;

float when_gt(float x, float y) {
return max(sign(x - y), 0.0);
}

void main()
{
// unpack inputs
Expand All @@ -45,7 +49,10 @@ void main()
vec4 position = vertex;
if (vertex.y <= 0.0) // use vertex here directly to help shader compiler optimization
{
position.y -= stretch;
// NOTE: 'stretch' may be:
// - if positive: building stretching
// - if negative: the height above the terrain of the model intance overall
position.y -= (stretch * when_gt(stretch, 0.f));
}

// Translate every vertex according to the Model View and Projection Matrix
Expand Down
18 changes: 15 additions & 3 deletions data/base/shaders/tcmask_instanced.frag
Expand Up @@ -17,6 +17,7 @@ uniform sampler2D TextureTcmask; // tcmask
uniform sampler2D TextureNormal; // normal map
uniform sampler2D TextureSpecular; // specular map
uniform sampler2DArrayShadow shadowMap; // shadow map
uniform sampler2D lightmap_tex;

uniform mat4 ViewMatrix;

Expand Down Expand Up @@ -56,6 +57,7 @@ FRAGMENT_INPUT mat4 NormalMatrix;
FRAGMENT_INPUT vec4 colour;
FRAGMENT_INPUT vec4 teamcolour;
FRAGMENT_INPUT vec4 packed_ecmState_alphaTest;
FRAGMENT_INPUT vec3 uvLightmap; // uvLightmap in .xy, heightAboveTerrain in .z

// For Shadows
FRAGMENT_INPUT vec3 fragPos;
Expand Down Expand Up @@ -289,6 +291,10 @@ float getShadowVisibility()
#endif
}

vec3 blendAddEffectLighting(vec3 a, vec3 b) {
return min(a + b, vec3(1.0));
}

void main()
{
// unpack inputs
Expand Down Expand Up @@ -327,6 +333,9 @@ void main()
vec3 L = normalize(lightDir);
float lambertTerm = max(dot(N, L), 0.0); //diffuse light
float visibility = getShadowVisibility();
vec4 lightmap_vec4 = texture(lightmap_tex, uvLightmap.xy, 0.f);
float distanceAboveTerrain = uvLightmap.z;
float lightmapFactor = 1.0f - (clamp(distanceAboveTerrain, 0.f, 300.f) / 300.f);

if (lambertTerm > 0.0)
{
Expand All @@ -350,7 +359,10 @@ void main()
light += diffuse * lambertTerm * diffuseMap * vanillaFactor;
}
// ambient light maxed for classic models to keep results similar to original
light += ambient * diffuseMap * (1.0 + (1.0 - float(specularmap)));
light += vec4(blendAddEffectLighting(ambient.rgb, ((lightmap_vec4.rgb * lightmapFactor) / 3.f)), ambient.a) * diffuseMap * (1.0 + (1.0 - float(specularmap)));

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

vec4 fragColour;
if (tcmask != 0)
Expand All @@ -359,11 +371,11 @@ void main()
float maskAlpha = texture(TextureTcmask, texCoord, WZ_MIP_LOAD_BIAS).r;

// Apply color using grain merge with tcmask
fragColour = visibility * (light + (teamcolour - 0.5) * maskAlpha) * colour;
fragColour = (light + (teamcolour - 0.5) * maskAlpha) * colour;
}
else
{
fragColour = visibility * light * colour;
fragColour = light * colour;
}

if (ecmEffect)
Expand Down
15 changes: 14 additions & 1 deletion data/base/shaders/tcmask_instanced.vert
Expand Up @@ -13,6 +13,8 @@

uniform mat4 ProjectionMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ModelUVLightmapMatrix;

uniform int hasTangents; // whether tangents were calculated for model
uniform vec4 lightPosition;

Expand Down Expand Up @@ -45,11 +47,16 @@ VERTEX_OUTPUT mat4 NormalMatrix;
VERTEX_OUTPUT vec4 colour;
VERTEX_OUTPUT vec4 teamcolour;
VERTEX_OUTPUT vec4 packed_ecmState_alphaTest;
VERTEX_OUTPUT vec3 uvLightmap; // uvLightmap in .xy, heightAboveTerrain in .z

// for Shadows
VERTEX_OUTPUT vec3 fragPos;
VERTEX_OUTPUT vec3 fragNormal;

float when_gt(float x, float y) {
return max(sign(x - y), 0.0);
}

void main()
{
// unpack inputs
Expand Down Expand Up @@ -93,13 +100,19 @@ void main()
vec4 position = vertex;
if (vertex.y <= 0.0) // use vertex here directly to help shader compiler optimization
{
position.y -= stretch;
// NOTE: 'stretch' may be:
// - if positive: building stretching
// - if negative: the height above the terrain of the model intance overall
position.y -= (stretch * when_gt(stretch, 0.f));
}

vec4 positionModelSpace = instanceModelMatrix * position;
fragPos = positionModelSpace.xyz;
fragNormal = vertexNormal;

float heightAboveTerrain = abs(clamp(sign(stretch), -1.f, 0.f)) * abs(stretch);
uvLightmap = vec3((ModelUVLightmapMatrix * positionModelSpace).xy, position.y + heightAboveTerrain);

// Translate every vertex according to the Model View and Projection Matrix
mat4 ModelViewProjectionMatrix = ProjectionMatrix * ModelViewMatrix;
vec4 gposition = ModelViewProjectionMatrix * position;
Expand Down
9 changes: 8 additions & 1 deletion data/base/shaders/vk/tcmask_depth_instanced.vert
Expand Up @@ -16,6 +16,10 @@ layout(location = 9) in vec4 instancePackedValues; // shaderStretch_ecmState_alp
layout(location = 10) in vec4 instanceColour;
layout(location = 11) in vec4 instanceTeamColour;

float when_gt(float x, float y) {
return max(sign(x - y), 0.0);
}

void main()
{
// unpack inputs
Expand All @@ -26,7 +30,10 @@ void main()
vec4 position = vertex;
if (vertex.y <= 0.0) // use vertex here directly to help shader compiler optimization
{
position.y -= stretch;
// NOTE: 'stretch' may be:
// - if positive: building stretching
// - if negative: the height above the terrain of the model intance overall
position.y -= (stretch * when_gt(stretch, 0.f));
}

// Translate every vertex according to the Model View and Projection Matrix
Expand Down
20 changes: 16 additions & 4 deletions data/base/shaders/vk/tcmask_instanced.frag
Expand Up @@ -13,6 +13,7 @@ layout(set = 2, binding = 1) uniform sampler2D TextureTcmask; // tcmask
layout(set = 2, binding = 2) uniform sampler2D TextureNormal; // normal map
layout(set = 2, binding = 3) uniform sampler2D TextureSpecular; // specular map
layout(set = 2, binding = 4) uniform sampler2DArrayShadow shadowMap; // shadow map
layout(set = 2, binding = 5) uniform sampler2D lightmap_tex;

layout(location = 0) in vec4 texCoord_vertexDistance; // vec(2) texCoord, float vertexDistance, (unused float)
layout(location = 1) in vec3 normal;
Expand All @@ -22,8 +23,9 @@ layout(location = 4) in mat4 NormalMatrix;
layout(location = 8) in vec4 colour;
layout(location = 9) in vec4 teamcolour;
layout(location = 10) in vec4 packed_ecmState_alphaTest;
layout(location = 11) in vec3 uvLightmap; // uvLightmap in .xy, heightAboveTerrain in .z
// For Shadows
layout(location = 11) in vec3 fragPos;
layout(location = 12) in vec3 fragPos;
//layout(location = 13) in vec3 fragNormal;

layout(location = 0) out vec4 FragColor;
Expand Down Expand Up @@ -259,6 +261,10 @@ float getShadowVisibility()
}
}

vec3 blendAddEffectLighting(vec3 a, vec3 b) {
return min(a + b, vec3(1.0));
}

void main()
{
// unpack inputs
Expand Down Expand Up @@ -297,6 +303,9 @@ void main()
vec3 L = normalize(lightDir);
float lambertTerm = max(dot(N, L), 0.0); //diffuse light
float visibility = getShadowVisibility();
vec4 lightmap_vec4 = texture(lightmap_tex, uvLightmap.xy, 0.f);
float distanceAboveTerrain = uvLightmap.z;
float lightmapFactor = 1.0f - (clamp(distanceAboveTerrain, 0.f, 300.f) / 300.f);

if (lambertTerm > 0.0)
{
Expand All @@ -320,7 +329,10 @@ void main()
light += diffuse * lambertTerm * diffuseMap * vanillaFactor;
}
// ambient light maxed for classic models to keep results similar to original
light += ambient * diffuseMap * (1.0 + (1.0 - float(specularmap)));
light += vec4(blendAddEffectLighting(ambient.rgb, ((lightmap_vec4.rgb * lightmapFactor) / 3.f)), ambient.a) * diffuseMap * (1.0 + (1.0 - float(specularmap)));

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

vec4 fragColour;
if (tcmask != 0)
Expand All @@ -329,11 +341,11 @@ void main()
float maskAlpha = texture(TextureTcmask, texCoord, WZ_MIP_LOAD_BIAS).r;

// Apply color using grain merge with tcmask
fragColour = visibility * (light + (teamcolour - 0.5) * maskAlpha) * colour;
fragColour = (light + (teamcolour - 0.5) * maskAlpha) * colour;
}
else
{
fragColour = visibility * light * colour;
fragColour = light * colour;
}

if (ecmEffect)
Expand Down
1 change: 1 addition & 0 deletions data/base/shaders/vk/tcmask_instanced.glsl
Expand Up @@ -6,6 +6,7 @@ layout(std140, set = 0, binding = 0) uniform globaluniforms
{
mat4 ProjectionMatrix;
mat4 ViewMatrix;
mat4 ModelUVLightmapMatrix;
mat4 ShadowMapMVPMatrix[WZ_MAX_SHADOW_CASCADES];
vec4 lightPosition;
vec4 sceneColor;
Expand Down
15 changes: 13 additions & 2 deletions data/base/shaders/vk/tcmask_instanced.vert
Expand Up @@ -20,10 +20,15 @@ layout(location = 4) out mat4 NormalMatrix;
layout(location = 8) out vec4 colour;
layout(location = 9) out vec4 teamcolour;
layout(location = 10) out vec4 packed_ecmState_alphaTest;
layout(location = 11) out vec3 uvLightmap; // uvLightmap in .xy, heightAboveTerrain in .z
// For Shadows
layout(location = 11) out vec3 fragPos;
layout(location = 12) out vec3 fragPos;
//layout(location = 13) out vec3 fragNormal;

float when_gt(float x, float y) {
return max(sign(x - y), 0.0);
}

void main()
{
// unpack inputs
Expand Down Expand Up @@ -67,13 +72,19 @@ void main()
vec4 position = vertex;
if (vertex.y <= 0.0) // use vertex here directly to help shader compiler optimization
{
position.y -= stretch;
// NOTE: 'stretch' may be:
// - if positive: building stretching
// - if negative: the height above the terrain of the model intance overall
position.y -= (stretch * when_gt(stretch, 0.f));
}

vec4 positionModelSpace = instanceModelMatrix * position;
fragPos = positionModelSpace.xyz;
// fragNormal = vertexNormal;

float heightAboveTerrain = abs(clamp(sign(stretch), -1.f, 0.f)) * abs(stretch);
uvLightmap = vec3((ModelUVLightmapMatrix * positionModelSpace).xy, position.y + heightAboveTerrain);

// Translate every vertex according to the Model View and Projection Matrix
mat4 ModelViewProjectionMatrix = ProjectionMatrix * ModelViewMatrix;
vec4 gposition = ModelViewProjectionMatrix * position;
Expand Down
4 changes: 3 additions & 1 deletion lib/ivis_opengl/gfx_api.h
Expand Up @@ -730,6 +730,7 @@ namespace gfx_api
{
glm::mat4 ProjectionMatrix;
glm::mat4 ViewMatrix;
glm::mat4 ModelUVLightmapMatrix;
glm::mat4 ShadowMapMVPMatrix[WZ_MAX_SHADOW_CASCADES];
glm::vec4 sunPos;
glm::vec4 sceneColor;
Expand Down Expand Up @@ -797,7 +798,8 @@ namespace gfx_api
texture_description<1, sampler_type::bilinear>, // team color mask
texture_description<2, sampler_type::anisotropic>, // normal map
texture_description<3, sampler_type::anisotropic>, // specular map
texture_description<4, sampler_type::bilinear_border, pixel_format_target::depth_map, border_color::opaque_white> // depth / shadow map
texture_description<4, sampler_type::bilinear_border, pixel_format_target::depth_map, border_color::opaque_white>, // depth / shadow map
texture_description<5, sampler_type::bilinear> // lightmap
>, shader>;

using Draw3DShapeOpaque_Instanced = Draw3DShapeInstanced<REND_OPAQUE, SHADER_COMPONENT_INSTANCED, DEPTH_CMP_LEQ_WRT_ON>;
Expand Down
42 changes: 22 additions & 20 deletions lib/ivis_opengl/gfx_api_gl.cpp
Expand Up @@ -647,12 +647,13 @@ static const std::map<SHADER_MODE, program_data> shader_to_file_table =
std::make_pair(SHADER_COMPONENT_INSTANCED, program_data{ "Component program", "shaders/tcmask_instanced.vert", "shaders/tcmask_instanced.frag",
{
// per-frame global uniforms
"ProjectionMatrix", "ViewMatrix", "ShadowMapMVPMatrix", "lightPosition", "sceneColor", "ambient", "diffuse", "specular", "fogColor", "ShadowMapCascadeSplits", "ShadowMapSize", "fogEnd", "fogStart", "graphicsCycle", "fogEnabled",
"ProjectionMatrix", "ViewMatrix", "ModelUVLightmapMatrix", "ShadowMapMVPMatrix", "lightPosition", "sceneColor", "ambient", "diffuse", "specular", "fogColor", "ShadowMapCascadeSplits", "ShadowMapSize", "fogEnd", "fogStart", "graphicsCycle", "fogEnabled",
// per-mesh uniforms
"tcmask", "normalmap", "specularmap", "hasTangents"
},
{
{"shadowMap", 4}
{"shadowMap", 4},
{"lightmap_tex", 5}
} }),
std::make_pair(SHADER_COMPONENT_DEPTH_INSTANCED, program_data{ "Component program", "shaders/tcmask_depth_instanced.vert", "shaders/tcmask_depth_instanced.frag",
{
Expand All @@ -671,7 +672,7 @@ static const std::map<SHADER_MODE, program_data> shader_to_file_table =
std::make_pair(SHADER_NOLIGHT_INSTANCED, program_data{ "Plain program", "shaders/nolight_instanced.vert", "shaders/nolight_instanced.frag",
{
// per-frame global uniforms
"ProjectionMatrix", "ViewMatrix", "ShadowMapMVPMatrix", "lightPosition", "sceneColor", "ambient", "diffuse", "specular", "fogColor", "ShadowMapCascadeSplits", "ShadowMapSize", "fogEnd", "fogStart", "graphicsCycle", "fogEnabled",
"ProjectionMatrix", "ViewMatrix", "ModelUVLightmapMatrix", "ShadowMapMVPMatrix", "lightPosition", "sceneColor", "ambient", "diffuse", "specular", "fogColor", "ShadowMapCascadeSplits", "ShadowMapSize", "fogEnd", "fogStart", "graphicsCycle", "fogEnabled",
// per-mesh uniforms
"tcmask", "normalmap", "specularmap", "hasTangents",
},
Expand Down Expand Up @@ -1862,27 +1863,28 @@ void gl_pipeline_state_object::set_constants(const gfx_api::Draw3DShapeInstanced
{
setUniforms(0, cbuf.ProjectionMatrix);
setUniforms(1, cbuf.ViewMatrix);
setUniforms(2, cbuf.ShadowMapMVPMatrix, WZ_MAX_SHADOW_CASCADES);
setUniforms(3, cbuf.sunPos);
setUniforms(4, cbuf.sceneColor);
setUniforms(5, cbuf.ambient);
setUniforms(6, cbuf.diffuse);
setUniforms(7, cbuf.specular);
setUniforms(8, cbuf.fogColour);
setUniforms(9, cbuf.ShadowMapCascadeSplits);
setUniforms(10, cbuf.ShadowMapSize);
setUniforms(11, cbuf.fogEnd);
setUniforms(12, cbuf.fogBegin);
setUniforms(13, cbuf.timeState);
setUniforms(14, cbuf.fogEnabled);
setUniforms(2, cbuf.ModelUVLightmapMatrix);
setUniforms(3, cbuf.ShadowMapMVPMatrix, WZ_MAX_SHADOW_CASCADES);
setUniforms(4, cbuf.sunPos);
setUniforms(5, cbuf.sceneColor);
setUniforms(6, cbuf.ambient);
setUniforms(7, cbuf.diffuse);
setUniforms(8, cbuf.specular);
setUniforms(9, cbuf.fogColour);
setUniforms(10, cbuf.ShadowMapCascadeSplits);
setUniforms(11, cbuf.ShadowMapSize);
setUniforms(12, cbuf.fogEnd);
setUniforms(13, cbuf.fogBegin);
setUniforms(14, cbuf.timeState);
setUniforms(15, cbuf.fogEnabled);
}

void gl_pipeline_state_object::set_constants(const gfx_api::Draw3DShapeInstancedPerMeshUniforms& cbuf)
{
setUniforms(15, cbuf.tcmask);
setUniforms(16, cbuf.normalMap);
setUniforms(17, cbuf.specularMap);
setUniforms(18, cbuf.hasTangents);
setUniforms(16, cbuf.tcmask);
setUniforms(17, cbuf.normalMap);
setUniforms(18, cbuf.specularMap);
setUniforms(19, cbuf.hasTangents);
}

void gl_pipeline_state_object::set_constants(const gfx_api::Draw3DShapeInstancedDepthOnlyGlobalUniforms& cbuf)
Expand Down

0 comments on commit 06283eb

Please sign in to comment.