mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-07 02:34:58 +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
63dc8ee923
commit
03f6125c68
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> {
|
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();
|
int getAlignment();
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,8 +52,7 @@ public class Loader implements ResourceManagerReloadListener {
|
||||||
FileResolution.run(errorReporter, sources);
|
FileResolution.run(errorReporter, sources);
|
||||||
|
|
||||||
if (errorReporter.hasErrored()) {
|
if (errorReporter.hasErrored()) {
|
||||||
errorReporter.dump();
|
throw errorReporter.dump();
|
||||||
throw new ShaderLoadingException("Failed to resolve all source files, see log for details");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sources.postResolve();
|
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.GlProgram;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
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.Memoizer;
|
||||||
import com.jozufozu.flywheel.core.compile.ProgramAssembler;
|
import com.jozufozu.flywheel.core.compile.ProgramAssembler;
|
||||||
import com.jozufozu.flywheel.core.compile.ShaderCompilationException;
|
import com.jozufozu.flywheel.core.compile.ShaderCompilationException;
|
||||||
|
@ -24,7 +25,7 @@ public class ComputeCullerCompiler extends Memoizer<FileResolution, GlProgram> {
|
||||||
|
|
||||||
CompilationContext context = new CompilationContext();
|
CompilationContext context = new CompilationContext();
|
||||||
|
|
||||||
var header = GLSLVersion.V460.getVersionLine();
|
var header = CompileUtil.generateHeader(GLSLVersion.V460, ShaderType.COMPUTE);
|
||||||
String source = file.getFile()
|
String source = file.getFile()
|
||||||
.generateFinalSource(context);
|
.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 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.
|
||||||
*/
|
*/
|
||||||
|
@ -77,7 +75,7 @@ public class IndirectEngine implements Engine {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
for (var group : groups) {
|
for (var group : groups) {
|
||||||
group.submit(frustumUBO);
|
group.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -146,26 +144,10 @@ 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) {
|
||||||
|
|
|
@ -21,7 +21,8 @@ import com.jozufozu.flywheel.core.vertex.Formats;
|
||||||
|
|
||||||
public class IndirectList<T extends InstancedPart> {
|
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 StorageBufferWriter<T> storageBufferWriter;
|
||||||
final GlProgram compute;
|
final GlProgram compute;
|
||||||
|
@ -31,18 +32,15 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
private final long objectStride;
|
private final long objectStride;
|
||||||
private final int maxBatchCount;
|
private final int maxBatchCount;
|
||||||
private final long objectClientStorage;
|
private final long objectClientStorage;
|
||||||
|
private final long batchIDClientStorage;
|
||||||
private final int elementBuffer;
|
private final int elementBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores raw instance data per-object.
|
* Stores raw instance data per-object.
|
||||||
*/
|
*/
|
||||||
int objectBuffer;
|
int objectBuffer;
|
||||||
|
|
||||||
int targetBuffer;
|
int targetBuffer;
|
||||||
/**
|
int batchBuffer;
|
||||||
* Stores bounding spheres
|
|
||||||
*/
|
|
||||||
int boundingSphereBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores drawIndirect structs.
|
* Stores drawIndirect structs.
|
||||||
|
@ -69,7 +67,7 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
glCreateBuffers(shaderStorageBuffers);
|
glCreateBuffers(shaderStorageBuffers);
|
||||||
objectBuffer = shaderStorageBuffers[0];
|
objectBuffer = shaderStorageBuffers[0];
|
||||||
targetBuffer = shaderStorageBuffers[1];
|
targetBuffer = shaderStorageBuffers[1];
|
||||||
boundingSphereBuffer = shaderStorageBuffers[2];
|
batchBuffer = shaderStorageBuffers[2];
|
||||||
drawBuffer = shaderStorageBuffers[3];
|
drawBuffer = shaderStorageBuffers[3];
|
||||||
debugBuffer = shaderStorageBuffers[4];
|
debugBuffer = shaderStorageBuffers[4];
|
||||||
meshPool = new IndirectMeshPool(Formats.BLOCK, 1024);
|
meshPool = new IndirectMeshPool(Formats.BLOCK, 1024);
|
||||||
|
@ -78,15 +76,15 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
maxObjectCount = 1024L;
|
maxObjectCount = 1024L;
|
||||||
maxBatchCount = 64;
|
maxBatchCount = 64;
|
||||||
|
|
||||||
// +4 for the batch id
|
|
||||||
objectStride = storageBufferWriter.getAlignment();
|
objectStride = storageBufferWriter.getAlignment();
|
||||||
glNamedBufferStorage(objectBuffer, objectStride * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
|
glNamedBufferStorage(objectBuffer, objectStride * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
|
||||||
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(batchBuffer, 4 * maxObjectCount, 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);
|
glNamedBufferStorage(debugBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
|
||||||
|
|
||||||
objectClientStorage = MemoryUtil.nmemAlloc(objectStride * maxObjectCount);
|
objectClientStorage = MemoryUtil.nmemAlloc(objectStride * maxObjectCount);
|
||||||
|
batchIDClientStorage = MemoryUtil.nmemAlloc(4 * maxObjectCount);
|
||||||
|
|
||||||
vertexArray = glCreateVertexArrays();
|
vertexArray = glCreateVertexArrays();
|
||||||
|
|
||||||
|
@ -121,7 +119,7 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
batches.add(new Batch<>(instancer, meshPool.alloc(mesh)));
|
batches.add(new Batch<>(instancer, meshPool.alloc(mesh)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void submit(FrustumUBO frustumUBO) {
|
void submit() {
|
||||||
int instanceCountThisFrame = calculateTotalInstanceCount();
|
int instanceCountThisFrame = calculateTotalInstanceCount();
|
||||||
|
|
||||||
if (instanceCountThisFrame == 0) {
|
if (instanceCountThisFrame == 0) {
|
||||||
|
@ -130,24 +128,22 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
|
|
||||||
meshPool.uploadAll();
|
meshPool.uploadAll();
|
||||||
uploadInstanceData();
|
uploadInstanceData();
|
||||||
uploadBoundingSpheres();
|
|
||||||
uploadIndirectCommands();
|
uploadIndirectCommands();
|
||||||
|
|
||||||
frustumUBO.bind();
|
UniformBuffer.getInstance().sync();
|
||||||
|
|
||||||
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);
|
||||||
glBindVertexArray(vertexArray);
|
glBindVertexArray(vertexArray);
|
||||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, drawBuffer);
|
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();
|
Materials.BELL.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,27 +151,11 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
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) {
|
private void dispatchCompute(int instanceCount) {
|
||||||
compute.bind();
|
compute.bind();
|
||||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, objectBuffer, 0, instanceCount * objectStride);
|
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, 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, 3, drawBuffer, 0, batches.size() * DRAW_COMMAND_STRIDE);
|
||||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 4, debugBuffer, 0, instanceCount * 4L);
|
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 4, debugBuffer, 0, instanceCount * 4L);
|
||||||
|
|
||||||
|
@ -184,22 +164,28 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void uploadInstanceData() {
|
private void uploadInstanceData() {
|
||||||
long ptr = objectClientStorage;
|
long objectPtr = objectClientStorage;
|
||||||
|
long batchIDPtr = batchIDClientStorage;
|
||||||
int baseInstance = 0;
|
int baseInstance = 0;
|
||||||
int batchID = 0;
|
int batchID = 0;
|
||||||
for (var batch : batches) {
|
for (var batch : batches) {
|
||||||
batch.baseInstance = baseInstance;
|
batch.baseInstance = baseInstance;
|
||||||
var instancer = batch.instancer;
|
var instancer = batch.instancer;
|
||||||
for (T t : instancer.getAll()) {
|
for (T t : instancer.getAll()) {
|
||||||
storageBufferWriter.write(ptr, t, batchID);
|
// write object
|
||||||
ptr += objectStride;
|
storageBufferWriter.write(objectPtr, t);
|
||||||
|
objectPtr += objectStride;
|
||||||
|
|
||||||
|
// write batchID
|
||||||
|
MemoryUtil.memPutInt(batchIDPtr, batchID);
|
||||||
|
batchIDPtr += 4;
|
||||||
}
|
}
|
||||||
baseInstance += batch.instancer.instanceCount;
|
baseInstance += batch.instancer.instanceCount;
|
||||||
batchID++;
|
batchID++;
|
||||||
}
|
}
|
||||||
|
|
||||||
nglNamedBufferSubData(objectBuffer, 0, ptr - objectClientStorage, objectClientStorage);
|
nglNamedBufferSubData(objectBuffer, 0, objectPtr - objectClientStorage, objectClientStorage);
|
||||||
|
nglNamedBufferSubData(batchBuffer, 0, batchIDPtr - batchIDClientStorage, batchIDClientStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void uploadIndirectCommands() {
|
private void uploadIndirectCommands() {
|
||||||
|
@ -235,11 +221,15 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeIndirectCommand(long ptr) {
|
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 + 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 + 8, 0); // firstIndex - all models share the same index buffer
|
||||||
MemoryUtil.memPutInt(ptr + 12, mesh.getBaseVertex()); // baseVertex
|
MemoryUtil.memPutInt(ptr + 12, mesh.getBaseVertex()); // baseVertex
|
||||||
MemoryUtil.memPutInt(ptr + 16, baseInstance); // baseInstance
|
MemoryUtil.memPutInt(ptr + 16, baseInstance); // baseInstance
|
||||||
|
|
||||||
|
boundingSphere.getToAddress(ptr + 32); // boundingSphere
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,11 +89,14 @@ public class IndirectMeshPool {
|
||||||
public class BufferedMesh {
|
public class BufferedMesh {
|
||||||
|
|
||||||
public final Mesh mesh;
|
public final Mesh mesh;
|
||||||
|
private final int vertexCount;
|
||||||
private long byteIndex;
|
private long byteIndex;
|
||||||
private int baseVertex;
|
private int baseVertex;
|
||||||
|
|
||||||
public BufferedMesh(Mesh mesh) {
|
public BufferedMesh(Mesh mesh) {
|
||||||
this.mesh = mesh;
|
this.mesh = mesh;
|
||||||
|
|
||||||
|
vertexCount = mesh.getVertexCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buffer(ByteBuffer buffer) {
|
private void buffer(ByteBuffer buffer) {
|
||||||
|
@ -103,7 +106,7 @@ public class IndirectMeshPool {
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getByteSize() {
|
public int getByteSize() {
|
||||||
return IndirectMeshPool.this.vertexType.getLayout().getStride() * this.mesh.getVertexCount();
|
return IndirectMeshPool.this.vertexType.getLayout().getStride() * this.vertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBaseVertex() {
|
public int getBaseVertex() {
|
||||||
|
@ -111,7 +114,11 @@ public class IndirectMeshPool {
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getVertexCount() {
|
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();
|
StringBuilder finalSource = new StringBuilder();
|
||||||
|
|
||||||
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V420, ShaderType.VERTEX));
|
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V420, ShaderType.VERTEX));
|
||||||
|
finalSource.append("#extension GL_ARB_explicit_attrib_location : enable\n");
|
||||||
|
|
||||||
var index = new CompilationContext();
|
var index = new CompilationContext();
|
||||||
|
|
||||||
|
@ -197,6 +198,7 @@ public class InstancedArraysCompiler extends Memoizer<InstancedArraysCompiler.Co
|
||||||
StringBuilder finalSource = new StringBuilder();
|
StringBuilder finalSource = new StringBuilder();
|
||||||
|
|
||||||
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V420, ShaderType.FRAGMENT));
|
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V420, ShaderType.FRAGMENT));
|
||||||
|
finalSource.append("#extension GL_ARB_conservative_depth : enable\n");
|
||||||
|
|
||||||
var ctx = new CompilationContext();
|
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.source.error.ErrorReporter;
|
||||||
import com.jozufozu.flywheel.core.structs.StructTypes;
|
import com.jozufozu.flywheel.core.structs.StructTypes;
|
||||||
import com.jozufozu.flywheel.core.uniform.FogProvider;
|
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.uniform.ViewProvider;
|
||||||
import com.jozufozu.flywheel.core.vertex.Formats;
|
import com.jozufozu.flywheel.core.vertex.Formats;
|
||||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
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 ViewProvider VIEW_PROVIDER = ComponentRegistry.register(new ViewProvider());
|
||||||
public static final FogProvider FOG_PROVIDER = ComponentRegistry.register(new FogProvider());
|
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 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));
|
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 VIEW_UNIFORMS = uniform(Flywheel.rl("uniform/view.glsl"));
|
||||||
public static final FileResolution FOG_UNIFORMS = uniform(Flywheel.rl("uniform/fog.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 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 POS_TEX_NORMAL_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.POS_TEX_NORMAL, ".vert"));
|
||||||
public static final FileResolution TRANSFORMED = instanceVertex(ResourceUtil.subPath(Names.TRANSFORMED, ".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 final Pattern matType = Pattern.compile("^mat([234])(?:x([234]))?$");
|
||||||
|
|
||||||
public static String generateHeader(GLSLVersion version, ShaderType type) {
|
public static String generateHeader(GLSLVersion version, ShaderType type) {
|
||||||
return "#version " + version + '\n'
|
return version.getVersionLine()
|
||||||
+ "#extension GL_ARB_explicit_attrib_location : enable\n"
|
|
||||||
+ "#extension GL_ARB_conservative_depth : enable\n"
|
|
||||||
+ type.getDefineStatement()
|
+ type.getDefineStatement()
|
||||||
+ '\n';
|
+ '\n';
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ public class FileResolution {
|
||||||
ErrorBuilder builder = errorReporter.error(String.format("could not find source for file %s", fileLoc));
|
ErrorBuilder builder = errorReporter.error(String.format("could not find source for file %s", fileLoc));
|
||||||
for (Span location : neededAt) {
|
for (Span location : neededAt) {
|
||||||
builder.pointAtFile(location.getSourceFile())
|
builder.pointAtFile(location.getSourceFile())
|
||||||
.pointAt(location, 1);
|
.pointAt(location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,10 @@ public class ErrorBuilder {
|
||||||
.pointAt(span, 0);
|
.pointAt(span, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ErrorBuilder pointAt(Span span) {
|
||||||
|
return pointAt(span, 0);
|
||||||
|
}
|
||||||
|
|
||||||
public ErrorBuilder pointAt(Span span, int ctxLines) {
|
public ErrorBuilder pointAt(Span span, int ctxLines) {
|
||||||
|
|
||||||
if (span.lines() == 1) {
|
if (span.lines() == 1) {
|
||||||
|
@ -123,7 +127,9 @@ public class ErrorBuilder {
|
||||||
for (ErrorLine line : lines) {
|
for (ErrorLine line : lines) {
|
||||||
int length = line.neededMargin();
|
int length = line.neededMargin();
|
||||||
|
|
||||||
if (length > maxLength) maxLength = length;
|
if (length > maxLength) {
|
||||||
|
maxLength = length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
|
@ -3,9 +3,11 @@ package com.jozufozu.flywheel.core.source.error;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
import com.jozufozu.flywheel.Flywheel;
|
||||||
import com.jozufozu.flywheel.backend.Backend;
|
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.SourceFile;
|
||||||
import com.jozufozu.flywheel.core.source.parse.ShaderFunction;
|
import com.jozufozu.flywheel.core.source.parse.ShaderFunction;
|
||||||
import com.jozufozu.flywheel.core.source.parse.ShaderStruct;
|
import com.jozufozu.flywheel.core.source.parse.ShaderStruct;
|
||||||
|
@ -82,10 +84,12 @@ public class ErrorReporter {
|
||||||
return !reportedErrors.isEmpty();
|
return !reportedErrors.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dump() {
|
public ShaderLoadingException dump() {
|
||||||
for (var error : reportedErrors) {
|
var allErrors = reportedErrors.stream()
|
||||||
Backend.LOGGER.error(error.build());
|
.map(ErrorBuilder::build)
|
||||||
}
|
.collect(Collectors.joining());
|
||||||
|
|
||||||
|
return new ShaderLoadingException(allErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void printLines(CharSequence source) {
|
public static void printLines(CharSequence source) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ public class OrientedStorageWriter implements StorageBufferWriter<OrientedPart>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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, d.qX);
|
||||||
MemoryUtil.memPutFloat(ptr + 4, d.qY);
|
MemoryUtil.memPutFloat(ptr + 4, d.qY);
|
||||||
MemoryUtil.memPutFloat(ptr + 8, d.qZ);
|
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 + 36, d.pivotY);
|
||||||
MemoryUtil.memPutFloat(ptr + 40, d.pivotZ);
|
MemoryUtil.memPutFloat(ptr + 40, d.pivotZ);
|
||||||
|
|
||||||
MemoryUtil.memPutShort(ptr + 44, d.blockLight);
|
MemoryUtil.memPutShort(ptr + 44, d.skyLight);
|
||||||
MemoryUtil.memPutShort(ptr + 46, d.skyLight);
|
MemoryUtil.memPutShort(ptr + 46, d.blockLight);
|
||||||
|
|
||||||
MemoryUtil.memPutByte(ptr + 48, d.r);
|
MemoryUtil.memPutByte(ptr + 48, d.r);
|
||||||
MemoryUtil.memPutByte(ptr + 49, d.g);
|
MemoryUtil.memPutByte(ptr + 49, d.g);
|
||||||
MemoryUtil.memPutByte(ptr + 50, d.b);
|
MemoryUtil.memPutByte(ptr + 50, d.b);
|
||||||
MemoryUtil.memPutByte(ptr + 51, d.a);
|
MemoryUtil.memPutByte(ptr + 51, d.a);
|
||||||
|
|
||||||
MemoryUtil.memPutInt(ptr + 52, batchID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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_vertexPos;
|
||||||
in vec4 flw_vertexColor;
|
in vec4 flw_vertexColor;
|
||||||
in vec2 flw_vertexTexCoord;
|
in vec2 flw_vertexTexCoord;
|
||||||
|
@ -32,3 +33,4 @@ vec4 flw_fogFilter(vec4 color);
|
||||||
* Guard calls with FLW_DISCARD
|
* Guard calls with FLW_DISCARD
|
||||||
*/
|
*/
|
||||||
bool flw_discardPredicate(vec4 finalColor);
|
bool flw_discardPredicate(vec4 finalColor);
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#ifdef VERTEX_SHADER
|
||||||
out vec4 flw_vertexPos;
|
out vec4 flw_vertexPos;
|
||||||
out vec4 flw_vertexColor;
|
out vec4 flw_vertexColor;
|
||||||
out vec2 flw_vertexTexCoord;
|
out vec2 flw_vertexTexCoord;
|
||||||
|
@ -11,3 +12,4 @@ out vec4 flw_var0;
|
||||||
out vec4 flw_var1;
|
out vec4 flw_var1;
|
||||||
out vec4 flw_var2;
|
out vec4 flw_var2;
|
||||||
out vec4 flw_var3;
|
out vec4 flw_var3;
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,67 +1,60 @@
|
||||||
#define FLW_SUBGROUP_SIZE 32
|
#define FLW_SUBGROUP_SIZE 32
|
||||||
layout(local_size_x = FLW_SUBGROUP_SIZE) in;
|
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:util/quaternion.glsl"
|
||||||
|
#use "flywheel:uniform/frustum.glsl"
|
||||||
|
#use "flywheel:instance/oriented_indirect.glsl"
|
||||||
|
|
||||||
uint flw_objectID;
|
struct MeshDrawCommand {
|
||||||
uint flw_batchID;
|
uint indexCount;
|
||||||
|
uint instanceCount;
|
||||||
|
uint firstIndex;
|
||||||
|
uint vertexOffset;
|
||||||
|
uint baseInstance;
|
||||||
|
|
||||||
layout(std140, binding = 0) uniform FrameData {
|
vec4 boundingSphere;
|
||||||
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[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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[];
|
uint objectIDs[];
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(std430, binding = 2) readonly buffer BoundingSpheres {
|
layout(std430, binding = 2) restrict readonly buffer BatchBuffer {
|
||||||
vec4 boundingSpheres[];
|
uint batchIDs[];
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(std430, binding = 3) buffer DrawCommands {
|
layout(std430, binding = 3) restrict buffer DrawCommands {
|
||||||
MeshDrawCommand drawCommands[];
|
MeshDrawCommand drawCommands[];
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(std430, binding = 4) writeonly buffer DebugVisibility {
|
layout(std430, binding = 4) restrict writeonly buffer DebugVisibility {
|
||||||
uint objectVisibilityBits[];
|
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) {
|
||||||
bvec4 resultA = greaterThanEqual(fma(frustum.a1, center.xxxx, fma(frustum.a2, center.yyyy, fma(frustum.a3, center.zzzz, frustum.a4))), -radius.xxxx);
|
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 resultB = greaterThanEqual(fma(frustum.b1, center.xx, fma(frustum.b2, center.yy, fma(frustum.b3, center.zz, frustum.b4))), -radius.xx);
|
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);
|
uint debug = uint(xyInside.x);
|
||||||
debug |= uint(resultA.y) << 1;
|
debug |= uint(xyInside.y) << 1;
|
||||||
debug |= uint(resultA.z) << 2;
|
debug |= uint(xyInside.z) << 2;
|
||||||
debug |= uint(resultA.w) << 3;
|
debug |= uint(xyInside.w) << 3;
|
||||||
debug |= uint(resultB.x) << 4;
|
debug |= uint(zInside.x) << 4;
|
||||||
debug |= uint(resultB.y) << 5;
|
debug |= uint(zInside.y) << 5;
|
||||||
|
|
||||||
objectVisibilityBits[flw_objectID] = debug;
|
objectVisibilityBits[flw_objectID] = debug;
|
||||||
|
|
||||||
return all(resultA) && all(resultB);
|
return all(xyInside) && all(zInside);
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isVisible() {
|
bool isVisible() {
|
||||||
vec4 sphere = boundingSpheres[flw_batchID];
|
vec4 sphere = drawCommands[flw_batchID].boundingSphere;
|
||||||
|
|
||||||
vec3 center = sphere.xyz;
|
vec3 center = sphere.xyz;
|
||||||
float radius = sphere.r;
|
float radius = sphere.r;
|
||||||
|
@ -77,7 +70,7 @@ void main() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
flw_batchID = objects[objectID].batchID;
|
flw_batchID = batchIDs[flw_objectID];
|
||||||
|
|
||||||
if (isVisible()) {
|
if (isVisible()) {
|
||||||
uint batchIndex = atomicAdd(drawCommands[flw_batchID].instanceCount, 1);
|
uint batchIndex = atomicAdd(drawCommands[flw_batchID].instanceCount, 1);
|
||||||
|
|
|
@ -1,25 +1,18 @@
|
||||||
#use "flywheel:api/vertex.glsl"
|
#use "flywheel:api/vertex.glsl"
|
||||||
#use "flywheel:compute/objects.glsl"
|
|
||||||
#use "flywheel:layout/block.vert"
|
#use "flywheel:layout/block.vert"
|
||||||
#use "flywheel:context/world.vert"
|
#use "flywheel:context/world.vert"
|
||||||
#use "flywheel:util/quaternion.glsl"
|
#use "flywheel:util/quaternion.glsl"
|
||||||
|
#use "flywheel:instance/oriented_indirect.glsl"
|
||||||
|
|
||||||
// populated by instancers
|
// populated by instancers
|
||||||
layout(std430, binding = 0) readonly buffer ObjectBuffer {
|
layout(std430, binding = 0) restrict readonly buffer ObjectBuffer {
|
||||||
Instance objects[];
|
FLW_INSTANCE_STRUCT objects[];
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(std430, binding = 1) readonly buffer TargetBuffer {
|
layout(std430, binding = 1) restrict readonly buffer TargetBuffer {
|
||||||
uint objectIDs[];
|
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() {
|
void main() {
|
||||||
uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID];
|
uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID];
|
||||||
flw_layoutVertex();
|
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