17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-30 09:40:29 +01:00

Vulkan: scene rendering (D1–D7) on a scene walk shared with GL (N6a, N6b)

This commit is contained in:
2026-10-24 20:10:24 +02:00
parent bd589f272d
commit 9b7d02e5fb
107 changed files with 14511 additions and 3924 deletions

View File

@@ -41,3 +41,25 @@ source, compile the binaries again (or delete them): a binary older than its sou
* The constants of the game (bindings, sizes) are written in `ogl46/common.glsl` and `vk14/common.glsl` for the binaries; the
game puts its own values before the sources and checks at the start that the files have the same ones (the shader
validator in `ci_shadervalidator` checks them too).
## vk14
The shaders of `vk14/` are those of `ogl46/` made for the descriptor sets of the Vulkan renderer
(`rendering/vulkan14/vulkan14bindings.h`), drawn with the same matrices and the same conventions as the OpenGL renderer
(nothing is turned upside down but the picture shown in the window, `present.frag`).
* A stage file includes `common.glsl` right after its stage define. The pipeline layout it is drawn with is picked by a
define before that include: none for the passes of the scene, `LAYOUT_POST` for the post-processing (with `quad.vert`),
`LAYOUT_CLUSTER` for the compute passes of the light clusters, `LAYOUT_UI` for the user interface.
* The scene: set `PASS_SET` holds the blocks of the scene, of the draws (`model_draws[]`, the one of a draw picked by the push
constant `pc.draw`), of the instances and of the lights and clusters, and the shadow, environment and headlight maps;
set `MATERIAL_SET` the textures of the material at `MATERIAL_TEXTURE_FIRST + unit` of their `#pragma texture`. The names of
the model block (`modelview`, `param`, `opacity` ...) stand for the fields of the draw, as in the `MODEL_DRAWS` variant of
`ogl46/`.
* The push constants (`pc`, `PUSH_CONSTANTS_SIZE` bytes) carry the draw and the parameters of the special shaders in
`pc.data[]`; each of those says at the top what it takes from them. In the post-processing `param` stands for `pc.data`.
* The settings are specialization constants with the ids `SPEC_*` (`vk14/settings.glsl`).
* The features of the later stages of the renderer (the shadows of the lamps and the headlights, the contact shadows, the
weather and its fog, the sky ambient light, the prefiltered environment map, the automatic exposure, soft and gpu
particles) aren't in `vk14/` yet; the code paths are the ones `ogl46/` takes with them off, the fog is an analytic one
(`vk14/apply_fog.glsl`).

View File

@@ -23,9 +23,10 @@ import sys
STAGES = ('.vert', '.frag', '.geom', '.comp')
TREES = {
# source directory, binary directory, target environment, variants of the vertex and fragment shaders
'ogl46': ('ogl46', 'ogl46bin', 'opengl4.5', ['MODEL_DRAWS']),
'vk14': ('vk14', 'vk14bin', 'vulkan1.4', []),
# source directory, binary directory, target environment, variants of the vertex and fragment shaders, whether a variant is
# made only for the files which use its name (opengl links a program from the binaries of all of its stages or from none)
'ogl46': ('ogl46', 'ogl46bin', 'opengl4.5', ['MODEL_DRAWS'], False),
'vk14': ('vk14', 'vk14bin', 'vulkan1.4', ['NO_MOTION_OUTPUT'], True),
}
INCLUDE = re.compile(r'^[ \t]*#include[ \t]*[<"]([^>"]+)[>"]', re.M)
@@ -84,7 +85,7 @@ def main():
failed = []
count = 0
for key, (sourcedir, binarydir, env, variants) in TREES.items():
for key, (sourcedir, binarydir, env, variants, onlyused) in TREES.items():
if args.only and args.only != key:
continue
sources = os.path.join(args.shaders, sourcedir)
@@ -96,13 +97,17 @@ def main():
names = sorted(n for n in os.listdir(sources) if os.path.splitext(n)[1] in STAGES)
for name in names:
jobs = [('', [])]
if os.path.splitext(name)[1] in ('.vert', '.frag'):
jobs += [(v, ['-D%s=1' % v]) for v in variants]
try:
deps = dependencies(sources, name)
except OSError as e:
failed.append('%s/%s (%s)' % (sourcedir, name, e))
continue
if os.path.splitext(name)[1] in ('.vert', '.frag'):
text = ''
for dep in deps:
with open(os.path.join(sources, dep), 'r', encoding='utf-8', errors='replace') as f:
text += f.read()
jobs += [(v, ['-D%s=1' % v]) for v in variants if (not onlyused) or (v in text)]
for variant, defines in jobs:
binary = name + ('.' + variant if variant else '') + '.spv'
command = [glslc, '--target-env=' + env] + defines + [os.path.join(sources, name), '-o', os.path.join(binaries, binary)]

View File

@@ -0,0 +1,13 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 2) in vec2 f_coord;
#pragma texture(tex1, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D tex1;
void main()
{
if (texture(tex1, f_coord).a < 0.5f)
discard;
}

View File

@@ -0,0 +1,40 @@
// fog between the camera and a fragment, the api of shaders/ogl46/apply_fog.glsl. the fog volume and the weather of the opengl
// renderer come with the stage P2 of the plan; until then the fog is analytic: exponential with the distance, of the density of
// the draw (fog_density of the model block, a draw with 0 is not fogged), of the colour fog_color of the light buffer, turned
// towards the colour of the sun around its direction
// rgb: light the fog adds, a: what it lets through
vec4 fog_at_fragment()
{
if (fog_density <= 0.0)
return vec4(0.0, 0.0, 0.0, 1.0);
float amount = 1.0 - clamp(exp(-length(f_pos.xyz) * fog_density), 0.0, 1.0);
vec3 color = fog_color;
if ((lights_count >= 1U) && (lights[0].type == LIGHT_DIR))
{
float sunward = pow(max(dot(normalize(f_pos.xyz), normalize(-lights[0].dir)), 0.0), 30.0);
color = mix(color, lights[0].color, sunward);
}
return vec4(color * amount, 1.0 - amount);
}
vec3 get_fog_color()
{
vec4 fog = fog_at_fragment();
return fog.rgb / max(1.0 - fog.a, 1e-4);
}
float get_fog_amount()
{
return 1.0 - fog_at_fragment().a;
}
vec3 apply_fog(vec3 color)
{
vec4 fog = fog_at_fragment();
return color * fog.a + fog.rgb;
}
vec3 add_fog(vec3 color, float amount)
{
return color + fog_at_fragment().rgb * amount;
}

View File

@@ -0,0 +1,34 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 2) in vec2 f_coord;
#pragma texture(tex1, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D tex1;
#include "tonemapping.glsl"
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
void main()
{
vec4 tex_color = texture(tex1, f_coord);
if (POSTFX_ENABLED)
{
out_color = tex_color * param[0];
}
else
{
out_color = tonemap(tex_color * param[0]);
}
if (MOTIONBLUR_ENABLED)
{
out_motion = vec4(0.0f);
}
}

View File

@@ -0,0 +1,93 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
// the sun, the moon and the textured sprite of the easter egg, drawn over the sky on a quad around the direction of the body
// (celestial.vert). param[0]: colour (rgb) and alpha, param[1]: position in view space and half the size of the quad,
// param[2].xy: corner (sprite) or centre (moon) of the picture in the texture, param[2].z: its size (sprite) or the radius of
// the disc in it (moon), in texture units, param[2].w: kind of body, 0: textured sprite, 1: sun, 2: moon.
// the colour goes out premultiplied, the alpha is how much of the sky behind the body it hides (blending ONE, ONE_MINUS_SRC_ALPHA)
layout(location = 2) in vec2 f_coord;
layout(location = 15) in vec2 f_local;
#pragma texture(tex1, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D tex1;
#include "tonemapping.glsl"
// shape and light of the sun and the moon, pc.data[0..2] of the push constants (a loose uniform vec4 body[3] in the opengl
// renderer, set by opengl46_renderer::Render(world_environment *)):
// [0].xy: direction to the zenith on the quad, [0].z: height over width of the disc (flattened by the refraction near the
// horizon), [0].w: radius of the disc in units of half the quad
// [1].xyz: direction to the sun in view space, [1].w: light of the earth on the dark part of the moon, against the light of
// the sun on the lit part
// [2].rgb: limb darkening of the sun per channel (linear law)
#define body pc.data
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
void main()
{
int kind = int(param[2].w + 0.5);
vec4 color = vec4(0.0);
if (kind == 0)
{
vec4 tex_color = texture(tex1, f_coord) * param[0];
color = vec4(tex_color.rgb * tex_color.a, 0.0);
}
else
{
// the point on the disc in its radii, x along the horizon, y to the zenith, with the flattening undone
vec2 zenith = body[0].xy;
vec2 across = vec2(zenith.y, -zenith.x);
vec2 p = vec2(dot(f_local, across), dot(f_local, zenith)) / body[0].w;
p.y /= body[0].z;
float r = length(p);
float coverage = clamp((1.0 - r) / max(fwidth(r), 1e-4) + 0.5, 0.0, 1.0);
// the horizon hides what is under it
vec3 direction = normalize(param[1].xyz + vec3(f_local * param[1].w, 0.0));
float height = (mat3(inv_view) * direction).y;
coverage *= clamp(height / max(fwidth(height), 1e-7) + 0.5, 0.0, 1.0);
// cosine of the angle between the line of sight and the surface of the sphere
float mu = sqrt(max(1.0 - r * r, 0.0));
if (kind == 1)
{
// limb darkening, kept to the average brightness of the disc
vec3 limb = (vec3(1.0) - body[2].rgb * (1.0 - mu)) / (vec3(1.0) - body[2].rgb / 3.0);
color = vec4(param[0].rgb * limb * coverage, 0.0);
}
else
{
// the moon as a sphere lit from the direction of the sun. the frame of the disc in view space, z to the viewer
vec3 z = -normalize(param[1].xyz);
vec3 x = vec3(across, 0.0);
x = normalize(x - z * dot(x, z));
vec3 y = cross(z, x);
vec2 q = p / max(r, 1.0);
vec3 normal = q.x * x + q.y * y + mu * z;
float mu0 = max(dot(normal, normalize(body[1].xyz)), 0.0);
// Lommel-Seeliger law: an even disc at the full moon, as the real one, no darkening towards the limb
float lit = 2.0 * mu0 / (mu0 + max(mu, 1e-3));
vec3 albedo = texture(tex1, param[2].xy + p * param[2].z).rgb;
color = vec4(albedo * param[0].rgb * ((lit + body[1].w) * coverage), coverage * param[0].a);
}
}
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = vec4(tonemap(vec4(color.rgb, 1.0)).rgb, color.a);
}
if (MOTIONBLUR_ENABLED)
{
out_motion = vec4(0.0f);
}
}

View File

@@ -0,0 +1,34 @@
#version 460 core
#define STAGE_VERTEX 1
#include "common.glsl"
const vec2 vert[4] = vec2[]
(
vec2(-1.0, 1.0),
vec2(-1.0, -1.0),
vec2( 1.0, 1.0),
vec2( 1.0, -1.0)
);
layout(location = 2) out vec2 f_coord;
// the corner of the quad, -1...1 across it
layout(location = 15) out vec2 f_local;
void main()
{
gl_Position = projection * (vec4(param[1].xyz, 1.0) + vec4(vert[gl_VertexIndex] * param[1].w, 0.0, 0.0));
f_local = vert[gl_VertexIndex];
vec2 coord = param[2].xy;
float size = param[2].z;
if (gl_VertexIndex == 0)
f_coord = vec2(coord.x, coord.y);
if (gl_VertexIndex == 1)
f_coord = vec2(coord.x, coord.y - size);
if (gl_VertexIndex == 2)
f_coord = vec2(coord.x + size, coord.y);
if (gl_VertexIndex == 3)
f_coord = vec2(coord.x + size, coord.y - size);
}

View File

@@ -0,0 +1,59 @@
#version 460 core
#define STAGE_COMPUTE 1
#define LAYOUT_CLUSTER 1
#include "common.glsl"
// bounding boxes of the light clusters in view space, see gl/cluster_grid.h
// one invocation per cluster, run when the projection or the depth range of the pass changes
layout(local_size_x = CLUSTER_BUILD_GROUP_SIZE) in;
// clip space w at the lower boundary of slice k: the inverse of the slice formula used when shading
float slice_depth(uint k)
{
return exp((float(k) - cluster_slice_bias) / cluster_slice_scale);
}
void main()
{
uint index = gl_GlobalInvocationID.x;
if (index >= uint(CLUSTER_COUNT))
return;
uvec3 cell = uvec3(
index % uint(CLUSTER_GRID_X),
(index / uint(CLUSTER_GRID_X)) % uint(CLUSTER_GRID_Y),
index / uint(CLUSTER_GRID_X * CLUSTER_GRID_Y));
// clip x, y and w are affine functions of the view space position, while clip z is constant (reverse z with
// the far plane at infinity), which makes the projection matrix singular. the position is recovered from
// those three alone, so off-axis and rotated screens of custom viewports and vr eyes work too
mat3 linear = mat3(
vec3(cluster_projection[0][0], cluster_projection[0][1], cluster_projection[0][3]),
vec3(cluster_projection[1][0], cluster_projection[1][1], cluster_projection[1][3]),
vec3(cluster_projection[2][0], cluster_projection[2][1], cluster_projection[2][3]));
vec3 translation = vec3(cluster_projection[3][0], cluster_projection[3][1], cluster_projection[3][3]);
mat3 unproject = inverse(linear);
// the tile in clip space xy, the slice in clip space w
vec2 tiles = vec2(CLUSTER_GRID_X, CLUSTER_GRID_Y);
vec2 ndc_min = vec2(cell.xy) / tiles * 2.0 - 1.0;
vec2 ndc_max = vec2(cell.xy + 1U) / tiles * 2.0 - 1.0;
float w_near = slice_depth(cell.z);
float w_far = slice_depth(cell.z + 1U);
vec3 lower = vec3(3.402823e38);
vec3 upper = vec3(-3.402823e38);
for (int corner = 0; corner < 8; ++corner)
{
vec2 ndc = vec2(
(corner & 1) != 0 ? ndc_max.x : ndc_min.x,
(corner & 2) != 0 ? ndc_max.y : ndc_min.y);
float w = (corner & 4) != 0 ? w_far : w_near;
vec3 position = unproject * (vec3(ndc * w, w) - translation);
lower = min(lower, position);
upper = max(upper, position);
}
cluster_aabbs[index].lower = vec4(lower, 0.0);
cluster_aabbs[index].upper = vec4(upper, 0.0);
}

View File

@@ -0,0 +1,157 @@
#version 460 core
#define STAGE_COMPUTE 1
#define LAYOUT_CLUSTER 1
#include "common.glsl"
// assigns the lights to the light clusters, see gl/cluster_grid.h
// one invocation per cluster: tests every light of light_ssbo (the sun, slot 0, is handled apart from the clusters)
// against the bounding box of the cluster in view space, and writes the indices of the lights which reach it.
// run every frame after the lights were updated, for the grid of the pass about to be drawn
layout(local_size_x = CLUSTER_CULL_GROUP_SIZE) in;
// a light is taken to end where its brightest possible contribution drops under this, a fraction of
// what the display can tell apart. there is no other limit: the 1 km filter on the cpu side is about the distance of a light
// from the camera, not about how far it reaches, and the shading lights a surface at any distance
const float MIN_CONTRIBUTION = 1.0 / 1024.0;
// reach of a light whose contribution does not fall off with the distance; its square still fits in a float
const float UNLIMITED_RANGE = 1.0e18;
// the boxes and the light data are floats: planes of the headlight projection let this much (in meters) of a box through
const float PLANE_MARGIN = 0.05;
// brightest value the light adds to a surface it hits, as the shading computes it
float light_peak(light_s light)
{
float peak = max(light.color.r, max(light.color.g, light.color.b)) * light.intensity;
if (light.type == LIGHT_HEADLIGHTS)
// weights are the state of the individual lamps and the beam texture, which is not brighter than 1, picks from them
return peak * max(light.headlight_weights.r, max(light.headlight_weights.g, light.headlight_weights.b));
return peak * (1.0 + light.ambient);
}
// distance from the light at which its contribution falls under MIN_CONTRIBUTION, 0 for a light which has none
float light_range(light_s light)
{
float peak = light_peak(light);
if (!(peak > MIN_CONTRIBUTION))
return 0.0;
// attenuation which the contribution can drop to without being lost: 1 / k
float k = peak / MIN_CONTRIBUTION;
if (light.type == LIGHT_HEADLIGHTS)
{
// 1 + linear * d + quadratic * d^2 <= k, the positive root written the way which has no cancellation for a small quadratic
float a = light.quadratic;
float b = light.linear;
float c = 1.0 - k;
float denominator = b + sqrt(b * b - 4.0 * a * c);
return (denominator > 1e-12) ? min(-2.0 * c / denominator, UNLIMITED_RANGE) : UNLIMITED_RANGE;
}
// point and spot lights fall off with the square of the distance; the shading ends them at 1 / sqrt(quadratic) where it is set
float range = sqrt(k);
return (light.quadratic > 0.0) ? min(range, inversesqrt(light.quadratic)) : range;
}
bool sphere_touches_box(vec3 center, float radius, vec3 lower, vec3 upper)
{
vec3 offset = center - clamp(center, lower, upper);
return dot(offset, offset) <= radius * radius;
}
// whether any part of the box, given by its center and half extents, is on the positive side of the plane
bool box_reaches_plane(vec4 plane, vec3 center, vec3 extent)
{
return dot(plane.xyz, center) + plane.w + dot(abs(plane.xyz), extent) + PLANE_MARGIN * length(plane.xyz) >= 0.0;
}
// planes bounding the beam of a headlight: the projection takes a view space position to the texture coordinates
// of the beam, and the beam is where those fall in 0..1 and the position is in front of the projector. clip z of that
// projection is a constant (reverse z, no far plane), so only the four sides and the near plane are real planes
bool box_in_headlight_beam(mat4 projection, vec3 center, vec3 extent)
{
vec4 row_x = vec4(projection[0][0], projection[1][0], projection[2][0], projection[3][0]);
vec4 row_y = vec4(projection[0][1], projection[1][1], projection[2][1], projection[3][1]);
vec4 row_z = vec4(projection[0][2], projection[1][2], projection[2][2], projection[3][2]);
vec4 row_w = vec4(projection[0][3], projection[1][3], projection[2][3], projection[3][3]);
return box_reaches_plane(row_x, center, extent)
&& box_reaches_plane(row_w - row_x, center, extent)
&& box_reaches_plane(row_y, center, extent)
&& box_reaches_plane(row_w - row_y, center, extent)
&& box_reaches_plane(row_z, center, extent)
&& box_reaches_plane(row_w - row_z, center, extent);
}
// whether the sphere touches the infinite cone with the apex at the origin, the unit axis and the cosine of the half angle
bool sphere_touches_cone(vec3 center, float radius, vec3 axis, float cosine)
{
float sine = max(sqrt(max(1.0 - cosine * cosine, 0.0)), 1e-4);
float along = dot(center, axis);
float across = sqrt(max(dot(center, center) - along * along, 0.0));
// distance to the boundary ray if the closest point of the cone is on it, and to the apex otherwise
float distance_to_cone = (along * cosine + across * sine > 0.0) ? across * cosine - along * sine : length(center);
return distance_to_cone <= radius;
}
bool light_reaches_box(light_s light, float range, vec3 lower, vec3 upper)
{
vec3 center = 0.5 * (lower + upper);
vec3 extent = 0.5 * (upper - lower);
if (light.type == LIGHT_DIR)
return true;
if (!sphere_touches_box(light.pos, range, lower, upper))
return false;
if (light.type == LIGHT_HEADLIGHTS)
return box_in_headlight_beam(light.headlight_projection, center, extent);
if ((light.type == LIGHT_SPOT) && (light.out_cutoff > 0.0))
// the cone is tested against the sphere around the box, which lets some of the corners through. a cone wider than
// a half of the space is taken as the whole sphere
return sphere_touches_cone(center - light.pos, length(extent), normalize(light.dir), light.out_cutoff);
return true;
}
void main()
{
uint index = gl_GlobalInvocationID.x;
if (index >= uint(CLUSTER_COUNT))
return;
vec3 lower = cluster_aabbs[index].lower.xyz;
vec3 upper = cluster_aabbs[index].upper.xyz;
// the lights are in the order of their importance, so when a cluster is full the least important are the ones left out
uint found[MAX_LIGHTS_PER_CLUSTER];
uint found_count = 0U;
uint dropped = 0U;
uint lights_end = min(lights_total, uint(lights.length()));
for (uint i = 1U; i < lights_end; ++i)
{
float range = light_range(lights[i]);
if (range <= 0.0 && lights[i].type != LIGHT_DIR)
continue;
if (!light_reaches_box(lights[i], range, lower, upper))
continue;
if (found_count < uint(MAX_LIGHTS_PER_CLUSTER))
found[found_count++] = i;
else
++dropped;
}
uint offset = 0U;
if (found_count > 0U)
{
offset = atomicAdd(cluster_index_count, found_count);
for (uint k = 0U; k < found_count; ++k)
cluster_light_indices[offset + k] = found[k];
}
if (dropped > 0U)
atomicAdd(cluster_overflow_count, dropped);
cluster_ranges[index] = cluster_range_s(offset, found_count);
}

35
shaders/vk14/color.frag Normal file
View File

@@ -0,0 +1,35 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 13) in vec3 f_color;
layout(location = 3) in vec4 f_pos;
#include "apply_fog.glsl"
#include "tonemapping.glsl"
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#include "sky_shoulder.glsl"
void main()
{
vec3 col = sky_shoulder(pow(max(f_color.rgb, vec3(0.0)), vec3(2.2)));
if (POSTFX_ENABLED)
{
out_color = vec4(apply_fog(col), 1.0f);
}
else
{
out_color = tonemap(vec4(apply_fog(col), 1.0f));
}
if (MOTIONBLUR_ENABLED)
{
out_motion = vec4(0.0f);
}
}

View File

@@ -1,7 +1,22 @@
// what the shaders of the vulkan 1.4 renderer share: the bindings of rendering/vulkan14/vulkan14bindings.h and the settings.
// what the shaders of the vulkan 1.4 renderer share: the bindings of rendering/vulkan14/vulkan14bindings.h, the constants of the
// game, the settings, the push constants and the resources of the pipeline layout a shader is drawn with.
// compiled by the game, the bindings come from the renderer (vk14::binding_preamble()) and are taken instead of these; the
// SPIR-V binaries (shaders/vk14bin) are compiled with the values written here, so they have to stay the same as in the game,
// which checks them when it starts (and doesn't load the binaries when they differ)
//
// the pipeline layout is picked by a define before the include of this file:
// (none) the passes of the scene (materials, shadows, picking, lines, sprites, sky, particles): set PASS_SET with
// the blocks of the scene, of the draws, of the instances, the lights, the clusters and the shadow,
// environment and headlight maps; set MATERIAL_SET with the textures of the material
// LAYOUT_POST the post-processing and the copies of whole images: set POST_SET pushed with the images read, the
// parameters in the push constants (param stands for pc.data)
// LAYOUT_CLUSTER the compute passes of the light clusters: set 0 pushed at the CL_* bindings
// LAYOUT_UI the user interface: none of the above, its own push constants
//
// the locations of the inputs and outputs between the stages are the table of shaders/ogl46/common.glsl, the same for a name
// in every shader: 0 f_normal, 1 f_normal_raw, 2 f_coord, 3 f_pos, 4 f_clip_pos, 5 f_clip_future_pos, 6 TangentFragPos,
// 7 UserData, 8-10 f_tbn, 12 f_albedo, 13 f_color, 14 f_coords, 15 f_local, 16 f_soft, 17 f_streak (11 f_model_draw is not
// used: the draw is in the push constants)
#ifndef COMMON_GLSL
#define COMMON_GLSL
@@ -15,18 +30,276 @@
#define UI_TEXTURE 0
#define PASS_SET 0
#define MATERIAL_SET 1
#define SCENE_UBO 0
#define DRAW_SSBO 1
#define INSTANCE_SSBO 2
#define LIGHT_SSBO 3
#define CLUSTER_UBO 4
#define CLUSTER_RANGE_SSBO 5
#define CLUSTER_INDEX_SSBO 6
#define SHADOW_TEX 7
#define ENV_TEX 8
#define HEADLIGHT_TEX 9
#define PASS_BINDING_COUNT 10
#define MATERIAL_TEXTURE_FIRST 0
#define CL_CLUSTER_UBO 0
#define CL_AABB_SSBO 1
#define CL_RANGE_SSBO 2
#define CL_INDEX_SSBO 3
#define CL_COUNTER_SSBO 4
#define CL_LIGHT_SSBO 5
#define POST_SET 0
#define POST_TEXTURE_FIRST 0
#define PUSH_CONSTANTS_SIZE 112
#define SPEC_OUTPUT_GAMMA 0
#define SPEC_SHADOWMAP_ENABLED 1
#define SPEC_ENVMAP_ENABLED 2
#define SPEC_MOTIONBLUR_ENABLED 3
#define SPEC_POSTFX_ENABLED 4
#define SPEC_EXTRAEFFECTS_ENABLED 5
#define SPEC_COUNT 6
#define MAX_LIGHTS 1024U
#define MAX_CASCADES 3U
#define MAX_PARAMS 3U
#define MAX_HEADLIGHT_SHADOWS 4U
#define CLUSTER_GRID_X 16
#define CLUSTER_GRID_Y 9
#define CLUSTER_GRID_Z 24
#define CLUSTER_COUNT 3456
#define MAX_LIGHTS_PER_CLUSTER 64
#define CLUSTER_BUILD_GROUP_SIZE 64
#define CLUSTER_CULL_GROUP_SIZE 64
#endif
// whether the colour written to the window is encoded by the shader (FBOUT): the window has no srgb format (gfx.shadergamma yes).
// a specialization constant, set by the renderer when it makes the pipeline
layout(constant_id = SPEC_OUTPUT_GAMMA) const bool OUTPUT_GAMMA = false;
#include "settings.glsl"
// the colour written to the window
vec4 FBOUT(vec4 x)
#ifndef LAYOUT_UI
// vk14::draw_constants, PUSH_CONSTANTS_SIZE bytes, visible in every stage. draw: the element of model_draws[] the draw reads
// (the passes of the scene); flags and data: the parameters of the special shaders, each says what it takes from them
layout(push_constant) uniform draw_constants_block
{
return (OUTPUT_GAMMA ? vec4(pow(x.rgb, vec3(1.0 / 2.2)), x.a) : x);
uint draw;
uint flags;
uint pad0;
uint pad1;
vec4 data[6];
} pc;
#endif
const uint LIGHT_SPOT = 0U;
const uint LIGHT_POINT = 1U;
const uint LIGHT_DIR = 2U;
const uint LIGHT_HEADLIGHTS = 3U;
// gl::light_element
struct light_s
{
vec3 pos;
uint type;
vec3 dir;
float in_cutoff;
vec3 color;
float out_cutoff;
float linear;
float quadratic;
float intensity;
float ambient;
mat4 headlight_projection;
vec4 headlight_weights;
};
// light clusters, see gl/cluster_grid.h
struct cluster_aabb_s
{
vec4 lower;
vec4 upper;
};
struct cluster_range_s
{
uint offset;
uint count;
};
#if defined(LAYOUT_CLUSTER)
layout(std140, set = 0, binding = CL_CLUSTER_UBO) uniform cluster_ubo
{
mat4 cluster_projection;
float cluster_znear;
float cluster_zfar;
float cluster_slice_scale;
float cluster_slice_bias;
vec2 cluster_viewport_size;
uint cluster_valid;
};
layout(std430, set = 0, binding = CL_AABB_SSBO) buffer cluster_aabb_ssbo
{
cluster_aabb_s cluster_aabbs[];
};
layout(std430, set = 0, binding = CL_RANGE_SSBO) buffer cluster_range_ssbo
{
cluster_range_s cluster_ranges[];
};
layout(std430, set = 0, binding = CL_INDEX_SSBO) buffer cluster_index_ssbo
{
uint cluster_light_indices[];
};
layout(std430, set = 0, binding = CL_COUNTER_SSBO) buffer cluster_counter_ssbo
{
uint cluster_index_count;
uint cluster_overflow_count;
};
layout(std430, set = 0, binding = CL_LIGHT_SSBO) readonly buffer light_ssbo
{
vec3 ambient;
// lights stored in lights[], what the cluster culling goes through
uint lights_total;
vec3 fog_color;
// lights the shading loop goes through when the lights are not clustered
uint lights_count;
// 1 if the shading takes the lights from the list of the cluster of a fragment, see cluster_ubo
uint lights_clustered;
// not used by the shaders of this renderer yet (the sky ambient light and the prefiltered environment map come later)
float sky_ambient_factor;
uint env_ggx;
light_s lights[];
};
#elif defined(LAYOUT_POST)
// the post-processing reads the parameters the opengl renderer gives it in the model block from the push constants
#define param pc.data
#elif !defined(LAYOUT_UI)
// the block of the scene, gl::scene_ubs (every member kept, the layout is the one of the c++ struct)
layout(std140, set = PASS_SET, binding = SCENE_UBO) uniform scene_ubo
{
mat4 projection;
mat4 inv_view;
mat4 lightview[MAX_CASCADES];
vec3 cascade_end;
float time;
vec4 rain_params;
vec4 wiper_pos;
vec4 wiper_timer_out;
vec4 wiper_timer_return;
mat4 headlight_shadow[MAX_HEADLIGHT_SHADOWS];
vec4 headlight_shadow_params[MAX_HEADLIGHT_SHADOWS];
vec4 contact_shadow_params;
vec4 contact_shadow_lamps;
vec4 shadow_fit;
};
// the model block of a draw, gl::model_ubs (256 bytes), the one of the draw picked by pc.draw. the names below stand for its
// fields, so the shaders read them as the uniform block of the opengl renderer
struct model_draw_s
{
mat4 modelview;
mat3 modelviewnormal;
vec4 param[MAX_PARAMS];
mat4 future;
float opacity;
float emission;
float fog_density;
float alpha_mult;
float shadow_tone;
};
layout(std430, set = PASS_SET, binding = DRAW_SSBO) readonly buffer model_draw_ssbo
{
model_draw_s model_draws[];
};
#define modelview model_draws[pc.draw].modelview
#define modelviewnormal model_draws[pc.draw].modelviewnormal
#define param model_draws[pc.draw].param
#define future model_draws[pc.draw].future
#define opacity model_draws[pc.draw].opacity
#define emission model_draws[pc.draw].emission
#define fog_density model_draws[pc.draw].fog_density
#define alpha_mult model_draws[pc.draw].alpha_mult
#define shadow_tone model_draws[pc.draw].shadow_tone
// per-instance modelview matrices of the instanced draws, element 0 the identity. a draw which isn't instanced is drawn with
// firstInstance 0, an instanced one from its base instance on, with modelview set to the submodel-local chain (computed from
// the identity, not from the camera or the instance), so the product is the final transform per instance per submodel
layout(std430, set = PASS_SET, binding = INSTANCE_SSBO) readonly buffer instance_ssbo
{
mat4 instance_modelview[];
};
// the light buffer of the pass, gl::light_data
layout(std430, set = PASS_SET, binding = LIGHT_SSBO) readonly buffer light_ssbo
{
vec3 ambient;
// lights stored in lights[], what the cluster culling goes through
uint lights_total;
vec3 fog_color;
// lights the shading loop goes through when the lights are not clustered
uint lights_count;
// 1 if the shading takes the lights from the list of the cluster of a fragment, see cluster_ubo
uint lights_clustered;
// not used by the shaders of this renderer yet (the sky ambient light and the prefiltered environment map come later)
float sky_ambient_factor;
uint env_ggx;
light_s lights[];
};
// the grid of the light clusters of the pass, gl::cluster_ubs; the compute passes fill the lists, shading only reads them
layout(std140, set = PASS_SET, binding = CLUSTER_UBO) uniform cluster_ubo
{
mat4 cluster_projection;
float cluster_znear;
float cluster_zfar;
float cluster_slice_scale;
float cluster_slice_bias;
vec2 cluster_viewport_size;
uint cluster_valid;
};
layout(std430, set = PASS_SET, binding = CLUSTER_RANGE_SSBO) readonly buffer cluster_range_ssbo
{
cluster_range_s cluster_ranges[];
};
layout(std430, set = PASS_SET, binding = CLUSTER_INDEX_SSBO) readonly buffer cluster_index_ssbo
{
uint cluster_light_indices[];
};
#ifdef STAGE_VERTEX
mat4 effective_modelview()
{
return instance_modelview[gl_InstanceIndex] * modelview;
}
mat3 effective_modelviewnormal()
{
// instance_modelview can include per-instance scale (uniform or per-axis), so its upper 3x3 is not its own inverse
// transpose in the non-uniform case
mat3 instance_mv3 = mat3(instance_modelview[gl_InstanceIndex]);
mat3 instance_normal = transpose(inverse(instance_mv3));
return instance_normal * modelviewnormal;
}
#endif
#endif
#endif

View File

@@ -0,0 +1,108 @@
vec3 rgb2yuv(vec3 val)
{
return
clamp(
vec3(
(0.257 * val.r) + (0.504 * val.g) + (0.098 * val.b) + 0.0625,
-(0.148 * val.r) - (0.291 * val.g) + (0.439 * val.b) + 0.5,
(0.439 * val.r) - (0.368 * val.g) - (0.071 * val.b) + 0.5 ),
0.0, 1.0);
}
vec3 yuv2rgb(vec3 val)
{
val -= vec3(0.0625, 0.5, 0.5);
return
clamp(
vec3(
(1.164 * val.r) + (1.596 * val.b),
(1.164 * val.r) - (0.391 * val.g) - (0.813 * val.b),
(1.164 * val.r) + (2.018 * val.g) ),
0.0, 1.0);
}
vec3 rgb2hsl( vec3 col )
{
float red = col.r;
float green = col.g;
float blue = col.b;
float minc = min( col.r, min( col.g, col.b ));
float maxc = max( col.r, max( col.g, col.b ));
float delta = maxc - minc;
float lum = (minc + maxc) * 0.5;
float sat = 0.0;
float hue = 0.0;
if (lum > 0.0 && lum < 1.0) {
float mul = (lum < 0.5) ? (lum) : (1.0-lum);
sat = delta / (mul * 2.0);
}
vec3 masks = vec3(
(maxc == red && maxc != green) ? 1.0 : 0.0,
(maxc == green && maxc != blue) ? 1.0 : 0.0,
(maxc == blue && maxc != red) ? 1.0 : 0.0
);
vec3 adds = vec3(
((green - blue ) / delta),
2.0 + ((blue - red ) / delta),
4.0 + ((red - green) / delta)
);
float deltaGtz = (delta > 0.0) ? 1.0 : 0.0;
hue += dot( adds, masks );
hue *= deltaGtz;
hue /= 6.0;
if (hue < 0.0)
hue += 1.0;
return vec3( hue, sat, lum );
}
vec3 hsl2rgb( vec3 col )
{
const float onethird = 1.0 / 3.0;
const float twothird = 2.0 / 3.0;
const float rcpsixth = 6.0;
float hue = col.x;
float sat = col.y;
float lum = col.z;
vec3 xt = vec3(
rcpsixth * (hue - twothird),
0.0,
rcpsixth * (1.0 - hue)
);
if (hue < twothird) {
xt.r = 0.0;
xt.g = rcpsixth * (twothird - hue);
xt.b = rcpsixth * (hue - onethird);
}
if (hue < onethird) {
xt.r = rcpsixth * (onethird - hue);
xt.g = rcpsixth * hue;
xt.b = 0.0;
}
xt = min( xt, 1.0 );
float sat2 = 2.0 * sat;
float satinv = 1.0 - sat;
float luminv = 1.0 - lum;
float lum2m1 = (2.0 * lum) - 1.0;
vec3 ct = (sat2 * xt) + satinv;
vec3 rgb;
if (lum >= 0.5) { rgb = (luminv * ct) + lum2m1; }
else { rgb = lum * ct; }
return rgb;
}

15
shaders/vk14/copy.frag Normal file
View File

@@ -0,0 +1,15 @@
#version 460 core
#define STAGE_FRAGMENT 1
#define LAYOUT_POST 1
#include "common.glsl"
layout(location = 14) in vec2 f_coords;
#pragma texture(tex1, 0, sRGB)
layout(set = POST_SET, binding = POST_TEXTURE_FIRST + 0) uniform sampler2D tex1;
layout(location = 0) out vec4 out_color;
void main()
{
out_color = texture(tex1, f_coords);
}

26
shaders/vk14/dither.glsl Normal file
View File

@@ -0,0 +1,26 @@
// noise of half a step of the 8-bit output, added to the colour about to be written to the window: smooth dark gradients (the
// fog at night) show no bands, which otherwise crawl over the image with the smallest change of the light. interleaved gradient
// noise (Jimenez 2014) of the pixel, the same in every frame. the colour is the one written to the window: encoded already with
// OUTPUT_GAMMA, linear otherwise (the sRGB framebuffer encodes it, so the step is taken in the encoded values)
#ifndef DITHER_GLSL
#define DITHER_GLSL
#include "common.glsl"
vec3 dither_output(vec3 color)
{
float noise = (fract(52.9829189 * fract(dot(gl_FragCoord.xy, vec2(0.06711056, 0.00583715)))) - 0.5) / 255.0;
if (OUTPUT_GAMMA)
{
return max(color + noise, vec3(0.0));
}
else
{
vec3 linear = max(color, vec3(0.0));
vec3 encoded = mix(linear * 12.92, 1.055 * pow(linear, vec3(1.0 / 2.4)) - 0.055, step(vec3(0.0031308), linear));
encoded = max(encoded + noise, vec3(0.0));
return mix(encoded / 12.92, pow((encoded + 0.055) / 1.055, vec3(2.4)), step(vec3(0.04045), encoded));
}
}
#endif

View File

@@ -0,0 +1,54 @@
layout(set = PASS_SET, binding = ENV_TEX) uniform samplerCube envmap;
vec3 envmap_color( vec3 normal )
{
vec3 envcolor;
if (ENVMAP_ENABLED)
{
vec3 refvec = reflect(f_pos.xyz, normal); // view space
refvec = vec3(inv_view * vec4(refvec, 0.0)); // world space
envcolor = texture(envmap, refvec).rgb;
// Sanitize. The env cubemap can briefly contain NaN/Inf after a
// reflection-pass regeneration (m_empty_cubemap was bound during the
// face render and on NVIDIA can sample as undefined). Without this
// guard, a single bad texel propagates through env_reflection in
// apply_lights() and produces one-frame black flashes on glossy
// (esp. specgloss) surfaces.
if (any(isnan(envcolor)) || any(isinf(envcolor))) envcolor = vec3(0.0);
envcolor = max(envcolor, vec3(0.0));
}
else
{
envcolor = vec3(0.5);
}
return envcolor;
}
// Roughness-aware env map lookup — uses mip levels for blurry reflections.
// lod 0.0 = mirror sharp, lod ~8.0 = fully diffuse blur.
vec3 envmap_color_lod(vec3 fragnormal, float lod)
{
if (ENVMAP_ENABLED)
{
vec3 refvec = reflect(f_pos.xyz, fragnormal); // view space — matches envmap_color exactly
refvec = vec3(inv_view * vec4(refvec, 0.0)); // world space — was missing
vec3 envcolor = textureLod(envmap, refvec, lod).rgb;
// See envmap_color() above — same NaN/Inf sanitize, also needed here
// because mipmap generation propagates a single NaN texel across the
// whole mip chain.
if (any(isnan(envcolor)) || any(isinf(envcolor))) envcolor = vec3(0.0);
return max(envcolor, vec3(0.0));
}
else
{
return vec3(0.5); // was vec3(0.0), match the non-LOD fallback
}
}
// reflection of the surroundings in a surface of the given perceptual roughness (0 mirror, 1 matte): the plain map, its mipmaps
// (box filtered) standing for the roughness. the prefiltered GGX map of the opengl renderer (env_ggx) comes in a later stage
vec3 envmap_color_rough(vec3 fragnormal, float roughness)
{
const float MAX_REFLECTION_LOD = 8.0;
return envmap_color_lod(fragnormal, roughness * MAX_REFLECTION_LOD);
}

View File

@@ -0,0 +1,38 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 3) in vec4 f_pos;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#include "tonemapping.glsl"
#include "apply_fog.glsl"
void main()
{
float x = (gl_PointCoord.x - 0.5f) * 2.0f;
float y = (gl_PointCoord.y - 0.5f) * 2.0f;
float dist = sqrt(x * x + y * y);
if (dist > 0.5f)
discard;
// vec4 color = vec4(param[0].rgb * emission, mix(param[0].a, 0.0f, dist * 2.0f));
vec4 color = vec4(apply_fog(pow(param[0].rgb, vec3(2.2)) * emission), mix(param[0].a, 0.0f, dist * 2.0f));
// vec4 color = vec4(add_fog(param[0].rgb * emission * (1.0 - get_fog_amount()), 1.0), mix(param[0].a, 0.0f, dist * 2.0f));
out_color = FBOUT(color);
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,21 @@
#version 460 core
#define STAGE_VERTEX 1
#include "common.glsl"
layout(location = 0) in vec3 v_vert;
layout(location = 1) in vec3 v_normal;
layout(location = 2) in vec2 v_coord;
layout(location = 3) out vec4 f_pos;
layout(location = 4) out vec4 f_clip_pos;
layout(location = 5) out vec4 f_clip_future_pos;
void main()
{
f_pos = modelview * vec4(v_vert, 1.0);
f_clip_pos = (projection * modelview) * vec4(v_vert, 1.0f);
f_clip_future_pos = (projection * future * modelview) * vec4(v_vert, 1.0f);
gl_Position = f_clip_pos;
gl_PointSize = param[1].x;
}

View File

@@ -1,5 +1,6 @@
#version 460 core
#define STAGE_FRAGMENT 1
#define LAYOUT_UI 1
// the user interface (imgui): the colour of the vertices times the texture of the draw (the font, an image, a texture), pushed
// with the draw

View File

@@ -1,5 +1,6 @@
#version 460 core
#define STAGE_VERTEX 1
#define LAYOUT_UI 1
// the user interface (imgui), drawn by vk14::imgui_backend over the image of the window
#include "common.glsl"

View File

@@ -0,0 +1,594 @@
// stage D of the vulkan renderer: the sun with its cascaded shadows, the environment map, the headlights and the lamps (in the
// clusters or not). the cube shadow maps of the lamps, the shadow maps of the headlights, the contact shadows, the shadows of
// the clouds, the directional sky ambient light and the prefiltered environment map of shaders/ogl46/light_common.glsl come
// with the later stages; the code below is the one of the opengl renderer with those left out, it shades as that one does
// with them off
layout(set = PASS_SET, binding = SHADOW_TEX) uniform sampler2DArrayShadow shadowmap;
layout(set = PASS_SET, binding = HEADLIGHT_TEX) uniform sampler2D headlightmap;
#include "envmapping.glsl"
#include "conversion.glsl"
float glossiness = 1.0;
float metalic = 0.0;
layout(location = 7) in vec4 UserData;
#pragma param(weathering, 2, 3, 1, zero)
// ---------------------------------------------------------------------
// Lighting balance tunables - tweak these to control overall scene
// exposure without touching tonemapping.glsl.
//
// AMBIENT_SCALE: brightness of SHADED faces (indirect/sky term).
// Lower -> deeper shadows, less burn under bright
// textures. Higher -> flatter / brighter shading.
//
// SUN_DIFFUSE_SCALE: brightness of UNSHADED (sun-lit) faces. Lower
// this to dim hot surfaces in direct sunlight
// without affecting shaded areas. Was 3.5; 2.5
// calmly fits the ACES tonemap shoulder.
//
// SUN_NDOTL_SHARPNESS: N.L curve on the sun. 1.0 = pure Lambert, higher
// = sharper terminator (more contrast between
// lit and shaded faces of the same surface).
// ---------------------------------------------------------------------
const float AMBIENT_SCALE = 0.65;
const float SUN_DIFFUSE_SCALE = 1.5;
const float SUN_NDOTL_SHARPNESS = 1.25;
float length2(vec3 v)
{
return dot(v, v);
}
// share of the sun (the moon) held back before the fragment by the shadow map, 0..1
float calc_shadow_map();
float calc_shadow()
{
return calc_shadow_map();
}
float calc_shadow_map()
{
if (SHADOWMAP_ENABLED)
{
float distance = dot(f_pos.xyz, f_pos.xyz);
uint cascade;
for (cascade = 0U; cascade < MAX_CASCADES; cascade++)
if (distance <= cascade_end[cascade])
break;
// cascades fitted to the depth of the view of an earlier frame (gfx.shadow.sdsm) cover only the area of the points seen
// then: a point at the edge of the view or one which came closer since may be outside the map of its cascade. it goes to
// the first further cascade whose map holds it with the reach of the filter, and is lit past the last one
if (shadow_fit.x > 0.0)
{
float border = 4.0 / float(textureSize(shadowmap, 0).x);
for (; cascade < MAX_CASCADES; cascade++)
{
vec2 fitcoords = (lightview[cascade] * vec4(f_pos.xyz, 1.0)).xy;
if (all(greaterThanEqual(fitcoords, vec2(border))) && all(lessThanEqual(fitcoords, vec2(1.0 - border))))
break;
}
if (cascade >= MAX_CASCADES)
return 0.0;
}
// Normal offset: sample the shadow map from a point pushed along the surface normal
// by a fraction of the cascade's texel footprint. A constant depth bias can't keep up
// with large texels (far cascades, small shadow maps) on surfaces at a grazing angle
// to the sun, which then show shadow acne stripes. lightview maps view space metres
// to [0,1] shadow map coordinates, so its x/y row lengths give texels per metre.
vec3 shadownormal = normalize(f_normal);
float shadowNdotL = clamp(dot(shadownormal, normalize(-lights[0].dir)), 0.0, 1.0);
mat4 shadowview = lightview[cascade];
float texelspermetre = min(length(vec3(shadowview[0][0], shadowview[1][0], shadowview[2][0])),
length(vec3(shadowview[0][1], shadowview[1][1], shadowview[2][1]))) * float(textureSize(shadowmap, 0).x);
float texelsize = 1.0 / texelspermetre;
vec3 shadowpos = f_pos.xyz + shadownormal * (texelsize * 1.5 * (1.0 - shadowNdotL));
vec4 lightpos = shadowview * vec4(shadowpos, 1.0);
vec3 coords = lightpos.xyz / lightpos.w;
if (coords.z < 0.0)
return 0.0f;
float bias = 0.00005f * float(cascade + 1U);
// Fast path: 4 textureGather() calls cover a 4x4 texel block. Raw gathered
// comparisons must be weighted by the sub-texel position (bilinear weights),
// otherwise the result is constant across each shadow map texel and shadow
// edges turn into texel-sized stair steps. With per-axis weights
// (1-f, 1, 1, f) this equals a 3x3 grid of hardware bilinear PCF taps.
vec2 size = vec2(textureSize(shadowmap, 0).xy);
vec2 uv = coords.xy * size - 0.5;
vec2 base = floor(uv);
vec2 f = uv - base;
float refz = coords.z + bias;
float layer = float(cascade);
// sampling at texel corners selects blocks with lower-left texel base-1 and base+1
vec4 g00 = textureGather(shadowmap, vec3((base + vec2(0.0, 0.0)) / size, layer), refz);
vec4 g10 = textureGather(shadowmap, vec3((base + vec2(2.0, 0.0)) / size, layer), refz);
vec4 g01 = textureGather(shadowmap, vec3((base + vec2(0.0, 2.0)) / size, layer), refz);
vec4 g11 = textureGather(shadowmap, vec3((base + vec2(2.0, 2.0)) / size, layer), refz);
// gather component order: x=(0,1) y=(1,1) z=(1,0) w=(0,0)
float shadow = dot(g00, vec4(1.0 - f.x, 1.0, 1.0 - f.y, (1.0 - f.x) * (1.0 - f.y)))
+ dot(g10, vec4(1.0, f.x, f.x * (1.0 - f.y), 1.0 - f.y))
+ dot(g01, vec4((1.0 - f.x) * f.y, f.y, 1.0, 1.0 - f.x))
+ dot(g11, vec4(f.y, f.x * f.y, f.x, 1.0));
return shadow / 9.0;
}
else
{
return 0.0;
}
}
// -----------------------------------------------------------------------
// GGX Microfacet BRDF helpers (Cook-Torrance)
// -----------------------------------------------------------------------
// Trowbridge-Reitz (GGX) Normal Distribution Function
// D(N,H,α) = α⁴ / (π · ((NdotH)²·(α⁴−1)+1)²)
// α = roughness² (perceptual remapping so the slider feels linear)
float D_GGX(float NdotH, float roughness)
{
float a = roughness * roughness; // perceptual -> linear roughness
float a2 = a * a;
float d = (NdotH * NdotH) * (a2 - 1.0) + 1.0;
return a2 / (3.14159265359 * d * d);
}
// Schlick-GGX single-term masking/shadowing (k remapped for direct lighting)
float G_SchlickGGX(float NdotX, float roughness)
{
float r = roughness + 1.0;
float k = (r * r) * (1.0 / 8.0); // k_direct = (roughness+1)²/8
return NdotX / (NdotX * (1.0 - k) + k);
}
// Separable Smith geometry term (not height-correlated)
// G(N,V,L) = G_SchlickGGX(NdotV) · G_SchlickGGX(NdotL)
float G_Smith(float NdotV, float NdotL, float roughness)
{
return G_SchlickGGX(NdotV, roughness) * G_SchlickGGX(NdotL, roughness);
}
const float BRDF_PI = 3.14159265359;
// the smoothest surface the lights are reflected by: a mirror would make a highlight smaller than a pixel
const float MIN_ROUGHNESS = 0.045;
// cap of the brdf for the lamps and headlights (see specular_light()): a tiny light next to a polished surface
const float LOCAL_LIGHT_BRDF_LIMIT = 16.0;
// no cap for the sun
const float SUN_BRDF_LIMIT = 1.0e6;
// the specular reflectance at normal incidence and the perceptual roughness the lights are reflected with, worked out by
// apply_lights() for the fragment before it adds the lamps (add_local_lights())
vec3 spec_f0 = vec3(0.04);
float spec_roughness = 0.5;
// a matte material (mat_default) reflects nothing: neither the surroundings nor the sun and the lamps, only the diffuse light
bool matte = false;
// light of a light from Light_dir reflected by the surface, in the units of the diffuse shading (a white lambertian surface
// facing the light reflects 1 of it): pi times the cook-torrance brdf with schlick's fresnel of F0, times n.l. Limit caps the
// brdf without the n.l
vec3 specular_light(vec3 light_dir, vec3 fragnormal, vec3 f0, float roughness, float limit)
{
float NdotL = dot(fragnormal, light_dir);
if (NdotL <= 0.0)
return vec3(0.0);
vec3 V = normalize(-f_pos.xyz);
vec3 H = normalize(light_dir + V);
float NdotV = max(dot(fragnormal, V), 1e-4);
float NdotH = max(dot(fragnormal, H), 0.0);
float VdotH = max(dot(V, H), 0.0);
float brdf = D_GGX(NdotH, roughness) * G_Smith(NdotV, NdotL, roughness) / (4.0 * NdotL * NdotV);
vec3 fresnel = f0 + (1.0 - f0) * pow(1.0 - VdotH, 5.0);
return fresnel * (min(brdf, limit) * NdotL * BRDF_PI);
}
// perceptual roughness raised where the normal changes much from a pixel to the next (normal maps, tight curves), so the
// highlight of a detail smaller than a pixel spreads over the pixel instead of flickering. Kaplanyan, Tokuyoshi, "Improved
// geometric specular antialiasing", 2019
float specular_antialiasing(vec3 fragnormal, float roughness)
{
vec3 dndx = dFdx(fragnormal);
vec3 dndy = dFdy(fragnormal);
float variance = 0.25 * (dot(dndx, dndx) + dot(dndy, dndy));
float kernel = min(2.0 * variance, 0.18);
float a2 = roughness * roughness * roughness * roughness;
return sqrt(sqrt(clamp(a2 + kernel, 0.0, 1.0)));
}
// the materials without a specgloss map give glossiness: (param[1].w, 10 by default) as the exponent of the blinn-phong
// highlight of the old renderer. a lobe of exponent n is about a ggx one of alpha sqrt(2 / (n + 2))
float phong_roughness(float exponent)
{
return sqrt(sqrt(2.0 / (max(exponent, 0.0) + 2.0)));
}
// glossiness which apply_lights() turns into the roughness of a blinn-phong exponent (it takes 1 - glossiness / param[1].w)
float phong_glossiness(float exponent)
{
return (1.0 - phong_roughness(exponent)) * max(abs(param[1].w), 1.0);
}
// the reflection of the surroundings of a material without a specgloss map is a smooth varnish over the rough surface: the
// old renderer showed it as a sharp reflection, as much of it as reflection: (and the masks of the material) asked for
bool legacy_coat = false;
// set up the gloss of a material without a specgloss map, before apply_lights()
void legacy_gloss()
{
glossiness = phong_glossiness(abs(param[1].w));
legacy_coat = true;
}
// Returns vec2(diffuse, specular) for a single punctual light.
//
// diffuse – Lambert N·L (Fresnel-weighted diffuse is handled per-material
// in apply_lights, so we return raw N·L here).
// specular – Cook-Torrance GGX: D·G / (4·NdotL·NdotV).
// The Fresnel factor (F) is intentionally omitted here;
// apply_lights already carries a per-material Fresnel term
// that is applied to env reflections and can be routed to
// direct specular there.
//
// Roughness is derived identically to env_roughness in apply_lights so
// that direct and indirect specular highlights read consistently.
vec2 calc_light(vec3 light_dir, vec3 fragnormal)
{
vec3 N = fragnormal;
vec3 L = light_dir;
vec3 V = normalize(-f_pos.xyz);
vec3 H = normalize(L + V);
float NdotL = max(dot(N, L), 0.0);
float NdotV = max(dot(N, V), 1e-4);
float NdotH = max(dot(N, H), 0.0);
float diffuse_v = NdotL;
// Mirror the env-map roughness derivation so direct and indirect lobes match.
// glossiness == param[1].w → roughness == 0.04 (near-mirror)
// glossiness == 0 → roughness == 1.0 (fully diffuse)
float roughness = clamp(1.0 - glossiness / max(abs(param[1].w), 1.0), 0.04, 1.0);
// Cook-Torrance specular (no Fresnel — see above):
// f_spec = D(N,H,α) · G(N,V,L,α) / (4 · NdotL · NdotV)
float D = D_GGX(NdotH, roughness);
float G = G_Smith(NdotV, NdotL, roughness);
float specular_v = (NdotL > 0.0)
? (D * G) / max(4.0 * NdotL * NdotV, 1e-4)
: 0.0;
return vec2(diffuse_v, specular_v);
}
vec2 calc_point_light(light_s light, vec3 fragnormal)
{
vec3 light_dir = normalize(light.pos - f_pos.xyz);
vec2 val = calc_light(light_dir, fragnormal);
val.x += light.ambient;
val *= light.intensity;
float distance = length(light.pos - f_pos.xyz);
float atten = 1.0f / (distance * distance);
//float atten = 1.0f / (1.0f + light.linear * distance + light.quadratic * (distance * distance));
return val * atten;
}
vec2 calc_spot_light(light_s light, vec3 fragnormal)
{
vec3 light_dir = normalize(light.pos - f_pos.xyz);
float theta = dot(light_dir, normalize(-light.dir));
float epsilon = light.in_cutoff - light.out_cutoff;
float intensity = clamp((theta - light.out_cutoff) / epsilon, 0.0, 1.0);
vec2 point = calc_point_light(light, fragnormal);
return point * intensity;
}
vec2 calc_dir_light(light_s light, vec3 fragnormal)
{
vec3 light_dir = normalize(-light.dir);
return calc_light(light_dir, fragnormal);
}
// dpdx and dpdy are the change of the view space position of the fragment from a pixel to the next one. the beam texture is
// sampled with gradients worked out from them instead of the ones of the hardware: those are undefined where the fragments of
// a quad do not go through the same lights, which is what happens at the edges of the clusters
vec2 calc_headlights(light_s light, vec3 fragnormal, vec3 dpdx, vec3 dpdy)
{
vec4 headlightpos = light.headlight_projection * f_pos;
vec3 coords = headlightpos.xyz / headlightpos.w;
if (coords.z > 1.0)
return vec2(0.0);
if (coords.z < 0.0)
return vec2(0.0);
// the beam is what the projection takes in. beyond its sides the texture would be clamped to its edge, and near the projector
// (where a pixel spans many texels) its coarsest levels spill the average of the whole beam over the surroundings
if (coords.x < 0.0 || coords.x > 1.0 || coords.y < 0.0 || coords.y > 1.0)
return vec2(0.0);
vec3 light_dir = normalize(light.pos - f_pos.xyz);
// Tighter wrap (was +0.25): faces angled away from the headlight cone
// fall off to dark much faster, so cab/exterior surfaces read with a
// clear directional shape instead of a flat half-lit wash.
vec2 part = vec2(1.0) * clamp(dot(fragnormal, light_dir) + 0.10, 0.0, 1.0);
float distance = length(light.pos - f_pos.xyz);
float atten = 1.0f / (1.0f + light.linear * distance + light.quadratic * (distance * distance));
atten *= mix(1.0, 0.0, clamp((coords.z - 0.998) * 500.0, 0.0, 1.0));
vec2 beamcoords = headlightpos.xy / headlightpos.w;
vec4 dheadlightposdx = light.headlight_projection * vec4(dpdx, 0.0);
vec4 dheadlightposdy = light.headlight_projection * vec4(dpdy, 0.0);
vec2 dbeamdx = (dheadlightposdx.xy - beamcoords * dheadlightposdx.w) / headlightpos.w;
vec2 dbeamdy = (dheadlightposdy.xy - beamcoords * dheadlightposdy.w) / headlightpos.w;
vec3 lights = textureGrad(headlightmap, beamcoords, dbeamdx, dbeamdy).rgb * light.headlight_weights.rgb;
float lightintensity = max(max(lights.r, lights.g), lights.b);
// x the diffuse light, y the light the specular reflection takes (specular_light() brings its own n.l)
return vec2(part.x, 1.0) * (atten * lightintensity);
}
// closest distance (squared) the light of a lamp is computed for: nearer the inverse square would grow without a limit
const float LOCAL_LIGHT_MIN_DISTANCE2 = 0.01;
// light of a lamp (point or spot light: the lamps of models and vehicles, the cab lamp) reaching the fragment, x the diffuse
// part and y the light the specular reflection takes (specular_light() brings its own n.l). it falls off with the square of the distance, and smoothly to nothing at the range of the light,
// 1 / sqrt(quadratic), past which the culling of the clusters does not take it. a spot light fades from its inner cone to the
// outer one
vec2 calc_local_light(light_s light, vec3 fragnormal)
{
vec3 tolight = light.pos - f_pos.xyz;
float distance2 = dot(tolight, tolight);
vec3 light_dir = tolight * inversesqrt(max(distance2, 1e-8));
float edge = clamp(1.0 - distance2 * distance2 * (light.quadratic * light.quadratic), 0.0, 1.0);
float atten = edge * edge / max(distance2, LOCAL_LIGHT_MIN_DISTANCE2);
if (light.type == LIGHT_SPOT)
atten *= smoothstep(light.out_cutoff, light.in_cutoff, dot(-light_dir, normalize(light.dir)));
if (atten <= 0.0)
return vec2(0.0);
return vec2(max(dot(fragnormal, light_dir), 0.0), 1.0) * atten;
}
// index of the light cluster the fragment is in, see gl/cluster_grid.h: its screen tile and slice of depth. the depth is the clip
// space w, which is 1 / gl_FragCoord.w. a tile is kept in the grid, as the far edge of the render target and rounding
// right below it give one past the last
uint fragment_cluster()
{
ivec2 tile = ivec2(gl_FragCoord.xy * (vec2(CLUSTER_GRID_X, CLUSTER_GRID_Y) / cluster_viewport_size));
tile = clamp(tile, ivec2(0), ivec2(CLUSTER_GRID_X - 1, CLUSTER_GRID_Y - 1));
int slice = clamp(int(floor(cluster_slice_bias - log(gl_FragCoord.w) * cluster_slice_scale)), 0, CLUSTER_GRID_Z - 1);
return uint(tile.x + CLUSTER_GRID_X * (tile.y + CLUSTER_GRID_Y * slice));
}
// adds the light of a headlight or lamp to the diffuse and the specular light of the fragment
void add_local_light(light_s light, vec2 part, vec3 fragnormal, inout vec3 diffuse, inout vec3 specular)
{
if (part.y <= 0.0)
return;
vec3 color = light.color * light.intensity;
diffuse += color * part.x;
if (matte)
return;
specular += color * (part.y * param[1].y) * specular_light(normalize(light.pos - f_pos.xyz), fragnormal, spec_f0, spec_roughness, LOCAL_LIGHT_BRDF_LIMIT);
}
// adds the light of the headlights and lamps which reach the fragment to its diffuse and specular light. these are the ones in
// the list of its cluster when the lights are clustered (the sun is not on the list, the callers take care of it), and the
// first lights_count - 1 of lights[] otherwise, which are headlights only. the specular light is reflected with spec_f0 and
// spec_roughness, and is already coloured by the fresnel term
void add_local_lights(vec3 fragnormal, inout vec3 diffuse, inout vec3 specular)
{
// worked out before the loops, which the fragments of a quad do not leave together
vec3 dpdx = dFdx(f_pos.xyz);
vec3 dpdy = dFdy(f_pos.xyz);
if (lights_clustered != 0U)
{
cluster_range_s range = cluster_ranges[fragment_cluster()];
for (uint i = 0U; i < range.count; i++)
{
light_s light = lights[cluster_light_indices[range.offset + i]];
vec2 part = (light.type == LIGHT_HEADLIGHTS) ? calc_headlights(light, fragnormal, dpdx, dpdy) : calc_local_light(light, fragnormal);
add_local_light(light, part, fragnormal, diffuse, specular);
}
}
else
{
for (uint i = 1U; i < lights_count; i++)
{
light_s light = lights[i];
add_local_light(light, calc_headlights(light, fragnormal, dpdx, dpdy), fragnormal, diffuse, specular);
}
}
}
// the light of the headlights and lamps added to Fragcolor, diffuse and specular together (for shaders which don't tell
// the albedo from the reflection)
vec3 add_headlights(vec3 fragcolor, vec3 fragnormal)
{
vec3 diffuse = vec3(0.0);
vec3 specular = vec3(0.0);
add_local_lights(fragnormal, diffuse, specular);
return fragcolor + diffuse + specular;
}
// -----------------------------------------------------------------------
// Split-sum environment BRDF (Karis / UE4 analytic approximation).
//
// This is the missing piece that made matte specgloss surfaces "shine like
// crazy": previously the env reflection was added at full strength
// (envcolor * fresnel * reflectivity) and roughness only blurred the mip,
// never dimmed the energy. A rough surface therefore mirrored the bright
// sky just as strongly as a polished one.
//
// EnvBRDFApprox returns the pre-integrated specular scale (the "DFG" term)
// for a given F0, roughness and view angle. For rough surfaces it collapses
// toward ~0, so low-glossiness materials reflect almost nothing — matching
// what Substance 3D Painter shows. Polished surfaces keep their full
// reflection, and the grazing-angle Fresnel edge is preserved.
// roughness 1.0 (matte) -> scale ~0.015 (virtually no reflection)
// roughness 0.0 (mirror) -> scale ~F0..1 (full reflection + Fresnel rim)
vec3 EnvBRDFApprox(vec3 F0, float roughness, float NoV)
{
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
const vec4 c1 = vec4( 1.0, 0.0425, 1.040, -0.040);
vec4 r = roughness * c0 + c1;
float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y;
vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;
return F0 * AB.x + AB.y;
}
// Diffuse colour of the submodel (t3d/e3d) or shape, used as the albedo multiplier:
// untextured materials take it as their colour, textured ones multiply the base texture by it
// (same as the legacy renderer's GL_MODULATE). param[0].rgb holds the authored sRGB colour,
// param[1].x its intensity (HSV value unless a material overrides it).
vec3 material_diffuse()
{
vec3 diffusecolor = pow(max(param[0].rgb, vec3(0.0)), vec3(2.2));
float value = max(param[0].r, max(param[0].g, param[0].b));
return (value > 0.0 ? diffusecolor * (param[1].x / value) : vec3(0.0));
}
// lights the surface: the ambient light, the sun (the moon), the headlights and lamps and the reflection of the surroundings.
// the units are the ones of the ambient light, the irradiance over pi: a white lambertian surface lit by 1 of it shows 1.
// Texturecolor is the albedo (the base colour of a metal), Specularity the specular level of a dielectric (0.5 is the
// reflectance of 4% at normal incidence), Reflectivity how much of the reflected surroundings is the cubemap rather than the
// ambient light, Shadowtone the share of the sun left in its shadow (1 for the materials which take no shadows).
// a Sunless surface (the interior of a cab) gets no light of the sun, its shadow only darkens the ambient light
vec3 shade_surface(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float reflectivity, float specularity, float shadowtone, bool sunless)
{
// Diffuse colour is applied once, to the albedo; the light terms below are not scaled by it again
texturecolor *= material_diffuse();
float polished = 0.0;
if (sunless)
{
// Cab interior: dim ambient less than the exterior path - ambient
// is the dominant indoor illumination, but it was still too bright.
fragcolor *= 0.80;
}
else
{
#ifndef NO_WEATHERING
float weathered = (param[2].w > 0.0 ? clamp(param[2].w * UserData.x, 0.0, 1.0) : 0.0);
float tinted = (param[2].w < 0.0 ? clamp(-param[2].w * UserData.x, 0.0, 1.0) : 0.0);
// a tint only scales the colour of the texture, the steel keeps its own polish
polished = weathered * smoothstep(0.03, 0.12, dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)));
float weatheredluma = min(dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)), 0.05);
vec3 unused = texturecolor * (weatheredluma / max(dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)), 1e-4));
unused = mix(unused, vec3(1.0, 0.82, 0.74) * (weatheredluma / 0.8525), 0.5);
texturecolor = mix(texturecolor, unused, smoothstep(0.0, 0.4, weathered));
texturecolor = (tinted > 0.0 ? texturecolor * mix(vec3(1.0), param[2].rgb, tinted) : texturecolor);
specularity = mix(specularity, min(specularity, 0.03), smoothstep(0.0, 0.4, polished));
metalic = mix(metalic, 0.0, polished);
glossiness = mix(glossiness, min(glossiness, 0.06 * abs(param[1].w)), polished);
reflectivity = mix(reflectivity, min(reflectivity, 0.08 * param[1].z), smoothstep(0.0, 0.4, polished));
#endif
// Scale ambient before it gets tinted by the texture.
// Sun, headlights and emission are added afterwards so they are NOT
// attenuated by AMBIENT_SCALE - this only dims the indirect term.
fragcolor *= AMBIENT_SCALE;
}
vec3 emissioncolor = vec3(emission);
vec3 view_dir = normalize(-f_pos.xyz);
float NdotV = max(dot(fragnormal, view_dir), 1e-4);
// glossiness == param[1].w -> mirror, glossiness == 0 -> fully rough
float roughness = clamp(1.0 - glossiness / max(abs(param[1].w), 1.0), 0.0, 1.0);
roughness = max(specular_antialiasing(fragnormal, roughness), MIN_ROUGHNESS);
// metals reflect with their base colour, dielectrics with the specular level (0.5 -> 0.04)
vec3 f0 = mix(vec3(0.08 * specularity), texturecolor, metalic);
spec_f0 = f0;
spec_roughness = roughness;
// Pre-integrated env BRDF: how much of the surroundings the surface reflects, for its F0, roughness and the view angle.
// the surroundings are the cubemap where the material asks for it (reflectivity) and the ambient light elsewhere, so a
// surface reflects them always, the rough one barely
vec3 env_spec = EnvBRDFApprox(f0, roughness, NdotV);
float env_roughness = roughness;
vec3 cubemap_spec = env_spec;
float cubemap_share = max(reflectivity, 0.0);
float ambient_share = clamp(1.0 - reflectivity, 0.0, 1.0);
if (matte)
{
env_spec = vec3(0.0);
cubemap_share = 0.0;
}
// what the diffuse layer is left with
vec3 diffuse_albedo = texturecolor * (1.0 - metalic) * (1.0 - env_spec);
if (legacy_coat)
{
// the varnish: a smooth dielectric layer reflecting the cubemap, worn off where the material is weathered
env_roughness = specular_antialiasing(fragnormal, roughness * smoothstep(0.0, 0.4, polished));
cubemap_spec = EnvBRDFApprox(mix(vec3(0.04), texturecolor, metalic), env_roughness, NdotV);
ambient_share = 1.0;
diffuse_albedo *= 1.0 - cubemap_spec * min(cubemap_share, 1.0);
}
vec3 envcolor = (matte ? vec3(0.0) : envmap_color_rough(fragnormal, env_roughness));
if (lights_count == 0U)
return fragcolor * diffuse_albedo
+ emissioncolor * texturecolor
+ fragcolor * env_spec * ambient_share
+ envcolor * cubemap_spec * cubemap_share;
vec3 light_dir = normalize(-lights[0].dir);
float NdotL = max(dot(fragnormal, light_dir), 0.0);
// Sharpen sun N.L falloff so the lit-to-shaded terminator on cab
// panels, vehicle bodies and terrain reads as a clear edge rather
// than a soft Lambertian ramp. Tunable via SUN_NDOTL_SHARPNESS.
float sun_NdotL = pow(NdotL, SUN_NDOTL_SHARPNESS);
// the shadows of the clouds come with the weather (stage P2): nothing holds the sun back yet
float cloudsun = 1.0;
// Sun HDR scale -> SUN_DIFFUSE_SCALE, the same for the diffuse and the specular light
vec3 sunlight = lights[0].color * (SUN_DIFFUSE_SCALE * lights[0].intensity * cloudsun);
float shadow = 0.0;
if (shadowtone < 1.0)
shadow = clamp(calc_shadow(), 0.0, 1.0);
// the cubemap knows nothing of what shades the fragment: it is dimmed a little in the shadow of the sun
float cubemap_shadow = 1.0;
if (sunless)
{
// the sun adds no light in the cab, where it would fall its shadow darkens the ambient light
float diffuseamount = sun_NdotL * lights[0].intensity;
float darkness = (shadowtone < 1.0 ? max(shadow, 1.0 - cloudsun) : 0.0);
fragcolor = mix(fragcolor, fragcolor * shadowtone, clamp(diffuseamount * darkness, 0.0, 1.0));
}
else
cubemap_shadow = 1.0 - (1.0 - shadowtone) * shadow * 0.5;
// the reflection of the surroundings, before the light of the sun and the lamps joins the ambient light
vec3 env_reflection = fragcolor * env_spec * ambient_share
+ envcolor * cubemap_spec * (cubemap_share * cubemap_shadow);
// the shadow leaves the share of the sun Shadowtone tells (the old shadow colour of the scenery) to the diffuse light,
// nothing to the highlight
if (!sunless)
fragcolor += sunlight * (sun_NdotL * (1.0 - (1.0 - shadowtone) * shadow));
vec3 specular = matte ? vec3(0.0) : sunlight * specular_light(light_dir, fragnormal, f0, roughness, SUN_BRDF_LIMIT) * (1.0 - shadow);
vec3 lampspecular = vec3(0.0);
add_local_lights(fragnormal, fragcolor, lampspecular);
return fragcolor * diffuse_albedo // ambient, sun and lamps on the diffuse layer
+ specular * param[1].y // highlight of the sun, fresnel coloured (metals take their base colour)
+ lampspecular // highlights of the lamps, param[1].y already applied
+ emissioncolor * texturecolor
+ env_reflection;
}
vec3 apply_lights(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float reflectivity, float specularity, float shadowtone)
{
return shade_surface(fragcolor, fragnormal, texturecolor, reflectivity, specularity, shadowtone, false);
}
// the interior of a cab: no light of the sun, its shadow darkens the ambient light
vec3 apply_lights_sunless(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float reflectivity, float specularity, float shadowtone)
{
return shade_surface(fragcolor, fragnormal, texturecolor, reflectivity, specularity, shadowtone, true);
}

View File

@@ -0,0 +1,4 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
#include "mat_colored.glsl"

View File

@@ -0,0 +1,60 @@
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
#include "common.glsl"
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, zero)
#pragma param(glossiness, 1, 3, 1, glossiness)
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
// no texture: the diffuse colour alone makes the albedo, apply_lights() applies it to the white base
vec4 tex_color = vec4(1.0, 1.0, 1.0, param[0].a);
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 fragnormal = normalize(f_normal);
float reflectivity = param[1].z;
float specularity = dot(pow(param[0].rgb, vec3(2.2)), vec3(0.5));
legacy_gloss();
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,4 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
#include "mat_default.glsl"

View File

@@ -0,0 +1,69 @@
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
#include "common.glsl"
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, zero)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(diffuse, f_coord);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 fragnormal = normalize(f_normal);
matte = true;
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, 0.0, 0.0, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
/*
float distance = dot(f_pos.xyz, f_pos.xyz);
if( distance <= cascade_end.x ) { color.r += 0.25; }
else if( distance <= cascade_end.y ) { color.g += 0.25; }
else if( distance <= cascade_end.z ) { color.b += 0.25; }
*/
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, tex_color.a * alpha_mult);
}
}

View File

@@ -0,0 +1,4 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
#include "mat_colored.glsl"

View File

@@ -0,0 +1,4 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
#include "mat_default.glsl"

View File

@@ -0,0 +1,4 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
#include "mat_reflmap.glsl"

View File

@@ -0,0 +1,77 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, zero)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma param(detail_scale, 2, 0, 1, one)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma texture(detailnormalmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D detailnormalmap;
#define NORMALMAP
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(diffuse, f_coord);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 normal;
normal.xy = (texture(detailnormalmap, f_coord * param[2].x).rg * 2.0 - 1.0);
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
float reflectivity = param[1].z;
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
legacy_gloss();
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, tex_color.a * alpha_mult);
}
}

View File

@@ -0,0 +1,77 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, zero)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(specgloss, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D specgloss;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(diffuse, f_coord);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 fragnormal = normalize(f_normal);
float reflectivity = param[1].z;
float specularity = texture(specgloss, f_coord).r;
glossiness = texture(specgloss, f_coord).g * abs(param[1].w);
metalic = texture(specgloss, f_coord).b;
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
/*
float distance = dot(f_pos.xyz, f_pos.xyz);
if( distance <= cascade_end.x ) { color.r += 0.25; }
else if( distance <= cascade_end.y ) { color.g += 0.25; }
else if( distance <= cascade_end.z ) { color.b += 0.25; }
*/
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, tex_color.a * alpha_mult);
}
}

View File

@@ -0,0 +1,89 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, one)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma param(detail_scale, 2, 0, 1, one)
#pragma param(detail_height_scale, 2, 1, 1, one)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(normalmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D normalmap;
#pragma texture(detailnormalmap, 2, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D detailnormalmap;
#define NORMALMAP
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(diffuse, f_coord);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
vec3 fragcolor = ambient;
vec4 normal_map = texture(normalmap, f_coord);
vec4 detailnormal_map = texture(detailnormalmap, f_coord * param[2].x);
vec3 normal;
vec3 normaldetail;
normaldetail.xy = detailnormal_map.rg* 2.0 - 1.0;
normaldetail.z = sqrt(1.0 - clamp((dot(normaldetail.xy, normaldetail.xy)), 0.0, 1.0));
normaldetail.xyz = normaldetail.xyz * param[2].y;
normal.xy = normal_map.rg* 2.0 - 1.0;
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(vec3(normal.xy + normaldetail.xy, normal.z)));
float reflblend = (normal_map.a + detailnormal_map.a);
float reflectivity = reflblend > 1.0 ? param[1].z * 1.0 : param[1].z * reflblend;
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
legacy_gloss();
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,96 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, one)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma param(detail_scale, 2, 0, 1, one)
#pragma param(detail_height_scale, 2, 1, 1, one)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(normalmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D normalmap;
#pragma texture(detailnormalmap, 2, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D detailnormalmap;
#pragma texture(specgloss, 3, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 3) uniform sampler2D specgloss;
#define NORMALMAP
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(diffuse, f_coord);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec4 normal_map = texture(normalmap, f_coord);
vec4 detailnormal_map = texture(detailnormalmap, f_coord * param[2].x);
vec4 specgloss_map = texture(specgloss, f_coord);
vec3 normal;
vec3 normaldetail;
normaldetail.xy = detailnormal_map.rg* 2.0 - 1.0;
normaldetail.z = sqrt(1.0 - clamp((dot(normaldetail.xy, normaldetail.xy)), 0.0, 1.0));
normaldetail.xyz = normaldetail.xyz * param[2].y;
normal.xy = normal_map.rg* 2.0 - 1.0;
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(vec3(normal.xy + normaldetail.xy, normal.z)));
float reflblend = (normal_map.a + detailnormal_map.a);
float reflectivity = reflblend > 1.0 ? param[1].z * 1.0 : param[1].z * reflblend;
float specularity = specgloss_map.r;
glossiness = specgloss_map.g * abs(param[1].w);
metalic = specgloss_map.b;
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,152 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn; //tangent matrix nietransponowany; mnożyć przez f_tbn dla TangentLightPos; TangentViewPos; TangentFragPos;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 6) in vec3 TangentFragPos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, one)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma param(detail_scale, 2, 0, 1, one)
#pragma param(detail_height_scale, 2, 1, 1, one)
#pragma param(height_scale, 2, 2, 1, zero)
#pragma param(height_offset, 2, 3, 1, zero)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(normalmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D normalmap;
#pragma texture(detailnormalmap, 2, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D detailnormalmap;
#define PARALLAX
// param[2].w is the height offset, not the weathering
#define NO_WEATHERING
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir);
void main()
{
//parallax mapping
vec3 viewDir = normalize(-TangentFragPos); //tangent view pos - tangent frag pos
vec2 f_coord_p = ParallaxMapping(f_coord, viewDir);
vec4 normal_map = texture(normalmap, f_coord_p);
vec4 detailnormal_map = texture(detailnormalmap, f_coord_p * param[2].x);
vec4 tex_color = texture(diffuse, f_coord_p);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 normal;
vec3 normaldetail;
normaldetail.xy = detailnormal_map.rg* 2.0 - 1.0;
normaldetail.z = sqrt(1.0 - clamp((dot(normaldetail.xy, normaldetail.xy)), 0.0, 1.0));
normaldetail.xyz = normaldetail.xyz * param[2].y;
normal.xy = normal_map.rg* 2.0 - 1.0;
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(vec3(normal.xy + normaldetail.xy, normal.z)));
float reflectivity = param[1].z * normal_map.a;
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
legacy_gloss();
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}
vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir)
{
float pos_len = length(f_pos.xyz);
// gradients of the coordinates taken here: inside the loop the fragments of a quad don't go the same way
vec2 dcoorddx = dFdx(f_coord);
vec2 dcoorddy = dFdy(f_coord);
if (pos_len > 100.0) {
return f_coord;
}
// the shift fades out before the distance it stops at, so it doesn't switch off at once there
float fade = 1.0 - smoothstep(80.0, 100.0, pos_len);
if (EXTRAEFFECTS_ENABLED)
{
const float minLayers = 8.0;
const float maxLayers = 32.0;
float LayersWeight = pos_len / 20.0;
vec2 currentTexCoords = f_coord;
float currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b;
LayersWeight = min(abs(dot(vec3(0.0, 0.0, 1.0), viewDir)),LayersWeight);
float numLayers = mix(maxLayers, minLayers, clamp(LayersWeight, 0.0, 1.0)); // number of depth layers
float layerDepth = 1.0 / numLayers; // calculate the size of each layer
float currentLayerDepth = 0.0; // depth of current layer
vec2 P = viewDir.xy * param[2].z * fade; // the amount to shift the texture coordinates per layer (from vector P)
vec2 deltaTexCoords = P / numLayers;
while(currentLayerDepth < currentDepthMapValue)
{
currentTexCoords -= deltaTexCoords; // shift texture coordinates along direction of P
currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b; // get depthmap value at current texture coordinates
currentLayerDepth += layerDepth; // get depth of next layer
}
vec2 prevTexCoords = currentTexCoords + deltaTexCoords; // get texture coordinates before collision (reverse operations)
float afterDepth = currentDepthMapValue - currentLayerDepth; // get depth after and before collision for linear interpolation
float beforeDepth = textureGrad(normalmap, prevTexCoords, dcoorddx, dcoorddy).b - currentLayerDepth + layerDepth;
float weight = afterDepth / (afterDepth - beforeDepth); // interpolation of texture coordinates
vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);
return finalTexCoords;
}
else
{
float height = texture(normalmap, f_coord).b;
vec2 p = viewDir.xy / viewDir.z * (height * (param[2].z - param[2].w) * 0.2) * fade;
return f_coord - p;
}
}

View File

@@ -0,0 +1,158 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn; //tangent matrix nietransponowany; mnożyć przez f_tbn dla TangentLightPos; TangentViewPos; TangentFragPos;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 6) in vec3 TangentFragPos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, one)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma param(detail_scale, 2, 0, 1, one)
#pragma param(detail_height_scale, 2, 1, 1, one)
#pragma param(height_scale, 2, 2, 1, zero)
#pragma param(height_offset, 2, 3, 1, zero)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(normalmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D normalmap;
#pragma texture(specgloss, 2, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D specgloss;
#pragma texture(detailnormalmap, 3, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 3) uniform sampler2D detailnormalmap;
#define PARALLAX
// param[2].w is the height offset, not the weathering
#define NO_WEATHERING
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir);
void main()
{
//parallax mapping
vec3 viewDir = normalize(vec3(0.0f, 0.0f, 0.0f) - TangentFragPos); //tangent view pos - tangent frag pos
vec2 f_coord_p = ParallaxMapping(f_coord, viewDir);
vec4 normal_map = texture(normalmap, f_coord_p);
vec4 detailnormal_map = texture(detailnormalmap, f_coord_p * param[2].x);
vec4 tex_color = texture(diffuse, f_coord_p);
vec4 specgloss_map = texture(specgloss, f_coord_p);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
vec3 fragcolor = ambient;
vec3 normal;
vec3 normaldetail;
normaldetail.xy = detailnormal_map.rg* 2.0 - 1.0;
normaldetail.z = sqrt(1.0 - clamp((dot(normaldetail.xy, normaldetail.xy)), 0.0, 1.0));
normaldetail.xyz = normaldetail.xyz * param[2].y;
normal.xy = normal_map.rg* 2.0 - 1.0;
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(vec3(normal.xy + normaldetail.xy, normal.z)));
float reflectivity = param[1].z * normal_map.a;
float specularity = specgloss_map.r;
glossiness = specgloss_map.g * abs(param[1].w);
metalic = specgloss_map.b;
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}
vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir)
{
float pos_len = length(f_pos.xyz);
// gradients of the coordinates taken here: inside the loop the fragments of a quad don't go the same way
vec2 dcoorddx = dFdx(f_coord);
vec2 dcoorddy = dFdy(f_coord);
if (pos_len > 100.0) {
return f_coord;
}
// the shift fades out before the distance it stops at, so it doesn't switch off at once there
float fade = 1.0 - smoothstep(80.0, 100.0, pos_len);
if (EXTRAEFFECTS_ENABLED)
{
const float minLayers = 8.0;
const float maxLayers = 32.0;
float LayersWeight = pos_len / 20.0;
vec2 currentTexCoords = f_coord;
float currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b;
LayersWeight = min(abs(dot(vec3(0.0, 0.0, 1.0), viewDir)),LayersWeight);
float numLayers = mix(maxLayers, minLayers, clamp(LayersWeight, 0.0, 1.0)); // number of depth layers
float layerDepth = 1.0 / numLayers; // calculate the size of each layer
float currentLayerDepth = 0.0; // depth of current layer
vec2 P = viewDir.xy * param[2].z * fade; // the amount to shift the texture coordinates per layer (from vector P)
vec2 deltaTexCoords = P / numLayers;
while(currentLayerDepth < currentDepthMapValue)
{
currentTexCoords -= deltaTexCoords; // shift texture coordinates along direction of P
currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b; // get depthmap value at current texture coordinates
currentLayerDepth += layerDepth; // get depth of next layer
}
vec2 prevTexCoords = currentTexCoords + deltaTexCoords; // get texture coordinates before collision (reverse operations)
float afterDepth = currentDepthMapValue - currentLayerDepth; // get depth after and before collision for linear interpolation
float beforeDepth = textureGrad(normalmap, prevTexCoords, dcoorddx, dcoorddy).b - currentLayerDepth + layerDepth;
float weight = afterDepth / (afterDepth - beforeDepth); // interpolation of texture coordinates
vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);
return finalTexCoords;
}
else
{
float height = texture(normalmap, f_coord).b;
vec2 p = viewDir.xy / viewDir.z * (height * (param[2].z - param[2].w) * 0.2) * fade;
return f_coord - p;
}
}

View File

@@ -0,0 +1,29 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
#include "tonemapping.glsl"
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
void main()
{
vec4 color = vec4(1.0, 0.0, 1.0, 1.0);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
out_motion = vec4(0.0f);
}
}

View File

@@ -0,0 +1,76 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, one)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(normalmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D normalmap;
#define NORMALMAP
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(diffuse, f_coord);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 normal;
normal.xy = (texture(normalmap, f_coord).rg * 2.0 - 1.0);
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
float reflectivity = param[1].z * texture(normalmap, f_coord).a;
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
legacy_gloss();
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,81 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, one)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(normalmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D normalmap;
#pragma texture(specgloss, 2, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D specgloss;
#define NORMALMAP
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(diffuse, f_coord);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 normal;
normal.xy = (texture(normalmap, f_coord).rg * 2.0 - 1.0);
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
float reflectivity = param[1].z * texture(normalmap, f_coord).a;
float specularity = texture(specgloss, f_coord).r;
glossiness = texture(specgloss, f_coord).g * abs(param[1].w);
metalic = texture(specgloss, f_coord).b;
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,137 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn; //tangent matrix nietransponowany; mnożyć przez f_tbn dla TangentLightPos; TangentViewPos; TangentFragPos;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 6) in vec3 TangentFragPos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, one)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma param(height_scale, 2, 1, 1, zero)
#pragma param(height_offset, 2, 2, 1, zero)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(normalmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D normalmap;
#define PARALLAX
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir);
void main()
{
//parallax mapping
vec3 viewDir = normalize(vec3(0.0f, 0.0f, 0.0f) - TangentFragPos); //tangent view pos - tangent frag pos
vec2 f_coord_p = ParallaxMapping(f_coord, viewDir);
vec4 tex_color = texture(diffuse, f_coord_p);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 normal;
normal.xy = (texture(normalmap, f_coord_p).rg * 2.0 - 1.0);
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
float reflectivity = param[1].z * texture(normalmap, f_coord_p).a;
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
legacy_gloss();
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}
vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir)
{
float pos_len = length(f_pos.xyz);
// gradients of the coordinates taken here: inside the loop the fragments of a quad don't go the same way
vec2 dcoorddx = dFdx(f_coord);
vec2 dcoorddy = dFdy(f_coord);
if (pos_len > 100.0) {
return f_coord;
}
// the shift fades out before the distance it stops at, so it doesn't switch off at once there
float fade = 1.0 - smoothstep(80.0, 100.0, pos_len);
if (EXTRAEFFECTS_ENABLED)
{
const float minLayers = 8.0;
const float maxLayers = 32.0;
float LayersWeight = pos_len / 20.0;
vec2 currentTexCoords = f_coord;
float currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b;
LayersWeight = min(abs(dot(vec3(0.0, 0.0, 1.0), viewDir)),LayersWeight);
float numLayers = mix(maxLayers, minLayers, clamp(LayersWeight, 0.0, 1.0)); // number of depth layers
float layerDepth = 1.0 / numLayers; // calculate the size of each layer
float currentLayerDepth = 0.0; // depth of current layer
vec2 P = viewDir.xy * param[2].y * fade; // the amount to shift the texture coordinates per layer (from vector P)
vec2 deltaTexCoords = P / numLayers;
while(currentLayerDepth < currentDepthMapValue)
{
currentTexCoords -= deltaTexCoords; // shift texture coordinates along direction of P
currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b; // get depthmap value at current texture coordinates
currentLayerDepth += layerDepth; // get depth of next layer
}
vec2 prevTexCoords = currentTexCoords + deltaTexCoords; // get texture coordinates before collision (reverse operations)
float afterDepth = currentDepthMapValue - currentLayerDepth; // get depth after and before collision for linear interpolation
float beforeDepth = textureGrad(normalmap, prevTexCoords, dcoorddx, dcoorddy).b - currentLayerDepth + layerDepth;
float weight = afterDepth / (afterDepth - beforeDepth); // interpolation of texture coordinates
vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);
return finalTexCoords;
}
else
{
float height = texture(normalmap, f_coord).b;
vec2 p = viewDir.xy / viewDir.z * (height * (param[2].y - param[2].z) * 0.2) * fade;
return f_coord - p;
}
}

View File

@@ -0,0 +1,142 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn; //tangent matrix nietransponowany; mnożyć przez f_tbn dla TangentLightPos; TangentViewPos; TangentFragPos;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 6) in vec3 TangentFragPos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, one)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma param(height_scale, 2, 1, 1, zero)
#pragma param(height_offset, 2, 2, 1, zero)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(normalmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D normalmap;
#pragma texture(specgloss, 2, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D specgloss;
#define PARALLAX
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir);
void main()
{
//parallax mapping
vec3 viewDir = normalize(vec3(0.0f, 0.0f, 0.0f) - TangentFragPos); //tangent view pos - tangent frag pos
vec2 f_coord_p = ParallaxMapping(f_coord, viewDir);
vec4 tex_color = texture(diffuse, f_coord_p);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 normal;
normal.xy = (texture(normalmap, f_coord_p).rg * 2.0 - 1.0);
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
float reflectivity = param[1].z * texture(normalmap, f_coord_p).a;
float specularity = texture(specgloss, f_coord_p).r;
glossiness = texture(specgloss, f_coord_p).g * abs(param[1].w);
metalic = texture(specgloss, f_coord_p).b;
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}
vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir)
{
float pos_len = length(f_pos.xyz);
// gradients of the coordinates taken here: inside the loop the fragments of a quad don't go the same way
vec2 dcoorddx = dFdx(f_coord);
vec2 dcoorddy = dFdy(f_coord);
if (pos_len > 100.0) {
return f_coord;
}
// the shift fades out before the distance it stops at, so it doesn't switch off at once there
float fade = 1.0 - smoothstep(80.0, 100.0, pos_len);
if (EXTRAEFFECTS_ENABLED)
{
const float minLayers = 8.0;
const float maxLayers = 32.0;
float LayersWeight = pos_len / 20.0;
vec2 currentTexCoords = f_coord;
float currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b;
LayersWeight = min(abs(dot(vec3(0.0, 0.0, 1.0), viewDir)),LayersWeight);
float numLayers = mix(maxLayers, minLayers, clamp(LayersWeight, 0.0, 1.0)); // number of depth layers
float layerDepth = 1.0 / numLayers; // calculate the size of each layer
float currentLayerDepth = 0.0; // depth of current layer
vec2 P = viewDir.xy * param[2].y * fade; // the amount to shift the texture coordinates per layer (from vector P)
vec2 deltaTexCoords = P / numLayers;
while(currentLayerDepth < currentDepthMapValue)
{
currentTexCoords -= deltaTexCoords; // shift texture coordinates along direction of P
currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b; // get depthmap value at current texture coordinates
currentLayerDepth += layerDepth; // get depth of next layer
}
vec2 prevTexCoords = currentTexCoords + deltaTexCoords; // get texture coordinates before collision (reverse operations)
float afterDepth = currentDepthMapValue - currentLayerDepth; // get depth after and before collision for linear interpolation
float beforeDepth = textureGrad(normalmap, prevTexCoords, dcoorddx, dcoorddy).b - currentLayerDepth + layerDepth;
float weight = afterDepth / (afterDepth - beforeDepth); // interpolation of texture coordinates
vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);
return finalTexCoords;
}
else
{
float height = texture(normalmap, f_coord).b;
vec2 p = viewDir.xy / viewDir.z * (height * (param[2].y - param[2].z) * 0.2) * fade;
return f_coord - p;
}
}

View File

@@ -0,0 +1,216 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
// Windshield rain effects
// by @lcddisplay; wiper movement @MichauSto
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma texture(diffuse, 0, sRGB_A)
#pragma texture(raindropsatlas, 1, sRGB_A)
#pragma texture(wipermask, 2, sRGB_A)
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, zero)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma param(raindrop_grid_size, 2, 0, 1, one)
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
#include "random.glsl"
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D raindropsatlas;
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D wipermask;
const float specular_intensity = 1.0;
const float wobble_strength = 0.002;
const float wobble_speed = 30.0;
vec4 getDropTex(float choice, vec2 uv) {
vec2 offset;
if (choice < 0.25) offset = vec2(0.0, 0.0);
else if (choice < 0.5) offset = vec2(0.5, 0.0);
else if (choice < 0.75) offset = vec2(0.0, 0.5);
else offset = vec2(0.5, 0.5);
return texture(raindropsatlas, offset + uv * 0.5);
}
float GetMixFactor(in vec2 co, out float side);
void main() {
vec4 tex_color = texture(diffuse, f_coord);
if (tex_color.a < 0.01) discard;
vec2 rainCoord = f_coord;
float gridSize = ceil(param[2].x);
const float numDrops = 20000.0;
const float cycleDuration = 4.0;
float squareMin = 0.5 / gridSize;
float squareMax = 1.2 / gridSize;
vec2 cell = floor(rainCoord * gridSize);
vec3 dropLayer = vec3(0.0);
float dropMaskSum = 0.0;
// Grid of 9 droplets in immediate neighbourhood
for (int oy = -1; oy <= 1; oy++) {
for (int ox = -1; ox <= 1; ox++) {
vec2 neighborCell = cell + vec2(ox, oy);
vec2 neighborCenter = (neighborCell + .5) / gridSize;
float side;
float mixFactor = GetMixFactor(neighborCenter, side);
uint seed = Hash(uvec3(neighborCell, side));
if(mixFactor < RandF(seed)) {
continue;
}
// Show a percentage of droplets given by rain intensity param
float activationSeed = RandF(seed);
if (activationSeed > rain_params.x)
continue; // kropla nieaktywna
// Randomly modulate droplet center & size
vec2 dropCenter = (neighborCell + vec2(RandF(seed), RandF(seed))) / gridSize;
float squareSize = mix(squareMin, squareMax, RandF(seed));
float lifeTime = time + RandF(seed) * cycleDuration;
float phase = fract(lifeTime / cycleDuration);
float actiwe = clamp(1.0 - phase, 0.0, 1.0);
// Gravity influence (TODO add vehicle speed & wind here!)
float gravityStart = 0.5;
float gravityPhase = smoothstep(gravityStart, 1.0, phase);
float dropMass = mix(0.3, 1.2, RandF(seed));
float gravitySpeed = 0.15 * dropMass;
vec2 gravityOffset = vec2(0.0, gravityPhase * gravitySpeed * phase);
// Random wobble
bool hasWobble = (RandF(seed) < 0.10);
vec2 wobbleOffset = vec2(0.0);
if (hasWobble && gravityPhase > 0.0) {
float intensity = sin(time * wobble_speed + RandF(seed) * 100.) * wobble_strength * gravityPhase;
wobbleOffset = vec2(intensity, 0.0);
}
vec2 slideOffset = gravityOffset + wobbleOffset;
// Flatten droplets influenced by gravity
float flattenAmount = smoothstep(0.1, 0.5, gravityPhase);
float flattenX = mix(1.0, 0.4, flattenAmount);
float stretchY = mix(1.0, 1.6, flattenAmount);
// Droplet local position & mask
vec2 diff = (rainCoord + slideOffset) - dropCenter;
diff.x *= 1.0 / flattenX;
diff.y *= 1.0 / stretchY;
float mask = smoothstep(squareSize * 0.5, squareSize * 0.45, max(abs(diff.x), abs(diff.y)));
if (mask > 0.001) {
vec2 localUV = (diff + squareSize * 0.5) / squareSize;
float choice = RandF(seed);
vec4 dropTex = getDropTex(choice, localUV);
float sharpAlpha = smoothstep(0.3, 0.9, dropTex.a);
float ambLum = clamp(dot(ambient, vec3(0.2126, 0.7152, 0.0722)), 0.0, 1.0);
float sunFactor = pow(clamp(ambLum * 6.0, 0.0, 1.0), 0.5);
float dynBright = mix(0.0, 1.0, sunFactor);
float colorLuma = length(dropTex.rgb);
float alphaRange = smoothstep(0.1, 0.3, colorLuma);
float blackAlpha = mix(0.25, 0.85, alphaRange);
float sparkle = 0.0;
if (hasWobble) {
sparkle = pow(abs(sin(f_coord.x * 8.0 + time * 2.0 + RandF(seed) * 6.2831)), 40.0)
* mix(0.2, 1.0, sunFactor);
}
vec3 specularColor = vec3(1.0) * specular_intensity * sparkle;
vec3 dropLit = dropTex.rgb * dynBright + specularColor * sharpAlpha;
dropLayer += dropLit * sharpAlpha * actiwe * blackAlpha * mask;
dropMaskSum += sharpAlpha * actiwe * blackAlpha * mask;
}
}
}
vec3 finalMix = dropLayer;
float alphaOut = clamp(dropMaskSum, 0.0, 1.0);
out_color = vec4(finalMix, alphaOut);
{ // Overlay windshield texture with alpha
vec3 fragcolor = ambient;
vec3 fragnormal = normalize(f_normal);
float reflectivity = param[1].z;
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
legacy_gloss();
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(fragcolor, tex_color.a * alpha_mult);
out_color.xyz = apply_fog(mix(out_color.xyz, color.xyz, color.a));
out_color.a = mix(out_color.a, 1., color.a);
}
if (MOTIONBLUR_ENABLED)
{
out_motion = vec4(0.0);
}
}
float GetMixFactor(in vec2 co, out float side) {
vec4 movePhase = wiper_pos;
bvec4 is_out = lessThanEqual(movePhase, vec4(1.));
movePhase = mix(vec4(2.) - movePhase, movePhase, is_out);
vec4 mask = texture(wipermask, co);
vec4 areaMask = step(.001, mask);
vec4 maskVal = mix(1. - mask, mask, is_out);
vec4 wipeWidth = smoothstep(1., .9, movePhase) * .25;
vec4 cleaned = smoothstep(movePhase - wipeWidth, movePhase, maskVal) * areaMask;
vec4 side_v = step(maskVal, movePhase);
cleaned *= side_v;
side_v = mix(side_v, vec4(1.) - side_v, is_out);
// "regeneration", raindrops gradually returning after wiper pass:
vec4 regenPhase = clamp((vec4(time) - mix(wiper_timer_out, wiper_timer_return, side_v) - vec4(.2)) / vec4(rain_params.y), vec4(0.), vec4(1.));
side_v = mix(vec4(0.), vec4(1.) - side_v, areaMask);
vec4 factor_v = mix(vec4(1.), regenPhase * (vec4(1.) - cleaned), areaMask);
side = 0.;
float out_factor = 1.;
// Find out the wiper blade that influences given grid cell the most
for(int i = 0; i < 4; ++i)
{
bool is_candidate = factor_v[i] < out_factor;
out_factor = mix(out_factor, factor_v[i], is_candidate);
side = mix(side, side_v[i], is_candidate);
}
return out_factor;
}

View File

@@ -0,0 +1,4 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
#include "mat_reflmap.glsl"

View File

@@ -0,0 +1,72 @@
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
#include "common.glsl"
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, one)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(reflmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D reflmap;
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(diffuse, f_coord);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 fragnormal = normalize(f_normal);
float reflectivity = param[1].z * texture(reflmap, f_coord).a;
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
legacy_gloss();
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, 0.0, shadow_tone);
if(alphatestfail)
fragcolor.r = 1.0;
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,79 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, one)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(reflmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D reflmap;
#pragma texture(specgloss, 2, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D specgloss;
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(diffuse, f_coord);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 fragnormal = normalize(f_normal);
float reflectivity = param[1].z * texture(reflmap, f_coord).a;
float specularity = texture(specgloss, f_coord).r;
glossiness = texture(specgloss, f_coord).g * abs(param[1].w);
metalic = texture(specgloss, f_coord).b;
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
if(alphatestfail)
fragcolor.r = 1.0;
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,75 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, zero)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(normalmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D normalmap;
#define NORMALMAP
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(diffuse, f_coord);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 normal;
normal.xy = (texture(normalmap, f_coord).rg * 2.0 - 1.0);
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
float reflectivity = param[1].z * texture(normalmap, f_coord).a;
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
legacy_gloss();
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, 1.0);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,80 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, zero)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(normalmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D normalmap;
#pragma texture(specgloss, 2, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D specgloss;
#define NORMALMAP
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(diffuse, f_coord);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 normal;
normal.xy = (texture(normalmap, f_coord).rg * 2.0 - 1.0);
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
float reflectivity = param[1].z * texture(normalmap, f_coord).a;
float specularity = texture(specgloss, f_coord).r;
glossiness = texture(specgloss, f_coord).g * abs(param[1].w);
metalic = texture(specgloss, f_coord).b;
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, 1.0);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,38 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
#include "tonemapping.glsl"
layout(location = 1) flat in vec3 f_normal_raw;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
void main()
{
float x = (gl_PointCoord.x - 0.5f) * 2.0f;
float y = (gl_PointCoord.y - 0.5f) * 2.0f;
float dist2 = abs(x * x + y * y);
if (dist2 > 0.5f * 0.5f)
discard;
// color data space is shared with normals, ugh
vec4 color = vec4(pow(f_normal_raw.rgb, vec3(2.2)), 1.0f);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
out_motion = vec4(0.0f);
}
}

View File

@@ -0,0 +1,75 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, zero)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(normalmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D normalmap;
#define NORMALMAP
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(diffuse, f_coord);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 normal;
normal.xy = (texture(normalmap, f_coord).rg * 2.0 - 1.0);
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
float reflectivity = param[1].z * texture(normalmap, f_coord).a;
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
legacy_gloss();
fragcolor = apply_lights_sunless(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,80 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, zero)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(normalmap, 1, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D normalmap;
#pragma texture(specgloss, 2, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D specgloss;
#define NORMALMAP
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(diffuse, f_coord);
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
// if (tex_color.a < opacity)
// discard;
vec3 fragcolor = ambient;
vec3 normal;
normal.xy = (texture(normalmap, f_coord).rg * 2.0 - 1.0);
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
float reflectivity = param[1].z * texture(normalmap, f_coord).a;
float specularity = texture(specgloss, f_coord).r;
glossiness = texture(specgloss, f_coord).g * abs(param[1].w);
metalic = texture(specgloss, f_coord).b;
fragcolor = apply_lights_sunless(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,13 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
// the rails and the ballast of a track faded into those of the tracks joined at its ends, see trackblend.glsl
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(diffuse1, 1, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D diffuse1;
#pragma texture(diffuse2, 2, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D diffuse2;
#pragma texture(diffuse3, 3, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 3) uniform sampler2D diffuse3;
#include "trackblend.glsl"

View File

@@ -0,0 +1,22 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
// the rails and the ballast of a track of a normal mapped material faded into those of the tracks joined at its ends, see trackblend.glsl
#define TRACKBLEND_NORMALMAP 1
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(diffuse1, 1, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D diffuse1;
#pragma texture(diffuse2, 2, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D diffuse2;
#pragma texture(diffuse3, 3, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 3) uniform sampler2D diffuse3;
#pragma texture(normalmap, 4, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 4) uniform sampler2D normalmap;
#pragma texture(normalmap1, 5, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 5) uniform sampler2D normalmap1;
#pragma texture(normalmap2, 6, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 6) uniform sampler2D normalmap2;
#pragma texture(normalmap3, 7, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 7) uniform sampler2D normalmap3;
#include "trackblend.glsl"

View File

@@ -0,0 +1,25 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
// the rails and the ballast of a track of a parallax material faded into those of the tracks joined at its ends, see trackblend.glsl
#define TRACKBLEND_NORMALMAP 1
#define TRACKBLEND_PARALLAX 1
#pragma param(height_scale, 2, 1, 1, zero)
#pragma param(height_offset, 2, 2, 1, zero)
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(diffuse1, 1, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D diffuse1;
#pragma texture(diffuse2, 2, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D diffuse2;
#pragma texture(diffuse3, 3, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 3) uniform sampler2D diffuse3;
#pragma texture(normalmap, 4, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 4) uniform sampler2D normalmap;
#pragma texture(normalmap1, 5, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 5) uniform sampler2D normalmap1;
#pragma texture(normalmap2, 6, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 6) uniform sampler2D normalmap2;
#pragma texture(normalmap3, 7, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 7) uniform sampler2D normalmap3;
#include "trackblend.glsl"

View File

@@ -0,0 +1,21 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
// the rails and the ballast of a track of a material with normal and specgloss maps faded into those of the tracks joined at its ends, see trackblend.glsl
#define TRACKBLEND_NORMALMAP 1
#define TRACKBLEND_SPECGLOSS 1
#pragma texture(diffuse, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
#pragma texture(diffuse1, 1, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D diffuse1;
#pragma texture(diffuse2, 2, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D diffuse2;
#pragma texture(normalmap, 3, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 3) uniform sampler2D normalmap;
#pragma texture(normalmap1, 4, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 4) uniform sampler2D normalmap1;
#pragma texture(normalmap2, 5, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 5) uniform sampler2D normalmap2;
#pragma texture(specgloss, 6, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 6) uniform sampler2D specgloss;
#include "trackblend.glsl"

View File

@@ -0,0 +1,98 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, one)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma param(wave_strength, 2, 1, 1, one)
#pragma param(wave_speed, 2, 2, 1, one)
#pragma texture(normalmap, 0, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D normalmap;
#pragma texture(dudvmap, 1, RGB)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D dudvmap;
#pragma texture(diffuse, 2, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D diffuse;
//wave distortion variables
float move_factor = 0.0;
#define WATER
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
//wave distortion
move_factor += (param[2].z * time);
move_factor = mod(move_factor, 1.0);
vec2 texture_coords = f_coord;
vec2 distorted_tex_coord = texture(dudvmap, vec2(texture_coords.x + move_factor, texture_coords.y)).rg * 0.1;
distorted_tex_coord = texture_coords + vec2(distorted_tex_coord.x , distorted_tex_coord.y + move_factor);
vec2 total_distorted_tex_coord = (texture(dudvmap, distorted_tex_coord).rg * 2.0 - 1.0 ) * param[2].y;
texture_coords += total_distorted_tex_coord;
vec4 tex_color = texture(diffuse, texture_coords);
vec3 fragcolor = ambient * 0.25;
vec3 normal;
normal.xy = (texture(normalmap, texture_coords).rg * 2.0 - 1.0);
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
float reflectivity = param[1].z * texture(normalmap, texture_coords ).a;
// water reflects 2% at normal incidence
float specularity = 0.25;
glossiness = abs(param[1].w);
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
//fragcolor = mix(fragcolor, param[0].rgb, param[1].z);
// fragcolor = (fragcolor * tex_color.rgb * param[1].z) + (fragcolor * (1.0 - param[1].z)); //multiply
//fragcolor = ( max(fragcolor + param[0].rgb -1.0,0.0) * param[1].z + fragcolor * (1.0 - param[1].z)); //linear burn
//fragcolor = ( min(param[0].rgb,fragcolor) * param[1].z + fragcolor * (1.0 - param[1].z)); //darken
// fresnel effect
vec3 view_dir = normalize(vec3(0.0f, 0.0f, 0.0f) - f_pos.xyz);
float fresnel = pow(max(dot(normalize(f_normal), view_dir), 0.0), 0.2);
float fresnel_inv = ((fresnel - 1.0 ) * -1.0 );
vec4 color = vec4(apply_fog(fragcolor), clamp((fresnel_inv + param[0].a), 0.0, 1.0));
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,103 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 8) in mat3 f_tbn;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, one)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma param(wave_strength, 2, 1, 1, one)
#pragma param(wave_speed, 2, 2, 1, one)
#pragma texture(normalmap, 0, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D normalmap;
#pragma texture(dudvmap, 1, RGB)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 1) uniform sampler2D dudvmap;
#pragma texture(diffuse, 2, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 2) uniform sampler2D diffuse;
#pragma texture(specgloss, 3, RGBA)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 3) uniform sampler2D specgloss;
//wave distortion variables
float move_factor = 0.0;
#define WATER
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
void main()
{
//wave distortion
move_factor += (param[2].z * time);
move_factor = mod(move_factor, 1.0);
vec2 texture_coords = f_coord;
vec2 distorted_tex_coord = texture(dudvmap, vec2(texture_coords.x + move_factor, texture_coords.y)).rg * 0.1;
distorted_tex_coord = texture_coords + vec2(distorted_tex_coord.x , distorted_tex_coord.y + move_factor);
vec2 total_distorted_tex_coord = (texture(dudvmap, distorted_tex_coord).rg * 2.0 - 1.0 ) * param[2].y;
texture_coords += total_distorted_tex_coord;
vec4 tex_color = texture(diffuse, texture_coords);
vec3 fragcolor = ambient * 0.25;
vec3 normal;
normal.xy = (texture(normalmap, texture_coords).rg * 2.0 - 1.0);
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
float reflectivity = param[1].z * texture(normalmap, texture_coords ).a;
vec4 specgloss_map = texture(specgloss, texture_coords);
float specularity = specgloss_map.r;
glossiness = specgloss_map.g * abs(param[1].w);
metalic = specgloss_map.b;
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
//fragcolor = mix(fragcolor, param[0].rgb, param[1].z);
// fragcolor = (fragcolor * tex_color.rgb * param[1].z) + (fragcolor * (1.0 - param[1].z)); //multiply
//fragcolor = ( max(fragcolor + param[0].rgb -1.0,0.0) * param[1].z + fragcolor * (1.0 - param[1].z)); //linear burn
//fragcolor = ( min(param[0].rgb,fragcolor) * param[1].z + fragcolor * (1.0 - param[1].z)); //darken
// fresnel effect
vec3 view_dir = normalize(vec3(0.0f, 0.0f, 0.0f) - f_pos.xyz);
float fresnel = pow(max(dot(normalize(f_normal), view_dir), 0.0), 0.2);
float fresnel_inv = ((fresnel - 1.0 ) * -1.0 );
vec4 color = vec4(apply_fog(fragcolor), clamp((fresnel_inv + param[0].a), 0.0, 1.0));
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

10
shaders/vk14/pick.frag Normal file
View File

@@ -0,0 +1,10 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) out vec4 out_color;
void main()
{
out_color = vec4(param[0].rgb, 1.0);
}

View File

@@ -0,0 +1,11 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 0) out vec4 out_color;
layout(location = 2) in vec2 f_coord;
void main()
{
out_color = vec4(param[0].r, f_coord, 1.0);
}

View File

@@ -0,0 +1,64 @@
#version 460 core
#define STAGE_FRAGMENT 1
#define LAYOUT_POST 1
#include "common.glsl"
layout(location = 14) in vec2 f_coords;
layout(location = 0) out vec4 out_color;
#pragma texture(color_tex, 0, RGB)
layout(set = POST_SET, binding = POST_TEXTURE_FIRST + 0) uniform sampler2D iChannel0;
#include "dither.glsl"
vec2 barrelDistortion(vec2 f_coords, float amt) {
vec2 cc = f_coords - 0.5;
float dist = dot(cc, cc);
return f_coords + cc * dist * amt;
}
float sat( float t )
{
return clamp( t, 0.0, 1.0 );
}
float linterp( float t ) {
return sat( 1.0 - abs( 1.0*t - 1.0 ) );
}
float remap( float t, float a, float b ) {
return sat( (t - a) / (b - a) );
}
vec4 spectrum_offset( float t ) {
vec4 ret;
float lo = step(t,0.5);
float hi = 1.0-lo;
float w = linterp( remap( t, 1.0/6.0, 5.0/6.0 ) );
ret = vec4(lo,1.0,hi, 1.) * vec4(1.0-w, w, 1.0-w, 1.);
return pow( ret, vec4(1.0/2.2) );
}
const float max_distort = 0.05;
const int num_iter = 10;
const float reci_num_iter_f = 1.0 / float(num_iter);
void main()
{
vec2 uv=f_coords.xy;
vec4 sumcol = vec4(0.0);
vec4 sumw = vec4(0.0);
for ( int i=0; i<num_iter;++i )
{
float t = float(i) * reci_num_iter_f;
vec4 w = spectrum_offset( t );
sumw += w;
sumcol += w * texture( iChannel0, barrelDistortion(uv, .6 * max_distort*t ) );
}
out_color = sumcol / sumw;
out_color.rgb = dither_output(out_color.rgb);
}

View File

@@ -0,0 +1,46 @@
#version 460 core
#define STAGE_FRAGMENT 1
#define LAYOUT_POST 1
#include "common.glsl"
// param is pc.data of the push constants (the model block in the opengl renderer): param[0].x the scale of the velocities
layout(location = 14) in vec2 f_coords;
layout(location = 0) out vec4 out_color;
#pragma texture(color_tex, 0, RGB)
layout(set = POST_SET, binding = POST_TEXTURE_FIRST + 0) uniform sampler2D color_tex;
#pragma texture(velocity_tex, 1, RG)
layout(set = POST_SET, binding = POST_TEXTURE_FIRST + 1) uniform sampler2D velocity_tex;
#pragma texture(depth_tex, 2, R)
layout(set = POST_SET, binding = POST_TEXTURE_FIRST + 2) uniform sampler2D depth_tex;
void main()
{
float ori_depth = texture(depth_tex, f_coords).x;
vec2 texelSize = 1.0 / vec2(textureSize(color_tex, 0));
vec2 velocity = texture(velocity_tex, f_coords).xy * param[0].x;
float speed = length(velocity / texelSize);
int nSamples = clamp(int(speed), 1, 32);
float depth_diff = 0.001 * 8.0;
vec4 result = vec4(0.0);
result += vec4(texture(color_tex, f_coords).rgb, 1.0);
for (int i = 1; i < nSamples; ++i)
{
vec2 offset = velocity * (float(i) / float(nSamples - 1) - 0.5);
vec2 coord = f_coords + offset;
float depth = texture(depth_tex, coord).x;
if (abs(depth - ori_depth) < depth_diff)
result += vec4(texture(color_tex, coord).rgb, 1.0);
}
out_color = vec4((result.rgb / result.w), 1.0);
}

View File

@@ -0,0 +1,78 @@
#version 460 core
#define STAGE_FRAGMENT 1
#define LAYOUT_POST 1
#include "common.glsl"
// the projection of the view (projection of the scene block in the opengl renderer) is pc.data[0..3] of the push constants,
// its columns
#define projection mat4(pc.data[0], pc.data[1], pc.data[2], pc.data[3])
layout(location = 14) in vec2 f_coords;
layout(location = 0) out vec4 out_color;
#pragma texture(depth_tex, 0, R)
layout(set = POST_SET, binding = POST_TEXTURE_FIRST + 0) uniform sampler2D depth_tex;
#pragma texture(noise_tex, 1, RGB)
layout(set = POST_SET, binding = POST_TEXTURE_FIRST + 1) uniform sampler2D noise_tex;
// the depth is reversed (0..1, 1 at the near plane, 0 at infinity), so it is the clip z itself
vec3 view_pos_from_depth(vec2 uv, float depth) {
vec4 clip = vec4(uv * 2.0 - 1.0, depth, 1.0);
vec4 view = inverse(projection) * clip;
return view.xyz / view.w;
}
// Deterministic hemisphere sample (z > 0), mimics the C++ kernel generator
vec3 kernel_sample(int i) {
float fi = float(i);
vec3 dir = normalize(vec3(
fract(sin(fi * 12.9898) * 43758.5453) * 2.0 - 1.0,
fract(sin(fi * 78.2330) * 43758.5453) * 2.0 - 1.0,
fract(sin(fi * 37.7190) * 43758.5453) // z >= 0 -> hemisphere
));
float len = fract(sin(fi * 94.6720) * 43758.5453);
float scale = fi / 32.0;
scale = mix(0.1, 1.0, scale * scale); // bias samples inward
return dir * len * scale;
}
void main() {
float d = texture(depth_tex, f_coords).r;
if (d <= 0.0) { out_color = vec4(1.0); return; } // skybox -> no occlusion
vec3 pos = view_pos_from_depth(f_coords, d);
vec3 ddx = dFdx(pos);
vec3 ddy = dFdy(pos);
vec3 n = normalize(cross(ddx, ddy));
// derive screen size from the depth texture instead of a UBO field
vec2 screen_size = vec2(textureSize(depth_tex, 0));
vec2 noise_uv = f_coords * (screen_size / 4.0);
vec3 rvec = texture(noise_tex, noise_uv).xyz;
vec3 t = normalize(rvec - n * dot(rvec, n));
vec3 b = cross(n, t);
mat3 TBN = mat3(t, b, n);
const int KERNEL = 32;
const float RADIUS = 0.5;
const float BIAS = 0.025;
float occ = 0.0;
for (int i = 0; i < KERNEL; ++i) {
vec3 sp = TBN * kernel_sample(i);
sp = pos + sp * RADIUS;
vec4 clip = projection * vec4(sp, 1.0);
vec3 ndc = clip.xyz / clip.w;
vec2 suv = ndc.xy * 0.5 + 0.5;
float sd = texture(depth_tex, suv).r;
float szv = view_pos_from_depth(suv, sd).z;
float range = smoothstep(0.0, 1.0, RADIUS / abs(pos.z - szv));
occ += (szv >= sp.z + BIAS ? 1.0 : 0.0) * range;
}
out_color = vec4(1.0 - occ / float(KERNEL));
}

View File

@@ -0,0 +1,99 @@
#version 460 core
#define STAGE_FRAGMENT 1
#define LAYOUT_POST 1
#include "common.glsl"
// applies the ambient occlusion of the half size target to the image at full size, as a multiplier: drawn with the
// blending dst * src over the image (opengl46_ao::apply). the four nearest pixels of the occlusion are weighed by how
// close they are and by how close their distance is to that of the pixel, so the occlusion does not spill over the
// edges of objects. each pixel of the occlusion stands for the top left one of the four full size pixels it covers
// params.x: 0 ground truth ambient occlusion, 1 the older ssao (its own fixed curve)
// params.y: strength, a power of the occlusion (1 = as computed); params.z: albedo assumed by the multiple bounce term.
// the fog in front of a surface hides its occlusion as it hides the surface: the analytic fog of apply_fog.glsl, the fog
// volume comes with the stage P2.
// the parameters are in the push constants (loose uniforms in the opengl renderer): pc.data[0..3] the columns of the inverse
// of the projection (inv_projection), pc.data[4] params, pc.data[5].x the density of the fog of the scene (fog_density of the
// regular draws, 0: no fog), pc.data[5].yzw unused
layout(location = 14) in vec2 f_coords;
layout(location = 0) out vec4 out_color;
layout(set = POST_SET, binding = POST_TEXTURE_FIRST + 0) uniform sampler2D depth_tex;
layout(set = POST_SET, binding = POST_TEXTURE_FIRST + 1) uniform sampler2D ao_tex;
#define inv_projection mat4(pc.data[0], pc.data[1], pc.data[2], pc.data[3])
#define params pc.data[4]
#define scene_fog_density pc.data[5].x
vec3 view_position(ivec2 pixel, float depth)
{
ivec2 full_size = textureSize(depth_tex, 0);
vec2 uv = (vec2(pixel) + 0.5) / vec2(full_size);
vec4 position = inv_projection * vec4(uv * 2.0 - 1.0, depth, 1.0);
return position.xyz / position.w;
}
float view_distance(ivec2 pixel, float depth)
{
return length(view_position(pixel, depth));
}
// light which comes back after more than one bounce off surfaces of the given albedo, fit of Jimenez et al. 2016
float multi_bounce(float visibility, float albedo)
{
float a = 2.0404 * albedo - 0.3324;
float b = -4.7951 * albedo + 0.6417;
float c = 2.7552 * albedo + 0.6903;
return max(visibility, ((visibility * a + b) * visibility + c) * visibility);
}
void main()
{
ivec2 full_size = textureSize(depth_tex, 0);
ivec2 half_size = textureSize(ao_tex, 0);
ivec2 pixel = ivec2(gl_FragCoord.xy);
float depth = texelFetch(depth_tex, pixel, 0).r;
if (depth <= 0.0)
{
// the sky
out_color = vec4(1.0);
return;
}
float distance = view_distance(pixel, depth);
vec2 position = vec2(pixel) * 0.5;
ivec2 base = ivec2(floor(position));
vec2 fraction = position - vec2(base);
float sum = 0.0;
float weights = 0.0;
for (int y = 0; y < 2; ++y)
{
for (int x = 0; x < 2; ++x)
{
ivec2 texel = clamp(base + ivec2(x, y), ivec2(0), half_size - 1);
ivec2 texelpixel = min(texel * 2, full_size - 1);
float texeldepth = texelFetch(depth_tex, texelpixel, 0).r;
float texeldistance = (texeldepth > 0.0) ? view_distance(texelpixel, texeldepth) : 1e30;
float bilinear = (x == 0 ? 1.0 - fraction.x : fraction.x) * (y == 0 ? 1.0 - fraction.y : fraction.y);
float weight = (bilinear + 1e-3) / (1e-3 + abs(texeldistance - distance) / distance);
sum += texelFetch(ao_tex, texel, 0).r * weight;
weights += weight;
}
}
float ao = clamp(sum / max(weights, 1e-6), 0.0, 1.0);
if (params.x > 0.5)
{
// the curve the older ssao was applied with, a floor so the shadows do not go black
ao = mix(0.3, 1.0, pow(ao, 0.8));
}
else
{
ao = pow(ao, params.y);
ao = multi_bounce(ao, params.z);
}
// what the fog lets through of the surface is what is left to occlude
float transmittance = (scene_fog_density > 0.0) ? clamp(exp(-distance * scene_fog_density), 0.0, 1.0) : 1.0;
ao = mix(1.0, ao, transmittance);
out_color = vec4(vec3(ao), 1.0);
}

View File

@@ -0,0 +1,18 @@
#version 460 core
#define STAGE_FRAGMENT 1
#define LAYOUT_POST 1
#include "common.glsl"
layout(location = 14) in vec2 f_coords;
layout(location = 0) out vec4 out_color;
#pragma texture(ssao_tex, 0, R)
layout(set = POST_SET, binding = POST_TEXTURE_FIRST + 0) uniform sampler2D ssao_tex;
void main() {
vec2 texel = 1.0 / vec2(textureSize(ssao_tex, 0));
float sum = 0.0;
for (int x = -2; x < 2; ++x)
for (int y = -2; y < 2; ++y)
sum += texture(ssao_tex, f_coords + vec2(x, y) * texel).r;
out_color = vec4(sum / 16.0);
}

View File

@@ -0,0 +1,40 @@
#version 460 core
#define STAGE_FRAGMENT 1
#define LAYOUT_POST 1
#include "common.glsl"
layout(location = 14) in vec2 f_coords;
layout(location = 0) out vec4 out_color;
#pragma texture(tex1, 0, RGB)
layout(set = POST_SET, binding = POST_TEXTURE_FIRST + 0) uniform sampler2D tex1;
// glow of the bright parts of the image (postfx_bloom_*.frag)
#pragma texture(bloom_tex, 1, RGB)
layout(set = POST_SET, binding = POST_TEXTURE_FIRST + 1) uniform sampler2D bloom_tex;
// the automatic exposure (exposure_ssbo of the opengl renderer, exposure_average.comp) comes in a later stage: the fixed
// exposure multiplier alone
const float exposure = 0.0;
#include "tonemapping.glsl"
#include "dither.glsl"
// param is pc.data of the push constants (the model block in the opengl renderer).
// param[0].x: share of the bloom in the image (0: no bloom, the texture is not read), param[0].y: 1 if the automatic
// exposure is applied (there is none yet, so it has no effect), param[0].z: fixed exposure multiplier, param[0].w: scale of
// the bloom texture (it holds the sum of the levels of the chain), param[1].x: 1 when this is the last pass before the
// window, which takes the dither
void main()
{
vec2 texcoord = f_coords;
vec3 hdr_color = texture(tex1, texcoord).xyz;
if (param[0].x > 0.0)
hdr_color = mix(hdr_color, texture(bloom_tex, texcoord).rgb * param[0].w, param[0].x);
float exposurescale = param[0].z;
if (param[0].y > 0.5 && exposure > 0.0)
exposurescale *= exposure;
out_color = tonemap(vec4(hdr_color * exposurescale, 1.0));
if (param[1].x > 0.5)
out_color.rgb = dither_output(out_color.rgb);
}

View File

@@ -0,0 +1,42 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 2) in vec2 f_coord;
#pragma texture(tex1, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D tex1;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
#include "tonemapping.glsl"
void main()
{
vec4 tex_color = texture(tex1, vec2(f_coord.x, f_coord.y + param[1].x));
vec4 color = tex_color * param[0];
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;
out_motion = vec4(a - b, 0.0f, tex_color.a * alpha_mult);
}
}

View File

@@ -0,0 +1,20 @@
#version 460 core
#define STAGE_VERTEX 1
#include "common.glsl"
layout(location = 0) in vec3 v_vert;
layout(location = 1) in vec2 v_coord;
layout(location = 2) out vec2 f_coord;
layout(location = 4) out vec4 f_clip_pos;
layout(location = 5) out vec4 f_clip_future_pos;
void main()
{
f_clip_pos = (projection * modelview) * vec4(v_vert, 1.0f);
f_clip_future_pos = (projection * future * modelview) * vec4(v_vert, 1.0f);
gl_Position = f_clip_pos;
f_coord = v_coord;
}

17
shaders/vk14/present.frag Normal file
View File

@@ -0,0 +1,17 @@
#version 460 core
#define STAGE_FRAGMENT 1
#define LAYOUT_POST 1
#include "common.glsl"
// the finished image to the window (with quad.vert). the renderer draws with the matrices of the opengl one, so its images
// have the rows in the memory order of opengl, the bottom of the picture first; the window shows the first row at the top.
// this is the only place the picture is turned upside down. no push constants
layout(location = 14) in vec2 f_coords;
layout(set = POST_SET, binding = POST_TEXTURE_FIRST + 0) uniform sampler2D tex1;
layout(location = 0) out vec4 out_color;
void main()
{
out_color = FBOUT(texture(tex1, vec2(f_coords.x, 1.0 - f_coords.y)));
}

27
shaders/vk14/quad.vert Normal file
View File

@@ -0,0 +1,27 @@
#version 460 core
#define STAGE_VERTEX 1
#define LAYOUT_POST 1
#include "common.glsl"
const vec2 vert[4] = vec2[]
(
vec2(-1.0, 1.0),
vec2(-1.0, -1.0),
vec2( 1.0, 1.0),
vec2( 1.0, -1.0)
);
const vec2 uv[4] = vec2[]
(
vec2(0.0, 1.0),
vec2(0.0, 0.0),
vec2(1.0, 1.0),
vec2(1.0, 0.0)
);
layout(location = 14) out vec2 f_coords;
void main()
{
gl_Position = vec4(vert[gl_VertexIndex], 0.0, 1.0);
f_coords = uv[gl_VertexIndex];
}

39
shaders/vk14/random.glsl Normal file
View File

@@ -0,0 +1,39 @@
uint Hash(uint s);
uint Hash(uvec2 s);
uint Hash(uvec3 s);
uint Hash(float s);
uint HashCombine(uint seed, uint value);
// Evolving Sub-Grid Turbulence for Smoke Animation
// H. Schechter and R. Bridson
uint Hash(uint s) {
s ^= 2747636419u;
s *= 2654435769u;
s ^= s >> 16u;
s *= 2654435769u;
s ^= s >> 16u;
s *= 2654435769u;
return s;
}
uint Hash(uvec2 s) {
return HashCombine(Hash(s.x), s.y);
}
uint Hash(uvec3 s) {
return HashCombine(Hash(s.xy), s.z);
}
uint HashCombine(uint seed, uint value) {
return seed ^ (Hash(value) + 0x9e3779b9u + (seed<<6u) + (seed>>2u));
}
uint Rand(inout uint seed) {
seed = Hash(seed);
return seed;
}
float RandF(inout uint seed) {
return float(Rand(seed)) * 2.3283064365386963e-10;
}

View File

@@ -0,0 +1,25 @@
// the settings of the game the shaders depend on (gfx.* in eu07.ini): specialization constants the renderer sets when it makes a
// pipeline, the ids are the SPEC_* of rendering/vulkan14/vulkan14bindings.h. included by common.glsl after the constants
#ifndef SETTINGS_GLSL
#define SETTINGS_GLSL
#ifndef SPEC_OUTPUT_GAMMA
#error "settings.glsl takes the ids of the specialization constants from common.glsl: include common.glsl instead"
#endif
layout(constant_id = SPEC_SHADOWMAP_ENABLED) const bool SHADOWMAP_ENABLED = true;
layout(constant_id = SPEC_ENVMAP_ENABLED) const bool ENVMAP_ENABLED = true;
layout(constant_id = SPEC_MOTIONBLUR_ENABLED) const bool MOTIONBLUR_ENABLED = true;
// the colour goes on to the post-processing; tonemapped by the shaders of the scene otherwise
layout(constant_id = SPEC_POSTFX_ENABLED) const bool POSTFX_ENABLED = true;
layout(constant_id = SPEC_EXTRAEFFECTS_ENABLED) const bool EXTRAEFFECTS_ENABLED = true;
// whether the colour written to the window is encoded by the shader (FBOUT): the window has no srgb format (gfx.shadergamma yes)
layout(constant_id = SPEC_OUTPUT_GAMMA) const bool OUTPUT_GAMMA = false;
// the colour written to the window
vec4 FBOUT(vec4 x)
{
return (OUTPUT_GAMMA ? vec4(pow(x.rgb, vec3(1.0 / 2.2)), x.a) : x);
}
#endif

View File

@@ -0,0 +1,8 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 2) in vec2 f_coord;
void main()
{
}

View File

@@ -0,0 +1,14 @@
#version 460 core
#define STAGE_VERTEX 1
#include "common.glsl"
layout(location = 0) in vec3 v_vert;
layout(location = 2) in vec2 v_coord;
layout(location = 2) out vec2 f_coord;
void main()
{
gl_Position = (projection * effective_modelview()) * vec4(v_vert, 1.0f);
f_coord = v_coord;
}

View File

@@ -0,0 +1,16 @@
// the skydome vertex colours carry Perez luminance scaled by a fixed exposure
// (see CSkyDome::SetExposure), so the circumsolar region and the horizon band
// routinely land well above 1.0. hard-clipping them, as this shader used to do,
// flattened everything within ~20 degrees of the sun - and most of the lower sky -
// into one solid white patch. compress the top end instead: below the knee the
// response is unchanged, above it it rolls off towards SKY_SHOULDER_WHITE, so the
// brightness gradient around the sun survives and the patch keeps a soft edge.
const float SKY_SHOULDER_KNEE = 0.25;
const float SKY_SHOULDER_WHITE = 0.95;
vec3 sky_shoulder(vec3 color)
{
const float range = SKY_SHOULDER_WHITE - SKY_SHOULDER_KNEE;
vec3 excess = max(color - vec3(SKY_SHOULDER_KNEE), vec3(0.0));
return min(color, vec3(SKY_SHOULDER_KNEE)) + range * (vec3(1.0) - exp(-excess / range));
}

43
shaders/vk14/smoke.frag Normal file
View File

@@ -0,0 +1,43 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 13) in vec4 f_color;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
#pragma texture(tex1, 0, sRGB_A)
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D tex1;
#include "apply_fog.glsl"
#include "tonemapping.glsl"
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
void main()
{
vec4 tex_color = texture(tex1, f_coord) * f_color;
if (POSTFX_ENABLED)
{
out_color = vec4(apply_fog(tex_color.rgb), tex_color.a);
}
else
{
out_color = tonemap(vec4(apply_fog(tex_color.rgb), tex_color.a));
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, tex_color.a * alpha_mult);
}
}

25
shaders/vk14/smoke.vert Normal file
View File

@@ -0,0 +1,25 @@
#version 460 core
#define STAGE_VERTEX 1
#include "common.glsl"
layout(location = 0) in vec3 v_vert;
layout(location = 1) in vec4 v_color;
layout(location = 2) in vec2 v_coord;
layout(location = 3) out vec4 f_pos;
layout(location = 13) out vec4 f_color;
layout(location = 2) out vec2 f_coord;
layout(location = 4) out vec4 f_clip_pos;
layout(location = 5) out vec4 f_clip_future_pos;
void main()
{
f_pos = modelview * vec4(v_vert, 1.0f);
f_clip_pos = (projection * modelview) * vec4(v_vert, 1.0f);
f_clip_future_pos = (projection * future * modelview) * vec4(v_vert, 1.0f);
gl_Position = f_clip_pos;
f_coord = v_coord;
f_color = v_color;
}

View File

@@ -0,0 +1,154 @@
#include "common.glsl"
const float pureWhite = 1.0;
vec3 reinhard(vec3 x)
{
// return x / (x + vec3(1.0));
// Reinhard tonemapping operator.
// see: "Photographic Tone Reproduction for Digital Images", eq. 4
float luminance = dot(x, vec3(0.2126, 0.7152, 0.0722));
float mappedLuminance = (luminance * (1.0 + luminance/(pureWhite*pureWhite))) / (1.0 + luminance);
// Scale color by ratio of average luminances.
return (mappedLuminance / luminance) * x;
}
// https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
vec3 ACESFilm(vec3 x)
{
float a = 2.51f;
float b = 0.03f;
float c = 2.43f;
float d = 0.59f;
float e = 0.14f;
return (x*(a*x+b))/(x*(c*x+d)+e);
}
// https://www.slideshare.net/ozlael/hable-john-uncharted2-hdr-lighting
vec3 filmicF(vec3 x)
{
float A = 0.22f;
float B = 0.30f;
float C = 0.10f;
float D = 0.20f;
float E = 0.01f;
float F = 0.30f;
return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F)) - E/F;
}
vec3 filmic(vec3 x)
{
return filmicF(x) / filmicF(vec3(11.2f));
}
// AgX tonemapping based on nxrighthere / Missing Deadlines implementation.
// 0: Default, 1: Golden, 2: Punchy
#ifndef AGX_LOOK
#define AGX_LOOK 0
#endif
vec3 AgxDefaultContrastApprox(vec3 x)
{
vec3 x2 = x * x;
vec3 x4 = x2 * x2;
return 15.5 * x4 * x2
- 40.14 * x4 * x
+ 31.96 * x4
- 6.868 * x2 * x
+ 0.4298 * x2
+ 0.1191 * x
- 0.00232;
}
vec3 Agx(vec3 val)
{
mat3 agx_mat = mat3(
0.842479062253094, 0.0784335999999992, 0.0792237451477643,
0.0423282422610123, 0.878468636469772, 0.0791661274605434,
0.0423756549057051, 0.0784336, 0.879142973793104
);
// DEFAULT_LOG2_MIN = -6.0
// DEFAULT_LOG2_MAX = +4.5
// MIDDLE_GRAY = 0.18
// log2(pow(2, VALUE) * MIDDLE_GRAY)
const float min_ev = -8.47393;
const float max_ev = 2.026069;
const float agx_eps = 1e-6;
// Input transform (inset)
val = agx_mat * val;
// Log2 space encoding. max() avoids -INF/NaN for zero/negative inputs.
val = clamp(log2(max(val, vec3(agx_eps))), min_ev, max_ev);
val = (val - min_ev) / (max_ev - min_ev);
// Apply sigmoid function approximation.
return AgxDefaultContrastApprox(val);
}
vec3 AgxEotf(vec3 val)
{
mat3 agx_mat_inv = mat3(
1.19687900512017, -0.0980208811401368, -0.0990297440797205,
-0.0528968517574562, 1.15190312990417, -0.0989611768448433,
-0.0529716355144438, -0.0980434501171241, 1.15107367264116
);
// Inverse input transform (outset)
val = agx_mat_inv * val;
return max(val, vec3(0.0));
}
vec3 AgxLook(vec3 val)
{
vec3 lw = vec3(0.2126, 0.7152, 0.0722);
float luma = dot(val, lw);
vec3 offset = vec3(0.0);
vec3 slope = vec3(1.0);
vec3 power = vec3(1.6);
float sat = 0.9;
#if AGX_LOOK == 1
// Golden
slope = vec3(1.0, 0.9, 0.5);
power = vec3(0.8);
sat = 0.8;
#elif AGX_LOOK == 2
// Punchy
slope = vec3(1.0);
power = vec3(1.35);
sat = 1.1;
#endif
// ASC CDL
val = pow(max(val * slope + offset, vec3(0.0)), power);
return vec3(luma) + sat * (val - vec3(luma));
}
vec3 ApplyAgX(vec3 linearColorRec709)
{
linearColorRec709 = Agx(linearColorRec709);
linearColorRec709 = AgxLook(linearColorRec709);
linearColorRec709 = AgxEotf(linearColorRec709);
return linearColorRec709;
}
vec4 tonemap(vec4 x)
{
// Use AgX by default. Reinhard and ACES above are kept for reference.
// Last-line-of-defense sanitize so NaN/Inf/negative HDR values do not
// escape into log2()/pow() and produce black flashes or invalid output.
vec3 hdr = x.rgb;
hdr = mix(hdr, vec3(0.0), vec3(any(isnan(hdr)) || any(isinf(hdr))));
hdr = max(hdr, vec3(0.0));
return FBOUT(vec4(ApplyAgX(hdr), x.a));
//return FBOUT(vec4(ACESFilm(hdr), x.a));
//return FBOUT(vec4(reinhard(x.rgb), x.a));
}

View File

@@ -0,0 +1,205 @@
// a track drawn with the textures of the tracks joined at its ends blended in near them (world/TrackBlend.h): the weights of the
// tracks joined at the ends p1, p2 and p4 of a switch in UserData.yzw, their textures in diffuse1..3, normalmap1..3, faded into
// the texture of the track. the including shader declares the textures and sets:
// TRACKBLEND_NORMALMAP with the normal maps of the four, lit as the shader of the material of the track: param[2].x 0 as
// mat_default, 1 normalmap, 2 sunlessnormalmap, 3 shadowlessnormalmap
// TRACKBLEND_SPECGLOSS the specgloss map of the track itself as well, the textures of the ends p1 and p2 alone (no room
// for a third set of them)
// TRACKBLEND_PARALLAX with the normal maps, as mat_parallax: each texture shifted by the heights in its own normal map
layout(location = 0) in vec3 f_normal;
layout(location = 2) in vec2 f_coord;
layout(location = 3) in vec4 f_pos;
#ifdef TRACKBLEND_NORMALMAP
layout(location = 8) in mat3 f_tbn;
#endif
#ifdef TRACKBLEND_PARALLAX
layout(location = 6) in vec3 TangentFragPos;
#endif
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
#include "common.glsl"
#pragma param(color, 0, 0, 4, diffuse)
#pragma param(diffuse, 1, 0, 1, diffuse)
#pragma param(specular, 1, 1, 1, specular)
#pragma param(reflection, 1, 2, 1, zero)
#pragma param(glossiness, 1, 3, 1, glossiness)
#pragma param(blendlighting, 2, 0, 1, zero)
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#include "light_common.glsl"
#include "apply_fog.glsl"
#include "tonemapping.glsl"
#ifdef TRACKBLEND_PARALLAX
// the texture coordinates shifted by the heights (b) of the normal map, as ParallaxMapping() of mat_parallax.frag
vec2 parallax_coord(sampler2D heights, vec2 coord, vec3 viewdir, vec2 dcoorddx, vec2 dcoorddy)
{
float pos_len = length(f_pos.xyz);
if (pos_len > 100.0)
return coord;
float fade = 1.0 - smoothstep(80.0, 100.0, pos_len);
if (EXTRAEFFECTS_ENABLED)
{
const float minLayers = 8.0;
const float maxLayers = 32.0;
float LayersWeight = pos_len / 20.0;
vec2 currentTexCoords = coord;
float currentDepthMapValue = textureGrad(heights, currentTexCoords, dcoorddx, dcoorddy).b;
LayersWeight = min(abs(dot(vec3(0.0, 0.0, 1.0), viewdir)), LayersWeight);
float numLayers = mix(maxLayers, minLayers, clamp(LayersWeight, 0.0, 1.0));
float layerDepth = 1.0 / numLayers;
float currentLayerDepth = 0.0;
vec2 P = viewdir.xy * param[2].y * fade;
vec2 deltaTexCoords = P / numLayers;
while (currentLayerDepth < currentDepthMapValue)
{
currentTexCoords -= deltaTexCoords;
currentDepthMapValue = textureGrad(heights, currentTexCoords, dcoorddx, dcoorddy).b;
currentLayerDepth += layerDepth;
}
vec2 prevTexCoords = currentTexCoords + deltaTexCoords;
float afterDepth = currentDepthMapValue - currentLayerDepth;
float beforeDepth = textureGrad(heights, prevTexCoords, dcoorddx, dcoorddy).b - currentLayerDepth + layerDepth;
float weight = afterDepth / (afterDepth - beforeDepth);
return prevTexCoords * weight + currentTexCoords * (1.0 - weight);
}
else
{
float height = textureGrad(heights, coord, dcoorddx, dcoorddy).b;
vec2 p = viewdir.xy / viewdir.z * (height * (param[2].y - param[2].z) * 0.2) * fade;
return coord - p;
}
}
// each texture at the coordinates shifted by the heights of its own normal map
#define TRACKBLEND_COORD(heights) parallax_coord(heights, f_coord, viewdir, dx, dy)
#else
#define TRACKBLEND_COORD(heights) f_coord
#endif
void main()
{
// how far the fragment is into the track from the ends, in the lengths of their blending (track_blend::blending::weigh()):
// from -100 down where the track joined there doesn't blend back and its texture goes all the way to the joint, 10000 where
// nothing's blended at the end
#ifdef TRACKBLEND_SPECGLOSS
vec3 along = vec3(UserData.yz, 10000.0);
#else
vec3 along = UserData.yzw;
#endif
vec3 single = vec3(lessThan(along, vec3(-50.0)));
vec3 fraction = mix(along, -100.0 - along, single);
vec3 weights = mix(vec3(0.5), vec3(1.0), single) * clamp(1.0 - fraction, 0.0, 1.0);
float total = weights.x + weights.y + weights.z;
if (total > 1.0)
{
weights /= total;
total = 1.0;
}
// the gradients are taken outside the branches the textures are sampled in
vec2 dx = dFdx(f_coord);
vec2 dy = dFdy(f_coord);
#ifdef TRACKBLEND_PARALLAX
vec3 viewdir = normalize(vec3(0.0) - TangentFragPos);
#endif
vec2 coord = TRACKBLEND_COORD(normalmap);
vec4 tex_color = textureGrad(diffuse, coord, dx, dy);
#ifdef TRACKBLEND_NORMALMAP
vec4 tex_normal = textureGrad(normalmap, coord, dx, dy);
#endif
if (total > 0.0)
{
vec4 blended = tex_color * (1.0 - total);
#ifdef TRACKBLEND_NORMALMAP
vec4 blendednormal = tex_normal * (1.0 - total);
#endif
if (weights.x > 0.0)
{
vec2 coord1 = TRACKBLEND_COORD(normalmap1);
blended += textureGrad(diffuse1, coord1, dx, dy) * weights.x;
#ifdef TRACKBLEND_NORMALMAP
blendednormal += textureGrad(normalmap1, coord1, dx, dy) * weights.x;
#endif
}
if (weights.y > 0.0)
{
vec2 coord2 = TRACKBLEND_COORD(normalmap2);
blended += textureGrad(diffuse2, coord2, dx, dy) * weights.y;
#ifdef TRACKBLEND_NORMALMAP
blendednormal += textureGrad(normalmap2, coord2, dx, dy) * weights.y;
#endif
}
#ifndef TRACKBLEND_SPECGLOSS
if (weights.z > 0.0)
{
vec2 coord3 = TRACKBLEND_COORD(normalmap3);
blended += textureGrad(diffuse3, coord3, dx, dy) * weights.z;
#ifdef TRACKBLEND_NORMALMAP
blendednormal += textureGrad(normalmap3, coord3, dx, dy) * weights.z;
#endif
}
#endif
tex_color = blended;
#ifdef TRACKBLEND_NORMALMAP
tex_normal = blendednormal;
#endif
}
bool alphatestfail = ( opacity >= 0.0 ? (tex_color.a < opacity) : (tex_color.a >= -opacity) );
if(alphatestfail)
discard;
vec3 fragcolor = ambient;
#ifdef TRACKBLEND_NORMALMAP
vec3 normal;
normal.xy = (tex_normal.rg * 2.0 - 1.0);
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
float reflectivity = param[1].z * tex_normal.a;
#ifdef TRACKBLEND_SPECGLOSS
vec4 tex_specgloss = textureGrad(specgloss, coord, dx, dy);
float specularity = tex_specgloss.r;
glossiness = tex_specgloss.g * abs(param[1].w);
metalic = tex_specgloss.b;
#else
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
legacy_gloss();
#endif
int lighting = int(param[2].x + 0.5);
if (lighting == 2)
fragcolor = apply_lights_sunless(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
else
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, (lighting == 3 ? 1.0 : shadow_tone));
#else
vec3 fragnormal = normalize(f_normal);
matte = true;
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, 0.0, 0.0, shadow_tone);
#endif
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;
out_motion = vec4(a - b, 0.0f, tex_color.a * alpha_mult);
}
}

View File

@@ -0,0 +1,39 @@
#version 460 core
#define STAGE_FRAGMENT 1
#include "common.glsl"
layout(location = 3) in vec4 f_pos;
layout(location = 4) in vec4 f_clip_pos;
layout(location = 5) in vec4 f_clip_future_pos;
layout(location = 0) out vec4 out_color;
#ifdef NO_MOTION_OUTPUT
// a pass without the velocity target: the writes go nowhere
vec4 out_motion;
#else
layout(location = 1) out vec4 out_motion;
#endif
#include "tonemapping.glsl"
#include "apply_fog.glsl"
void main()
{
vec4 color = vec4(apply_fog(pow(param[0].rgb, vec3(2.2))), param[0].a);
if (POSTFX_ENABLED)
{
out_color = color;
}
else
{
out_color = tonemap(color);
}
if (MOTIONBLUR_ENABLED)
{
vec2 a = (f_clip_future_pos.xy / f_clip_future_pos.w) * 0.5 + 0.5;;
vec2 b = (f_clip_pos.xy / f_clip_pos.w) * 0.5 + 0.5;;
out_motion = vec4(a - b, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,20 @@
#version 460 core
#define STAGE_VERTEX 1
#include "common.glsl"
layout(location = 0) in vec3 v_vert;
layout(location = 1) in vec3 v_normal;
layout(location = 2) in vec2 v_coord;
layout(location = 4) out vec4 f_clip_pos;
layout(location = 5) out vec4 f_clip_future_pos;
layout(location = 3) out vec4 f_pos;
void main()
{
f_pos = modelview * vec4(v_vert, 1.0f);
f_clip_pos = (projection * modelview) * vec4(v_vert, 1.0f);
f_clip_future_pos = (projection * future * modelview) * vec4(v_vert, 1.0f);
gl_Position = f_clip_pos;
}

View File

@@ -0,0 +1,19 @@
#version 460 core
#define STAGE_VERTEX 1
#include "common.glsl"
layout(location = 0) in vec3 v_vert;
layout(location = 1) in vec3 v_color;
layout(location = 13) out vec3 f_color;
layout(location = 3) out vec4 f_pos;
layout(location = 4) out vec4 f_clip_pos;
void main()
{
f_pos = modelview * vec4(v_vert, 1.0);
f_clip_pos = (projection * modelview) * vec4(v_vert, 1.0);
f_color = pow(v_color, vec3(1.0));
gl_Position = f_clip_pos;
}

55
shaders/vk14/vertex.vert Normal file
View File

@@ -0,0 +1,55 @@
#version 460 core
#define STAGE_VERTEX 1
#include "common.glsl"
layout(location = 0) in vec3 v_vert;
layout(location = 1) in vec3 v_normal;
layout(location = 2) in vec2 v_coord;
layout(location = 3) in vec4 v_tangent;
layout(location = 4) in vec4 v_userdata;
// the depth prepass (depthprepass.vert) works the position out the same way, and has to get the same depth
invariant gl_Position;
layout(location = 0) out vec3 f_normal;
layout(location = 1) flat out vec3 f_normal_raw;
layout(location = 2) out vec2 f_coord;
layout(location = 3) out vec4 f_pos;
layout(location = 8) out mat3 f_tbn;
layout(location = 4) out vec4 f_clip_pos;
layout(location = 5) out vec4 f_clip_future_pos;
//out vec3 TangentLightPos;
//out vec3 TangentViewPos;
layout(location = 6) out vec3 TangentFragPos;
layout(location = 7) out vec4 UserData;
void main()
{
mat4 mv = effective_modelview();
mat3 mvn = effective_modelviewnormal();
f_normal = normalize(mvn * v_normal);
f_normal_raw = v_normal;
f_coord = v_coord;
f_pos = mv * vec4(v_vert, 1.0);
f_clip_pos = projection * f_pos;
f_clip_future_pos = (projection * future) * f_pos;
gl_Position = f_clip_pos;
gl_PointSize = param[1].x;
vec3 N = f_normal;
vec3 T = mvn * v_tangent.xyz;
T = normalize(T - N * dot(N, T));
// w is -1 where the texture is mirrored (calculate_tangents()), the bitangent turns with it
vec3 B = cross(N, T) * (v_tangent.w < 0.0 ? -1.0 : 1.0);
f_tbn = mat3(T, B, N);
mat3 TBN = transpose(f_tbn);
// TangentLightPos = TBN * f_light_pos.xyz;
// TangentViewPos = TBN * vec3(0.0, 0.0, 0.0);
TangentFragPos = TBN * f_pos.xyz;
UserData = v_userdata;
}

View File

@@ -0,0 +1,10 @@
#version 460 core
#define STAGE_VERTEX 1
#include "common.glsl"
layout(location = 0) in vec3 v_vert;
void main()
{
gl_Position = (projection * effective_modelview()) * vec4(v_vert, 1.0);
}