mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-30 14:20:28 +01:00
Take the ambient occlusion into the lighting and add a probe of the cab
This commit is contained in:
20
shaders/ogl46/cabprobe.frag
Normal file
20
shaders/ogl46/cabprobe.frag
Normal file
@@ -0,0 +1,20 @@
|
||||
#version 460 core
|
||||
#define STAGE_FRAGMENT 1
|
||||
// the probe of the occupied cab (gfx::cab_probe), the materials without the alpha test (cabprobe.glsl)
|
||||
layout(location = 0) in vec3 f_normal;
|
||||
layout(location = 2) in vec2 f_coord;
|
||||
layout(location = 3) in vec4 f_pos;
|
||||
|
||||
#include "common.glsl"
|
||||
|
||||
#pragma texture(diffuse, 0, sRGB_A)
|
||||
layout(binding = 0) uniform sampler2D diffuse;
|
||||
// the cube shadow map of the cab lamp, see gl::LOCAL_SHADOW_TEX
|
||||
layout(binding = LOCAL_SHADOW_TEX) uniform samplerCubeArrayShadow probe_shadowmap;
|
||||
|
||||
#include "cabprobe.glsl"
|
||||
|
||||
void main()
|
||||
{
|
||||
probe_shade(texture(diffuse, f_coord));
|
||||
}
|
||||
52
shaders/ogl46/cabprobe.geom
Normal file
52
shaders/ogl46/cabprobe.geom
Normal file
@@ -0,0 +1,52 @@
|
||||
#version 460 core
|
||||
#define STAGE_GEOMETRY 1
|
||||
// draws the cab into the six faces of its probe at once, one invocation per face (as shadowcube.geom draws the cube shadow maps of
|
||||
// the lamps). the input is in the space of the probe; the faces go in the order of the faces of a cube map (+x, -x, +y, -y, +z,
|
||||
// -z), each looks the way glm::lookAt() with the usual up vectors of cube maps sets it, with a 90 degree projection of infinite
|
||||
// reach and reversed depth like the one of the scene: the depth is near / d, d the distance along the axis of the face
|
||||
layout(triangles, invocations = 6) in;
|
||||
layout(triangle_strip, max_vertices = 3) out;
|
||||
|
||||
layout(location = 20) in vec3 g_pos[];
|
||||
layout(location = 21) in vec3 g_normal[];
|
||||
layout(location = 18) in vec2 g_coord[];
|
||||
layout(location = 0) out vec3 f_normal;
|
||||
layout(location = 2) out vec2 f_coord;
|
||||
layout(location = 3) out vec4 f_pos;
|
||||
|
||||
// near plane of the probe, metres
|
||||
const float PROBE_NEAR = 0.05;
|
||||
|
||||
// right, up and forward axes of the faces
|
||||
const vec3 face_right[6] = vec3[](vec3(0.0, 0.0, -1.0), vec3(0.0, 0.0, 1.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0));
|
||||
const vec3 face_up[6] = vec3[](vec3(0.0, -1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0), vec3(0.0, -1.0, 0.0), vec3(0.0, -1.0, 0.0));
|
||||
const vec3 face_forward[6] = vec3[](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0));
|
||||
|
||||
void main()
|
||||
{
|
||||
int face = gl_InvocationID;
|
||||
vec4 clip[3];
|
||||
for (int i = 0; i < 3; i++)
|
||||
clip[i] = vec4(dot(g_pos[i], face_right[face]), dot(g_pos[i], face_up[face]), PROBE_NEAR, dot(g_pos[i], face_forward[face]));
|
||||
// triangles wholly outside of the face are not sent further
|
||||
if ((clip[0].w < PROBE_NEAR) && (clip[1].w < PROBE_NEAR) && (clip[2].w < PROBE_NEAR))
|
||||
return;
|
||||
if ((clip[0].x > clip[0].w) && (clip[1].x > clip[1].w) && (clip[2].x > clip[2].w))
|
||||
return;
|
||||
if ((clip[0].x < -clip[0].w) && (clip[1].x < -clip[1].w) && (clip[2].x < -clip[2].w))
|
||||
return;
|
||||
if ((clip[0].y > clip[0].w) && (clip[1].y > clip[1].w) && (clip[2].y > clip[2].w))
|
||||
return;
|
||||
if ((clip[0].y < -clip[0].w) && (clip[1].y < -clip[1].w) && (clip[2].y < -clip[2].w))
|
||||
return;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
gl_Layer = face;
|
||||
gl_Position = clip[i];
|
||||
f_normal = g_normal[i];
|
||||
f_coord = g_coord[i];
|
||||
f_pos = vec4(g_pos[i], 1.0);
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
61
shaders/ogl46/cabprobe.glsl
Normal file
61
shaders/ogl46/cabprobe.glsl
Normal file
@@ -0,0 +1,61 @@
|
||||
// the shading of the probe of the occupied cab (gfx::cab_probe), for cabprobe.frag and cabprobe_alpha.frag: what the cab shows
|
||||
// towards the middle of its box lit by the cab lamp alone, with the cube shadow map of the lamp (and what glows in it, the lights
|
||||
// of the desk), and its albedo, each with 1 in the alpha: the probe is cleared to nothing, so the alpha of a direction tells how
|
||||
// much of it the cab fills, and both are premultiplied by it. the light of the cab lamp is the one the shading gives it
|
||||
// (calc_local_light() in light_common.glsl); the ambient light and the sun are left out, the cab gets those as before. the
|
||||
// parameters of the lamp are in the block of the scene (gl::scene_ubs::cab_probe_lamp), in the space of the probe
|
||||
|
||||
layout(location = 0) out vec4 out_light;
|
||||
layout(location = 1) out vec4 out_albedo;
|
||||
|
||||
// closest distance (squared) the light of the lamp is computed for, as LOCAL_LIGHT_MIN_DISTANCE2 of light_common.glsl
|
||||
const float PROBE_LIGHT_MIN_DISTANCE2 = 0.01;
|
||||
|
||||
// the diffuse colour of the submodel or shape, as material_diffuse() of light_common.glsl
|
||||
vec3 probe_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));
|
||||
}
|
||||
|
||||
// share of the light of the cab lamp held back before the point of the space of its cube shadow map (origin at the lamp), 0..1, as
|
||||
// local_light_shadow() of light_common.glsl takes it with a single sample
|
||||
float probe_lamp_shadow(vec3 position, vec3 normal)
|
||||
{
|
||||
vec4 weights = cab_probe_lamp_shadow;
|
||||
float distance = length(position);
|
||||
float texel = weights.z * distance;
|
||||
vec3 tolamp = -position / max(distance, 1e-4);
|
||||
float NdotL = clamp(dot(normal, tolamp), 0.0, 1.0);
|
||||
position += normal * (texel * (0.5 + 1.5 * (1.0 - NdotL)));
|
||||
vec3 axes = abs(position);
|
||||
float major = max(axes.x, max(axes.y, axes.z));
|
||||
float reference = weights.y / max(major - texel * 1.5, weights.y);
|
||||
return texture(probe_shadowmap, vec4(position, weights.x), reference);
|
||||
}
|
||||
|
||||
void probe_shade(vec4 tex_color)
|
||||
{
|
||||
vec3 albedo = tex_color.rgb * probe_material_diffuse();
|
||||
vec3 position = f_pos.xyz;
|
||||
vec3 normal = normalize(f_normal);
|
||||
// the walls are drawn from both sides: the side the probe sees
|
||||
if (dot(normal, position) > 0.0)
|
||||
normal = -normal;
|
||||
vec3 light = vec3(emission);
|
||||
if (cab_probe_lamp.w > 0.0)
|
||||
{
|
||||
vec3 tolight = cab_probe_lamp.xyz - position;
|
||||
float distance2 = dot(tolight, tolight);
|
||||
vec3 light_dir = tolight * inversesqrt(max(distance2, 1e-8));
|
||||
float edge = clamp(1.0 - distance2 * distance2 * (cab_probe_lamp.w * cab_probe_lamp.w), 0.0, 1.0);
|
||||
float atten = edge * edge / max(distance2, PROBE_LIGHT_MIN_DISTANCE2);
|
||||
float NdotL = max(dot(normal, light_dir), 0.0);
|
||||
if ((atten > 0.0) && (NdotL > 0.0) && (cab_probe_lamp_color.a > 0.5))
|
||||
atten *= 1.0 - probe_lamp_shadow(-tolight, normal);
|
||||
light += cab_probe_lamp_color.rgb * (NdotL * atten);
|
||||
}
|
||||
out_light = vec4(albedo * light, 1.0);
|
||||
out_albedo = vec4(albedo, 1.0);
|
||||
}
|
||||
21
shaders/ogl46/cabprobe.vert
Normal file
21
shaders/ogl46/cabprobe.vert
Normal file
@@ -0,0 +1,21 @@
|
||||
#version 460 core
|
||||
#define STAGE_VERTEX 1
|
||||
// the occupied cab drawn into the six faces of its probe at once (gfx::cab_probe, cabprobe.geom picks the faces). the modelview
|
||||
// takes the cab model to the space of the probe: the axes of the model, the origin in the middle of the box of the cab
|
||||
layout(location = 0) in vec3 v_vert;
|
||||
layout(location = 1) in vec3 v_normal;
|
||||
layout(location = 2) in vec2 v_coord;
|
||||
|
||||
layout(location = 20) out vec3 g_pos;
|
||||
layout(location = 21) out vec3 g_normal;
|
||||
layout(location = 18) out vec2 g_coord;
|
||||
|
||||
#include "common.glsl"
|
||||
|
||||
void main()
|
||||
{
|
||||
g_pos = (effective_modelview() * vec4(v_vert, 1.0)).xyz;
|
||||
g_normal = effective_modelviewnormal() * v_normal;
|
||||
g_coord = v_coord;
|
||||
gl_Position = vec4(g_pos, 1.0);
|
||||
}
|
||||
24
shaders/ogl46/cabprobe_alpha.frag
Normal file
24
shaders/ogl46/cabprobe_alpha.frag
Normal file
@@ -0,0 +1,24 @@
|
||||
#version 460 core
|
||||
#define STAGE_FRAGMENT 1
|
||||
// the probe of the occupied cab (gfx::cab_probe), the materials whose colour shader tests the alpha of the diffuse texture against
|
||||
// the opacity of the material, with the test of depthprepass_alpha.frag (cabprobe.glsl)
|
||||
layout(location = 0) in vec3 f_normal;
|
||||
layout(location = 2) in vec2 f_coord;
|
||||
layout(location = 3) in vec4 f_pos;
|
||||
|
||||
#include "common.glsl"
|
||||
|
||||
#pragma texture(diffuse, 0, sRGB_A)
|
||||
layout(binding = 0) uniform sampler2D diffuse;
|
||||
// the cube shadow map of the cab lamp, see gl::LOCAL_SHADOW_TEX
|
||||
layout(binding = LOCAL_SHADOW_TEX) uniform samplerCubeArrayShadow probe_shadowmap;
|
||||
|
||||
#include "cabprobe.glsl"
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 tex_color = texture(diffuse, f_coord);
|
||||
if (tex_color.a < opacity + 1.0 / 255.0)
|
||||
discard;
|
||||
probe_shade(tex_color);
|
||||
}
|
||||
93
shaders/ogl46/cabprobe_sh.comp
Normal file
93
shaders/ogl46/cabprobe_sh.comp
Normal file
@@ -0,0 +1,93 @@
|
||||
#version 460 core
|
||||
#define STAGE_COMPUTE 1
|
||||
// the light the occupied cab lights itself with again, from its probe (gfx::cab_probe), in one work group: the light of its lamps the
|
||||
// cab reflects towards the middle of its box, as spherical harmonics of bands 0..2, convolved with the cosine lobe and divided by
|
||||
// pi, so their value for a direction is the light a white lambertian surface facing it gets, in the units of the ambient light
|
||||
// (light_common.glsl, cab_probe_bounce()). the light is taken from a level of the probe of at most CAB_PROBE_SH_SIZE pixels a
|
||||
// face, each pixel weighed by its solid angle. the basis is the one of the sky (gl::sky_data)
|
||||
|
||||
#include "common.glsl"
|
||||
|
||||
layout(local_size_x = CAB_PROBE_SH_GROUP_SIZE) in;
|
||||
|
||||
layout(binding = 0) uniform samplerCube probe_light;
|
||||
|
||||
layout(std430, binding = CAB_PROBE_SSBO_BINDING) writeonly buffer cab_probe_result_ssbo
|
||||
{
|
||||
vec4 result_sh[9];
|
||||
};
|
||||
|
||||
// x: the level of the probe read, y: its size, pixels
|
||||
layout(location = 0) uniform ivec2 level;
|
||||
|
||||
shared vec3 partial[CAB_PROBE_SH_GROUP_SIZE][9];
|
||||
shared float partialweight[CAB_PROBE_SH_GROUP_SIZE];
|
||||
|
||||
// the direction through the middle of the pixel (s, t) of the face, -1..1 across it, in the order of the faces of a cube map
|
||||
vec3 face_direction(int face, float s, float t)
|
||||
{
|
||||
switch (face)
|
||||
{
|
||||
case 0: return vec3(1.0, -t, -s);
|
||||
case 1: return vec3(-1.0, -t, s);
|
||||
case 2: return vec3(s, 1.0, t);
|
||||
case 3: return vec3(s, -1.0, -t);
|
||||
case 4: return vec3(s, -t, 1.0);
|
||||
default: return vec3(-s, -t, -1.0);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
uint invocation = gl_LocalInvocationID.x;
|
||||
int size = max(level.y, 1);
|
||||
int texels = 6 * size * size;
|
||||
vec3 sum[9];
|
||||
for (int i = 0; i < 9; ++i)
|
||||
sum[i] = vec3(0.0);
|
||||
float weights = 0.0;
|
||||
for (int index = int(invocation); index < texels; index += CAB_PROBE_SH_GROUP_SIZE)
|
||||
{
|
||||
int face = index / (size * size);
|
||||
int texel = index - face * size * size;
|
||||
float s = (float(texel % size) + 0.5) / float(size) * 2.0 - 1.0;
|
||||
float t = (float(texel / size) + 0.5) / float(size) * 2.0 - 1.0;
|
||||
vec3 direction = face_direction(face, s, t);
|
||||
// the solid angle of the pixel
|
||||
float lengthsquared = dot(direction, direction);
|
||||
float weight = 1.0 / (lengthsquared * sqrt(lengthsquared));
|
||||
vec3 n = direction * inversesqrt(lengthsquared);
|
||||
vec3 light = textureLod(probe_light, n, float(level.x)).rgb * weight;
|
||||
sum[0] += light * 0.282095;
|
||||
sum[1] += light * (0.488603 * n.y);
|
||||
sum[2] += light * (0.488603 * n.z);
|
||||
sum[3] += light * (0.488603 * n.x);
|
||||
sum[4] += light * (1.092548 * n.x * n.y);
|
||||
sum[5] += light * (1.092548 * n.y * n.z);
|
||||
sum[6] += light * (0.315392 * (3.0 * n.z * n.z - 1.0));
|
||||
sum[7] += light * (1.092548 * n.x * n.z);
|
||||
sum[8] += light * (0.546274 * (n.x * n.x - n.y * n.y));
|
||||
weights += weight;
|
||||
}
|
||||
for (int i = 0; i < 9; ++i)
|
||||
partial[invocation][i] = sum[i];
|
||||
partialweight[invocation] = weights;
|
||||
barrier();
|
||||
for (uint stride = CAB_PROBE_SH_GROUP_SIZE / 2; stride > 0U; stride /= 2U)
|
||||
{
|
||||
if (invocation < stride)
|
||||
{
|
||||
for (int i = 0; i < 9; ++i)
|
||||
partial[invocation][i] += partial[invocation + stride][i];
|
||||
partialweight[invocation] += partialweight[invocation + stride];
|
||||
}
|
||||
barrier();
|
||||
}
|
||||
if (invocation < 9U)
|
||||
{
|
||||
// the weights add up to the whole sphere, 4 pi; the cosine lobe over pi: 1 for band 0, 2/3 for band 1, 1/4 for band 2
|
||||
float sphere = 12.566371 / max(partialweight[0], 1e-6);
|
||||
float band = (invocation == 0U) ? 1.0 : (invocation < 4U) ? (2.0 / 3.0) : 0.25;
|
||||
result_sh[invocation] = vec4(partial[0][invocation] * (sphere * band), 0.0);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
// the locations of the inputs and outputs between the stages, the same for a name in every shader (SPIR-V links the stages by
|
||||
// the locations, not by the names): 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, 11 f_model_draw, 12 f_albedo, 13 f_color, 14 f_coords, 15 f_local, 16 f_soft,
|
||||
// 17 f_streak, 18 g_coord, 19 g_coords, 20 g_pos
|
||||
// 17 f_streak, 18 g_coord, 19 g_coords, 20 g_pos, 21 g_normal
|
||||
#ifndef COMMON_GLSL
|
||||
#define COMMON_GLSL
|
||||
|
||||
@@ -106,6 +106,12 @@
|
||||
#define CLOUD_HISTORY_TEX 22
|
||||
#define SCENE_DEPTH_TEX 23
|
||||
#define SSR_HISTORY_TEX 24
|
||||
#define SCENE_AO_TEX 26
|
||||
#define CAB_PROBE_TEX 27
|
||||
#define CAB_PROBE_ALBEDO_TEX 28
|
||||
#define CAB_PROBE_SSBO_BINDING 17
|
||||
#define CAB_PROBE_SH_SIZE 16
|
||||
#define CAB_PROBE_SH_GROUP_SIZE 64
|
||||
#define WEATHER_UBO_BINDING 5
|
||||
#define WEATHER_SCRATCH_SSBO_BINDING 9
|
||||
#define MAX_CLOUD_LAYERS 4
|
||||
@@ -239,6 +245,8 @@ struct model_draw_s
|
||||
float fog_density;
|
||||
float alpha_mult;
|
||||
float shadow_tone;
|
||||
// 1 for the parts of the occupied cab, see gl::model_ubs
|
||||
float cab_interior;
|
||||
};
|
||||
|
||||
layout(std430, binding = MODEL_DRAW_SSBO_BINDING) readonly buffer model_draw_ssbo
|
||||
@@ -265,6 +273,7 @@ layout(location = 11) flat in uint f_model_draw;
|
||||
#define fog_density model_draws[MODEL_DRAW].fog_density
|
||||
#define alpha_mult model_draws[MODEL_DRAW].alpha_mult
|
||||
#define shadow_tone model_draws[MODEL_DRAW].shadow_tone
|
||||
#define cab_interior model_draws[MODEL_DRAW].cab_interior
|
||||
#else
|
||||
layout(std140, binding = MODEL_UBO_BINDING) uniform model_ubo
|
||||
{
|
||||
@@ -278,6 +287,8 @@ layout(std140, binding = MODEL_UBO_BINDING) uniform model_ubo
|
||||
float fog_density;
|
||||
float alpha_mult;
|
||||
float shadow_tone;
|
||||
// 1 for the parts of the occupied cab, see gl::model_ubs
|
||||
float cab_interior;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -309,6 +320,15 @@ layout(std140, binding = SCENE_UBO_BINDING) uniform scene_ubo
|
||||
vec4 env_params;
|
||||
// the air against the vehicle of the camera, see gl::scene_ubs
|
||||
vec4 rain_wind;
|
||||
// the ambient occlusion in the light of the surfaces, see gl::scene_ubs
|
||||
vec4 ao_params;
|
||||
// the probe of the occupied cab, and the lamp it's drawn with, see gl::scene_ubs
|
||||
mat4 cab_probe_view;
|
||||
vec4 cab_probe_box;
|
||||
vec4 cab_probe_params;
|
||||
vec4 cab_probe_lamp;
|
||||
vec4 cab_probe_lamp_color;
|
||||
vec4 cab_probe_lamp_shadow;
|
||||
};
|
||||
|
||||
#ifdef STAGE_VERTEX
|
||||
|
||||
@@ -8,6 +8,17 @@ layout(binding = LOCAL_SHADOW_LAMPS_TEX) uniform samplerCubeArrayShadow local_sh
|
||||
layout(binding = HEADLIGHT_SHADOW_TEX) uniform sampler2DArrayShadow headlight_shadowmap;
|
||||
// depth of the opaque scene drawn before the colour, for the contact shadows (gl::scene_ubs::contact_shadow_params)
|
||||
layout(binding = SCENE_DEPTH_TEX) uniform sampler2D scene_depth;
|
||||
// the ambient occlusion of the main view, half its size, for the ambient light (gl::scene_ubs::ao_params)
|
||||
layout(binding = SCENE_AO_TEX) uniform sampler2D scene_ao;
|
||||
// the probe of the occupied cab (gl::scene_ubs::cab_probe_box, gfx::cab_probe): the light of its lamps the cab reflects and its
|
||||
// albedo, each premultiplied by the share of the direction the cab fills, which is in their alpha, and the light the cab lights
|
||||
// itself with again (gl::cab_probe_data)
|
||||
layout(binding = CAB_PROBE_TEX) uniform samplerCube cab_probe_light;
|
||||
layout(binding = CAB_PROBE_ALBEDO_TEX) uniform samplerCube cab_probe_albedo;
|
||||
layout(std430, binding = CAB_PROBE_SSBO_BINDING) readonly buffer cab_probe_ssbo
|
||||
{
|
||||
vec4 cab_probe_sh[9];
|
||||
};
|
||||
|
||||
#include "envmapping.glsl"
|
||||
#include "ssr.glsl"
|
||||
@@ -45,6 +56,10 @@ float length2(vec3 v)
|
||||
return dot(v, v);
|
||||
}
|
||||
|
||||
// the largest difference of the distance of a texel of the ambient occlusion from the one of the fragment (a share of it) the
|
||||
// texel is taken to be of the surface of the fragment at
|
||||
const float AO_SURFACE_MATCH = 0.05;
|
||||
|
||||
// how many more lamps and headlights the fragment traces contact shadows to, see add_headlights()
|
||||
int contact_shadow_budget = 0;
|
||||
|
||||
@@ -707,6 +722,103 @@ vec4 reflection_scene(vec3 fragnormal, float roughness)
|
||||
return result;
|
||||
}
|
||||
|
||||
// the ambient occlusion of the view in the ambient light of the fragment, 0..1 (1: none): the occlusion of the main view worked out
|
||||
// from the depth of the opaque scene drawn before its colour (gfx.postfx.ao.lighting), half its size. the four nearest texels are
|
||||
// weighed by how close they are and by how close their distance is to the one of the fragment (as in postfx_ssao_apply.frag); where
|
||||
// none of them is of the surface of the fragment (what the depth before the colour doesn't hold: the blended surfaces, the grass,
|
||||
// the cab drawn after the precipitation, the edges of objects) there's no occlusion. the distance is the one along the axis of the
|
||||
// view, near / depth with the far plane at infinity
|
||||
float ambient_occlusion()
|
||||
{
|
||||
if (ao_params.x <= 0.0)
|
||||
return 1.0;
|
||||
ivec2 full_size = textureSize(scene_depth, 0);
|
||||
ivec2 half_size = textureSize(scene_ao, 0);
|
||||
ivec2 pixel = ivec2(gl_FragCoord.xy);
|
||||
float distance = max(-f_pos.z, 1e-3);
|
||||
vec2 position = vec2(pixel) * 0.5;
|
||||
ivec2 base = ivec2(floor(position));
|
||||
vec2 fraction = position - vec2(base);
|
||||
float sum = 0.0;
|
||||
float weights = 0.0;
|
||||
float closest = 1e30;
|
||||
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);
|
||||
float depth = texelFetch(scene_depth, min(texel * 2, full_size - 1), 0).r;
|
||||
float difference = (depth > 0.0) ? abs(projection[3][2] / depth - distance) / distance : 1e30;
|
||||
closest = min(closest, difference);
|
||||
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 + difference);
|
||||
sum += texelFetch(scene_ao, texel, 0).r * weight;
|
||||
weights += weight;
|
||||
}
|
||||
}
|
||||
if (closest > AO_SURFACE_MATCH)
|
||||
return 1.0;
|
||||
return pow(clamp(sum / max(weights, 1e-6), 0.0, 1.0), ao_params.y);
|
||||
}
|
||||
|
||||
// the light which comes back after more than one bounce off surfaces of the given albedo, for the occlusion of the ambient light
|
||||
// (Jimenez et al. 2016), for each channel
|
||||
vec3 ao_multi_bounce(float visibility, vec3 albedo)
|
||||
{
|
||||
vec3 a = 2.0404 * albedo - 0.3324;
|
||||
vec3 b = -4.7951 * albedo + 0.6417;
|
||||
vec3 c = 2.7552 * albedo + 0.6903;
|
||||
return max(vec3(visibility), ((visibility * a + b) * visibility + c) * visibility);
|
||||
}
|
||||
|
||||
// the share of the reflection of the surroundings the occlusion leaves to a surface of the perceptual roughness seen at the angle
|
||||
// NdotV (Lagarde and de Rousiers 2014)
|
||||
float ao_specular(float visibility, float NdotV, float roughness)
|
||||
{
|
||||
return clamp(pow(NdotV + visibility, exp2(-16.0 * roughness - 1.0)) - 1.0 + visibility, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// whether the fragment is a part of the occupied cab with its probe (gl::scene_ubs::cab_probe_box, gl::model_ubs::cab_interior)
|
||||
bool cab_probe_active()
|
||||
{
|
||||
return (cab_probe_box.w > 0.0) && (cab_interior > 0.5);
|
||||
}
|
||||
|
||||
// the light of the lamps the cab reflects which reaches a surface of the cab facing the view space Fragnormal, in the units of the
|
||||
// ambient light: the spherical harmonics cabprobe_sh.comp worked out from the probe, in the space of the probe
|
||||
vec3 cab_probe_bounce(vec3 fragnormal)
|
||||
{
|
||||
vec3 n = normalize(mat3(cab_probe_view) * fragnormal);
|
||||
vec3 light = cab_probe_sh[0].rgb * 0.282095
|
||||
+ cab_probe_sh[1].rgb * (0.488603 * n.y)
|
||||
+ cab_probe_sh[2].rgb * (0.488603 * n.z)
|
||||
+ cab_probe_sh[3].rgb * (0.488603 * n.x)
|
||||
+ cab_probe_sh[4].rgb * (1.092548 * n.x * n.y)
|
||||
+ cab_probe_sh[5].rgb * (1.092548 * n.y * n.z)
|
||||
+ cab_probe_sh[6].rgb * (0.315392 * (3.0 * n.z * n.z - 1.0))
|
||||
+ cab_probe_sh[7].rgb * (1.092548 * n.x * n.z)
|
||||
+ cab_probe_sh[8].rgb * (0.546274 * (n.x * n.x - n.y * n.y));
|
||||
return max(light, vec3(0.0)) * cab_probe_params.x;
|
||||
}
|
||||
|
||||
// the reflection of the cab in a surface of the cab of the perceptual roughness, over the reflection of the surroundings, where the
|
||||
// probe holds the cab: the reflected ray from the fragment to the box of the cab, looked up from the middle of the box, where the
|
||||
// probe was drawn from (the box stands for the walls of the cab). the cab shows the light of its lamps it reflects (the probe) and
|
||||
// its albedo lit by the ambient light of the fragment (Ambientlight), the light the cab gets from the outside
|
||||
vec3 cab_probe_reflection(vec3 surroundings, vec3 fragnormal, float roughness, vec3 ambientlight)
|
||||
{
|
||||
vec3 position = (cab_probe_view * vec4(f_pos.xyz, 1.0)).xyz;
|
||||
vec3 direction = normalize(mat3(cab_probe_view) * reflect(normalize(f_pos.xyz), fragnormal));
|
||||
vec3 invdir = (step(0.0, direction) * 2.0 - 1.0) / max(abs(direction), vec3(1e-5));
|
||||
vec3 far = max((cab_probe_box.xyz - position) * invdir, (-cab_probe_box.xyz - position) * invdir);
|
||||
float reach = max(min(min(far.x, far.y), far.z), 0.0);
|
||||
vec3 lookup = position + direction * reach;
|
||||
float level = roughness * cab_probe_params.z;
|
||||
vec4 light = textureLod(cab_probe_light, lookup, level);
|
||||
vec4 albedo = textureLod(cab_probe_albedo, lookup, level);
|
||||
return surroundings * (1.0 - albedo.a) + light.rgb + albedo.rgb * ambientlight;
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -761,6 +873,23 @@ vec3 shade_surface(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float ref
|
||||
spec_f0 = f0;
|
||||
spec_roughness = roughness;
|
||||
|
||||
// the light of the lamps the cab reflects, which lights the cab again (the probe of the cab), joins the ambient light
|
||||
bool cabprobe = cab_probe_active();
|
||||
vec3 cabambient = fragcolor;
|
||||
if (cabprobe)
|
||||
fragcolor += cab_probe_bounce(fragnormal);
|
||||
// the ambient occlusion of the view holds back the ambient light of the diffuse layer (with the light coming back from more
|
||||
// bounces off surfaces of the albedo) and the reflection of the surroundings; not the light of the sun and the lamps, nor the
|
||||
// reflection of the scene, which the rays find as it is
|
||||
float occlusion = ambient_occlusion();
|
||||
vec3 diffuse_occlusion = vec3(1.0);
|
||||
float specular_occlusion = 1.0;
|
||||
if (occlusion < 1.0)
|
||||
{
|
||||
diffuse_occlusion = ao_multi_bounce(occlusion, texturecolor);
|
||||
specular_occlusion = ao_specular(occlusion, NdotV, 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
|
||||
@@ -791,15 +920,18 @@ vec3 shade_surface(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float ref
|
||||
if (!matte)
|
||||
{
|
||||
envcolor = reflection_surroundings(fragnormal, env_roughness);
|
||||
// inside the cab the cab is what the surroundings are, where the probe holds it
|
||||
if (cabprobe && (cab_probe_params.y > 0.0))
|
||||
envcolor = cab_probe_reflection(envcolor, fragnormal, env_roughness, cabambient);
|
||||
if (((ssr_params.x > 0.0) || (ssr_params2.z > 0.0)) && (cubemap_share * dot(cubemap_spec, vec3(1.0 / 3.0)) > REFLECTION_SCENE_WEIGHT))
|
||||
scenecolor = reflection_scene(fragnormal, env_roughness);
|
||||
}
|
||||
|
||||
if (lights_count == 0U)
|
||||
return fragcolor * diffuse_albedo
|
||||
return fragcolor * diffuse_occlusion * diffuse_albedo
|
||||
+ emissioncolor * texturecolor
|
||||
+ fragcolor * env_spec * ambient_share
|
||||
+ (scenecolor.rgb + envcolor * (1.0 - scenecolor.a)) * cubemap_spec * cubemap_share;
|
||||
+ fragcolor * env_spec * ambient_share * specular_occlusion
|
||||
+ (scenecolor.rgb + envcolor * ((1.0 - scenecolor.a) * specular_occlusion)) * cubemap_spec * cubemap_share;
|
||||
|
||||
vec3 light_dir = normalize(-lights[0].dir);
|
||||
float NdotL = max(dot(fragnormal, light_dir), 0.0);
|
||||
@@ -830,8 +962,10 @@ vec3 shade_surface(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float ref
|
||||
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
|
||||
+ (scenecolor.rgb + envcolor * ((1.0 - scenecolor.a) * cubemap_shadow)) * cubemap_spec * cubemap_share;
|
||||
vec3 env_reflection = fragcolor * env_spec * ambient_share * specular_occlusion
|
||||
+ (scenecolor.rgb + envcolor * ((1.0 - scenecolor.a) * cubemap_shadow * specular_occlusion)) * cubemap_spec * cubemap_share;
|
||||
// the occlusion of the ambient light, before the light of the sun and the lamps joins it
|
||||
fragcolor *= diffuse_occlusion;
|
||||
|
||||
// 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
|
||||
|
||||
19
shaders/vk14/cabprobe.frag
Normal file
19
shaders/vk14/cabprobe.frag
Normal file
@@ -0,0 +1,19 @@
|
||||
#version 460 core
|
||||
#define STAGE_FRAGMENT 1
|
||||
#include "common.glsl"
|
||||
// the probe of the occupied cab (gfx::cab_probe), the materials without the alpha test (cabprobe.glsl)
|
||||
layout(location = 0) in vec3 f_normal;
|
||||
layout(location = 2) in vec2 f_coord;
|
||||
layout(location = 3) in vec4 f_pos;
|
||||
|
||||
#pragma texture(diffuse, 0, sRGB_A)
|
||||
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
|
||||
// the cube shadow map of the cab lamp
|
||||
layout(set = PASS_SET, binding = LOCAL_SHADOW_TEX) uniform samplerCubeArrayShadow probe_shadowmap;
|
||||
|
||||
#include "cabprobe.glsl"
|
||||
|
||||
void main()
|
||||
{
|
||||
probe_shade(texture(diffuse, f_coord));
|
||||
}
|
||||
61
shaders/vk14/cabprobe.glsl
Normal file
61
shaders/vk14/cabprobe.glsl
Normal file
@@ -0,0 +1,61 @@
|
||||
// the shading of the probe of the occupied cab (gfx::cab_probe, as shaders/ogl46/cabprobe.glsl), for cabprobe.frag and cabprobe_alpha.frag: what the cab shows
|
||||
// towards the middle of its box lit by the cab lamp alone, with the cube shadow map of the lamp (and what glows in it, the lights
|
||||
// of the desk), and its albedo, each with 1 in the alpha: the probe is cleared to nothing, so the alpha of a direction tells how
|
||||
// much of it the cab fills, and both are premultiplied by it. the light of the cab lamp is the one the shading gives it
|
||||
// (calc_local_light() in light_common.glsl); the ambient light and the sun are left out, the cab gets those as before. the
|
||||
// parameters of the lamp are in the block of the scene (gl::scene_ubs::cab_probe_lamp), in the space of the probe
|
||||
|
||||
layout(location = 0) out vec4 out_light;
|
||||
layout(location = 1) out vec4 out_albedo;
|
||||
|
||||
// closest distance (squared) the light of the lamp is computed for, as LOCAL_LIGHT_MIN_DISTANCE2 of light_common.glsl
|
||||
const float PROBE_LIGHT_MIN_DISTANCE2 = 0.01;
|
||||
|
||||
// the diffuse colour of the submodel or shape, as material_diffuse() of light_common.glsl
|
||||
vec3 probe_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));
|
||||
}
|
||||
|
||||
// share of the light of the cab lamp held back before the point of the space of its cube shadow map (origin at the lamp), 0..1, as
|
||||
// local_light_shadow() of light_common.glsl takes it with a single sample
|
||||
float probe_lamp_shadow(vec3 position, vec3 normal)
|
||||
{
|
||||
vec4 weights = cab_probe_lamp_shadow;
|
||||
float distance = length(position);
|
||||
float texel = weights.z * distance;
|
||||
vec3 tolamp = -position / max(distance, 1e-4);
|
||||
float NdotL = clamp(dot(normal, tolamp), 0.0, 1.0);
|
||||
position += normal * (texel * (0.5 + 1.5 * (1.0 - NdotL)));
|
||||
vec3 axes = abs(position);
|
||||
float major = max(axes.x, max(axes.y, axes.z));
|
||||
float reference = weights.y / max(major - texel * 1.5, weights.y);
|
||||
return texture(probe_shadowmap, vec4(position, weights.x), reference);
|
||||
}
|
||||
|
||||
void probe_shade(vec4 tex_color)
|
||||
{
|
||||
vec3 albedo = tex_color.rgb * probe_material_diffuse();
|
||||
vec3 position = f_pos.xyz;
|
||||
vec3 normal = normalize(f_normal);
|
||||
// the walls are drawn from both sides: the side the probe sees
|
||||
if (dot(normal, position) > 0.0)
|
||||
normal = -normal;
|
||||
vec3 light = vec3(emission);
|
||||
if (cab_probe_lamp.w > 0.0)
|
||||
{
|
||||
vec3 tolight = cab_probe_lamp.xyz - position;
|
||||
float distance2 = dot(tolight, tolight);
|
||||
vec3 light_dir = tolight * inversesqrt(max(distance2, 1e-8));
|
||||
float edge = clamp(1.0 - distance2 * distance2 * (cab_probe_lamp.w * cab_probe_lamp.w), 0.0, 1.0);
|
||||
float atten = edge * edge / max(distance2, PROBE_LIGHT_MIN_DISTANCE2);
|
||||
float NdotL = max(dot(normal, light_dir), 0.0);
|
||||
if ((atten > 0.0) && (NdotL > 0.0) && (cab_probe_lamp_color.a > 0.5))
|
||||
atten *= 1.0 - probe_lamp_shadow(-tolight, normal);
|
||||
light += cab_probe_lamp_color.rgb * (NdotL * atten);
|
||||
}
|
||||
out_light = vec4(albedo * light, 1.0);
|
||||
out_albedo = vec4(albedo, 1.0);
|
||||
}
|
||||
38
shaders/vk14/cabprobe.vert
Normal file
38
shaders/vk14/cabprobe.vert
Normal file
@@ -0,0 +1,38 @@
|
||||
#version 460 core
|
||||
#extension GL_EXT_multiview : require
|
||||
#define STAGE_VERTEX 1
|
||||
// the occupied cab drawn into the six faces of its probe at once (gfx::cab_probe), a view of the multiview rendering per face (the
|
||||
// geometry shader cabprobe.geom of the opengl renderer). the modelview takes the cab model to the space of the probe: the axes of
|
||||
// the model, the origin in the middle of the box of the cab. the faces go in the order of the faces of a cube map (+x, -x, +y, -y,
|
||||
// +z, -z), each looks the way glm::lookAt() with the usual up vectors of cube maps sets it, with a 90 degree projection of infinite
|
||||
// reach and reversed depth like the one of the scene: the depth is near / d, d the distance along the axis of the face
|
||||
#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 = 0) out vec3 f_normal;
|
||||
layout(location = 2) out vec2 f_coord;
|
||||
layout(location = 3) out vec4 f_pos;
|
||||
|
||||
// near plane of the probe, metres
|
||||
const float PROBE_NEAR = 0.05;
|
||||
|
||||
// right, up and forward axes of the faces
|
||||
const vec3 face_right[6] = vec3[](vec3(0.0, 0.0, -1.0), vec3(0.0, 0.0, 1.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0));
|
||||
const vec3 face_up[6] = vec3[](vec3(0.0, -1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0), vec3(0.0, -1.0, 0.0), vec3(0.0, -1.0, 0.0));
|
||||
const vec3 face_forward[6] = vec3[](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0));
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 position = (effective_modelview() * vec4(v_vert, 1.0)).xyz;
|
||||
int face = int(gl_ViewIndex);
|
||||
gl_Position = vec4(dot(position, face_right[face]), dot(position, face_up[face]), PROBE_NEAR, dot(position, face_forward[face]));
|
||||
f_normal = effective_modelviewnormal() * v_normal;
|
||||
f_coord = v_coord;
|
||||
f_pos = vec4(position, 1.0);
|
||||
#ifdef MODEL_DRAWS
|
||||
// which block of the multi draw the fragments read (common.glsl)
|
||||
f_model_draw = MODEL_DRAW;
|
||||
#endif
|
||||
}
|
||||
23
shaders/vk14/cabprobe_alpha.frag
Normal file
23
shaders/vk14/cabprobe_alpha.frag
Normal file
@@ -0,0 +1,23 @@
|
||||
#version 460 core
|
||||
#define STAGE_FRAGMENT 1
|
||||
#include "common.glsl"
|
||||
// the probe of the occupied cab (gfx::cab_probe), the materials whose colour shader tests the alpha of the diffuse texture against
|
||||
// the opacity of the material, with the test of depthprepass_alpha.frag (cabprobe.glsl)
|
||||
layout(location = 0) in vec3 f_normal;
|
||||
layout(location = 2) in vec2 f_coord;
|
||||
layout(location = 3) in vec4 f_pos;
|
||||
|
||||
#pragma texture(diffuse, 0, sRGB_A)
|
||||
layout(set = MATERIAL_SET, binding = MATERIAL_TEXTURE_FIRST + 0) uniform sampler2D diffuse;
|
||||
// the cube shadow map of the cab lamp
|
||||
layout(set = PASS_SET, binding = LOCAL_SHADOW_TEX) uniform samplerCubeArrayShadow probe_shadowmap;
|
||||
|
||||
#include "cabprobe.glsl"
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 tex_color = texture(diffuse, f_coord);
|
||||
if (tex_color.a < opacity + 1.0 / 255.0)
|
||||
discard;
|
||||
probe_shade(tex_color);
|
||||
}
|
||||
96
shaders/vk14/cabprobe_sh.comp
Normal file
96
shaders/vk14/cabprobe_sh.comp
Normal file
@@ -0,0 +1,96 @@
|
||||
#version 460 core
|
||||
#define STAGE_COMPUTE 1
|
||||
#define LAYOUT_COMPUTE 1
|
||||
#include "common.glsl"
|
||||
// the light the occupied cab lights itself with again, from its probe (gfx::cab_probe), in one work group: the light of its lamps the
|
||||
// cab reflects towards the middle of its box, as spherical harmonics of bands 0..2, convolved with the cosine lobe and divided by
|
||||
// pi, so their value for a direction is the light a white lambertian surface facing it gets, in the units of the ambient light
|
||||
// (light_common.glsl, cab_probe_bounce()). the light is taken from a level of the probe of at most CAB_PROBE_SH_SIZE pixels a
|
||||
// face, each pixel weighed by its solid angle. the basis is the one of the sky (gl::sky_data)
|
||||
|
||||
layout(local_size_x = CAB_PROBE_SH_GROUP_SIZE) in;
|
||||
|
||||
layout(set = COMPUTE_SET, binding = 0) uniform samplerCube probe_light;
|
||||
|
||||
layout(std430, set = COMPUTE_SET, binding = 1) writeonly buffer cab_probe_result_ssbo
|
||||
{
|
||||
vec4 result_sh[9];
|
||||
};
|
||||
|
||||
// the parameters of the kernel (push constants): x the level of the probe read, y its size, pixels
|
||||
layout(push_constant) uniform kernel_constants
|
||||
{
|
||||
ivec2 level;
|
||||
};
|
||||
|
||||
shared vec3 partial[CAB_PROBE_SH_GROUP_SIZE][9];
|
||||
shared float partialweight[CAB_PROBE_SH_GROUP_SIZE];
|
||||
|
||||
// the direction through the middle of the pixel (s, t) of the face, -1..1 across it, in the order of the faces of a cube map
|
||||
vec3 face_direction(int face, float s, float t)
|
||||
{
|
||||
switch (face)
|
||||
{
|
||||
case 0: return vec3(1.0, -t, -s);
|
||||
case 1: return vec3(-1.0, -t, s);
|
||||
case 2: return vec3(s, 1.0, t);
|
||||
case 3: return vec3(s, -1.0, -t);
|
||||
case 4: return vec3(s, -t, 1.0);
|
||||
default: return vec3(-s, -t, -1.0);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
uint invocation = gl_LocalInvocationID.x;
|
||||
int size = max(level.y, 1);
|
||||
int texels = 6 * size * size;
|
||||
vec3 sum[9];
|
||||
for (int i = 0; i < 9; ++i)
|
||||
sum[i] = vec3(0.0);
|
||||
float weights = 0.0;
|
||||
for (int index = int(invocation); index < texels; index += CAB_PROBE_SH_GROUP_SIZE)
|
||||
{
|
||||
int face = index / (size * size);
|
||||
int texel = index - face * size * size;
|
||||
float s = (float(texel % size) + 0.5) / float(size) * 2.0 - 1.0;
|
||||
float t = (float(texel / size) + 0.5) / float(size) * 2.0 - 1.0;
|
||||
vec3 direction = face_direction(face, s, t);
|
||||
// the solid angle of the pixel
|
||||
float lengthsquared = dot(direction, direction);
|
||||
float weight = 1.0 / (lengthsquared * sqrt(lengthsquared));
|
||||
vec3 n = direction * inversesqrt(lengthsquared);
|
||||
vec3 light = textureLod(probe_light, n, float(level.x)).rgb * weight;
|
||||
sum[0] += light * 0.282095;
|
||||
sum[1] += light * (0.488603 * n.y);
|
||||
sum[2] += light * (0.488603 * n.z);
|
||||
sum[3] += light * (0.488603 * n.x);
|
||||
sum[4] += light * (1.092548 * n.x * n.y);
|
||||
sum[5] += light * (1.092548 * n.y * n.z);
|
||||
sum[6] += light * (0.315392 * (3.0 * n.z * n.z - 1.0));
|
||||
sum[7] += light * (1.092548 * n.x * n.z);
|
||||
sum[8] += light * (0.546274 * (n.x * n.x - n.y * n.y));
|
||||
weights += weight;
|
||||
}
|
||||
for (int i = 0; i < 9; ++i)
|
||||
partial[invocation][i] = sum[i];
|
||||
partialweight[invocation] = weights;
|
||||
barrier();
|
||||
for (uint stride = CAB_PROBE_SH_GROUP_SIZE / 2; stride > 0U; stride /= 2U)
|
||||
{
|
||||
if (invocation < stride)
|
||||
{
|
||||
for (int i = 0; i < 9; ++i)
|
||||
partial[invocation][i] += partial[invocation + stride][i];
|
||||
partialweight[invocation] += partialweight[invocation + stride];
|
||||
}
|
||||
barrier();
|
||||
}
|
||||
if (invocation < 9U)
|
||||
{
|
||||
// the weights add up to the whole sphere, 4 pi; the cosine lobe over pi: 1 for band 0, 2/3 for band 1, 1/4 for band 2
|
||||
float sphere = 12.566371 / max(partialweight[0], 1e-6);
|
||||
float band = (invocation == 0U) ? 1.0 : (invocation < 4U) ? (2.0 / 3.0) : 0.25;
|
||||
result_sh[invocation] = vec4(partial[0][invocation] * (sphere * band), 0.0);
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,11 @@
|
||||
#define SCENE_DEPTH_TEX 24
|
||||
#define SSR_HISTORY_TEX 25
|
||||
#define WATER_SSBO 26
|
||||
#define PASS_BINDING_COUNT 27
|
||||
#define SCENE_AO_TEX 27
|
||||
#define CAB_PROBE_TEX 28
|
||||
#define CAB_PROBE_ALBEDO_TEX 29
|
||||
#define CAB_PROBE_SSBO 30
|
||||
#define PASS_BINDING_COUNT 31
|
||||
#define MATERIAL_TEXTURE_FIRST 0
|
||||
#define CL_CLUSTER_UBO 0
|
||||
#define CL_AABB_SSBO 1
|
||||
@@ -129,6 +133,8 @@
|
||||
#define WATER_TRAIL 1024
|
||||
#define WATER_MAP 256
|
||||
#define WATER_GROUP_SIZE 64
|
||||
#define CAB_PROBE_SH_SIZE 16
|
||||
#define CAB_PROBE_SH_GROUP_SIZE 64
|
||||
#endif
|
||||
|
||||
#include "settings.glsl"
|
||||
@@ -281,6 +287,15 @@ layout(std140, set = PASS_SET, binding = SCENE_UBO) uniform scene_ubo
|
||||
vec4 env_params;
|
||||
// the air against the vehicle of the camera, see gl::scene_ubs
|
||||
vec4 rain_wind;
|
||||
// the ambient occlusion in the light of the surfaces, see gl::scene_ubs
|
||||
vec4 ao_params;
|
||||
// the probe of the occupied cab, and the lamp it's drawn with, see gl::scene_ubs
|
||||
mat4 cab_probe_view;
|
||||
vec4 cab_probe_box;
|
||||
vec4 cab_probe_params;
|
||||
vec4 cab_probe_lamp;
|
||||
vec4 cab_probe_lamp_color;
|
||||
vec4 cab_probe_lamp_shadow;
|
||||
};
|
||||
|
||||
#ifndef LAYOUT_COMPUTE
|
||||
@@ -298,6 +313,8 @@ struct model_draw_s
|
||||
float fog_density;
|
||||
float alpha_mult;
|
||||
float shadow_tone;
|
||||
// 1 for the parts of the occupied cab, see gl::model_ubs
|
||||
float cab_interior;
|
||||
};
|
||||
|
||||
layout(std430, set = PASS_SET, binding = DRAW_SSBO) readonly buffer model_draw_ssbo
|
||||
@@ -331,6 +348,7 @@ layout(location = 11) flat in uint f_model_draw;
|
||||
#define fog_density model_draws[MODEL_DRAW].fog_density
|
||||
#define alpha_mult model_draws[MODEL_DRAW].alpha_mult
|
||||
#define shadow_tone model_draws[MODEL_DRAW].shadow_tone
|
||||
#define cab_interior model_draws[MODEL_DRAW].cab_interior
|
||||
|
||||
// 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
|
||||
|
||||
@@ -12,6 +12,17 @@ layout(set = PASS_SET, binding = LOCAL_SHADOW_LAMPS_TEX) uniform samplerCubeArra
|
||||
layout(set = PASS_SET, binding = HEADLIGHT_SHADOW_TEX) uniform sampler2DArrayShadow headlight_shadowmap;
|
||||
// depth of the opaque scene drawn before the colour, for the contact shadows (gl::scene_ubs::contact_shadow_params)
|
||||
layout(set = PASS_SET, binding = SCENE_DEPTH_TEX) uniform sampler2D scene_depth;
|
||||
// the ambient occlusion of the main view, half its size, for the ambient light (gl::scene_ubs::ao_params)
|
||||
layout(set = PASS_SET, binding = SCENE_AO_TEX) uniform sampler2D scene_ao;
|
||||
// the probe of the occupied cab (gl::scene_ubs::cab_probe_box, gfx::cab_probe): the light of its lamps the cab reflects and its
|
||||
// albedo, each premultiplied by the share of the direction the cab fills, which is in their alpha, and the light the cab lights
|
||||
// itself with again (gl::cab_probe_data)
|
||||
layout(set = PASS_SET, binding = CAB_PROBE_TEX) uniform samplerCube cab_probe_light;
|
||||
layout(set = PASS_SET, binding = CAB_PROBE_ALBEDO_TEX) uniform samplerCube cab_probe_albedo;
|
||||
layout(std430, set = PASS_SET, binding = CAB_PROBE_SSBO) readonly buffer cab_probe_ssbo
|
||||
{
|
||||
vec4 cab_probe_sh[9];
|
||||
};
|
||||
|
||||
#include "envmapping.glsl"
|
||||
#include "ssr.glsl"
|
||||
@@ -49,6 +60,10 @@ float length2(vec3 v)
|
||||
return dot(v, v);
|
||||
}
|
||||
|
||||
// the largest difference of the distance of a texel of the ambient occlusion from the one of the fragment (a share of it) the
|
||||
// texel is taken to be of the surface of the fragment at
|
||||
const float AO_SURFACE_MATCH = 0.05;
|
||||
|
||||
// how many more lamps and headlights the fragment traces contact shadows to, see add_headlights()
|
||||
int contact_shadow_budget = 0;
|
||||
|
||||
@@ -720,6 +735,103 @@ vec4 reflection_scene(vec3 fragnormal, float roughness, float weight)
|
||||
return result;
|
||||
}
|
||||
|
||||
// the ambient occlusion of the view in the ambient light of the fragment, 0..1 (1: none): the occlusion of the main view worked out
|
||||
// from the depth of the opaque scene drawn before its colour (gfx.postfx.ao.lighting), half its size. the four nearest texels are
|
||||
// weighed by how close they are and by how close their distance is to the one of the fragment (as in postfx_ssao_apply.frag); where
|
||||
// none of them is of the surface of the fragment (what the depth before the colour doesn't hold: the blended surfaces, the grass,
|
||||
// the cab drawn after the precipitation, the edges of objects) there's no occlusion. the distance is the one along the axis of the
|
||||
// view, near / depth with the far plane at infinity
|
||||
float ambient_occlusion()
|
||||
{
|
||||
if (ao_params.x <= 0.0)
|
||||
return 1.0;
|
||||
ivec2 full_size = textureSize(scene_depth, 0);
|
||||
ivec2 half_size = textureSize(scene_ao, 0);
|
||||
ivec2 pixel = ivec2(gl_FragCoord.xy);
|
||||
float distance = max(-f_pos.z, 1e-3);
|
||||
vec2 position = vec2(pixel) * 0.5;
|
||||
ivec2 base = ivec2(floor(position));
|
||||
vec2 fraction = position - vec2(base);
|
||||
float sum = 0.0;
|
||||
float weights = 0.0;
|
||||
float closest = 1e30;
|
||||
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);
|
||||
float depth = texelFetch(scene_depth, min(texel * 2, full_size - 1), 0).r;
|
||||
float difference = (depth > 0.0) ? abs(projection[3][2] / depth - distance) / distance : 1e30;
|
||||
closest = min(closest, difference);
|
||||
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 + difference);
|
||||
sum += texelFetch(scene_ao, texel, 0).r * weight;
|
||||
weights += weight;
|
||||
}
|
||||
}
|
||||
if (closest > AO_SURFACE_MATCH)
|
||||
return 1.0;
|
||||
return pow(clamp(sum / max(weights, 1e-6), 0.0, 1.0), ao_params.y);
|
||||
}
|
||||
|
||||
// the light which comes back after more than one bounce off surfaces of the given albedo, for the occlusion of the ambient light
|
||||
// (Jimenez et al. 2016), for each channel
|
||||
vec3 ao_multi_bounce(float visibility, vec3 albedo)
|
||||
{
|
||||
vec3 a = 2.0404 * albedo - 0.3324;
|
||||
vec3 b = -4.7951 * albedo + 0.6417;
|
||||
vec3 c = 2.7552 * albedo + 0.6903;
|
||||
return max(vec3(visibility), ((visibility * a + b) * visibility + c) * visibility);
|
||||
}
|
||||
|
||||
// the share of the reflection of the surroundings the occlusion leaves to a surface of the perceptual roughness seen at the angle
|
||||
// NdotV (Lagarde and de Rousiers 2014)
|
||||
float ao_specular(float visibility, float NdotV, float roughness)
|
||||
{
|
||||
return clamp(pow(NdotV + visibility, exp2(-16.0 * roughness - 1.0)) - 1.0 + visibility, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// whether the fragment is a part of the occupied cab with its probe (gl::scene_ubs::cab_probe_box, gl::model_ubs::cab_interior)
|
||||
bool cab_probe_active()
|
||||
{
|
||||
return (cab_probe_box.w > 0.0) && (cab_interior > 0.5);
|
||||
}
|
||||
|
||||
// the light of the lamps the cab reflects which reaches a surface of the cab facing the view space Fragnormal, in the units of the
|
||||
// ambient light: the spherical harmonics cabprobe_sh.comp worked out from the probe, in the space of the probe
|
||||
vec3 cab_probe_bounce(vec3 fragnormal)
|
||||
{
|
||||
vec3 n = normalize(mat3(cab_probe_view) * fragnormal);
|
||||
vec3 light = cab_probe_sh[0].rgb * 0.282095
|
||||
+ cab_probe_sh[1].rgb * (0.488603 * n.y)
|
||||
+ cab_probe_sh[2].rgb * (0.488603 * n.z)
|
||||
+ cab_probe_sh[3].rgb * (0.488603 * n.x)
|
||||
+ cab_probe_sh[4].rgb * (1.092548 * n.x * n.y)
|
||||
+ cab_probe_sh[5].rgb * (1.092548 * n.y * n.z)
|
||||
+ cab_probe_sh[6].rgb * (0.315392 * (3.0 * n.z * n.z - 1.0))
|
||||
+ cab_probe_sh[7].rgb * (1.092548 * n.x * n.z)
|
||||
+ cab_probe_sh[8].rgb * (0.546274 * (n.x * n.x - n.y * n.y));
|
||||
return max(light, vec3(0.0)) * cab_probe_params.x;
|
||||
}
|
||||
|
||||
// the reflection of the cab in a surface of the cab of the perceptual roughness, over the reflection of the surroundings, where the
|
||||
// probe holds the cab: the reflected ray from the fragment to the box of the cab, looked up from the middle of the box, where the
|
||||
// probe was drawn from (the box stands for the walls of the cab). the cab shows the light of its lamps it reflects (the probe) and
|
||||
// its albedo lit by the ambient light of the fragment (Ambientlight), the light the cab gets from the outside
|
||||
vec3 cab_probe_reflection(vec3 surroundings, vec3 fragnormal, float roughness, vec3 ambientlight)
|
||||
{
|
||||
vec3 position = (cab_probe_view * vec4(f_pos.xyz, 1.0)).xyz;
|
||||
vec3 direction = normalize(mat3(cab_probe_view) * reflect(normalize(f_pos.xyz), fragnormal));
|
||||
vec3 invdir = (step(0.0, direction) * 2.0 - 1.0) / max(abs(direction), vec3(1e-5));
|
||||
vec3 far = max((cab_probe_box.xyz - position) * invdir, (-cab_probe_box.xyz - position) * invdir);
|
||||
float reach = max(min(min(far.x, far.y), far.z), 0.0);
|
||||
vec3 lookup = position + direction * reach;
|
||||
float level = roughness * cab_probe_params.z;
|
||||
vec4 light = textureLod(cab_probe_light, lookup, level);
|
||||
vec4 albedo = textureLod(cab_probe_albedo, lookup, level);
|
||||
return surroundings * (1.0 - albedo.a) + light.rgb + albedo.rgb * ambientlight;
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -774,6 +886,23 @@ vec3 shade_surface(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float ref
|
||||
spec_f0 = f0;
|
||||
spec_roughness = roughness;
|
||||
|
||||
// the light of the lamps the cab reflects, which lights the cab again (the probe of the cab), joins the ambient light
|
||||
bool cabprobe = cab_probe_active();
|
||||
vec3 cabambient = fragcolor;
|
||||
if (cabprobe)
|
||||
fragcolor += cab_probe_bounce(fragnormal);
|
||||
// the ambient occlusion of the view holds back the ambient light of the diffuse layer (with the light coming back from more
|
||||
// bounces off surfaces of the albedo) and the reflection of the surroundings; not the light of the sun and the lamps, nor the
|
||||
// reflection of the scene, which the rays find as it is
|
||||
float occlusion = ambient_occlusion();
|
||||
vec3 diffuse_occlusion = vec3(1.0);
|
||||
float specular_occlusion = 1.0;
|
||||
if (occlusion < 1.0)
|
||||
{
|
||||
diffuse_occlusion = ao_multi_bounce(occlusion, texturecolor);
|
||||
specular_occlusion = ao_specular(occlusion, NdotV, 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
|
||||
@@ -804,16 +933,19 @@ vec3 shade_surface(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float ref
|
||||
if (!matte)
|
||||
{
|
||||
envcolor = reflection_surroundings(fragnormal, env_roughness);
|
||||
// inside the cab the cab is what the surroundings are, where the probe holds it
|
||||
if (cabprobe && (cab_probe_params.y > 0.0))
|
||||
envcolor = cab_probe_reflection(envcolor, fragnormal, env_roughness, cabambient);
|
||||
float sceneweight = cubemap_share * dot(cubemap_spec, vec3(1.0 / 3.0));
|
||||
if (((ssr_params.x > 0.0) || (ssr_params2.z > 0.0)) && (sceneweight > REFLECTION_SCENE_WEIGHT))
|
||||
scenecolor = reflection_scene(fragnormal, env_roughness, sceneweight);
|
||||
}
|
||||
|
||||
if (lights_count == 0U)
|
||||
return fragcolor * diffuse_albedo
|
||||
return fragcolor * diffuse_occlusion * diffuse_albedo
|
||||
+ emissioncolor * texturecolor
|
||||
+ fragcolor * env_spec * ambient_share
|
||||
+ (scenecolor.rgb + envcolor * (1.0 - scenecolor.a)) * cubemap_spec * cubemap_share;
|
||||
+ fragcolor * env_spec * ambient_share * specular_occlusion
|
||||
+ (scenecolor.rgb + envcolor * ((1.0 - scenecolor.a) * specular_occlusion)) * cubemap_spec * cubemap_share;
|
||||
|
||||
vec3 light_dir = normalize(-lights[0].dir);
|
||||
float NdotL = max(dot(fragnormal, light_dir), 0.0);
|
||||
@@ -844,8 +976,10 @@ vec3 shade_surface(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float ref
|
||||
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
|
||||
+ (scenecolor.rgb + envcolor * ((1.0 - scenecolor.a) * cubemap_shadow)) * cubemap_spec * cubemap_share;
|
||||
vec3 env_reflection = fragcolor * env_spec * ambient_share * specular_occlusion
|
||||
+ (scenecolor.rgb + envcolor * ((1.0 - scenecolor.a) * cubemap_shadow * specular_occlusion)) * cubemap_spec * cubemap_share;
|
||||
// the occlusion of the ambient light, before the light of the sun and the lamps joins it
|
||||
fragcolor *= diffuse_occlusion;
|
||||
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user