mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-25 22:46:26 +01:00
Separate shader logic and fix rendering errors
- Batch IDs are stored in a separate buffer - Bounding spheres in draw command buffer, subject to change - Guard shader api files - Generate complete header for compute culler compiler - Move Frustum UBO to uniform shader/provider
This commit is contained in:
parent
0a4fcf27d8
commit
a9ee85ff76
24 changed files with 230 additions and 174 deletions
|
@ -4,7 +4,7 @@ import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
|||
|
||||
public interface StorageBufferWriter<T extends InstancedPart> {
|
||||
|
||||
void write(final long ptr, final T instance, final int batchID);
|
||||
void write(final long ptr, final T instance);
|
||||
|
||||
int getAlignment();
|
||||
}
|
||||
|
|
|
@ -52,8 +52,7 @@ public class Loader implements ResourceManagerReloadListener {
|
|||
FileResolution.run(errorReporter, sources);
|
||||
|
||||
if (errorReporter.hasErrored()) {
|
||||
errorReporter.dump();
|
||||
throw new ShaderLoadingException("Failed to resolve all source files, see log for details");
|
||||
throw errorReporter.dump();
|
||||
}
|
||||
|
||||
sources.postResolve();
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
|||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.core.compile.CompileUtil;
|
||||
import com.jozufozu.flywheel.core.compile.Memoizer;
|
||||
import com.jozufozu.flywheel.core.compile.ProgramAssembler;
|
||||
import com.jozufozu.flywheel.core.compile.ShaderCompilationException;
|
||||
|
@ -24,7 +25,7 @@ public class ComputeCullerCompiler extends Memoizer<FileResolution, GlProgram> {
|
|||
|
||||
CompilationContext context = new CompilationContext();
|
||||
|
||||
var header = GLSLVersion.V460.getVersionLine();
|
||||
var header = CompileUtil.generateHeader(GLSLVersion.V460, ShaderType.COMPUTE);
|
||||
String source = file.getFile()
|
||||
.generateFinalSource(context);
|
||||
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -45,8 +45,6 @@ public class IndirectEngine implements Engine {
|
|||
protected final List<InstancedModel<?>> uninitializedModels = new ArrayList<>();
|
||||
protected final RenderLists renderLists = new RenderLists();
|
||||
|
||||
private FrustumUBO frustumUBO;
|
||||
|
||||
/**
|
||||
* The set of instance managers that are attached to this engine.
|
||||
*/
|
||||
|
@ -77,7 +75,7 @@ public class IndirectEngine implements Engine {
|
|||
setup();
|
||||
|
||||
for (var group : groups) {
|
||||
group.submit(frustumUBO);
|
||||
group.submit();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -146,26 +144,10 @@ public class IndirectEngine implements Engine {
|
|||
|
||||
@Override
|
||||
public void beginFrame(TaskEngine taskEngine, RenderContext context) {
|
||||
if (frustumUBO == null) {
|
||||
frustumUBO = new FrustumUBO();
|
||||
}
|
||||
|
||||
for (var model : uninitializedModels) {
|
||||
model.init(renderLists);
|
||||
}
|
||||
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) {
|
||||
|
|
|
@ -21,7 +21,8 @@ import com.jozufozu.flywheel.core.vertex.Formats;
|
|||
|
||||
public class IndirectList<T extends InstancedPart> {
|
||||
|
||||
private static final long DRAW_COMMAND_STRIDE = 20;
|
||||
private static final long DRAW_COMMAND_STRIDE = 48;
|
||||
private static final long DRAW_COMMAND_OFFSET = 0;
|
||||
|
||||
final StorageBufferWriter<T> storageBufferWriter;
|
||||
final GlProgram compute;
|
||||
|
@ -31,18 +32,15 @@ public class IndirectList<T extends InstancedPart> {
|
|||
private final long objectStride;
|
||||
private final int maxBatchCount;
|
||||
private final long objectClientStorage;
|
||||
private final long batchIDClientStorage;
|
||||
private final int elementBuffer;
|
||||
|
||||
/**
|
||||
* Stores raw instance data per-object.
|
||||
*/
|
||||
int objectBuffer;
|
||||
|
||||
int targetBuffer;
|
||||
/**
|
||||
* Stores bounding spheres
|
||||
*/
|
||||
int boundingSphereBuffer;
|
||||
int batchBuffer;
|
||||
|
||||
/**
|
||||
* Stores drawIndirect structs.
|
||||
|
@ -69,7 +67,7 @@ public class IndirectList<T extends InstancedPart> {
|
|||
glCreateBuffers(shaderStorageBuffers);
|
||||
objectBuffer = shaderStorageBuffers[0];
|
||||
targetBuffer = shaderStorageBuffers[1];
|
||||
boundingSphereBuffer = shaderStorageBuffers[2];
|
||||
batchBuffer = shaderStorageBuffers[2];
|
||||
drawBuffer = shaderStorageBuffers[3];
|
||||
debugBuffer = shaderStorageBuffers[4];
|
||||
meshPool = new IndirectMeshPool(Formats.BLOCK, 1024);
|
||||
|
@ -78,15 +76,15 @@ public class IndirectList<T extends InstancedPart> {
|
|||
maxObjectCount = 1024L;
|
||||
maxBatchCount = 64;
|
||||
|
||||
// +4 for the batch id
|
||||
objectStride = storageBufferWriter.getAlignment();
|
||||
glNamedBufferStorage(objectBuffer, objectStride * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
|
||||
glNamedBufferStorage(targetBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
|
||||
glNamedBufferStorage(boundingSphereBuffer, 16 * maxBatchCount, GL_DYNAMIC_STORAGE_BIT);
|
||||
glNamedBufferStorage(batchBuffer, 4 * maxObjectCount, 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);
|
||||
batchIDClientStorage = MemoryUtil.nmemAlloc(4 * maxObjectCount);
|
||||
|
||||
vertexArray = glCreateVertexArrays();
|
||||
|
||||
|
@ -121,7 +119,7 @@ public class IndirectList<T extends InstancedPart> {
|
|||
batches.add(new Batch<>(instancer, meshPool.alloc(mesh)));
|
||||
}
|
||||
|
||||
void submit(FrustumUBO frustumUBO) {
|
||||
void submit() {
|
||||
int instanceCountThisFrame = calculateTotalInstanceCount();
|
||||
|
||||
if (instanceCountThisFrame == 0) {
|
||||
|
@ -130,24 +128,22 @@ public class IndirectList<T extends InstancedPart> {
|
|||
|
||||
meshPool.uploadAll();
|
||||
uploadInstanceData();
|
||||
uploadBoundingSpheres();
|
||||
uploadIndirectCommands();
|
||||
|
||||
frustumUBO.bind();
|
||||
UniformBuffer.getInstance().sync();
|
||||
|
||||
dispatchCompute(instanceCountThisFrame);
|
||||
issueMemoryBarrier();
|
||||
dispatchDraw();
|
||||
}
|
||||
|
||||
private void dispatchDraw() {
|
||||
UniformBuffer.getInstance().sync();
|
||||
|
||||
draw.bind();
|
||||
Materials.BELL.setup();
|
||||
glVertexArrayElementBuffer(vertexArray, elementBuffer);
|
||||
glBindVertexArray(vertexArray);
|
||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, drawBuffer);
|
||||
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, 0, batches.size(), 0);
|
||||
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, DRAW_COMMAND_OFFSET, batches.size(), (int) DRAW_COMMAND_STRIDE);
|
||||
Materials.BELL.clear();
|
||||
}
|
||||
|
||||
|
@ -155,27 +151,11 @@ public class IndirectList<T extends InstancedPart> {
|
|||
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
}
|
||||
|
||||
private void uploadBoundingSpheres() {
|
||||
try (var stack = MemoryStack.stackPush()) {
|
||||
final int size = batches.size() * 16;
|
||||
final long basePtr = stack.nmalloc(size);
|
||||
|
||||
long ptr = basePtr;
|
||||
for (Batch<T> batch : batches) {
|
||||
var boundingSphere = batch.mesh.mesh.getBoundingSphere();
|
||||
boundingSphere.getToAddress(ptr);
|
||||
ptr += 16;
|
||||
}
|
||||
|
||||
nglNamedBufferSubData(boundingSphereBuffer, 0, size, basePtr);
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchCompute(int instanceCount) {
|
||||
compute.bind();
|
||||
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, 2, batchBuffer, 0, instanceCount * 4L);
|
||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 3, drawBuffer, 0, batches.size() * DRAW_COMMAND_STRIDE);
|
||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 4, debugBuffer, 0, instanceCount * 4L);
|
||||
|
||||
|
@ -184,22 +164,28 @@ public class IndirectList<T extends InstancedPart> {
|
|||
}
|
||||
|
||||
private void uploadInstanceData() {
|
||||
long ptr = objectClientStorage;
|
||||
long objectPtr = objectClientStorage;
|
||||
long batchIDPtr = batchIDClientStorage;
|
||||
int baseInstance = 0;
|
||||
int batchID = 0;
|
||||
for (var batch : batches) {
|
||||
batch.baseInstance = baseInstance;
|
||||
var instancer = batch.instancer;
|
||||
for (T t : instancer.getAll()) {
|
||||
storageBufferWriter.write(ptr, t, batchID);
|
||||
ptr += objectStride;
|
||||
// write object
|
||||
storageBufferWriter.write(objectPtr, t);
|
||||
objectPtr += objectStride;
|
||||
|
||||
// write batchID
|
||||
MemoryUtil.memPutInt(batchIDPtr, batchID);
|
||||
batchIDPtr += 4;
|
||||
}
|
||||
baseInstance += batch.instancer.instanceCount;
|
||||
batchID++;
|
||||
}
|
||||
|
||||
nglNamedBufferSubData(objectBuffer, 0, ptr - objectClientStorage, objectClientStorage);
|
||||
|
||||
nglNamedBufferSubData(objectBuffer, 0, objectPtr - objectClientStorage, objectClientStorage);
|
||||
nglNamedBufferSubData(batchBuffer, 0, batchIDPtr - batchIDClientStorage, batchIDClientStorage);
|
||||
}
|
||||
|
||||
private void uploadIndirectCommands() {
|
||||
|
@ -235,11 +221,15 @@ public class IndirectList<T extends InstancedPart> {
|
|||
}
|
||||
|
||||
public void writeIndirectCommand(long ptr) {
|
||||
MemoryUtil.memPutInt(ptr, mesh.getVertexCount()); // count
|
||||
var boundingSphere = mesh.mesh.getBoundingSphere();
|
||||
|
||||
MemoryUtil.memPutInt(ptr, mesh.getIndexCount()); // count
|
||||
MemoryUtil.memPutInt(ptr + 4, 0); // instanceCount - to be incremented by the compute shader
|
||||
MemoryUtil.memPutInt(ptr + 8, 0); // firstIndex - all models share the same index buffer
|
||||
MemoryUtil.memPutInt(ptr + 12, mesh.getBaseVertex()); // baseVertex
|
||||
MemoryUtil.memPutInt(ptr + 16, baseInstance); // baseInstance
|
||||
|
||||
boundingSphere.getToAddress(ptr + 32); // boundingSphere
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,11 +89,14 @@ public class IndirectMeshPool {
|
|||
public class BufferedMesh {
|
||||
|
||||
public final Mesh mesh;
|
||||
private final int vertexCount;
|
||||
private long byteIndex;
|
||||
private int baseVertex;
|
||||
|
||||
public BufferedMesh(Mesh mesh) {
|
||||
this.mesh = mesh;
|
||||
|
||||
vertexCount = mesh.getVertexCount();
|
||||
}
|
||||
|
||||
private void buffer(ByteBuffer buffer) {
|
||||
|
@ -103,7 +106,7 @@ public class IndirectMeshPool {
|
|||
}
|
||||
|
||||
public int getByteSize() {
|
||||
return IndirectMeshPool.this.vertexType.getLayout().getStride() * this.mesh.getVertexCount();
|
||||
return IndirectMeshPool.this.vertexType.getLayout().getStride() * this.vertexCount;
|
||||
}
|
||||
|
||||
public int getBaseVertex() {
|
||||
|
@ -111,7 +114,11 @@ public class IndirectMeshPool {
|
|||
}
|
||||
|
||||
public int getVertexCount() {
|
||||
return this.mesh.getVertexCount();
|
||||
return this.vertexCount;
|
||||
}
|
||||
|
||||
public int getIndexCount() {
|
||||
return this.vertexCount * 6 / 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,6 +112,7 @@ public class InstancedArraysCompiler extends Memoizer<InstancedArraysCompiler.Co
|
|||
StringBuilder finalSource = new StringBuilder();
|
||||
|
||||
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V420, ShaderType.VERTEX));
|
||||
finalSource.append("#extension GL_ARB_explicit_attrib_location : enable\n");
|
||||
|
||||
var index = new CompilationContext();
|
||||
|
||||
|
@ -197,6 +198,7 @@ public class InstancedArraysCompiler extends Memoizer<InstancedArraysCompiler.Co
|
|||
StringBuilder finalSource = new StringBuilder();
|
||||
|
||||
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V420, ShaderType.FRAGMENT));
|
||||
finalSource.append("#extension GL_ARB_conservative_depth : enable\n");
|
||||
|
||||
var ctx = new CompilationContext();
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import com.jozufozu.flywheel.core.source.SourceFile;
|
|||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.core.structs.StructTypes;
|
||||
import com.jozufozu.flywheel.core.uniform.FogProvider;
|
||||
import com.jozufozu.flywheel.core.uniform.FrustumProvider;
|
||||
import com.jozufozu.flywheel.core.uniform.ViewProvider;
|
||||
import com.jozufozu.flywheel.core.vertex.Formats;
|
||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||
|
@ -22,6 +23,7 @@ public class Components {
|
|||
|
||||
public static final ViewProvider VIEW_PROVIDER = ComponentRegistry.register(new ViewProvider());
|
||||
public static final FogProvider FOG_PROVIDER = ComponentRegistry.register(new FogProvider());
|
||||
public static final FrustumProvider FRUSTUM_PROVIDER = ComponentRegistry.register(new FrustumProvider());
|
||||
public static final ContextShader WORLD = ComponentRegistry.register(new ContextShader(WorldProgram::new, Files.WORLD_VERTEX, Files.WORLD_FRAGMENT));
|
||||
public static final ContextShader CRUMBLING = ComponentRegistry.register(new ContextShader(CrumblingProgram::new, Files.WORLD_VERTEX, Files.CRUMBLING_FRAGMENT));
|
||||
|
||||
|
@ -36,6 +38,7 @@ public class Components {
|
|||
|
||||
public static final FileResolution VIEW_UNIFORMS = uniform(Flywheel.rl("uniform/view.glsl"));
|
||||
public static final FileResolution FOG_UNIFORMS = uniform(Flywheel.rl("uniform/fog.glsl"));
|
||||
public static final FileResolution FRUSTUM_UNIFORMS = uniform(Flywheel.rl("uniform/frustum.glsl"));
|
||||
public static final FileResolution BLOCK_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.BLOCK, ".vert"));
|
||||
public static final FileResolution POS_TEX_NORMAL_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.POS_TEX_NORMAL, ".vert"));
|
||||
public static final FileResolution TRANSFORMED = instanceVertex(ResourceUtil.subPath(Names.TRANSFORMED, ".vert"));
|
||||
|
|
|
@ -17,9 +17,7 @@ public class CompileUtil {
|
|||
public static final Pattern matType = Pattern.compile("^mat([234])(?:x([234]))?$");
|
||||
|
||||
public static String generateHeader(GLSLVersion version, ShaderType type) {
|
||||
return "#version " + version + '\n'
|
||||
+ "#extension GL_ARB_explicit_attrib_location : enable\n"
|
||||
+ "#extension GL_ARB_conservative_depth : enable\n"
|
||||
return version.getVersionLine()
|
||||
+ type.getDefineStatement()
|
||||
+ '\n';
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ public class FileResolution {
|
|||
ErrorBuilder builder = errorReporter.error(String.format("could not find source for file %s", fileLoc));
|
||||
for (Span location : neededAt) {
|
||||
builder.pointAtFile(location.getSourceFile())
|
||||
.pointAt(location, 1);
|
||||
.pointAt(location);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,10 @@ public class ErrorBuilder {
|
|||
.pointAt(span, 0);
|
||||
}
|
||||
|
||||
public ErrorBuilder pointAt(Span span) {
|
||||
return pointAt(span, 0);
|
||||
}
|
||||
|
||||
public ErrorBuilder pointAt(Span span, int ctxLines) {
|
||||
|
||||
if (span.lines() == 1) {
|
||||
|
@ -123,7 +127,9 @@ public class ErrorBuilder {
|
|||
for (ErrorLine line : lines) {
|
||||
int length = line.neededMargin();
|
||||
|
||||
if (length > maxLength) maxLength = length;
|
||||
if (length > maxLength) {
|
||||
maxLength = length;
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
|
|
@ -3,9 +3,11 @@ package com.jozufozu.flywheel.core.source.error;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderFunction;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderStruct;
|
||||
|
@ -82,10 +84,12 @@ public class ErrorReporter {
|
|||
return !reportedErrors.isEmpty();
|
||||
}
|
||||
|
||||
public void dump() {
|
||||
for (var error : reportedErrors) {
|
||||
Backend.LOGGER.error(error.build());
|
||||
}
|
||||
public ShaderLoadingException dump() {
|
||||
var allErrors = reportedErrors.stream()
|
||||
.map(ErrorBuilder::build)
|
||||
.collect(Collectors.joining());
|
||||
|
||||
return new ShaderLoadingException(allErrors);
|
||||
}
|
||||
|
||||
public static void printLines(CharSequence source) {
|
||||
|
|
|
@ -13,7 +13,7 @@ public class OrientedStorageWriter implements StorageBufferWriter<OrientedPart>
|
|||
}
|
||||
|
||||
@Override
|
||||
public void write(final long ptr, OrientedPart d, final int batchID) {
|
||||
public void write(final long ptr, OrientedPart d) {
|
||||
MemoryUtil.memPutFloat(ptr, d.qX);
|
||||
MemoryUtil.memPutFloat(ptr + 4, d.qY);
|
||||
MemoryUtil.memPutFloat(ptr + 8, d.qZ);
|
||||
|
@ -27,15 +27,13 @@ public class OrientedStorageWriter implements StorageBufferWriter<OrientedPart>
|
|||
MemoryUtil.memPutFloat(ptr + 36, d.pivotY);
|
||||
MemoryUtil.memPutFloat(ptr + 40, d.pivotZ);
|
||||
|
||||
MemoryUtil.memPutShort(ptr + 44, d.blockLight);
|
||||
MemoryUtil.memPutShort(ptr + 46, d.skyLight);
|
||||
MemoryUtil.memPutShort(ptr + 44, d.skyLight);
|
||||
MemoryUtil.memPutShort(ptr + 46, d.blockLight);
|
||||
|
||||
MemoryUtil.memPutByte(ptr + 48, d.r);
|
||||
MemoryUtil.memPutByte(ptr + 49, d.g);
|
||||
MemoryUtil.memPutByte(ptr + 50, d.b);
|
||||
MemoryUtil.memPutByte(ptr + 51, d.a);
|
||||
|
||||
MemoryUtil.memPutInt(ptr + 52, batchID);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
package com.jozufozu.flywheel.core.uniform;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.uniform.UniformProvider;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.jozufozu.flywheel.core.Components;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
||||
import com.jozufozu.flywheel.util.extension.MatrixExtension;
|
||||
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
public class FrustumProvider extends UniformProvider {
|
||||
|
||||
public FrustumProvider() {
|
||||
MinecraftForge.EVENT_BUS.addListener(this::beginFrame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActualByteSize() {
|
||||
return 96;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResolution getUniformShader() {
|
||||
return Components.Files.FRUSTUM_UNIFORMS;
|
||||
}
|
||||
|
||||
public void beginFrame(BeginFrameEvent event) {
|
||||
update(event.getContext());
|
||||
}
|
||||
|
||||
public void update(RenderContext context) {
|
||||
if (buffer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(context.level());
|
||||
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 shiftedCuller = RenderContext.createCuller(context.viewProjection(), -camX, -camY, -camZ);
|
||||
|
||||
long ptr = MemoryUtil.memAddress(buffer);
|
||||
|
||||
shiftedCuller.getJozuPackedPlanes(ptr);
|
||||
|
||||
notifier.signalChanged();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
#ifdef COMPUTE_SHADER
|
||||
uint flw_objectID;
|
||||
uint flw_batchID;
|
||||
#endif
|
|
@ -1,3 +1,4 @@
|
|||
#ifdef FRAGMENT_SHADER
|
||||
in vec4 flw_vertexPos;
|
||||
in vec4 flw_vertexColor;
|
||||
in vec2 flw_vertexTexCoord;
|
||||
|
@ -32,3 +33,4 @@ vec4 flw_fogFilter(vec4 color);
|
|||
* Guard calls with FLW_DISCARD
|
||||
*/
|
||||
bool flw_discardPredicate(vec4 finalColor);
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#ifdef VERTEX_SHADER
|
||||
out vec4 flw_vertexPos;
|
||||
out vec4 flw_vertexColor;
|
||||
out vec2 flw_vertexTexCoord;
|
||||
|
@ -11,3 +12,4 @@ out vec4 flw_var0;
|
|||
out vec4 flw_var1;
|
||||
out vec4 flw_var2;
|
||||
out vec4 flw_var3;
|
||||
#endif
|
||||
|
|
|
@ -1,67 +1,60 @@
|
|||
#define FLW_SUBGROUP_SIZE 32
|
||||
layout(local_size_x = FLW_SUBGROUP_SIZE) in;
|
||||
#use "flywheel:compute/objects.glsl"
|
||||
#use "flywheel:api/cull.glsl"
|
||||
#use "flywheel:util/quaternion.glsl"
|
||||
#use "flywheel:uniform/frustum.glsl"
|
||||
#use "flywheel:instance/oriented_indirect.glsl"
|
||||
|
||||
uint flw_objectID;
|
||||
uint flw_batchID;
|
||||
struct MeshDrawCommand {
|
||||
uint indexCount;
|
||||
uint instanceCount;
|
||||
uint firstIndex;
|
||||
uint vertexOffset;
|
||||
uint baseInstance;
|
||||
|
||||
layout(std140, binding = 0) uniform FrameData {
|
||||
vec4 a1; // vec4(nx.x, px.x, ny.x, py.x)
|
||||
vec4 a2; // vec4(nx.y, px.y, ny.y, py.y)
|
||||
vec4 a3; // vec4(nx.z, px.z, ny.z, py.z)
|
||||
vec4 a4; // vec4(nx.w, px.w, ny.w, py.w)
|
||||
vec2 b1; // vec2(nz.x, pz.x)
|
||||
vec2 b2; // vec2(nz.y, pz.y)
|
||||
vec2 b3; // vec2(nz.z, pz.z)
|
||||
vec2 b4; // vec2(nz.w, pz.w)
|
||||
} frustum;
|
||||
|
||||
// populated by instancers
|
||||
layout(std430, binding = 0) readonly buffer ObjectBuffer {
|
||||
Instance objects[];
|
||||
vec4 boundingSphere;
|
||||
};
|
||||
|
||||
layout(std430, binding = 1) writeonly buffer TargetBuffer {
|
||||
// populated by instancers
|
||||
layout(std430, binding = 0) restrict readonly buffer ObjectBuffer {
|
||||
FLW_INSTANCE_STRUCT objects[];
|
||||
};
|
||||
|
||||
layout(std430, binding = 1) restrict writeonly buffer TargetBuffer {
|
||||
uint objectIDs[];
|
||||
};
|
||||
|
||||
layout(std430, binding = 2) readonly buffer BoundingSpheres {
|
||||
vec4 boundingSpheres[];
|
||||
layout(std430, binding = 2) restrict readonly buffer BatchBuffer {
|
||||
uint batchIDs[];
|
||||
};
|
||||
|
||||
layout(std430, binding = 3) buffer DrawCommands {
|
||||
layout(std430, binding = 3) restrict buffer DrawCommands {
|
||||
MeshDrawCommand drawCommands[];
|
||||
};
|
||||
|
||||
layout(std430, binding = 4) writeonly buffer DebugVisibility {
|
||||
layout(std430, binding = 4) restrict writeonly buffer DebugVisibility {
|
||||
uint objectVisibilityBits[];
|
||||
};
|
||||
|
||||
// 83 - 27 = 56 spirv instruction results
|
||||
bool testSphere(vec3 center, float radius) {
|
||||
bvec4 resultA = greaterThanEqual(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);
|
||||
bvec4 xyInside = greaterThanEqual(fma(flw_planes.xyX, center.xxxx, fma(flw_planes.xyY, center.yyyy, fma(flw_planes.xyZ, center.zzzz, flw_planes.xyW))), -radius.xxxx);
|
||||
bvec2 zInside = greaterThanEqual(fma(flw_planes.zX, center.xx, fma(flw_planes.zY, center.yy, fma(flw_planes.zZ, center.zz, flw_planes.zW))), -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;
|
||||
uint debug = uint(xyInside.x);
|
||||
debug |= uint(xyInside.y) << 1;
|
||||
debug |= uint(xyInside.z) << 2;
|
||||
debug |= uint(xyInside.w) << 3;
|
||||
debug |= uint(zInside.x) << 4;
|
||||
debug |= uint(zInside.y) << 5;
|
||||
|
||||
objectVisibilityBits[flw_objectID] = debug;
|
||||
|
||||
return all(resultA) && all(resultB);
|
||||
}
|
||||
|
||||
void flw_transformBoundingSphere(in Instance i, inout vec3 center, inout float radius) {
|
||||
center = rotateVertexByQuat(center - i.pivot, i.rotation) + i.pivot + i.pos;
|
||||
radius = radius;
|
||||
return all(xyInside) && all(zInside);
|
||||
}
|
||||
|
||||
bool isVisible() {
|
||||
vec4 sphere = boundingSpheres[flw_batchID];
|
||||
vec4 sphere = drawCommands[flw_batchID].boundingSphere;
|
||||
|
||||
vec3 center = sphere.xyz;
|
||||
float radius = sphere.r;
|
||||
|
@ -77,7 +70,7 @@ void main() {
|
|||
return;
|
||||
}
|
||||
|
||||
flw_batchID = objects[objectID].batchID;
|
||||
flw_batchID = batchIDs[flw_objectID];
|
||||
|
||||
if (isVisible()) {
|
||||
uint batchIndex = atomicAdd(drawCommands[flw_batchID].instanceCount, 1);
|
||||
|
|
|
@ -1,25 +1,18 @@
|
|||
#use "flywheel:api/vertex.glsl"
|
||||
#use "flywheel:compute/objects.glsl"
|
||||
#use "flywheel:layout/block.vert"
|
||||
#use "flywheel:context/world.vert"
|
||||
#use "flywheel:util/quaternion.glsl"
|
||||
#use "flywheel:instance/oriented_indirect.glsl"
|
||||
|
||||
// populated by instancers
|
||||
layout(std430, binding = 0) readonly buffer ObjectBuffer {
|
||||
Instance objects[];
|
||||
layout(std430, binding = 0) restrict readonly buffer ObjectBuffer {
|
||||
FLW_INSTANCE_STRUCT objects[];
|
||||
};
|
||||
|
||||
layout(std430, binding = 1) readonly buffer TargetBuffer {
|
||||
layout(std430, binding = 1) restrict readonly buffer TargetBuffer {
|
||||
uint objectIDs[];
|
||||
};
|
||||
|
||||
void flw_instanceVertex(Instance i) {
|
||||
flw_vertexPos = vec4(rotateVertexByQuat(flw_vertexPos.xyz - i.pivot, i.rotation) + i.pivot + i.pos, 1.0);
|
||||
flw_vertexNormal = rotateVertexByQuat(flw_vertexNormal, i.rotation);
|
||||
flw_vertexColor = unpackUnorm4x8(i.color);
|
||||
flw_vertexLight = unpackUnorm2x16(i.light) / 15.0;
|
||||
}
|
||||
|
||||
void main() {
|
||||
uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID];
|
||||
flw_layoutVertex();
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
|
||||
struct Instance {
|
||||
vec4 rotation;
|
||||
vec3 pos;
|
||||
vec3 pivot;
|
||||
uint light;
|
||||
uint color;
|
||||
uint batchID;
|
||||
};
|
||||
|
||||
struct MeshDrawCommand {
|
||||
uint indexCount;
|
||||
uint instanceCount;
|
||||
uint firstIndex;
|
||||
uint vertexOffset;
|
||||
uint baseInstance;
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
#use "flywheel:api/vertex.glsl"
|
||||
#use "flywheel:util/quaternion.glsl"
|
||||
#define FLW_INSTANCE_STRUCT Instance
|
||||
|
||||
struct Instance {
|
||||
vec4 rotation;
|
||||
vec3 pos;
|
||||
vec3 pivot;
|
||||
uint light;
|
||||
uint color;
|
||||
};
|
||||
|
||||
void flw_transformBoundingSphere(in Instance i, inout vec3 center, inout float radius) {
|
||||
center = rotateVertexByQuat(center - i.pivot, i.rotation) + i.pivot + i.pos;
|
||||
}
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
void flw_instanceVertex(Instance i) {
|
||||
flw_vertexPos = vec4(rotateVertexByQuat(flw_vertexPos.xyz - i.pivot, i.rotation) + i.pivot + i.pos, 1.0);
|
||||
flw_vertexNormal = rotateVertexByQuat(flw_vertexNormal, i.rotation);
|
||||
flw_vertexColor = unpackUnorm4x8(i.color);
|
||||
flw_vertexLight = vec2(float((i.light >> 16) & 0xFFFFu), float(i.light & 0xFFFFu)) / 15.0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,22 @@
|
|||
#use "flywheel:api/vertex.glsl"
|
||||
#define FLW_INSTANCE_STRUCT Instance
|
||||
|
||||
struct Instance {
|
||||
mat4 pose;
|
||||
mat3 normal;
|
||||
uint color;
|
||||
uint light;
|
||||
};
|
||||
|
||||
void flw_transformBoundingSphere(in Instance i, inout vec3 center, inout float radius) {
|
||||
center = (i.pose * vec4(center, 1.0)).xyz;
|
||||
}
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
void flw_instanceVertex(Instance i) {
|
||||
flw_vertexPos = i.pose * flw_vertexPos;
|
||||
flw_vertexNormal = i.normal * flw_vertexNormal;
|
||||
flw_vertexColor = unpackUnorm4x8(i.color);
|
||||
flw_vertexLight = vec2(float((i.light >> 16) & 0xFFFFu), float(i.light & 0xFFFFu)) / 15.0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,14 @@
|
|||
struct FLWPackedPlanes {
|
||||
vec4 xyX; // <nx.x, px.x, ny.x, py.x>
|
||||
vec4 xyY; // <nx.y, px.y, ny.y, py.y>
|
||||
vec4 xyZ; // <nx.z, px.z, ny.z, py.z>
|
||||
vec4 xyW; // <nx.w, px.w, ny.w, py.w>
|
||||
vec2 zX; // <nz.x, pz.x>
|
||||
vec2 zY; // <nz.y, pz.y>
|
||||
vec2 zZ; // <nz.z, pz.z>
|
||||
vec2 zW; // <nz.w, pz.w>
|
||||
};
|
||||
|
||||
layout(std140, binding = 2) uniform FLWFrustum {
|
||||
FLWPackedPlanes flw_planes;
|
||||
};
|
Loading…
Reference in a new issue