mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-14 08:16:13 +01:00
Smoothest operator
- Implement RogueLogix's normal-dependent smooth lighting function - Uses a lot of fetches, so I imagine occupancy is kinda bad
This commit is contained in:
parent
ef2bb09fcd
commit
b9a51d0e5f
3 changed files with 114 additions and 1 deletions
|
@ -1,3 +1,9 @@
|
|||
// TODO: Add config for light smoothness. Should work at a compile flag level
|
||||
|
||||
/// Get the light at the given world position from the given normal.
|
||||
/// This may be interpolated for smooth lighting.
|
||||
bool flw_light(vec3 worldPos, vec3 normal, out vec2 light);
|
||||
|
||||
/// Get the light at the given world position.
|
||||
/// This may be interpolated for smooth lighting.
|
||||
bool flw_light(vec3 worldPos, out vec2 light);
|
||||
|
|
|
@ -125,3 +125,110 @@ bool flw_light(vec3 worldPos, out vec2 lightCoord) {
|
|||
return true;
|
||||
}
|
||||
|
||||
uint _flw_lightIndex(in uvec3 p) {
|
||||
return p.x + p.z * 3u + p.y * 9u;
|
||||
}
|
||||
|
||||
/// Premtively collect all light in a 3x3x3 area centered on our block.
|
||||
/// Depending on the normal, we won't use all the data, but fetching on demand will have many duplicated fetches.
|
||||
vec2[27] _flw_lightFetch3x3x3(uint sectionOffset, ivec3 blockInSectionPos) {
|
||||
vec2[27] lights;
|
||||
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
for (int z = -1; z <= 1; z++) {
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
lights[_flw_lightIndex(uvec3(x + 1, y + 1, z + 1))] = _flw_lightAt(sectionOffset, uvec3(blockInSectionPos + ivec3(x, y, z)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lights;
|
||||
}
|
||||
|
||||
/// Calculate the light for a direction by averaging the light at the corners of the block.
|
||||
///
|
||||
/// To make this reusable across directions, c00..c11 choose what values relative to each corner to use.
|
||||
/// e.g. (0, 0, 0) (0, 0, 1) (0, 1, 0) (0, 1, 1) would give you the light coming from -x at each corner.
|
||||
/// In general, to get the light for a particular direction, you fix the x, y, or z coordinate of the c values, and permutate 0 and 1 for the other two.
|
||||
/// Fixing the x coordinate to 0 gives you the light from -x, 1 gives you the light from +x.
|
||||
///
|
||||
/// @param lights The light data for the 3x3x3 area.
|
||||
/// @param interpolant The position within the center block.
|
||||
/// @param c00..c11 4 offsets to determine which "direction" we are averaging.
|
||||
vec2 _flw_lightForDirection(in vec2[27] lights, in vec3 interpolant, in uvec3 c00, in uvec3 c01, in uvec3 c10, in uvec3 c11) {
|
||||
|
||||
vec2 light000 = lights[_flw_lightIndex(c00 + uvec3(0u, 0u, 0u))] + lights[_flw_lightIndex(c01 + uvec3(0u, 0u, 0u))] + lights[_flw_lightIndex(c10 + uvec3(0u, 0u, 0u))] + lights[_flw_lightIndex(c11 + uvec3(0u, 0u, 0u))];
|
||||
vec2 light001 = lights[_flw_lightIndex(c00 + uvec3(0u, 0u, 1u))] + lights[_flw_lightIndex(c01 + uvec3(0u, 0u, 1u))] + lights[_flw_lightIndex(c10 + uvec3(0u, 0u, 1u))] + lights[_flw_lightIndex(c11 + uvec3(0u, 0u, 1u))];
|
||||
vec2 light010 = lights[_flw_lightIndex(c00 + uvec3(0u, 1u, 0u))] + lights[_flw_lightIndex(c01 + uvec3(0u, 1u, 0u))] + lights[_flw_lightIndex(c10 + uvec3(0u, 1u, 0u))] + lights[_flw_lightIndex(c11 + uvec3(0u, 1u, 0u))];
|
||||
vec2 light011 = lights[_flw_lightIndex(c00 + uvec3(0u, 1u, 1u))] + lights[_flw_lightIndex(c01 + uvec3(0u, 1u, 1u))] + lights[_flw_lightIndex(c10 + uvec3(0u, 1u, 1u))] + lights[_flw_lightIndex(c11 + uvec3(0u, 1u, 1u))];
|
||||
vec2 light100 = lights[_flw_lightIndex(c00 + uvec3(1u, 0u, 0u))] + lights[_flw_lightIndex(c01 + uvec3(1u, 0u, 0u))] + lights[_flw_lightIndex(c10 + uvec3(1u, 0u, 0u))] + lights[_flw_lightIndex(c11 + uvec3(1u, 0u, 0u))];
|
||||
vec2 light101 = lights[_flw_lightIndex(c00 + uvec3(1u, 0u, 1u))] + lights[_flw_lightIndex(c01 + uvec3(1u, 0u, 1u))] + lights[_flw_lightIndex(c10 + uvec3(1u, 0u, 1u))] + lights[_flw_lightIndex(c11 + uvec3(1u, 0u, 1u))];
|
||||
vec2 light110 = lights[_flw_lightIndex(c00 + uvec3(1u, 1u, 0u))] + lights[_flw_lightIndex(c01 + uvec3(1u, 1u, 0u))] + lights[_flw_lightIndex(c10 + uvec3(1u, 1u, 0u))] + lights[_flw_lightIndex(c11 + uvec3(1u, 1u, 0u))];
|
||||
vec2 light111 = lights[_flw_lightIndex(c00 + uvec3(1u, 1u, 1u))] + lights[_flw_lightIndex(c01 + uvec3(1u, 1u, 1u))] + lights[_flw_lightIndex(c10 + uvec3(1u, 1u, 1u))] + lights[_flw_lightIndex(c11 + uvec3(1u, 1u, 1u))];
|
||||
|
||||
vec2 light00 = mix(light000, light001, interpolant.z);
|
||||
vec2 light01 = mix(light010, light011, interpolant.z);
|
||||
vec2 light10 = mix(light100, light101, interpolant.z);
|
||||
vec2 light11 = mix(light110, light111, interpolant.z);
|
||||
|
||||
vec2 light0 = mix(light00, light01, interpolant.y);
|
||||
vec2 light1 = mix(light10, light11, interpolant.y);
|
||||
|
||||
// Divide by 60 (15 * 4) to normalize.
|
||||
return mix(light0, light1, interpolant.x) / 60.;
|
||||
}
|
||||
|
||||
bool flw_light(vec3 worldPos, vec3 normal, out vec2 lightCoord) {
|
||||
// Always use the section of the block we are contained in to ensure accuracy.
|
||||
// We don't want to interpolate between sections, but also we might not be able
|
||||
// to rely on the existence neighboring sections, so don't do any extra rounding here.
|
||||
ivec3 blockPos = ivec3(floor(worldPos));
|
||||
|
||||
uint lightSectionIndex;
|
||||
if (_flw_chunkCoordToSectionIndex(blockPos >> 4, lightSectionIndex)) {
|
||||
return false;
|
||||
}
|
||||
// The offset of the section in the light buffer.
|
||||
uint sectionOffset = lightSectionIndex * _FLW_LIGHT_SECTION_SIZE_INTS;
|
||||
|
||||
// The block's position in the section adjusted into 18x18x18 space
|
||||
ivec3 blockInSectionPos = (blockPos & 0xF) + 1;
|
||||
|
||||
// Fetch everything in a 3x3x3 area centered around the block.
|
||||
vec2[27] lights = _flw_lightFetch3x3x3(sectionOffset, blockInSectionPos);
|
||||
|
||||
vec3 interpolant = fract(worldPos);
|
||||
|
||||
vec2 lightX;
|
||||
if (normal.x > 0) {
|
||||
lightX = _flw_lightForDirection(lights, interpolant, uvec3(1u, 0u, 0u), uvec3(1u, 0u, 1u), uvec3(1u, 1u, 0u), uvec3(1u, 1u, 1u));
|
||||
} else if (normal.x < 0) {
|
||||
lightX = _flw_lightForDirection(lights, interpolant, uvec3(0u, 0u, 0u), uvec3(0u, 0u, 1u), uvec3(0u, 1u, 0u), uvec3(0u, 1u, 1u));
|
||||
} else {
|
||||
lightX = vec2(0.);
|
||||
}
|
||||
|
||||
vec2 lightZ;
|
||||
if (normal.z > 0) {
|
||||
lightZ = _flw_lightForDirection(lights, interpolant, uvec3(0u, 0u, 1u), uvec3(0u, 1u, 1u), uvec3(1u, 0u, 1u), uvec3(1u, 1u, 1u));
|
||||
} else if (normal.z < 0) {
|
||||
lightZ = _flw_lightForDirection(lights, interpolant, uvec3(0u, 0u, 0u), uvec3(0u, 1u, 0u), uvec3(1u, 0u, 0u), uvec3(1u, 1u, 0u));
|
||||
} else {
|
||||
lightZ = vec2(0.);
|
||||
}
|
||||
|
||||
vec2 lightY;
|
||||
// Average the light in relevant directions at each corner.
|
||||
if (normal.y > 0.) {
|
||||
lightY = _flw_lightForDirection(lights, interpolant, uvec3(0u, 1u, 0u), uvec3(0u, 1u, 1u), uvec3(1u, 1u, 0u), uvec3(1u, 1u, 1u));
|
||||
} else if (normal.y < 0.) {
|
||||
lightY = _flw_lightForDirection(lights, interpolant, uvec3(0u, 0u, 0u), uvec3(0u, 0u, 1u), uvec3(1u, 0u, 0u), uvec3(1u, 0u, 1u));
|
||||
} else {
|
||||
lightY = vec2(0.);
|
||||
}
|
||||
|
||||
lightCoord = (lightX * abs(normal.x) + lightY * abs(normal.y) + lightZ * abs(normal.z));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
void flw_materialFragment() {
|
||||
#ifdef FLW_EMBEDDED
|
||||
vec2 embeddedLight;
|
||||
if (flw_light(flw_vertexPos.xyz, embeddedLight)) {
|
||||
if (flw_light(flw_vertexPos.xyz, flw_vertexNormal, embeddedLight)) {
|
||||
flw_fragLight = max(flw_fragLight, embeddedLight);
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue