Add a depth prepass and fix occlusion culling boxes.

more progress for #133
This commit is contained in:
IntegratedQuantum 2024-07-06 14:13:04 +02:00
parent 62320b293f
commit 8616289b47
3 changed files with 127 additions and 11 deletions

View File

@ -0,0 +1,65 @@
#version 430
in vec3 mvVertexPos;
in vec3 direction;
in vec2 uv;
flat in vec3 normal;
flat in uint textureIndexOffset;
flat in int isBackFace;
flat in int ditherSeed;
flat in uint lightBufferIndex;
flat in uvec2 lightArea;
in vec2 lightPosition;
uniform sampler2DArray texture_sampler;
uniform sampler2DArray emissionSampler;
uniform sampler2DArray reflectivityAndAbsorptionSampler;
uniform samplerCube reflectionMap;
uniform float reflectionMapSize;
uniform float contrast;
uniform vec3 ambientLight;
layout(std430, binding = 1) buffer _animatedTexture
{
float animatedTexture[];
};
layout(std430, binding = 11) buffer _textureData
{
uint textureData[];
};
float ditherThresholds[16] = float[16] (
1/17.0, 9/17.0, 3/17.0, 11/17.0,
13/17.0, 5/17.0, 15/17.0, 7/17.0,
4/17.0, 12/17.0, 2/17.0, 10/17.0,
16/17.0, 8/17.0, 14/17.0, 6/17.0
);
ivec2 random1to2(int v) {
ivec4 fac = ivec4(11248723, 105436839, 45399083, 5412951);
int seed = v.x*fac.x ^ fac.y;
return seed*fac.zw;
}
bool passDitherTest(float alpha) {
ivec2 screenPos = ivec2(gl_FragCoord.xy);
screenPos += random1to2(ditherSeed);
screenPos &= 3;
return alpha > ditherThresholds[screenPos.x*4 + screenPos.y];
}
uint readTextureIndex() {
uint x = clamp(uint(lightPosition.x), 0, lightArea.x - 2);
uint y = clamp(uint(lightPosition.y), 0, lightArea.y - 2);
uint index = textureIndexOffset + x*(lightArea.y - 1) + y;
return textureData[index >> 1] >> 16*(index & 1u) & 65535u;
}
void main() {
uint textureIndex = readTextureIndex();
float animatedTextureIndex = animatedTexture[textureIndex];
vec3 textureCoords = vec3(uv, animatedTextureIndex);
float alpha = texture(texture_sampler, textureCoords).a;
if(!passDitherTest(alpha)) discard;
}

View File

@ -16,9 +16,10 @@ pub const Samples = enum(u8) {
clear,
animation,
chunk_rendering_preparation,
chunk_rendering_previous_visible,
chunk_rendering_depth_prepass_previous_visible,
chunk_rendering_occlusion_test,
chunk_rendering_new_visible,
chunk_rendering_depth_prepass_new_visible,
chunk_rendering,
entity_rendering,
transparent_rendering_preparation,
transparent_rendering_occlusion_test,
@ -35,9 +36,10 @@ const names = [_][]const u8 {
"Clear",
"Pre-processing Block Animations",
"Chunk Rendering Preparation",
"Chunk Rendering Previous Visible",
"Chunk Rendering (Depth Prepass) Previous Visible",
"Chunk Rendering Occlusion Test",
"Chunk Rendering New Visible",
"Chunk Rendering (Depth Prepass) New Visible",
"Chunk Rendering",
"Entity Rendering",
"Transparent Rendering Preparation",
"Transparent Rendering Occlusion Test",

View File

@ -24,6 +24,7 @@ const gpu_performance_measuring = main.gui.windowlist.gpu_performance_measuring;
const mesh_storage = @import("mesh_storage.zig");
var depthPrepassShader: Shader = undefined;
var shader: Shader = undefined;
var transparentShader: Shader = undefined;
const UniformStruct = struct {
@ -45,6 +46,7 @@ const UniformStruct = struct {
zFar: c_int,
transparent: c_int,
};
pub var depthPrepassUniforms: UniformStruct = undefined;
pub var uniforms: UniformStruct = undefined;
pub var transparentUniforms: UniformStruct = undefined;
pub var commandShader: Shader = undefined;
@ -77,6 +79,7 @@ pub var transparentQuadsDrawn: usize = 0;
pub fn init() void {
lighting.init();
depthPrepassShader = Shader.initAndGetUniforms("assets/cubyz/shaders/chunks/chunk_vertex.vs", "assets/cubyz/shaders/chunks/depth_prepass_fragment.fs", &depthPrepassUniforms);
shader = Shader.initAndGetUniforms("assets/cubyz/shaders/chunks/chunk_vertex.vs", "assets/cubyz/shaders/chunks/chunk_fragment.fs", &uniforms);
transparentShader = Shader.initAndGetUniforms("assets/cubyz/shaders/chunks/chunk_vertex.vs", "assets/cubyz/shaders/chunks/transparent_fragment.fs", &transparentUniforms);
commandShader = Shader.initComputeAndGetUniforms("assets/cubyz/shaders/chunks/fillIndirectBuffer.glsl", &commandUniforms);
@ -106,6 +109,7 @@ pub fn init() void {
pub fn deinit() void {
lighting.deinit();
depthPrepassShader.deinit();
shader.deinit();
transparentShader.deinit();
commandShader.deinit();
@ -160,6 +164,15 @@ fn bindCommonUniforms(locations: *UniformStruct, projMatrix: Mat4f, ambient: Vec
c.glUniform3f(locations.playerPositionFraction, @floatCast(@mod(playerPos[0], 1)), @floatCast(@mod(playerPos[1], 1)), @floatCast(@mod(playerPos[2], 1)));
}
pub fn bindPrepassShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, playerPos: Vec3d) void {
depthPrepassShader.bind();
bindCommonUniforms(&depthPrepassUniforms, projMatrix, ambient, playerPos);
c.glUniform1i(depthPrepassUniforms.transparent, 0);
c.glBindVertexArray(vao);
}
pub fn bindShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, playerPos: Vec3d) void {
shader.bind();
@ -195,7 +208,7 @@ pub fn drawChunksIndirect(chunkIDs: []const u32, projMatrix: Mat4f, ambient: Vec
c.glUniform1i(commandUniforms.isTransparent, @intFromBool(transparent));
c.glUniform3i(commandUniforms.playerPositionInteger, @intFromFloat(@floor(playerPos[0])), @intFromFloat(@floor(playerPos[1])), @intFromFloat(@floor(playerPos[2])));
if(!transparent) {
gpu_performance_measuring.startQuery(.chunk_rendering_previous_visible);
gpu_performance_measuring.startQuery(.chunk_rendering_depth_prepass_previous_visible);
c.glUniform1i(commandUniforms.onlyDrawPreviouslyInvisible, 0);
c.glDispatchCompute(@intCast(@divFloor(chunkIDs.len + 63, 64)), 1, 1); // TODO: Replace with @divCeil once available
c.glMemoryBarrier(c.GL_SHADER_STORAGE_BARRIER_BIT | c.GL_COMMAND_BARRIER_BIT);
@ -203,7 +216,8 @@ pub fn drawChunksIndirect(chunkIDs: []const u32, projMatrix: Mat4f, ambient: Vec
if(transparent) {
bindTransparentShaderAndUniforms(projMatrix, ambient, playerPos);
} else {
bindShaderAndUniforms(projMatrix, ambient, playerPos);
bindPrepassShaderAndUniforms(projMatrix, ambient, playerPos);
c.glColorMask(c.GL_FALSE, c.GL_FALSE, c.GL_FALSE, c.GL_FALSE);
}
c.glBindBuffer(c.GL_DRAW_INDIRECT_BUFFER, commandBuffer.ssbo.bufferID);
c.glMultiDrawElementsIndirect(c.GL_TRIANGLES, c.GL_UNSIGNED_INT, @ptrFromInt(allocation.start*@sizeOf(IndirectData)), drawCallsEstimate, 0);
@ -220,14 +234,18 @@ pub fn drawChunksIndirect(chunkIDs: []const u32, projMatrix: Mat4f, ambient: Vec
c.glDepthMask(c.GL_FALSE);
c.glColorMask(c.GL_FALSE, c.GL_FALSE, c.GL_FALSE, c.GL_FALSE);
c.glBindVertexArray(vao);
var oldDepthFunc: c_uint = undefined;
c.glGetIntegerv(c.GL_DEPTH_FUNC, @ptrCast(&oldDepthFunc));
c.glDepthFunc(c.GL_LEQUAL);
c.glDrawElementsBaseVertex(c.GL_TRIANGLES, @intCast(6*6*chunkIDs.len), c.GL_UNSIGNED_INT, null, chunkIDAllocation.start*24);
c.glDepthFunc(oldDepthFunc);
c.glDepthMask(c.GL_TRUE);
c.glColorMask(c.GL_TRUE, c.GL_TRUE, c.GL_TRUE, c.GL_TRUE);
c.glMemoryBarrier(c.GL_SHADER_STORAGE_BARRIER_BIT);
gpu_performance_measuring.stopQuery();
// Draw again:
gpu_performance_measuring.startQuery(if(transparent) .transparent_rendering else .chunk_rendering_new_visible);
gpu_performance_measuring.startQuery(if(transparent) .transparent_rendering else .chunk_rendering_depth_prepass_new_visible);
commandShader.bind();
c.glUniform1i(commandUniforms.onlyDrawPreviouslyInvisible, 1);
c.glDispatchCompute(@intCast(@divFloor(chunkIDs.len + 63, 64)), 1, 1); // TODO: Replace with @divCeil once available
@ -237,11 +255,31 @@ pub fn drawChunksIndirect(chunkIDs: []const u32, projMatrix: Mat4f, ambient: Vec
bindTransparentShaderAndUniforms(projMatrix, ambient, playerPos);
c.glDepthMask(c.GL_FALSE);
} else {
bindShaderAndUniforms(projMatrix, ambient, playerPos);
bindPrepassShaderAndUniforms(projMatrix, ambient, playerPos);
c.glColorMask(c.GL_FALSE, c.GL_FALSE, c.GL_FALSE, c.GL_FALSE);
}
c.glBindBuffer(c.GL_DRAW_INDIRECT_BUFFER, commandBuffer.ssbo.bufferID);
c.glMultiDrawElementsIndirect(c.GL_TRIANGLES, c.GL_UNSIGNED_INT, @ptrFromInt(allocation.start*@sizeOf(IndirectData)), drawCallsEstimate, 0);
gpu_performance_measuring.stopQuery();
if(!transparent) {
gpu_performance_measuring.startQuery(.chunk_rendering);
// Draw after the depth prepass
commandShader.bind();
c.glUniform1i(commandUniforms.onlyDrawPreviouslyInvisible, 0);
c.glDispatchCompute(@intCast(@divFloor(chunkIDs.len + 63, 64)), 1, 1); // TODO: Replace with @divCeil once available
c.glMemoryBarrier(c.GL_SHADER_STORAGE_BARRIER_BIT | c.GL_COMMAND_BARRIER_BIT);
bindShaderAndUniforms(projMatrix, ambient, playerPos);
c.glDepthFunc(c.GL_EQUAL);
c.glDepthMask(c.GL_FALSE);
c.glColorMask(c.GL_TRUE, c.GL_TRUE, c.GL_TRUE, c.GL_TRUE);
c.glBindBuffer(c.GL_DRAW_INDIRECT_BUFFER, commandBuffer.ssbo.bufferID);
c.glMultiDrawElementsIndirect(c.GL_TRIANGLES, c.GL_UNSIGNED_INT, @ptrFromInt(allocation.start*@sizeOf(IndirectData)), drawCallsEstimate, 0);
c.glDepthFunc(c.GL_LESS);
c.glDepthMask(c.GL_TRUE);
gpu_performance_measuring.stopQuery();
}
}
pub const FaceData = extern struct {
@ -430,9 +468,20 @@ const PrimitiveMesh = struct {
@floatFromInt(face.position.y),
@floatFromInt(face.position.z),
};
for(main.models.quads.items[face.blockAndQuad.quadIndex].corners) |cornerPos| {
self.min = @min(self.min, basePos + cornerPos);
self.max = @max(self.max, basePos + cornerPos);
for(0..2) |x| {
for(0..2) |y| {
const quadIndex = face.blockAndQuad.quadIndex;
var vertexPos = models.quads.items[quadIndex].corners[0];
vertexPos += (models.quads.items[quadIndex].corners[2] - models.quads.items[quadIndex].corners[0])*@as(Vec3f, @splat(@floatFromInt(x*(face.position.xSizeMinusOne + 1))));
if(x != 0) {
vertexPos += (models.quads.items[quadIndex].corners[3] - models.quads.items[quadIndex].corners[2])*@as(Vec3f, @splat(@floatFromInt(y*(face.position.ySizeMinusOne + 1))));
} else {
vertexPos += (models.quads.items[quadIndex].corners[1] - models.quads.items[quadIndex].corners[0])*@as(Vec3f, @splat(@floatFromInt(y*(face.position.ySizeMinusOne + 1))));
}
self.min = @min(self.min, basePos + vertexPos);
self.max = @max(self.max, basePos + vertexPos);
}
}
}
parent.lightingData[0].lock.unlockRead();