Indirectly lit

- "Functional" arena based lighting for indirect
- Strip out most of the reference counting stuffs for embeddings
- Naively re-buffer all tracked light sections every frame
This commit is contained in:
Jozufozu 2024-06-21 15:26:48 -07:00
parent e10852fe7a
commit 51224d618f
26 changed files with 134 additions and 110 deletions

View file

@ -8,5 +8,4 @@ public class Samplers {
public static final GlTextureUnit LIGHT = GlTextureUnit.T2;
public static final GlTextureUnit CRUMBLING = GlTextureUnit.T3;
public static final GlTextureUnit INSTANCE_BUFFER = GlTextureUnit.T4;
public static final GlTextureUnit EMBEDDED_LIGHT = GlTextureUnit.T5;
}

View file

@ -13,7 +13,7 @@ public enum ContextShader {
DEFAULT(null, $ -> {
}),
CRUMBLING("_FLW_CRUMBLING", program -> program.setSamplerBinding("_flw_crumblingTex", Samplers.CRUMBLING)),
EMBEDDED("_FLW_EMBEDDED", program -> program.setSamplerBinding("_flw_lightVolume", Samplers.EMBEDDED_LIGHT));
EMBEDDED("_FLW_EMBEDDED", $ -> {});
@Nullable
private final String define;

View file

@ -5,7 +5,7 @@ import java.util.ArrayList;
import dev.engine_room.flywheel.api.Flywheel;
import dev.engine_room.flywheel.api.instance.InstanceType;
import dev.engine_room.flywheel.api.layout.Layout;
import dev.engine_room.flywheel.backend.engine.indirect.IndirectBuffers;
import dev.engine_room.flywheel.backend.engine.indirect.BufferBindings;
import dev.engine_room.flywheel.backend.glsl.generate.FnSignature;
import dev.engine_room.flywheel.backend.glsl.generate.GlslBlock;
import dev.engine_room.flywheel.backend.glsl.generate.GlslBuilder;
@ -43,7 +43,7 @@ public class SsboInstanceComponent extends InstanceAssemblerComponent {
fnBody.ret(GlslExpr.call(STRUCT_NAME, unpackArgs));
builder._addRaw("layout(std430, binding = " + IndirectBuffers.INSTANCE_INDEX + ") restrict readonly buffer InstanceBuffer {\n"
builder._addRaw("layout(std430, binding = " + BufferBindings.INSTANCE_BUFFER_BINDING + ") restrict readonly buffer InstanceBuffer {\n"
+ " uint _flw_instances[];\n"
+ "};");
builder.blankLine();

View file

@ -25,8 +25,6 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
protected AbstractInstancer(InstanceType<I> type, Environment environment) {
this.type = type;
this.environment = environment;
environment.acquire();
}
@Override
@ -177,9 +175,7 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
deleted.clear();
}
public void delete() {
environment.release();
}
public abstract void delete();
@Override
public String toString() {

View file

@ -16,6 +16,7 @@ import dev.engine_room.flywheel.api.instance.Instancer;
import dev.engine_room.flywheel.api.model.Model;
import dev.engine_room.flywheel.backend.FlwBackend;
import dev.engine_room.flywheel.backend.engine.embed.Environment;
import dev.engine_room.flywheel.backend.engine.embed.LightStorage;
import dev.engine_room.flywheel.lib.util.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@ -45,7 +46,7 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
initializationQueue.clear();
}
public void flush() {
public void flush(LightStorage lightStorage) {
// Thread safety: flush is called from the render thread after all visual updates have been made,
// so there are no:tm: threads we could be racing with.
for (var instancer : initializationQueue) {

View file

@ -31,7 +31,7 @@ import net.minecraft.world.phys.Vec3;
public class EngineImpl implements Engine {
private final int sqrMaxOriginDistance;
private final DrawManager<? extends AbstractInstancer<?>> drawManager;
private final EnvironmentStorage environmentStorage = new EnvironmentStorage();
private final EnvironmentStorage environmentStorage;
private final LightStorage lightStorage;
private final Flag flushFlag = new NamedFlag("flushed");
@ -40,12 +40,13 @@ public class EngineImpl implements Engine {
public EngineImpl(LevelAccessor level, DrawManager<? extends AbstractInstancer<?>> drawManager, int maxOriginDistance) {
this.drawManager = drawManager;
sqrMaxOriginDistance = maxOriginDistance * maxOriginDistance;
lightStorage = new LightStorage(level);
environmentStorage = new EnvironmentStorage();
lightStorage = new LightStorage(level, environmentStorage);
}
@Override
public Plan<RenderContext> createFramePlan() {
return SyncedPlan.of(this::flush);
return lightStorage.createFramePlan().then(SyncedPlan.of(this::flush));
}
@Override
@ -96,7 +97,6 @@ public class EngineImpl implements Engine {
@Override
public void delete() {
drawManager.delete();
environmentStorage.delete();
lightStorage.delete();
}
@ -107,8 +107,8 @@ public class EngineImpl implements Engine {
private void flush(RenderContext ctx) {
try (var state = GlStateTracker.getRestoreState()) {
Uniforms.update(ctx);
drawManager.flush();
environmentStorage.flush();
drawManager.flush(lightStorage);
}
flushFlag.raise();

View file

@ -1,6 +1,8 @@
package dev.engine_room.flywheel.backend.engine;
import dev.engine_room.flywheel.backend.engine.embed.AbstractEmbeddedEnvironment;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet;
import it.unimi.dsi.fastutil.objects.ReferenceSet;
import it.unimi.dsi.fastutil.objects.ReferenceSets;
@ -13,10 +15,13 @@ public class EnvironmentStorage {
}
public void flush() {
environments.removeIf(AbstractEmbeddedEnvironment::isDeleted);
environments.forEach(AbstractEmbeddedEnvironment::flush);
}
public void delete() {
environments.clear();
public LongSet allLightSections() {
var out = new LongOpenHashSet();
environments.forEach(e -> e.addLightSections(out));
return out;
}
}

View file

@ -15,10 +15,10 @@ import dev.engine_room.flywheel.api.visualization.VisualEmbedding;
import dev.engine_room.flywheel.backend.compile.ContextShader;
import dev.engine_room.flywheel.backend.engine.EngineImpl;
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
import dev.engine_room.flywheel.backend.util.AtomicReferenceCounted;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.core.Vec3i;
public abstract class AbstractEmbeddedEnvironment extends AtomicReferenceCounted implements Environment, VisualEmbedding {
public abstract class AbstractEmbeddedEnvironment implements Environment, VisualEmbedding {
protected final Matrix4f pose = new Matrix4f();
protected final Matrix3f normal = new Matrix3f();
private final Matrix4f poseComposed = new Matrix4f();
@ -27,6 +27,8 @@ public abstract class AbstractEmbeddedEnvironment extends AtomicReferenceCounted
protected final EngineImpl engine;
private final RenderStage renderStage;
private boolean deleted = false;
public AbstractEmbeddedEnvironment(EngineImpl engine, RenderStage renderStage) {
this.engine = engine;
this.renderStage = renderStage;
@ -38,9 +40,6 @@ public abstract class AbstractEmbeddedEnvironment extends AtomicReferenceCounted
return engine.instancer(AbstractEmbeddedEnvironment.this, type, model, renderStage);
}
};
// Acquire the reference owned by the visual that created this.
acquire();
}
@Override
@ -94,15 +93,20 @@ public abstract class AbstractEmbeddedEnvironment extends AtomicReferenceCounted
return out;
}
public boolean isDeleted() {
return deleted;
}
public void addLightSections(LongSet out) {
}
/**
* Called by visuals
*/
@Override
public void delete() {
// Release the reference owned by the visual that created this.
// Note that visuals don't explicitly call acquire, instead the
// storage acquired a reference when this was constructed.
release();
deleted = true;
}
public abstract void setupLight(GlProgram program);

View file

@ -47,4 +47,8 @@ public class Arena {
public void delete() {
memoryBlock.free();
}
public int capacity() {
return top;
}
}

View file

@ -9,8 +9,4 @@ public interface Environment {
void setupDraw(GlProgram drawProgram);
void setupCull(GlProgram cullProgram);
void acquire();
void release();
}

View file

@ -23,14 +23,4 @@ public class GlobalEnvironment implements Environment {
public void setupCull(GlProgram cullProgram) {
cullProgram.setBool(EmbeddingUniforms.USE_MODEL_MATRIX, false);
}
@Override
public void acquire() {
}
@Override
public void release() {
}
}

View file

@ -4,7 +4,11 @@ import java.util.BitSet;
import org.lwjgl.system.MemoryUtil;
import dev.engine_room.flywheel.api.event.RenderContext;
import dev.engine_room.flywheel.api.task.Plan;
import dev.engine_room.flywheel.backend.engine.EnvironmentStorage;
import dev.engine_room.flywheel.backend.engine.indirect.StagingBuffer;
import dev.engine_room.flywheel.lib.task.SimplePlan;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.longs.Long2IntMap;
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
@ -29,11 +33,12 @@ import net.minecraft.world.level.LightLayer;
* <p>Thus, each section occupies 5832 bytes.
*/
public class LightStorage {
private final long SECTION_SIZE_BYTES = 9 * 9 * 9 * 8;
private final int DEFAULT_ARENA_CAPACITY_SECTIONS = 64;
private final int INVALID_SECTION = -1;
public static final long SECTION_SIZE_BYTES = 9 * 9 * 9 * 8;
private static final int DEFAULT_ARENA_CAPACITY_SECTIONS = 64;
private static final int INVALID_SECTION = -1;
private final LevelAccessor level;
private final EnvironmentStorage environmentStorage;
private final Arena arena;
private final Long2IntMap section2ArenaIndex = new Long2IntOpenHashMap();
@ -44,12 +49,24 @@ public class LightStorage {
private final BitSet changed = new BitSet();
private boolean newSections = false;
public LightStorage(LevelAccessor level) {
public LightStorage(LevelAccessor level, EnvironmentStorage environmentStorage) {
this.level = level;
this.environmentStorage = environmentStorage;
arena = new Arena(SECTION_SIZE_BYTES, DEFAULT_ARENA_CAPACITY_SECTIONS);
}
public Plan<RenderContext> createFramePlan() {
return SimplePlan.of(() -> {
var longs = environmentStorage.allLightSections();
longs.forEach(this::addSection);
});
}
public int capacity() {
return arena.capacity();
}
public void addSection(long section) {
var lightEngine = level.getLightEngine();
@ -187,6 +204,7 @@ public class LightStorage {
for (int i = changed.nextSetBit(0); i >= 0; i = changed.nextSetBit(i + 1)) {
staging.enqueueCopy(arena.indexToPointer(i), SECTION_SIZE_BYTES, dstVbo, i * SECTION_SIZE_BYTES);
}
changed.clear();
}
public IntArrayList createLut() {

View file

@ -14,7 +14,6 @@ public class NestedEmbeddedEnvironment extends AbstractEmbeddedEnvironment {
public NestedEmbeddedEnvironment(AbstractEmbeddedEnvironment parent, EngineImpl engine, RenderStage renderStage) {
super(engine, renderStage);
this.parent = parent;
parent.acquire();
}
@Override
@ -33,9 +32,4 @@ public class NestedEmbeddedEnvironment extends AbstractEmbeddedEnvironment {
pose.mul(this.pose);
normal.mul(this.normal);
}
@Override
public void _delete() {
parent.release();
}
}

View file

@ -16,19 +16,17 @@ public class TopLevelEmbeddedEnvironment extends AbstractEmbeddedEnvironment {
super(engine, renderStage);
}
@Override
public void flush() {
super.flush();
lightSections.forEach(engine.lightStorage()::addSection);
}
@Override
public void lightChunks(LongSet chunks) {
lightSections.clear();
lightSections.addAll(chunks);
}
@Override
public void addLightSections(LongSet out) {
out.addAll(lightSections);
}
@Override
public void setupLight(GlProgram program) {
program.setBool(EmbeddingUniforms.USE_LIGHT_VOLUME, !lightSections.isEmpty());
@ -39,9 +37,4 @@ public class TopLevelEmbeddedEnvironment extends AbstractEmbeddedEnvironment {
pose.set(this.pose);
normal.set(this.normal);
}
@Override
protected void _delete() {
}
}

View file

@ -0,0 +1,14 @@
package dev.engine_room.flywheel.backend.engine.indirect;
public class BufferBindings {
public static final int INSTANCE_BUFFER_BINDING = 0;
public static final int TARGET_BUFFER_BINDING = 1;
public static final int MODEL_INDEX_BUFFER_BINDING = 2;
public static final int MODEL_BUFFER_BINDING = 3;
public static final int DRAW_BUFFER_BINDING = 4;
public static final int EMBEDDING_LUT_BINDING = 5;
public static final int EMBEDDING_LIGHT_BINDING = 6;
private BufferBindings() {
}
}

View file

@ -22,13 +22,6 @@ public class IndirectBuffers {
public static final long DRAW_COMMAND_STRIDE = 40;
public static final long DRAW_COMMAND_OFFSET = 0;
public static final int INSTANCE_INDEX = 0;
public static final int TARGET_INDEX = 1;
public static final int MODEL_INDEX_INDEX = 2;
public static final int MODEL_INDEX = 3;
public static final int DRAW_INDEX = 4;
// Offsets to the 3 segments
private static final long HANDLE_OFFSET = 0;
private static final long OFFSET_OFFSET = BUFFER_COUNT * INT_SIZE;
@ -117,7 +110,7 @@ public class IndirectBuffers {
private void multiBind() {
final long ptr = multiBindBlock.ptr();
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, 0, IndirectBuffers.BUFFER_COUNT, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET);
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, BufferBindings.INSTANCE_BUFFER_BINDING, IndirectBuffers.BUFFER_COUNT, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET);
}
/**
@ -125,7 +118,7 @@ public class IndirectBuffers {
*/
public void bindForCrumbling() {
final long ptr = multiBindBlock.ptr();
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, 0, 4, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET);
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, BufferBindings.INSTANCE_BUFFER_BINDING, 4, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET);
}
public void delete() {

View file

@ -23,6 +23,7 @@ import dev.engine_room.flywheel.backend.engine.InstancerKey;
import dev.engine_room.flywheel.backend.engine.MaterialRenderState;
import dev.engine_room.flywheel.backend.engine.MeshPool;
import dev.engine_room.flywheel.backend.engine.TextureBinder;
import dev.engine_room.flywheel.backend.engine.embed.LightStorage;
import dev.engine_room.flywheel.backend.engine.uniform.Uniforms;
import dev.engine_room.flywheel.backend.gl.GlStateTracker;
import dev.engine_room.flywheel.backend.gl.array.GlVertexArray;
@ -40,6 +41,8 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
private final Map<GroupKey<?>, IndirectCullingGroup<?>> cullingGroups = new HashMap<>();
private final GlBuffer crumblingDrawBuffer = new GlBuffer();
private final LightBuffers lightBuffers;
public IndirectDrawManager(IndirectPrograms programs) {
this.programs = programs;
programs.acquire();
@ -50,6 +53,7 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
vertexArray = GlVertexArray.create();
meshPool.bind(vertexArray);
lightBuffers = new LightBuffers();
}
@Override
@ -83,6 +87,7 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
TextureBinder.bindLightAndOverlay();
vertexArray.bindForDraw();
lightBuffers.bind();
Uniforms.bindAll();
for (var group : cullingGroups.values()) {
@ -95,8 +100,8 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
}
@Override
public void flush() {
super.flush();
public void flush(LightStorage lightStorage) {
super.flush(lightStorage);
for (var group : cullingGroups.values()) {
group.flushInstancers();
@ -108,6 +113,8 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
stagingBuffer.reclaim();
lightBuffers.flush(stagingBuffer, lightStorage);
for (var group : cullingGroups.values()) {
group.upload(stagingBuffer);
}
@ -159,7 +166,7 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
var block = MemoryBlock.malloc(IndirectBuffers.DRAW_COMMAND_STRIDE);
GlBufferType.DRAW_INDIRECT_BUFFER.bind(crumblingDrawBuffer.handle());
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, IndirectBuffers.DRAW_INDEX, crumblingDrawBuffer.handle(), 0, IndirectBuffers.DRAW_COMMAND_STRIDE);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BufferBindings.DRAW_BUFFER_BINDING, crumblingDrawBuffer.handle(), 0, IndirectBuffers.DRAW_COMMAND_STRIDE);
for (var groupEntry : byType.entrySet()) {
var byProgress = groupEntry.getValue();

View file

@ -125,8 +125,6 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
@Override
public void delete() {
super.delete();
for (IndirectDraw draw : draws()) {
draw.delete();
}

View file

@ -1,17 +1,25 @@
package dev.engine_room.flywheel.backend.engine.indirect;
import org.lwjgl.opengl.GL46;
import org.lwjgl.system.MemoryUtil;
import dev.engine_room.flywheel.backend.engine.embed.LightStorage;
public class LightBuffers {
private final ResizableStorageBuffer lightArena = new ResizableStorageBuffer();
private final ResizableStorageArray lightArena = new ResizableStorageArray(LightStorage.SECTION_SIZE_BYTES);
private final ResizableStorageArray lut = new ResizableStorageArray(4);
public LightBuffers() {
}
public void flush(StagingBuffer staging, LightStorage light) {
var capacity = light.capacity();
if (capacity == 0) {
return;
}
lightArena.ensureCapacity(capacity);
light.uploadChangedSections(staging, lightArena.handle());
if (light.hasNewSections()) {
@ -26,4 +34,13 @@ public class LightBuffers {
});
}
}
public void bind() {
if (lightArena.capacity() == 0) {
return;
}
GL46.glBindBufferRange(GL46.GL_SHADER_STORAGE_BUFFER, BufferBindings.EMBEDDING_LUT_BINDING, lut.handle(), 0, lut.byteCapacity());
GL46.glBindBufferRange(GL46.GL_SHADER_STORAGE_BUFFER, BufferBindings.EMBEDDING_LIGHT_BINDING, lightArena.handle(), 0, lightArena.byteCapacity());
}
}

View file

@ -22,6 +22,7 @@ import dev.engine_room.flywheel.backend.engine.MaterialEncoder;
import dev.engine_room.flywheel.backend.engine.MaterialRenderState;
import dev.engine_room.flywheel.backend.engine.MeshPool;
import dev.engine_room.flywheel.backend.engine.TextureBinder;
import dev.engine_room.flywheel.backend.engine.embed.LightStorage;
import dev.engine_room.flywheel.backend.engine.uniform.Uniforms;
import dev.engine_room.flywheel.backend.gl.GlStateTracker;
import dev.engine_room.flywheel.backend.gl.TextureBuffer;
@ -55,8 +56,8 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
}
@Override
public void flush() {
super.flush();
public void flush(LightStorage lightStorage) {
super.flush(lightStorage);
var instancers = this.instancers.values();
instancers.removeIf(instancer -> {

View file

@ -116,8 +116,6 @@ public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I>
}
public void delete() {
super.delete();
if (vbo == null) {
return;
}

View file

@ -13,14 +13,6 @@ uniform sampler2D _flw_crumblingTex;
in vec2 _flw_crumblingTexCoord;
#endif
#ifdef _FLW_EMBEDDED
uniform sampler3D _flw_lightVolume;
uniform bool _flw_useLightVolume;
in vec3 _flw_lightVolumeCoord;
#endif
flat in uint _flw_instanceID;
out vec4 _flw_outputColor;
@ -43,12 +35,6 @@ void _flw_main() {
flw_fragOverlay = flw_vertexOverlay;
flw_fragLight = flw_vertexLight;
#ifdef _FLW_EMBEDDED
if (_flw_useLightVolume) {
flw_fragLight = max(flw_fragLight, texture(_flw_lightVolume, _flw_lightVolumeCoord).rg);
}
#endif
flw_materialFragment();
#ifdef _FLW_CRUMBLING
@ -98,11 +84,6 @@ void _flw_main() {
case 6u:
color = vec4(vec3(diffuseFactor), 1.);
break;
#ifdef _FLW_EMBEDDED
case 7u:
color = vec4(_flw_lightVolumeCoord, 1.);
break;
#endif
}
_flw_outputColor = flw_fogFilter(color);

View file

@ -70,7 +70,7 @@ vec2 getCrumblingTexCoord() {
uniform mat4 _flw_modelMatrix;
uniform mat3 _flw_normalMatrix;
bool _flw_embeddedLight(vec3 worldPos, vec3 normal, out vec2 lightCoord);
bool _flw_embeddedLight(vec3 worldPos, out vec2 lightCoord);
#endif
flat out uint _flw_instanceID;
@ -89,7 +89,7 @@ void _flw_main(in FlwInstance instance, in uint stableInstanceID) {
flw_vertexNormal = _flw_normalMatrix * flw_vertexNormal;
vec2 embeddedLight;
if (_flw_embeddedLight(flw_vertexPos, flw_vertexNormal, embeddedLight)) {
if (_flw_embeddedLight(flw_vertexPos.xyz, embeddedLight)) {
flw_vertexLight = max(flw_vertexLight, embeddedLight);
}
#endif

View file

@ -3,3 +3,5 @@
#define _FLW_MODEL_INDEX_BUFFER_BINDING 2
#define _FLW_MODEL_BUFFER_BINDING 3
#define _FLW_DRAW_BUFFER_BINDING 4
#define _FLW_EMBEDDING_LUT_BINDING 5
#define _FLW_EMBEDDING_LIGHT_BINDING 6

View file

@ -13,24 +13,33 @@ layout(std430, binding = _FLW_DRAW_BUFFER_BINDING) restrict readonly buffer Draw
#ifdef _FLW_EMBEDDED
layout(std430, binding = 8) restrict readonly buffer EmbeddingLut {
layout(std430, binding = _FLW_EMBEDDING_LUT_BINDING) restrict readonly buffer EmbeddingLut {
uint _flw_embeddingLut[];
};
const uint _FLW_LIGHT_SECTION_SIZE_BYTES = 18 * 18 * 18;
const uint _FLW_LIGHT_SECTION_SIZE_INTS = _FLW_LIGHT_SECTION_SIZE_BYTES / 4;
layout(std430, binding = 9) restrict readonly buffer LightSections {
layout(std430, binding = _FLW_EMBEDDING_LIGHT_BINDING) restrict readonly buffer LightSections {
uint _flw_lightSections[];
};
/// Find the index for the next step in the LUT.
/// @param base The base index in the LUT, should point to the start of a coordinate span.
/// @param coord The coordinate to look for.
/// @param next Output. The index of the next step in the LUT.
/// @return true if the coordinate is not in the span.
bool _flw_nextLut(uint base, int coord, out uint next) {
// The base coordinate.
int start = int(_flw_embeddingLut[base]);
// The width of the coordinate span.
uint size = _flw_embeddingLut[base + 1];
// Index of the coordinate in the span.
int i = coord - start;
if (i < 0 || i >= size) {
// We missed.
return true;
}
@ -52,25 +61,29 @@ bool _flw_chunkCoordToSectionIndex(ivec3 sectionPos, out uint index) {
return _flw_nextLut(z, sectionPos.z, index);
}
vec2 _flw_lightAt(uint sectionOffset, ivec3 blockInSectionPos) {
vec2 _flw_lightAt(uint sectionOffset, uvec3 blockInSectionPos) {
uint byteOffset = blockInSectionPos.x + blockInSectionPos.z * 18u + blockInSectionPos.y * 18u * 18u;
uint uintOffset = byteOffset >> 2u;
uint bitOffset = (byteOffset & 3u) << 3;
uint packed = _flw_lightSections[sectionOffset + uintOffset];
uint block = (packed >> bitOffset) & 0xFu;
uint sky = (packed >> (bitOffset + 4u)) & 0xFu;
uint raw = _flw_lightSections[sectionOffset + uintOffset];
uint block = (raw >> bitOffset) & 0xFu;
uint sky = (raw >> (bitOffset + 4u)) & 0xFu;
return vec2(block, sky);
}
bool _flw_embeddedLight(vec3 worldPos, vec3 normal, out vec2 lightCoord) {
bool _flw_embeddedLight(vec3 worldPos, out vec2 lightCoord) {
ivec3 blockPos = ivec3(floor(worldPos));
ivec3 sectionPos = blockPos >> 4;
uvec3 blockInSectionPos = (blockPos & 0xF) + 1;
uint lightSectionIndex;
if (_flw_chunkCoordToSectionIndex(sectionPos, lightSectionIndex)) {
// TODO: useful debug mode for this.
// flw_vertexOverlay = ivec2(0, 3);
return false;
}

View file

@ -5,7 +5,7 @@ uniform uvec4 _flw_packedMaterial;
uniform int _flw_baseInstance = 0;
#ifdef _FLW_EMBEDDED
bool _flw_embeddedLight(vec3 worldPos, vec3 normal, out vec2 lightCoord) {
bool _flw_embeddedLight(vec3 worldPos, out vec2 lightCoord) {
return true;
}
#endif