Functional frustum filter

- Manually fix alignment issue
 - Align UBO size to 16
 - Manual frustum ubo upload
This commit is contained in:
Jozufozu 2022-08-05 21:53:21 -07:00
parent 9d657aed40
commit 63dc8ee923
13 changed files with 137 additions and 65 deletions

View file

@ -9,7 +9,7 @@ public abstract class UniformProvider {
protected ByteBuffer buffer; protected ByteBuffer buffer;
protected Notifier notifier; protected Notifier notifier;
public abstract int getSize(); public abstract int getActualByteSize();
public void updatePtr(ByteBuffer backing, Notifier notifier) { public void updatePtr(ByteBuffer backing, Notifier notifier) {
this.buffer = backing; this.buffer = backing;

View file

@ -0,0 +1,31 @@
package com.jozufozu.flywheel.backend.instancing.indirect;
import static org.lwjgl.opengl.GL46.*;
import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
// This should be a push constant :whywheel:
public class FrustumUBO {
public static final int BUFFER_SIZE = 96;
private final int ubo;
private final long clientStorage;
FrustumUBO() {
ubo = glCreateBuffers();
glNamedBufferStorage(ubo, BUFFER_SIZE, GL_DYNAMIC_STORAGE_BIT);
clientStorage = MemoryUtil.nmemAlloc(BUFFER_SIZE);
}
public void update(FrustumIntersection frustum) {
frustum.getJozuPackedPlanes(clientStorage);
nglNamedBufferSubData(ubo, 0, BUFFER_SIZE, clientStorage);
}
public void bind() {
glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo);
}
}

View file

@ -17,7 +17,6 @@ import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.Engine;
import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.backend.instancing.instancing.MeshPool;
import com.jozufozu.flywheel.core.RenderContext; import com.jozufozu.flywheel.core.RenderContext;
import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.context.ContextShader;
import com.jozufozu.flywheel.backend.instancing.instancing.InstancedArraysCompiler; import com.jozufozu.flywheel.backend.instancing.instancing.InstancedArraysCompiler;
@ -46,6 +45,8 @@ public class IndirectEngine implements Engine {
protected final List<InstancedModel<?>> uninitializedModels = new ArrayList<>(); protected final List<InstancedModel<?>> uninitializedModels = new ArrayList<>();
protected final RenderLists renderLists = new RenderLists(); protected final RenderLists renderLists = new RenderLists();
private FrustumUBO frustumUBO;
/** /**
* The set of instance managers that are attached to this engine. * The set of instance managers that are attached to this engine.
*/ */
@ -76,7 +77,7 @@ public class IndirectEngine implements Engine {
setup(); setup();
for (var group : groups) { for (var group : groups) {
group.submit(); group.submit(frustumUBO);
} }
} }
@ -145,10 +146,26 @@ public class IndirectEngine implements Engine {
@Override @Override
public void beginFrame(TaskEngine taskEngine, RenderContext context) { public void beginFrame(TaskEngine taskEngine, RenderContext context) {
if (frustumUBO == null) {
frustumUBO = new FrustumUBO();
}
for (var model : uninitializedModels) { for (var model : uninitializedModels) {
model.init(renderLists); model.init(renderLists);
} }
uninitializedModels.clear(); uninitializedModels.clear();
Vec3 camera = context.camera()
.getPosition();
var camX = (float) (camera.x - originCoordinate.getX());
var camY = (float) (camera.y - originCoordinate.getY());
var camZ = (float) (camera.z - originCoordinate.getZ());
var culler = RenderContext.createCuller(context.viewProjection(), -camX, -camY, -camZ);
frustumUBO.update(culler);
} }
private void shiftListeners(int cX, int cY, int cZ) { private void shiftListeners(int cX, int cY, int cZ) {

View file

@ -2,18 +2,15 @@ package com.jozufozu.flywheel.backend.instancing.indirect;
import static org.lwjgl.opengl.GL46.*; import static org.lwjgl.opengl.GL46.*;
import java.text.Format;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.lwjgl.opengl.GL46C;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.InstancedPart;
import com.jozufozu.flywheel.api.struct.StorageBufferWriter; import com.jozufozu.flywheel.api.struct.StorageBufferWriter;
import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.backend.gl.GlNumericType;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.Components;
import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.Materials;
@ -24,7 +21,7 @@ import com.jozufozu.flywheel.core.vertex.Formats;
public class IndirectList<T extends InstancedPart> { public class IndirectList<T extends InstancedPart> {
private static final int DRAW_COMMAND_STRIDE = 20; private static final long DRAW_COMMAND_STRIDE = 20;
final StorageBufferWriter<T> storageBufferWriter; final StorageBufferWriter<T> storageBufferWriter;
final GlProgram compute; final GlProgram compute;
@ -51,12 +48,13 @@ public class IndirectList<T extends InstancedPart> {
* Stores drawIndirect structs. * Stores drawIndirect structs.
*/ */
int drawBuffer; int drawBuffer;
int debugBuffer;
final IndirectMeshPool meshPool; final IndirectMeshPool meshPool;
int vertexArray; int vertexArray;
final int[] shaderStorageBuffers = new int[4]; final int[] shaderStorageBuffers = new int[5];
final List<Batch<T>> batches = new ArrayList<>(); final List<Batch<T>> batches = new ArrayList<>();
@ -73,10 +71,11 @@ public class IndirectList<T extends InstancedPart> {
targetBuffer = shaderStorageBuffers[1]; targetBuffer = shaderStorageBuffers[1];
boundingSphereBuffer = shaderStorageBuffers[2]; boundingSphereBuffer = shaderStorageBuffers[2];
drawBuffer = shaderStorageBuffers[3]; drawBuffer = shaderStorageBuffers[3];
debugBuffer = shaderStorageBuffers[4];
meshPool = new IndirectMeshPool(Formats.BLOCK, 1024); meshPool = new IndirectMeshPool(Formats.BLOCK, 1024);
// FIXME: Resizable buffers // FIXME: Resizable buffers
maxObjectCount = 1024L * 100L; maxObjectCount = 1024L;
maxBatchCount = 64; maxBatchCount = 64;
// +4 for the batch id // +4 for the batch id
@ -85,6 +84,7 @@ public class IndirectList<T extends InstancedPart> {
glNamedBufferStorage(targetBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT); glNamedBufferStorage(targetBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
glNamedBufferStorage(boundingSphereBuffer, 16 * maxBatchCount, GL_DYNAMIC_STORAGE_BIT); glNamedBufferStorage(boundingSphereBuffer, 16 * maxBatchCount, GL_DYNAMIC_STORAGE_BIT);
glNamedBufferStorage(drawBuffer, DRAW_COMMAND_STRIDE * maxBatchCount, GL_DYNAMIC_STORAGE_BIT); glNamedBufferStorage(drawBuffer, DRAW_COMMAND_STRIDE * maxBatchCount, GL_DYNAMIC_STORAGE_BIT);
glNamedBufferStorage(debugBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
objectClientStorage = MemoryUtil.nmemAlloc(objectStride * maxObjectCount); objectClientStorage = MemoryUtil.nmemAlloc(objectStride * maxObjectCount);
@ -115,17 +115,13 @@ public class IndirectList<T extends InstancedPart> {
offset += attribute offset += attribute
.getByteWidth(); .getByteWidth();
} }
glEnableVertexArrayAttrib(vertexArray, meshAttribs);
glVertexArrayVertexBuffer(vertexArray, meshAttribs, targetBuffer, 0, 4);
glVertexArrayAttribIFormat(vertexArray, meshAttribs, 1, GlNumericType.UINT.getGlEnum(), 0);
} }
public void add(Mesh mesh, IndirectInstancer<T> instancer) { public void add(Mesh mesh, IndirectInstancer<T> instancer) {
batches.add(new Batch<>(instancer, meshPool.alloc(mesh))); batches.add(new Batch<>(instancer, meshPool.alloc(mesh)));
} }
void submit() { void submit(FrustumUBO frustumUBO) {
int instanceCountThisFrame = calculateTotalInstanceCount(); int instanceCountThisFrame = calculateTotalInstanceCount();
if (instanceCountThisFrame == 0) { if (instanceCountThisFrame == 0) {
@ -137,14 +133,15 @@ public class IndirectList<T extends InstancedPart> {
uploadBoundingSpheres(); uploadBoundingSpheres();
uploadIndirectCommands(); uploadIndirectCommands();
UniformBuffer.getInstance().sync(); frustumUBO.bind();
dispatchCompute(instanceCountThisFrame); dispatchCompute(instanceCountThisFrame);
issueMemoryBarrier(); issueMemoryBarrier();
dispatchDraw(); dispatchDraw();
} }
private void dispatchDraw() { private void dispatchDraw() {
UniformBuffer.getInstance().sync();
draw.bind(); draw.bind();
Materials.BELL.setup(); Materials.BELL.setup();
glVertexArrayElementBuffer(vertexArray, elementBuffer); glVertexArrayElementBuffer(vertexArray, elementBuffer);
@ -170,13 +167,17 @@ public class IndirectList<T extends InstancedPart> {
ptr += 16; ptr += 16;
} }
GL46C.nglNamedBufferSubData(boundingSphereBuffer, 0, size, basePtr); nglNamedBufferSubData(boundingSphereBuffer, 0, size, basePtr);
} }
} }
private void dispatchCompute(int instanceCount) { private void dispatchCompute(int instanceCount) {
compute.bind(); compute.bind();
glBindBuffersBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffers); glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, objectBuffer, 0, instanceCount * objectStride);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 1, targetBuffer, 0, instanceCount * 4L);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 2, boundingSphereBuffer, 0, batches.size() * 16L);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 3, drawBuffer, 0, batches.size() * DRAW_COMMAND_STRIDE);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 4, debugBuffer, 0, instanceCount * 4L);
var groupCount = (instanceCount + 31) >> 5; // ceil(totalInstanceCount / 32) var groupCount = (instanceCount + 31) >> 5; // ceil(totalInstanceCount / 32)
glDispatchCompute(groupCount, 1, 1); glDispatchCompute(groupCount, 1, 1);
@ -197,20 +198,20 @@ public class IndirectList<T extends InstancedPart> {
batchID++; batchID++;
} }
GL46C.nglNamedBufferSubData(objectBuffer, 0, ptr - objectClientStorage, objectClientStorage); nglNamedBufferSubData(objectBuffer, 0, ptr - objectClientStorage, objectClientStorage);
} }
private void uploadIndirectCommands() { private void uploadIndirectCommands() {
try (var stack = MemoryStack.stackPush()) { try (var stack = MemoryStack.stackPush()) {
var size = batches.size() * DRAW_COMMAND_STRIDE; long size = batches.size() * DRAW_COMMAND_STRIDE;
long basePtr = stack.nmalloc(size); long basePtr = stack.nmalloc((int) size);
long writePtr = basePtr; long writePtr = basePtr;
for (Batch<T> batch : batches) { for (Batch<T> batch : batches) {
batch.writeIndirectCommand(writePtr); batch.writeIndirectCommand(writePtr);
writePtr += DRAW_COMMAND_STRIDE; writePtr += DRAW_COMMAND_STRIDE;
} }
GL46C.nglNamedBufferSubData(drawBuffer, 0, size, basePtr); nglNamedBufferSubData(drawBuffer, 0, size, basePtr);
} }
} }

View file

@ -1,5 +1,6 @@
package com.jozufozu.flywheel.backend.instancing.indirect; package com.jozufozu.flywheel.backend.instancing.indirect;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.EnumMap; import java.util.EnumMap;

View file

@ -23,13 +23,10 @@ public record RenderContext(LevelRenderer renderer, ClientLevel level, PoseStack
return viewProjection; return viewProjection;
} }
public static FrustumIntersection createCuller(Camera camera, Matrix4f viewProjection) { public static FrustumIntersection createCuller(Matrix4f viewProjection, float camX, float camY, float camZ) {
com.jozufozu.flywheel.util.joml.Matrix4f proj = Matrix4fExtension.clone(viewProjection); com.jozufozu.flywheel.util.joml.Matrix4f proj = Matrix4fExtension.clone(viewProjection);
Vec3 cam = camera proj.translate(camX, camY, camZ);
.getPosition();
proj.translate((float) -cam.x, (float) -cam.y, (float) -cam.z);
return new FrustumIntersection(proj); return new FrustumIntersection(proj);
} }

View file

@ -23,23 +23,23 @@ public class OrientedStorageWriter implements StorageBufferWriter<OrientedPart>
MemoryUtil.memPutFloat(ptr + 20, d.posY); MemoryUtil.memPutFloat(ptr + 20, d.posY);
MemoryUtil.memPutFloat(ptr + 24, d.posZ); MemoryUtil.memPutFloat(ptr + 24, d.posZ);
MemoryUtil.memPutFloat(ptr + 28, d.pivotX); MemoryUtil.memPutFloat(ptr + 32, d.pivotX);
MemoryUtil.memPutFloat(ptr + 32, d.pivotY); MemoryUtil.memPutFloat(ptr + 36, d.pivotY);
MemoryUtil.memPutFloat(ptr + 36, d.pivotZ); MemoryUtil.memPutFloat(ptr + 40, d.pivotZ);
MemoryUtil.memPutShort(ptr + 40, d.blockLight); MemoryUtil.memPutShort(ptr + 44, d.blockLight);
MemoryUtil.memPutShort(ptr + 42, d.skyLight); MemoryUtil.memPutShort(ptr + 46, d.skyLight);
MemoryUtil.memPutByte(ptr + 44, d.r); MemoryUtil.memPutByte(ptr + 48, d.r);
MemoryUtil.memPutByte(ptr + 45, d.g); MemoryUtil.memPutByte(ptr + 49, d.g);
MemoryUtil.memPutByte(ptr + 46, d.b); MemoryUtil.memPutByte(ptr + 50, d.b);
MemoryUtil.memPutByte(ptr + 47, d.a); MemoryUtil.memPutByte(ptr + 51, d.a);
MemoryUtil.memPutInt(ptr + 48, batchID); MemoryUtil.memPutInt(ptr + 52, batchID);
} }
@Override @Override
public int getAlignment() { public int getAlignment() {
return 52; return 64;
} }
} }

View file

@ -12,7 +12,7 @@ public class FogProvider extends UniformProvider {
@Override @Override
public int getSize() { public int getActualByteSize() {
return 16 + 8 + 4; return 16 + 8 + 4;
} }

View file

@ -47,11 +47,11 @@ public class UniformBuffer {
int totalBytes = 0; int totalBytes = 0;
int index = 0; int index = 0;
for (UniformProvider provider : providers) { for (UniformProvider provider : providers) {
int size = provider.getSize(); int size = alignPo2(provider.getActualByteSize(), 16);
builder.add(new Allocated(provider, totalBytes, size, index)); builder.add(new Allocated(provider, totalBytes, size, index));
totalBytes = align(totalBytes + size); totalBytes = alignUniformBuffer(totalBytes + size);
index++; index++;
} }
@ -82,7 +82,7 @@ public class UniformBuffer {
} }
// https://stackoverflow.com/questions/3407012/rounding-up-to-the-nearest-multiple-of-a-number // https://stackoverflow.com/questions/3407012/rounding-up-to-the-nearest-multiple-of-a-number
private static int align(int numToRound) { private static int alignUniformBuffer(int numToRound) {
if (PO2_ALIGNMENT) { if (PO2_ALIGNMENT) {
return (numToRound + OFFSET_ALIGNMENT - 1) & -OFFSET_ALIGNMENT; return (numToRound + OFFSET_ALIGNMENT - 1) & -OFFSET_ALIGNMENT;
} else { } else {
@ -90,6 +90,10 @@ public class UniformBuffer {
} }
} }
private static int alignPo2(int numToRound, int alignment) {
return (numToRound + alignment - 1) & -alignment;
}
private class Allocated implements UniformProvider.Notifier { private class Allocated implements UniformProvider.Notifier {
private final UniformProvider provider; private final UniformProvider provider;
private final int offset; private final int offset;

View file

@ -26,7 +26,7 @@ public class ViewProvider extends UniformProvider {
} }
@Override @Override
public int getSize() { public int getActualByteSize() {
return 4 * 16 + 16 + 4; return 4 * 16 + 16 + 4;
} }

View file

@ -27,6 +27,7 @@ import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderBuffers; import net.minecraft.client.renderer.RenderBuffers;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
@Mixin(value = LevelRenderer.class, priority = 1001) // Higher priority to go after sodium @Mixin(value = LevelRenderer.class, priority = 1001) // Higher priority to go after sodium
@ -44,7 +45,8 @@ public class LevelRendererMixin {
@Inject(at = @At("HEAD"), method = "renderLevel") @Inject(at = @At("HEAD"), method = "renderLevel")
private void beginRender(PoseStack pPoseStack, float pPartialTick, long pFinishNanoTime, boolean pRenderBlockOutline, Camera pCamera, GameRenderer pGameRenderer, LightTexture pLightTexture, Matrix4f pProjectionMatrix, CallbackInfo ci) { private void beginRender(PoseStack pPoseStack, float pPartialTick, long pFinishNanoTime, boolean pRenderBlockOutline, Camera pCamera, GameRenderer pGameRenderer, LightTexture pLightTexture, Matrix4f pProjectionMatrix, CallbackInfo ci) {
var viewProjection = RenderContext.createViewProjection(pPoseStack, pProjectionMatrix); var viewProjection = RenderContext.createViewProjection(pPoseStack, pProjectionMatrix);
var culler = RenderContext.createCuller(pCamera, viewProjection); var cameraPos = pCamera.getPosition();
var culler = RenderContext.createCuller(viewProjection, (float) -cameraPos.x, (float) -cameraPos.y, (float) -cameraPos.z);
renderContext = new RenderContext((LevelRenderer) (Object) this, level, pPoseStack, viewProjection, pProjectionMatrix, renderBuffers, pCamera, culler); renderContext = new RenderContext((LevelRenderer) (Object) this, level, pPoseStack, viewProjection, pProjectionMatrix, renderBuffers, pCamera, culler);
try (var restoreState = GlStateTracker.getRestoreState()) { try (var restoreState = GlStateTracker.getRestoreState()) {

View file

@ -1004,11 +1004,9 @@ public class FrustumIntersection {
* {@code vec2(nzZ, pzZ)}<br> * {@code vec2(nzZ, pzZ)}<br>
* {@code vec2(nzW, pzW)}<br> * {@code vec2(nzW, pzW)}<br>
* *
* @param buffer The buffer to write the planes to. * @param addr The buffer to write the planes to.
*/ */
public void getJozuPackedPlanes(ByteBuffer buffer) { public void getJozuPackedPlanes(long addr) {
long addr = MemoryUtil.memAddress(buffer);
MemoryUtil.memPutFloat(addr, nxX); MemoryUtil.memPutFloat(addr, nxX);
MemoryUtil.memPutFloat(addr + 4, pxX); MemoryUtil.memPutFloat(addr + 4, pxX);
MemoryUtil.memPutFloat(addr + 8, nyX); MemoryUtil.memPutFloat(addr + 8, nyX);

View file

@ -3,7 +3,10 @@ layout(local_size_x = FLW_SUBGROUP_SIZE) in;
#use "flywheel:compute/objects.glsl" #use "flywheel:compute/objects.glsl"
#use "flywheel:util/quaternion.glsl" #use "flywheel:util/quaternion.glsl"
layout(std140, binding = 3) uniform FrameData { uint flw_objectID;
uint flw_batchID;
layout(std140, binding = 0) uniform FrameData {
vec4 a1; // vec4(nx.x, px.x, ny.x, py.x) vec4 a1; // vec4(nx.x, px.x, ny.x, py.x)
vec4 a2; // vec4(nx.y, px.y, ny.y, py.y) vec4 a2; // vec4(nx.y, px.y, ny.y, py.y)
vec4 a3; // vec4(nx.z, px.z, ny.z, py.z) vec4 a3; // vec4(nx.z, px.z, ny.z, py.z)
@ -31,37 +34,55 @@ layout(std430, binding = 3) buffer DrawCommands {
MeshDrawCommand drawCommands[]; MeshDrawCommand drawCommands[];
}; };
layout(std430, binding = 4) writeonly buffer DebugVisibility {
uint objectVisibilityBits[];
};
// 83 - 27 = 56 spirv instruction results // 83 - 27 = 56 spirv instruction results
bool testSphere(vec3 center, float radius) { bool testSphere(vec3 center, float radius) {
return bvec4 resultA = greaterThanEqual(fma(frustum.a1, center.xxxx, fma(frustum.a2, center.yyyy, fma(frustum.a3, center.zzzz, frustum.a4))), -radius.xxxx);
all(lessThanEqual(fma(frustum.a1, center.xxxx, fma(frustum.a2, center.yyyy, fma(frustum.a3, center.zzzz, frustum.a4))), -radius.xxxx)) && bvec2 resultB = greaterThanEqual(fma(frustum.b1, center.xx, fma(frustum.b2, center.yy, fma(frustum.b3, center.zz, frustum.b4))), -radius.xx);
all(lessThanEqual(fma(frustum.b1, center.xx, fma(frustum.b2, center.yy, fma(frustum.b3, center.zz, frustum.b4))), -radius.xx));
uint debug = uint(resultA.x);
debug |= uint(resultA.y) << 1;
debug |= uint(resultA.z) << 2;
debug |= uint(resultA.w) << 3;
debug |= uint(resultB.x) << 4;
debug |= uint(resultB.y) << 5;
objectVisibilityBits[flw_objectID] = debug;
return all(resultA) && all(resultB);
} }
bool isVisible(uint objectID, uint batchID) { void flw_transformBoundingSphere(in Instance i, inout vec3 center, inout float radius) {
vec4 sphere = boundingSpheres[batchID]; center = rotateVertexByQuat(center - i.pivot, i.rotation) + i.pivot + i.pos;
radius = radius;
}
vec3 pivot = objects[objectID].pivot; bool isVisible() {
vec3 center = rotateVertexByQuat(sphere.xyz - pivot, objects[objectID].rotation) + pivot + objects[objectID].pos; vec4 sphere = boundingSpheres[flw_batchID];
vec3 center = sphere.xyz;
float radius = sphere.r; float radius = sphere.r;
flw_transformBoundingSphere(objects[flw_objectID], center, radius);
return true; //testSphere(center, radius); return testSphere(center, radius);
} }
void main() { void main() {
uint objectID = gl_GlobalInvocationID.x; flw_objectID = gl_GlobalInvocationID.x;
if (objectID >= objects.length()) { if (flw_objectID >= objects.length()) {
return; return;
} }
uint batchID = objects[objectID].batchID; flw_batchID = objects[objectID].batchID;
bool visible = isVisible(objectID, batchID);
if (visible) { if (isVisible()) {
uint batchIndex = atomicAdd(drawCommands[batchID].instanceCount, 1); uint batchIndex = atomicAdd(drawCommands[flw_batchID].instanceCount, 1);
uint globalIndex = drawCommands[batchID].baseInstance + batchIndex; uint globalIndex = drawCommands[flw_batchID].baseInstance + batchIndex;
objectIDs[globalIndex] = objectID; objectIDs[globalIndex] = flw_objectID;
} }
} }