mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-28 22:47:28 +01:00
Shade the sky and the sun by the scenery around the camera instead of the track environment flags
This commit is contained in:
@@ -282,8 +282,9 @@ the height of the highest surface (the top) and of the lowest one facing down (t
|
||||
bridge seen from below, a roof). Taken are the shapes (the terrain, the heightmap terrain, roads, platforms) and the opaque parts
|
||||
of the models at their nearest level of detail; not the vehicles, the tracks, the catenary, nor what is see-through (trees).
|
||||
Things narrower than about three texels (poles, masts, fences) are left out. From the heights around, each texel gets:
|
||||
- the share of the sky a surface facing up sees above the top, and under the ceiling (light comes in under the vault from the
|
||||
portal, along the tunnel);
|
||||
- the share of the sky seen above the top, and under the ceiling: near it and a metre above the ground around (the ground under
|
||||
a high viaduct sees much of the sky on its sides, the vault of a tunnel lets light in only along the tunnel from the portal); a
|
||||
point under the ceiling gets a blend of the two by its height;
|
||||
- the heights between which the sun (the moon at night) comes in: above the top what is higher than the shadow of the hills
|
||||
and buildings towards it, under the ceiling what the rays reach under the vault from the portal (a low sun shines a little way
|
||||
into a tunnel).
|
||||
@@ -304,7 +305,7 @@ terrain, models shown or hidden by events); the sun is followed every quarter of
|
||||
|
||||
Cost: on the main thread, the triangles of a tile gathered when it comes in (one tile a frame, more at the start), a fraction
|
||||
of a millisecond; in the background, a few to some tens of milliseconds per tile, which doesn't hold the frame up. On the GPU,
|
||||
two textures (`medium`: 3 MB, `high`: 12 MB) and five texture reads per pixel in the shading. With `no` nothing of it is made
|
||||
two textures (`medium`: 6 MB, `high`: 24 MB) and eight texture gathers per pixel in the shading. With `no` nothing of it is made
|
||||
and the scenery is lit as in the open everywhere.
|
||||
|
||||
| Entry | Default | Meaning |
|
||||
|
||||
5
gl/ubo.h
5
gl/ubo.h
@@ -92,8 +92,9 @@ namespace gl
|
||||
const size_t CAB_PROBE_TEX = MAX_TEXTURES + HELPER_TEXTURES + 15;
|
||||
const size_t CAB_PROBE_ALBEDO_TEX = MAX_TEXTURES + HELPER_TEXTURES + 16;
|
||||
// the occlusion of the sky and of the sun by the scenery around the camera (gfx::sky_occlusion, gl::scene_ubs::sky_occlusion_*):
|
||||
// the height of the top of the scenery (R32F) and the shares of the sky and the limits of the key light (RGBA16F), toroidal maps
|
||||
// read texel by texel with textureGather. bound directly, like the ones above
|
||||
// the heights of the scenery (RGBA32F: the top, the ceiling, the limit of the key light under it, the height of the deep share of
|
||||
// the sky under it) and the shares of the sky and the limit of the key light above the top (RGBA16F), toroidal maps read texel by
|
||||
// texel with textureGather. bound directly, like the ones above
|
||||
const size_t SKY_OCCLUSION_HEIGHT_TEX = MAX_TEXTURES + HELPER_TEXTURES + 17;
|
||||
const size_t SKY_OCCLUSION_TEX = MAX_TEXTURES + HELPER_TEXTURES + 18;
|
||||
|
||||
|
||||
@@ -39,14 +39,20 @@ bool has_ceiling(float const Ceiling)
|
||||
{
|
||||
return Ceiling < 0.5f * NONE_CEILING;
|
||||
}
|
||||
// the limits of the heights between which the key light is let through, relative to the top: lit always, never
|
||||
// the height above the top over which the key light comes, relative to the top: lit always, never
|
||||
float const LIT_ABOVE_ALWAYS{-1000.f};
|
||||
float const LIT_BELOW_ALWAYS{1000.f};
|
||||
float const LIT_NEVER_BELOW{-1000.f};
|
||||
float const LIT_ABOVE_NEVER{1000.f};
|
||||
// the height under the ceiling below which the key light comes in, world space: lit always, never
|
||||
float const LIT_BELOW_ALWAYS{1.0e4f};
|
||||
float const LIT_NEVER_BELOW{-1.0e4f};
|
||||
// how high above the top the share of the sky above it is worked out (a surface on the ground isn't held back by the slope it's on),
|
||||
// and how far below the ceiling the share under it (the middle of the height under a vault of a tunnel or a deck of a bridge)
|
||||
// and how far below the ceiling the share under it is worked out near the ceiling; the other share under it is worked out a metre
|
||||
// above the ground around (the ground under a viaduct sees the sky on the sides much more than a point right under the deck), at
|
||||
// most this far below the ceiling
|
||||
float const ABOVE_TOP{1.f};
|
||||
float const BELOW_CEILING{2.5f};
|
||||
float const DEEP_BELOW_CEILING_MAX{30.f};
|
||||
float const DEEP_BELOW_CEILING_UNKNOWN{6.f};
|
||||
// a fragment this far below the top of its texel is under it, fully this much further. as in light_common.glsl, sky_occlusion()
|
||||
float const COVER_START{0.75f};
|
||||
float const COVER_SPAN{1.f};
|
||||
@@ -81,31 +87,47 @@ std::uint64_t hash_mix_double(std::uint64_t Hash, double const Value)
|
||||
return hash_mix(Hash, bits);
|
||||
}
|
||||
|
||||
// the share of the sky of an elevation band, weighed by the cosine on a surface facing up, from the tangents of its ends
|
||||
// the share of the sky of an elevation band, from the tangents of its ends: the share of the solid angle of the hemisphere, not
|
||||
// weighed by the cosine (the ambient light lights the surfaces facing every way, the low sky lights the walls and the sides of what
|
||||
// stands under a roof)
|
||||
float sky_share(float const Tangent)
|
||||
{
|
||||
if (Tangent <= 0.f)
|
||||
return 0.f;
|
||||
if (Tangent >= 1.0e6f)
|
||||
return 1.f;
|
||||
auto const squared{Tangent * Tangent};
|
||||
return squared / (1.f + squared);
|
||||
return Tangent / std::sqrt(1.f + Tangent * Tangent);
|
||||
}
|
||||
|
||||
// the values of a texel nothing is known of or which holds nothing: the heights (no top, no ceiling, the key light under the ceiling
|
||||
// always, the deep share under it at no height) and the occlusion (the whole sky, the key light always)
|
||||
glm::vec4 const NEUTRAL_HEIGHTS{NONE_TOP, NONE_CEILING, LIT_BELOW_ALWAYS, NONE_TOP};
|
||||
glm::vec4 const NEUTRAL_OCCLUSION{1.f, 1.f, 1.f, LIT_ABOVE_ALWAYS};
|
||||
|
||||
float smoothstep(float const Edge0, float const Edge1, float const Value)
|
||||
{
|
||||
auto const t{std::clamp((Value - Edge0) / (Edge1 - Edge0), 0.f, 1.f)};
|
||||
return t * t * (3.f - 2.f * t);
|
||||
}
|
||||
|
||||
// the occlusion of a point at Height, over a texel of the given top and occlusion values: the share of the sky and of the key
|
||||
// light. the same as light_common.glsl, sky_occlusion_texel()
|
||||
glm::vec2 texel_occlusion(float const Top, glm::vec4 const &Occlusion, float const Height)
|
||||
// the occlusion of a point at Height, over a texel of the given heights (the top, the ceiling, the limit of the key light under the
|
||||
// ceiling, the height of the deep share under it) and occlusion values (the share above the top, under the ceiling near it and deep,
|
||||
// the limit of the key light above the top): the share of the sky and of the key light. the same as sky_occlusion.glsl
|
||||
glm::vec2 texel_occlusion(glm::vec4 const &Heights, glm::vec4 const &Occlusion, float const Height)
|
||||
{
|
||||
auto const cover{std::clamp((Top - Height - COVER_START) / COVER_SPAN, 0.f, 1.f)};
|
||||
auto const sky{Occlusion.x + (Occlusion.y - Occlusion.x) * cover};
|
||||
auto const suntop{smoothstep(-SUN_SOFTNESS, SUN_SOFTNESS, Height - (Top + Occlusion.z))};
|
||||
auto const sununder{smoothstep(-SUN_SOFTNESS, SUN_SOFTNESS, (Top + Occlusion.w) - Height)};
|
||||
auto const top{Heights.x};
|
||||
auto const ceiling{Heights.y};
|
||||
auto const cover{std::clamp((top - Height - COVER_START) / COVER_SPAN, 0.f, 1.f)};
|
||||
auto under{0.f};
|
||||
if (has_ceiling(ceiling))
|
||||
{
|
||||
auto const nearheight{ceiling - BELOW_CEILING};
|
||||
auto const t{std::clamp((Height - Heights.w) / std::max(nearheight - Heights.w, 1e-3f), 0.f, 1.f)};
|
||||
under = Occlusion.z + (Occlusion.y - Occlusion.z) * t;
|
||||
}
|
||||
auto const sky{Occlusion.x + (under - Occlusion.x) * cover};
|
||||
auto const suntop{smoothstep(-SUN_SOFTNESS, SUN_SOFTNESS, Height - (top + Occlusion.w))};
|
||||
auto const sununder{smoothstep(-SUN_SOFTNESS, SUN_SOFTNESS, Heights.z - Height)};
|
||||
return {sky, suntop + (sununder - suntop) * cover};
|
||||
}
|
||||
|
||||
@@ -217,21 +239,19 @@ void sky_occlusion::start(int const Level)
|
||||
auto const count{static_cast<std::size_t>(m_layout.tiles * m_layout.tiles)};
|
||||
m_slots.assign(count, slot{});
|
||||
auto const texels{static_cast<std::size_t>(side) * side};
|
||||
m_heights.assign(texels, NONE_TOP);
|
||||
m_occlusion.assign(texels, glm::vec4{1.f, 1.f, LIT_ABOVE_ALWAYS, LIT_BELOW_ALWAYS});
|
||||
m_heights.assign(texels, NEUTRAL_HEIGHTS);
|
||||
m_occlusion.assign(texels, NEUTRAL_OCCLUSION);
|
||||
auto const tiletexels{static_cast<std::size_t>(m_layout.tile_texels) * m_layout.tile_texels};
|
||||
m_neutralheights.assign(tiletexels, NONE_TOP);
|
||||
m_neutralheights.assign(tiletexels, NEUTRAL_HEIGHTS);
|
||||
m_neutralocclusion.resize(tiletexels * 4);
|
||||
for (std::size_t i = 0; i < tiletexels; ++i)
|
||||
{
|
||||
m_neutralocclusion[i * 4 + 0] = glm::packHalf1x16(1.f);
|
||||
m_neutralocclusion[i * 4 + 1] = glm::packHalf1x16(1.f);
|
||||
m_neutralocclusion[i * 4 + 2] = glm::packHalf1x16(LIT_ABOVE_ALWAYS);
|
||||
m_neutralocclusion[i * 4 + 3] = glm::packHalf1x16(LIT_BELOW_ALWAYS);
|
||||
for (int c = 0; c < 4; ++c)
|
||||
m_neutralocclusion[i * 4 + c] = glm::packHalf1x16(NEUTRAL_OCCLUSION[c]);
|
||||
}
|
||||
for (int index = 0; index < static_cast<int>(count); ++index)
|
||||
{
|
||||
gpu_upload((index % m_layout.tiles) * m_layout.tile_texels, (index / m_layout.tiles) * m_layout.tile_texels, m_layout.tile_texels, m_neutralheights.data(), m_neutralocclusion.data());
|
||||
gpu_upload((index % m_layout.tiles) * m_layout.tile_texels, (index / m_layout.tiles) * m_layout.tile_texels, m_layout.tile_texels, glm::value_ptr(m_neutralheights.front()), m_neutralocclusion.data());
|
||||
}
|
||||
m_rawtop.assign(texels, NONE_TOP);
|
||||
m_rawceiling.assign(texels, NONE_CEILING);
|
||||
@@ -305,10 +325,10 @@ void sky_occlusion::neutral(int const Slot)
|
||||
for (int z = 0; z < px; ++z)
|
||||
{
|
||||
auto const row{static_cast<std::size_t>(z0 + z) * m_side + x0};
|
||||
std::fill_n(m_heights.begin() + row, px, NONE_TOP);
|
||||
std::fill_n(m_occlusion.begin() + row, px, glm::vec4{1.f, 1.f, LIT_ABOVE_ALWAYS, LIT_BELOW_ALWAYS});
|
||||
std::fill_n(m_heights.begin() + row, px, NEUTRAL_HEIGHTS);
|
||||
std::fill_n(m_occlusion.begin() + row, px, NEUTRAL_OCCLUSION);
|
||||
}
|
||||
gpu_upload(x0, z0, px, m_neutralheights.data(), m_neutralocclusion.data());
|
||||
gpu_upload(x0, z0, px, glm::value_ptr(m_neutralheights.front()), m_neutralocclusion.data());
|
||||
++m_uploaded;
|
||||
}
|
||||
|
||||
@@ -327,7 +347,7 @@ void sky_occlusion::apply(tile_result &Result)
|
||||
for (int x = 0; x < px; ++x)
|
||||
{
|
||||
auto const source{static_cast<std::size_t>(z) * px + x};
|
||||
m_heights[row + x] = Result.heights[source];
|
||||
m_heights[row + x] = glm::vec4{Result.heights[source * 4 + 0], Result.heights[source * 4 + 1], Result.heights[source * 4 + 2], Result.heights[source * 4 + 3]};
|
||||
m_occlusion[row + x] = glm::vec4{glm::unpackHalf1x16(Result.occlusion[source * 4 + 0]), glm::unpackHalf1x16(Result.occlusion[source * 4 + 1]),
|
||||
glm::unpackHalf1x16(Result.occlusion[source * 4 + 2]), glm::unpackHalf1x16(Result.occlusion[source * 4 + 3])};
|
||||
}
|
||||
@@ -1077,8 +1097,9 @@ void sky_occlusion::occlude(int const Slot, tile_result &Result)
|
||||
auto const rise{overhead ? 1e6f : keylight.y / across};
|
||||
|
||||
// the share of the sky seen from the height Origin over a texel, the search around it. a ceiling above the origin lets the sky
|
||||
// through below its underside, what has none blocks it from the horizon up to its top
|
||||
auto const sky = [&](int const X, int const Z, float const Origin) {
|
||||
// through below its underside, what has none blocks it from the horizon up to its top. Ground, when given, gets the lowest top
|
||||
// without a ceiling met below the origin (the ground around what stands over the texel), or keeps its value when there's none
|
||||
auto const sky = [&](int const X, int const Z, float const Origin, float *Ground) {
|
||||
float sum{0.f};
|
||||
for (auto const &direction : directions)
|
||||
{
|
||||
@@ -1095,7 +1116,9 @@ void sky_occlusion::occlude(int const Slot, tile_result &Result)
|
||||
high = std::min(high, (c - Origin) / distance);
|
||||
else if (t > Origin)
|
||||
low = std::max(low, (t - Origin) / distance);
|
||||
if (low >= high)
|
||||
else if ((Ground != nullptr) && has_top(t) && (false == has_ceiling(c)))
|
||||
*Ground = std::min(*Ground, t);
|
||||
if ((low >= high) && (Ground == nullptr))
|
||||
break;
|
||||
}
|
||||
sum += std::max(0.f, sky_share(high) - sky_share(low));
|
||||
@@ -1103,7 +1126,7 @@ void sky_occlusion::occlude(int const Slot, tile_result &Result)
|
||||
return sum / static_cast<float>(directions.size());
|
||||
};
|
||||
|
||||
Result.heights.resize(static_cast<std::size_t>(px) * px);
|
||||
Result.heights.resize(static_cast<std::size_t>(px) * px * 4);
|
||||
Result.occlusion.resize(static_cast<std::size_t>(px) * px * 4);
|
||||
for (int z = 0; z < px; ++z)
|
||||
{
|
||||
@@ -1112,18 +1135,22 @@ void sky_occlusion::occlude(int const Slot, tile_result &Result)
|
||||
auto const index{at(x, z)};
|
||||
auto const t0{top[index]};
|
||||
auto const c0{ceiling[index]};
|
||||
glm::vec4 value{1.f, 1.f, LIT_ABOVE_ALWAYS, LIT_BELOW_ALWAYS};
|
||||
auto heights{NEUTRAL_HEIGHTS};
|
||||
auto value{NEUTRAL_OCCLUSION};
|
||||
if (has_top(t0))
|
||||
{
|
||||
heights.x = t0;
|
||||
auto const origin{t0 + ABOVE_TOP};
|
||||
value.x = sky(x, z, origin);
|
||||
// under a top with no ceiling is the inside of what is solid (a hill, a wall seen edge on): no sky, no sun
|
||||
value.x = sky(x, z, origin, nullptr);
|
||||
// under a top with no ceiling is the inside of what is solid (a hill, a wall seen edge on): no sky, no key light
|
||||
value.y = 0.f;
|
||||
value.z = 0.f;
|
||||
heights.z = (sun ? LIT_NEVER_BELOW : LIT_BELOW_ALWAYS);
|
||||
// the key light above the top: the height above which the rays towards it pass over all
|
||||
if (false == sun)
|
||||
value.z = LIT_ABOVE_ALWAYS;
|
||||
value.w = LIT_ABOVE_ALWAYS;
|
||||
else if (false == keyup)
|
||||
value.z = LIT_BELOW_ALWAYS;
|
||||
value.w = LIT_ABOVE_NEVER;
|
||||
else if (false == overhead)
|
||||
{
|
||||
auto shadow{NONE_TOP};
|
||||
@@ -1138,19 +1165,25 @@ void sky_occlusion::occlude(int const Slot, tile_result &Result)
|
||||
continue;
|
||||
shadow = std::max(shadow, top[sample] - drop);
|
||||
}
|
||||
value.z = has_top(shadow) ? std::clamp(shadow - t0, LIT_ABOVE_ALWAYS, LIT_BELOW_ALWAYS) : LIT_ABOVE_ALWAYS;
|
||||
value.w = has_top(shadow) ? std::clamp(shadow - t0, LIT_ABOVE_ALWAYS, LIT_ABOVE_NEVER) : LIT_ABOVE_ALWAYS;
|
||||
}
|
||||
else
|
||||
value.z = LIT_ABOVE_ALWAYS;
|
||||
value.w = LIT_ABOVE_ALWAYS;
|
||||
if (has_ceiling(c0))
|
||||
{
|
||||
// under the ceiling
|
||||
// under the ceiling: the share near it, and the one a metre above the ground around (the deeper the space under the
|
||||
// ceiling, the more of the sky its bottom sees on the sides), which the shading blends by the height of the point
|
||||
heights.y = c0;
|
||||
auto const under{c0 - BELOW_CEILING};
|
||||
value.y = sky(x, z, under);
|
||||
auto ground{std::numeric_limits<float>::max()};
|
||||
value.y = sky(x, z, under, &ground);
|
||||
auto const deep{ground < c0 ? std::clamp(ground + 1.f, c0 - DEEP_BELOW_CEILING_MAX, under) : c0 - DEEP_BELOW_CEILING_UNKNOWN};
|
||||
heights.w = deep;
|
||||
value.z = (deep < under - 0.25f) ? sky(x, z, deep, nullptr) : value.y;
|
||||
if (false == sun)
|
||||
value.w = LIT_BELOW_ALWAYS;
|
||||
heights.z = LIT_BELOW_ALWAYS;
|
||||
else if (false == keyup)
|
||||
value.w = LIT_NEVER_BELOW;
|
||||
heights.z = LIT_NEVER_BELOW;
|
||||
else
|
||||
{
|
||||
// the height below which the rays towards the key light pass under the ceilings, out to the open
|
||||
@@ -1176,18 +1209,16 @@ void sky_occlusion::occlude(int const Slot, tile_result &Result)
|
||||
}
|
||||
}
|
||||
// the rays which don't come out within the reach stay in the tunnel
|
||||
value.w = (out && has_top(limit)) ? std::clamp(limit - t0, LIT_NEVER_BELOW, LIT_BELOW_ALWAYS) : LIT_NEVER_BELOW;
|
||||
heights.z = (out && has_top(limit)) ? limit : LIT_NEVER_BELOW;
|
||||
}
|
||||
}
|
||||
else
|
||||
value.w = (sun ? LIT_NEVER_BELOW : LIT_BELOW_ALWAYS);
|
||||
}
|
||||
auto const target{static_cast<std::size_t>(z) * px + x};
|
||||
Result.heights[target] = t0;
|
||||
Result.occlusion[target * 4 + 0] = glm::packHalf1x16(value.x);
|
||||
Result.occlusion[target * 4 + 1] = glm::packHalf1x16(value.y);
|
||||
Result.occlusion[target * 4 + 2] = glm::packHalf1x16(value.z);
|
||||
Result.occlusion[target * 4 + 3] = glm::packHalf1x16(value.w);
|
||||
for (int c = 0; c < 4; ++c)
|
||||
{
|
||||
Result.heights[target * 4 + c] = heights[c];
|
||||
Result.occlusion[target * 4 + c] = glm::packHalf1x16(value[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1250,7 +1281,8 @@ void sky_occlusion::draw_debug_ui()
|
||||
auto const x{wrap(static_cast<int>(std::floor(wx / texel)), m_side)};
|
||||
auto const z{wrap(static_cast<int>(std::floor(wz / texel)), m_side)};
|
||||
auto const index{static_cast<std::size_t>(z) * m_side + x};
|
||||
auto const top{m_heights[index]};
|
||||
auto const &heights{m_heights[index]};
|
||||
auto const top{heights.x};
|
||||
auto const &occlusion{m_occlusion[index]};
|
||||
float value{0.f};
|
||||
switch (m_previewmode)
|
||||
@@ -1259,10 +1291,11 @@ void sky_occlusion::draw_debug_ui()
|
||||
value = occlusion.x;
|
||||
break;
|
||||
case 2:
|
||||
value = occlusion.y;
|
||||
// near the ground under them
|
||||
value = occlusion.z;
|
||||
break;
|
||||
case 3:
|
||||
value = texel_occlusion(top, occlusion, top + 0.1f).y;
|
||||
value = texel_occlusion(heights, occlusion, top + 0.1f).y;
|
||||
break;
|
||||
default:
|
||||
value = has_top(top) ? std::clamp(0.5f + static_cast<float>(top - camera.y) / 40.f, 0.f, 1.f) : 0.f;
|
||||
|
||||
@@ -117,11 +117,13 @@ class sky_occlusion
|
||||
void draw_debug_ui();
|
||||
|
||||
protected:
|
||||
// the textures of Side x Side texels: the height of the top (one 32 bit float per texel) and the occlusion (four 16 bit floats);
|
||||
// false when they can't be made
|
||||
// the textures of Side x Side texels: the heights (four 32 bit floats per texel: the top, the ceiling, the height below which the
|
||||
// key light comes in under the ceiling, the height the deep share of the sky under the ceiling is worked out at) and the occlusion
|
||||
// (four 16 bit floats: the share of the sky above the top, under the ceiling near it and deep, the height above the top over which
|
||||
// the key light comes); false when they can't be made
|
||||
virtual bool gpu_allocate(int const Side) = 0;
|
||||
virtual void gpu_release() = 0;
|
||||
// copies a square of Size x Size texels at X, Y of the textures: Heights one float per texel, Occlusion four halves per texel,
|
||||
// copies a square of Size x Size texels at X, Y of the textures: Heights four floats per texel, Occlusion four halves per texel,
|
||||
// rows along x, one after another along z
|
||||
virtual void gpu_upload(int const X, int const Y, int const Size, float const *Heights, std::uint16_t const *Occlusion) = 0;
|
||||
|
||||
@@ -141,7 +143,7 @@ class sky_occlusion
|
||||
std::uint32_t generation{0};
|
||||
std::vector<triangle> triangles;
|
||||
};
|
||||
// what it gives back: the top and the occlusion of the texels of a tile
|
||||
// what it gives back: the heights (four per texel) and the occlusion of the texels of a tile
|
||||
struct tile_result
|
||||
{
|
||||
int slot{0};
|
||||
@@ -193,11 +195,11 @@ class sky_occlusion
|
||||
glm::ivec2 m_cameratile{0};
|
||||
glm::dvec3 m_camera{0.0};
|
||||
glm::vec3 m_keylight{0.f, 1.f, 0.f}; // the direction the thread was given last
|
||||
// the copy of the maps the cpu samples (sample()): the top, and the occlusion as floats
|
||||
std::vector<float> m_heights;
|
||||
// the copy of the maps the cpu samples (sample()): the heights, and the occlusion as floats
|
||||
std::vector<glm::vec4> m_heights;
|
||||
std::vector<glm::vec4> m_occlusion;
|
||||
// neutral tiles, uploaded when a tile comes into the square
|
||||
std::vector<float> m_neutralheights;
|
||||
std::vector<glm::vec4> m_neutralheights;
|
||||
std::vector<std::uint16_t> m_neutralocclusion;
|
||||
std::size_t m_checkslot{0}; // the slot whose signature is checked next
|
||||
scene::basic_region const *m_region{nullptr};
|
||||
|
||||
@@ -42,11 +42,11 @@ opengl46_sky_occlusion::~opengl46_sky_occlusion()
|
||||
void opengl46_sky_occlusion::init()
|
||||
{
|
||||
// a sampler with no texture to read from is undefined, also where the shading doesn't read it
|
||||
m_emptyheights = make_map(GL_R32F, 1);
|
||||
float const none{-1.0e4f};
|
||||
glClearTexImage(m_emptyheights, 0, GL_RED, GL_FLOAT, &none);
|
||||
m_emptyheights = make_map(GL_RGBA32F, 1);
|
||||
float const none[4]{-1.0e4f, 1.0e4f, 1.0e4f, -1.0e4f};
|
||||
glClearTexImage(m_emptyheights, 0, GL_RGBA, GL_FLOAT, none);
|
||||
m_emptyocclusion = make_map(GL_RGBA16F, 1);
|
||||
float const open[4]{1.f, 1.f, -1000.f, 1000.f};
|
||||
float const open[4]{1.f, 1.f, 1.f, -1000.f};
|
||||
glClearTexImage(m_emptyocclusion, 0, GL_RGBA, GL_FLOAT, open);
|
||||
bind();
|
||||
}
|
||||
@@ -60,7 +60,7 @@ void opengl46_sky_occlusion::bind() const
|
||||
bool opengl46_sky_occlusion::gpu_allocate(int const Side)
|
||||
{
|
||||
gpu_release();
|
||||
m_heights = make_map(GL_R32F, Side);
|
||||
m_heights = make_map(GL_RGBA32F, Side);
|
||||
m_occlusion = make_map(GL_RGBA16F, Side);
|
||||
if ((m_heights == 0) || (m_occlusion == 0))
|
||||
return false;
|
||||
@@ -90,7 +90,7 @@ void opengl46_sky_occlusion::gpu_upload(int const X, int const Y, int const Size
|
||||
glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
glTextureSubImage2D(m_heights, 0, X, Y, Size, Size, GL_RED, GL_FLOAT, Heights);
|
||||
glTextureSubImage2D(m_heights, 0, X, Y, Size, Size, GL_RGBA, GL_FLOAT, Heights);
|
||||
glTextureSubImage2D(m_occlusion, 0, X, Y, Size, Size, GL_RGBA, GL_HALF_FLOAT, Occlusion);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, static_cast<GLuint>(unpack));
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
|
||||
|
||||
@@ -684,7 +684,7 @@ bool vulkan14_renderer::init_scene(std::string &Reason)
|
||||
}
|
||||
return true;
|
||||
};
|
||||
if ((false == standin(scene.skyocclusion_heights_empty, VK_FORMAT_R32_SFLOAT, "empty sky occlusion heights")) || (false == standin(scene.skyocclusion_empty, VK_FORMAT_R16G16B16A16_SFLOAT, "empty sky occlusion")))
|
||||
if ((false == standin(scene.skyocclusion_heights_empty, VK_FORMAT_R32G32B32A32_SFLOAT, "empty sky occlusion heights")) || (false == standin(scene.skyocclusion_empty, VK_FORMAT_R16G16B16A16_SFLOAT, "empty sky occlusion")))
|
||||
{
|
||||
Reason = "no stand-ins of the maps of the occlusion of the sky";
|
||||
return false;
|
||||
|
||||
@@ -63,7 +63,7 @@ bool sky_occlusion_maps::gpu_allocate(int const Side)
|
||||
}
|
||||
return true;
|
||||
};
|
||||
if ((false == make(m_heights, VK_FORMAT_R32_SFLOAT, "sky occlusion heights")) || (false == make(m_occlusion, VK_FORMAT_R16G16B16A16_SFLOAT, "sky occlusion")))
|
||||
if ((false == make(m_heights, VK_FORMAT_R32G32B32A32_SFLOAT, "sky occlusion heights")) || (false == make(m_occlusion, VK_FORMAT_R16G16B16A16_SFLOAT, "sky occlusion")))
|
||||
{
|
||||
let_go();
|
||||
return false;
|
||||
@@ -99,9 +99,9 @@ void sky_occlusion_maps::gpu_upload(int const X, int const Y, int const Size, fl
|
||||
}
|
||||
auto const texels{static_cast<std::size_t>(Size) * Size};
|
||||
auto const offset{m_data.size()};
|
||||
m_data.resize(offset + texels * (sizeof(float) + 4 * sizeof(std::uint16_t)));
|
||||
std::memcpy(m_data.data() + offset, Heights, texels * sizeof(float));
|
||||
std::memcpy(m_data.data() + offset + texels * sizeof(float), Occlusion, texels * 4 * sizeof(std::uint16_t));
|
||||
m_data.resize(offset + texels * (4 * sizeof(float) + 4 * sizeof(std::uint16_t)));
|
||||
std::memcpy(m_data.data() + offset, Heights, texels * 4 * sizeof(float));
|
||||
std::memcpy(m_data.data() + offset + texels * 4 * sizeof(float), Occlusion, texels * 4 * sizeof(std::uint16_t));
|
||||
m_squares.push_back(square{X, Y, Size, offset});
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ void sky_occlusion_maps::flush(command_stream *Commands)
|
||||
region.imageOffset = {entry.x, entry.y, 0};
|
||||
region.imageExtent = {static_cast<std::uint32_t>(entry.size), static_cast<std::uint32_t>(entry.size), 1};
|
||||
heights.push_back(region);
|
||||
region.bufferOffset += static_cast<VkDeviceSize>(entry.size) * entry.size * sizeof(float);
|
||||
region.bufferOffset += static_cast<VkDeviceSize>(entry.size) * entry.size * 4 * sizeof(float);
|
||||
occlusion.push_back(region);
|
||||
}
|
||||
auto copy = [&](image &Target, std::vector<VkBufferImageCopy2> const &Regions) {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// the occlusion of the sky and of the sun by the scenery around the camera (gfx.skyvisibility, gfx::sky_occlusion, the track T):
|
||||
// toroidal maps of the square around the camera, read texel by texel. SKY_OCCLUSION_HEIGHT_TEX holds the height of the top of the
|
||||
// scenery over a texel (the highest surface, world space), SKY_OCCLUSION_TEX for the texel: x the share of the sky a surface facing
|
||||
// up sees above the top, y the same under the ceiling (the vault of a tunnel, the deck of a bridge), z the height above the top over
|
||||
// which the key light (the sun, the moon) comes, w the height above the top under which it comes in under the ceilings.
|
||||
// toroidal maps of the square around the camera, read texel by texel. SKY_OCCLUSION_HEIGHT_TEX holds for a texel, world space: x the
|
||||
// height of the top of the scenery (the highest surface), y of the ceiling (the lowest surface facing down: the vault of a tunnel, the
|
||||
// deck of a bridge; 1e4 for none), z the height under the ceiling below which the key light (the sun, the moon) comes in, w the height
|
||||
// the deep share of the sky under the ceiling was worked out at (a metre above the ground around). SKY_OCCLUSION_TEX: x the share of
|
||||
// the sky above the top, y under the ceiling near it, z deep under it, w the height above the top over which the key light comes.
|
||||
// the same as gfx::sky_occlusion::sample() of rendering/common/skyocclusion.cpp, which the cpu works out the light around the
|
||||
// vehicles with: a change here goes there as well
|
||||
#ifndef SKY_OCCLUSION_GLSL
|
||||
@@ -11,12 +12,27 @@
|
||||
layout(binding = SKY_OCCLUSION_HEIGHT_TEX) uniform sampler2D sky_occlusion_height;
|
||||
layout(binding = SKY_OCCLUSION_TEX) uniform sampler2D sky_occlusion_map;
|
||||
|
||||
// a point this far below the top of a texel is under it, fully this much further; half the height over which the key light comes
|
||||
// in at the edge of its shadow
|
||||
// a point this far below the top of a texel is under it, fully this much further; how far below the ceiling the near share under
|
||||
// it was worked out; half the height over which the key light comes in at the edge of its shadow
|
||||
const float SKY_OCCLUSION_COVER_START = 0.75;
|
||||
const float SKY_OCCLUSION_COVER_SPAN = 1.0;
|
||||
const float SKY_OCCLUSION_BELOW_CEILING = 2.5;
|
||||
const float SKY_OCCLUSION_SUN_SOFTNESS = 0.6;
|
||||
|
||||
// the coordinates of the gather of the four texels around a world point (offset from the camera) and the bilinear weights of
|
||||
// the texels in the order of a gather: (0, 1), (1, 1), (1, 0), (0, 0). false out of the square (Fade 1)
|
||||
bool sky_occlusion_texels(vec2 world, out vec2 uv, out vec4 weights, out float fade)
|
||||
{
|
||||
fade = clamp((max(abs(world.x - sky_occlusion_center.x), abs(world.y - sky_occlusion_center.y)) - sky_occlusion_params.z) / max(sky_occlusion_params.w, 1e-3), 0.0, 1.0);
|
||||
float texel = sky_occlusion_params.x / sky_occlusion_params.y;
|
||||
vec2 coords = (world + sky_occlusion_origin.xy) / texel - 0.5;
|
||||
vec2 base = floor(coords);
|
||||
vec2 f = coords - base;
|
||||
uv = (base + 1.0) / sky_occlusion_params.y;
|
||||
weights = vec4((1.0 - f.x) * f.y, f.x * f.y, f.x * (1.0 - f.y), (1.0 - f.x) * (1.0 - f.y));
|
||||
return fade < 1.0;
|
||||
}
|
||||
|
||||
// the share of the sky (x) and of the key light (y) a point gets, 0..1. World: its offset from the camera along the world axes,
|
||||
// Worldnormal: the normal of its surface in the world space (zero for a point in the air), the texels are read a little in front of
|
||||
// the surface (a wall reads the ground in front of it, not the roof above it)
|
||||
@@ -24,30 +40,32 @@ vec2 sky_occlusion_world(vec3 world, vec3 worldnormal)
|
||||
{
|
||||
if (sky_occlusion_origin.w <= 0.0)
|
||||
return vec2(1.0);
|
||||
float fade = clamp((max(abs(world.x - sky_occlusion_center.x), abs(world.z - sky_occlusion_center.y)) - sky_occlusion_params.z) / max(sky_occlusion_params.w, 1e-3), 0.0, 1.0);
|
||||
if (fade >= 1.0)
|
||||
vec3 point = world + worldnormal * (0.75 * sky_occlusion_params.x / sky_occlusion_params.y);
|
||||
vec2 uv;
|
||||
vec4 weights;
|
||||
float fade;
|
||||
if (false == sky_occlusion_texels(point.xz, uv, weights, fade))
|
||||
return vec2(1.0);
|
||||
float texel = sky_occlusion_params.x / sky_occlusion_params.y;
|
||||
vec3 point = world + worldnormal * (0.75 * texel);
|
||||
vec2 coords = (point.xz + sky_occlusion_origin.xy) / texel - 0.5;
|
||||
vec2 base = floor(coords);
|
||||
vec2 f = coords - base;
|
||||
vec2 uv = (base + 1.0) / sky_occlusion_params.y;
|
||||
// the four texels around the point, each with its own top: under one of them a point gets what is under it, above it what is
|
||||
// above, and the four are blended as bilinear filtering would
|
||||
// the four texels around the point, each with its own heights: under the top of one a point gets what is under it (between the
|
||||
// near and the deep share, by its height), above it what is above, and the four are blended as bilinear filtering would
|
||||
vec4 tops = textureGather(sky_occlusion_height, uv, 0);
|
||||
vec4 ceilings = textureGather(sky_occlusion_height, uv, 1);
|
||||
vec4 litbelow = textureGather(sky_occlusion_height, uv, 2);
|
||||
vec4 deeps = textureGather(sky_occlusion_height, uv, 3);
|
||||
vec4 skytop = textureGather(sky_occlusion_map, uv, 0);
|
||||
vec4 skyunder = textureGather(sky_occlusion_map, uv, 1);
|
||||
vec4 litabove = textureGather(sky_occlusion_map, uv, 2);
|
||||
vec4 litbelow = textureGather(sky_occlusion_map, uv, 3);
|
||||
float height = point.y + sky_occlusion_origin.z;
|
||||
vec4 cover = clamp((tops - vec4(height) - SKY_OCCLUSION_COVER_START) / SKY_OCCLUSION_COVER_SPAN, 0.0, 1.0);
|
||||
vec4 skynear = textureGather(sky_occlusion_map, uv, 1);
|
||||
vec4 skydeep = textureGather(sky_occlusion_map, uv, 2);
|
||||
vec4 litabove = textureGather(sky_occlusion_map, uv, 3);
|
||||
vec4 height = vec4(point.y + sky_occlusion_origin.z);
|
||||
vec4 cover = clamp((tops - height - SKY_OCCLUSION_COVER_START) / SKY_OCCLUSION_COVER_SPAN, 0.0, 1.0);
|
||||
vec4 nearheight = ceilings - SKY_OCCLUSION_BELOW_CEILING;
|
||||
vec4 skyunder = mix(skydeep, skynear, clamp((height - deeps) / max(nearheight - deeps, vec4(1e-3)), 0.0, 1.0));
|
||||
// no ceiling: the inside of what is solid
|
||||
skyunder *= step(ceilings, vec4(5000.0));
|
||||
vec4 sky = mix(skytop, skyunder, cover);
|
||||
vec4 suntop = smoothstep(vec4(-SKY_OCCLUSION_SUN_SOFTNESS), vec4(SKY_OCCLUSION_SUN_SOFTNESS), vec4(height) - (tops + litabove));
|
||||
vec4 sununder = smoothstep(vec4(-SKY_OCCLUSION_SUN_SOFTNESS), vec4(SKY_OCCLUSION_SUN_SOFTNESS), (tops + litbelow) - vec4(height));
|
||||
vec4 suntop = smoothstep(vec4(-SKY_OCCLUSION_SUN_SOFTNESS), vec4(SKY_OCCLUSION_SUN_SOFTNESS), height - (tops + litabove));
|
||||
vec4 sununder = smoothstep(vec4(-SKY_OCCLUSION_SUN_SOFTNESS), vec4(SKY_OCCLUSION_SUN_SOFTNESS), litbelow - height);
|
||||
vec4 sun = mix(suntop, sununder, cover);
|
||||
// the order of the texels of a gather: (0, 1), (1, 1), (1, 0), (0, 0)
|
||||
vec4 weights = vec4((1.0 - f.x) * f.y, f.x * f.y, f.x * (1.0 - f.y), (1.0 - f.x) * (1.0 - f.y));
|
||||
return mix(vec2(dot(sky, weights), dot(sun, weights)), vec2(1.0), fade);
|
||||
}
|
||||
|
||||
@@ -57,16 +75,13 @@ float sky_occlusion_cover(vec3 world)
|
||||
{
|
||||
if (sky_occlusion_origin.w <= 0.0)
|
||||
return 0.0;
|
||||
float fade = clamp((max(abs(world.x - sky_occlusion_center.x), abs(world.z - sky_occlusion_center.y)) - sky_occlusion_params.z) / max(sky_occlusion_params.w, 1e-3), 0.0, 1.0);
|
||||
if (fade >= 1.0)
|
||||
vec2 uv;
|
||||
vec4 weights;
|
||||
float fade;
|
||||
if (false == sky_occlusion_texels(world.xz, uv, weights, fade))
|
||||
return 0.0;
|
||||
float texel = sky_occlusion_params.x / sky_occlusion_params.y;
|
||||
vec2 coords = (world.xz + sky_occlusion_origin.xy) / texel - 0.5;
|
||||
vec2 base = floor(coords);
|
||||
vec2 f = coords - base;
|
||||
vec4 tops = textureGather(sky_occlusion_height, (base + 1.0) / sky_occlusion_params.y, 0);
|
||||
vec4 tops = textureGather(sky_occlusion_height, uv, 0);
|
||||
vec4 cover = clamp((tops - vec4(world.y + sky_occlusion_origin.z) - SKY_OCCLUSION_COVER_START) / SKY_OCCLUSION_COVER_SPAN, 0.0, 1.0);
|
||||
vec4 weights = vec4((1.0 - f.x) * f.y, f.x * f.y, f.x * (1.0 - f.y), (1.0 - f.x) * (1.0 - f.y));
|
||||
return dot(cover, weights) * (1.0 - fade);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// the occlusion of the sky and of the sun by the scenery around the camera (gfx.skyvisibility, gfx::sky_occlusion, the track T):
|
||||
// toroidal maps of the square around the camera, read texel by texel. SKY_OCCLUSION_HEIGHT_TEX holds the height of the top of the
|
||||
// scenery over a texel (the highest surface, world space), SKY_OCCLUSION_TEX for the texel: x the share of the sky a surface facing
|
||||
// up sees above the top, y the same under the ceiling (the vault of a tunnel, the deck of a bridge), z the height above the top over
|
||||
// which the key light (the sun, the moon) comes, w the height above the top under which it comes in under the ceilings.
|
||||
// toroidal maps of the square around the camera, read texel by texel. SKY_OCCLUSION_HEIGHT_TEX holds for a texel, world space: x the
|
||||
// height of the top of the scenery (the highest surface), y of the ceiling (the lowest surface facing down: the vault of a tunnel, the
|
||||
// deck of a bridge; 1e4 for none), z the height under the ceiling below which the key light (the sun, the moon) comes in, w the height
|
||||
// the deep share of the sky under the ceiling was worked out at (a metre above the ground around). SKY_OCCLUSION_TEX: x the share of
|
||||
// the sky above the top, y under the ceiling near it, z deep under it, w the height above the top over which the key light comes.
|
||||
// the same as gfx::sky_occlusion::sample() of rendering/common/skyocclusion.cpp, which the cpu works out the light around the
|
||||
// vehicles with: a change here goes there as well
|
||||
#ifndef SKY_OCCLUSION_GLSL
|
||||
@@ -11,12 +12,27 @@
|
||||
layout(set = PASS_SET, binding = SKY_OCCLUSION_HEIGHT_TEX) uniform sampler2D sky_occlusion_height;
|
||||
layout(set = PASS_SET, binding = SKY_OCCLUSION_TEX) uniform sampler2D sky_occlusion_map;
|
||||
|
||||
// a point this far below the top of a texel is under it, fully this much further; half the height over which the key light comes
|
||||
// in at the edge of its shadow
|
||||
// a point this far below the top of a texel is under it, fully this much further; how far below the ceiling the near share under
|
||||
// it was worked out; half the height over which the key light comes in at the edge of its shadow
|
||||
const float SKY_OCCLUSION_COVER_START = 0.75;
|
||||
const float SKY_OCCLUSION_COVER_SPAN = 1.0;
|
||||
const float SKY_OCCLUSION_BELOW_CEILING = 2.5;
|
||||
const float SKY_OCCLUSION_SUN_SOFTNESS = 0.6;
|
||||
|
||||
// the coordinates of the gather of the four texels around a world point (offset from the camera) and the bilinear weights of
|
||||
// the texels in the order of a gather: (0, 1), (1, 1), (1, 0), (0, 0). false out of the square (Fade 1)
|
||||
bool sky_occlusion_texels(vec2 world, out vec2 uv, out vec4 weights, out float fade)
|
||||
{
|
||||
fade = clamp((max(abs(world.x - sky_occlusion_center.x), abs(world.y - sky_occlusion_center.y)) - sky_occlusion_params.z) / max(sky_occlusion_params.w, 1e-3), 0.0, 1.0);
|
||||
float texel = sky_occlusion_params.x / sky_occlusion_params.y;
|
||||
vec2 coords = (world + sky_occlusion_origin.xy) / texel - 0.5;
|
||||
vec2 base = floor(coords);
|
||||
vec2 f = coords - base;
|
||||
uv = (base + 1.0) / sky_occlusion_params.y;
|
||||
weights = vec4((1.0 - f.x) * f.y, f.x * f.y, f.x * (1.0 - f.y), (1.0 - f.x) * (1.0 - f.y));
|
||||
return fade < 1.0;
|
||||
}
|
||||
|
||||
// the share of the sky (x) and of the key light (y) a point gets, 0..1. World: its offset from the camera along the world axes,
|
||||
// Worldnormal: the normal of its surface in the world space (zero for a point in the air), the texels are read a little in front of
|
||||
// the surface (a wall reads the ground in front of it, not the roof above it)
|
||||
@@ -24,30 +40,32 @@ vec2 sky_occlusion_world(vec3 world, vec3 worldnormal)
|
||||
{
|
||||
if (sky_occlusion_origin.w <= 0.0)
|
||||
return vec2(1.0);
|
||||
float fade = clamp((max(abs(world.x - sky_occlusion_center.x), abs(world.z - sky_occlusion_center.y)) - sky_occlusion_params.z) / max(sky_occlusion_params.w, 1e-3), 0.0, 1.0);
|
||||
if (fade >= 1.0)
|
||||
vec3 point = world + worldnormal * (0.75 * sky_occlusion_params.x / sky_occlusion_params.y);
|
||||
vec2 uv;
|
||||
vec4 weights;
|
||||
float fade;
|
||||
if (false == sky_occlusion_texels(point.xz, uv, weights, fade))
|
||||
return vec2(1.0);
|
||||
float texel = sky_occlusion_params.x / sky_occlusion_params.y;
|
||||
vec3 point = world + worldnormal * (0.75 * texel);
|
||||
vec2 coords = (point.xz + sky_occlusion_origin.xy) / texel - 0.5;
|
||||
vec2 base = floor(coords);
|
||||
vec2 f = coords - base;
|
||||
vec2 uv = (base + 1.0) / sky_occlusion_params.y;
|
||||
// the four texels around the point, each with its own top: under one of them a point gets what is under it, above it what is
|
||||
// above, and the four are blended as bilinear filtering would
|
||||
// the four texels around the point, each with its own heights: under the top of one a point gets what is under it (between the
|
||||
// near and the deep share, by its height), above it what is above, and the four are blended as bilinear filtering would
|
||||
vec4 tops = textureGather(sky_occlusion_height, uv, 0);
|
||||
vec4 ceilings = textureGather(sky_occlusion_height, uv, 1);
|
||||
vec4 litbelow = textureGather(sky_occlusion_height, uv, 2);
|
||||
vec4 deeps = textureGather(sky_occlusion_height, uv, 3);
|
||||
vec4 skytop = textureGather(sky_occlusion_map, uv, 0);
|
||||
vec4 skyunder = textureGather(sky_occlusion_map, uv, 1);
|
||||
vec4 litabove = textureGather(sky_occlusion_map, uv, 2);
|
||||
vec4 litbelow = textureGather(sky_occlusion_map, uv, 3);
|
||||
float height = point.y + sky_occlusion_origin.z;
|
||||
vec4 cover = clamp((tops - vec4(height) - SKY_OCCLUSION_COVER_START) / SKY_OCCLUSION_COVER_SPAN, 0.0, 1.0);
|
||||
vec4 skynear = textureGather(sky_occlusion_map, uv, 1);
|
||||
vec4 skydeep = textureGather(sky_occlusion_map, uv, 2);
|
||||
vec4 litabove = textureGather(sky_occlusion_map, uv, 3);
|
||||
vec4 height = vec4(point.y + sky_occlusion_origin.z);
|
||||
vec4 cover = clamp((tops - height - SKY_OCCLUSION_COVER_START) / SKY_OCCLUSION_COVER_SPAN, 0.0, 1.0);
|
||||
vec4 nearheight = ceilings - SKY_OCCLUSION_BELOW_CEILING;
|
||||
vec4 skyunder = mix(skydeep, skynear, clamp((height - deeps) / max(nearheight - deeps, vec4(1e-3)), 0.0, 1.0));
|
||||
// no ceiling: the inside of what is solid
|
||||
skyunder *= step(ceilings, vec4(5000.0));
|
||||
vec4 sky = mix(skytop, skyunder, cover);
|
||||
vec4 suntop = smoothstep(vec4(-SKY_OCCLUSION_SUN_SOFTNESS), vec4(SKY_OCCLUSION_SUN_SOFTNESS), vec4(height) - (tops + litabove));
|
||||
vec4 sununder = smoothstep(vec4(-SKY_OCCLUSION_SUN_SOFTNESS), vec4(SKY_OCCLUSION_SUN_SOFTNESS), (tops + litbelow) - vec4(height));
|
||||
vec4 suntop = smoothstep(vec4(-SKY_OCCLUSION_SUN_SOFTNESS), vec4(SKY_OCCLUSION_SUN_SOFTNESS), height - (tops + litabove));
|
||||
vec4 sununder = smoothstep(vec4(-SKY_OCCLUSION_SUN_SOFTNESS), vec4(SKY_OCCLUSION_SUN_SOFTNESS), litbelow - height);
|
||||
vec4 sun = mix(suntop, sununder, cover);
|
||||
// the order of the texels of a gather: (0, 1), (1, 1), (1, 0), (0, 0)
|
||||
vec4 weights = vec4((1.0 - f.x) * f.y, f.x * f.y, f.x * (1.0 - f.y), (1.0 - f.x) * (1.0 - f.y));
|
||||
return mix(vec2(dot(sky, weights), dot(sun, weights)), vec2(1.0), fade);
|
||||
}
|
||||
|
||||
@@ -57,16 +75,13 @@ float sky_occlusion_cover(vec3 world)
|
||||
{
|
||||
if (sky_occlusion_origin.w <= 0.0)
|
||||
return 0.0;
|
||||
float fade = clamp((max(abs(world.x - sky_occlusion_center.x), abs(world.z - sky_occlusion_center.y)) - sky_occlusion_params.z) / max(sky_occlusion_params.w, 1e-3), 0.0, 1.0);
|
||||
if (fade >= 1.0)
|
||||
vec2 uv;
|
||||
vec4 weights;
|
||||
float fade;
|
||||
if (false == sky_occlusion_texels(world.xz, uv, weights, fade))
|
||||
return 0.0;
|
||||
float texel = sky_occlusion_params.x / sky_occlusion_params.y;
|
||||
vec2 coords = (world.xz + sky_occlusion_origin.xy) / texel - 0.5;
|
||||
vec2 base = floor(coords);
|
||||
vec2 f = coords - base;
|
||||
vec4 tops = textureGather(sky_occlusion_height, (base + 1.0) / sky_occlusion_params.y, 0);
|
||||
vec4 tops = textureGather(sky_occlusion_height, uv, 0);
|
||||
vec4 cover = clamp((tops - vec4(world.y + sky_occlusion_origin.z) - SKY_OCCLUSION_COVER_START) / SKY_OCCLUSION_COVER_SPAN, 0.0, 1.0);
|
||||
vec4 weights = vec4((1.0 - f.x) * f.y, f.x * f.y, f.x * (1.0 - f.y), (1.0 - f.x) * (1.0 - f.y));
|
||||
return dot(cover, weights) * (1.0 - fade);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user