mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 19:28:49 -04:00
Precalculate animation data to avoid recalculating it a million times in the fragment shader.
Improves performance by about 1 ms in a test scene.
This commit is contained in:
parent
657aa8dc9d
commit
045ba9c65a
42
assets/cubyz/shaders/animation_pre_processing.glsl
Normal file
42
assets/cubyz/shaders/animation_pre_processing.glsl
Normal file
@ -0,0 +1,42 @@
|
||||
#version 430
|
||||
|
||||
layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
struct AnimationData {
|
||||
int frames;
|
||||
int time;
|
||||
};
|
||||
|
||||
struct TextureData {
|
||||
int textureIndices[6];
|
||||
uint absorption;
|
||||
float reflectivity;
|
||||
float fogDensity;
|
||||
uint fogColor;
|
||||
};
|
||||
|
||||
layout(std430, binding = 0) buffer _animation
|
||||
{
|
||||
AnimationData animation[];
|
||||
};
|
||||
layout(std430, binding = 6) buffer _textureDataIn
|
||||
{
|
||||
TextureData textureDataIn[];
|
||||
};
|
||||
layout(std430, binding = 1) buffer _textureDataOut
|
||||
{
|
||||
TextureData textureDataOut[];
|
||||
};
|
||||
|
||||
uniform int time;
|
||||
uniform int size;
|
||||
|
||||
void main() {
|
||||
uint index = gl_GlobalInvocationID.x;
|
||||
if(index >= size) return;
|
||||
for(int i = 0; i < 6; i++) {
|
||||
int textureIndex = textureDataIn[index].textureIndices[i];
|
||||
textureIndex = textureIndex + time / animation[textureIndex].time % animation[textureIndex].frames;
|
||||
textureDataOut[index].textureIndices[i] = textureIndex;
|
||||
}
|
||||
}
|
@ -10,18 +10,12 @@ flat in int ditherSeed;
|
||||
in vec3 startPosition;
|
||||
in vec3 direction;
|
||||
|
||||
uniform int time;
|
||||
uniform vec3 ambientLight;
|
||||
uniform sampler2DArray texture_sampler;
|
||||
uniform sampler2DArray emissionSampler;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
struct AnimationData {
|
||||
int frames;
|
||||
int time;
|
||||
};
|
||||
|
||||
#define modelSize 16
|
||||
struct VoxelModel {
|
||||
ivec4 minimum;
|
||||
@ -37,10 +31,6 @@ struct TextureData {
|
||||
uint fogColor;
|
||||
};
|
||||
|
||||
layout(std430, binding = 0) buffer _animation
|
||||
{
|
||||
AnimationData animation[];
|
||||
};
|
||||
layout(std430, binding = 1) buffer _textureData
|
||||
{
|
||||
TextureData textureData[];
|
||||
@ -237,7 +227,6 @@ void main() {
|
||||
}
|
||||
if(!result.hitAThing) discard;
|
||||
int textureIndex = textureData[blockType].textureIndices[result.textureDir];
|
||||
textureIndex = textureIndex + time / animation[textureIndex].time % animation[textureIndex].frames;
|
||||
float normalVariation = normalVariations[result.normal];
|
||||
float lod = getLod(result.voxelPosition, result.normal, direction, variance);
|
||||
ivec2 textureCoords = getTextureCoords(result.voxelPosition, result.textureDir);
|
||||
|
@ -9,7 +9,6 @@ flat in int ditherSeed;
|
||||
in vec3 startPosition;
|
||||
in vec3 direction;
|
||||
|
||||
uniform int time;
|
||||
uniform vec3 ambientLight;
|
||||
uniform sampler2DArray texture_sampler;
|
||||
uniform sampler2DArray emissionSampler;
|
||||
@ -26,11 +25,6 @@ struct Fog {
|
||||
float density;
|
||||
};
|
||||
|
||||
struct AnimationData {
|
||||
int frames;
|
||||
int time;
|
||||
};
|
||||
|
||||
struct TextureData {
|
||||
int textureIndices[6];
|
||||
uint absorption;
|
||||
@ -39,10 +33,6 @@ struct TextureData {
|
||||
uint fogColor;
|
||||
};
|
||||
|
||||
layout(std430, binding = 0) buffer _animation
|
||||
{
|
||||
AnimationData animation[];
|
||||
};
|
||||
layout(std430, binding = 1) buffer _textureData
|
||||
{
|
||||
TextureData textureData[];
|
||||
@ -143,7 +133,6 @@ vec4 fixedCubeMapLookup(vec3 v) { // Taken from http://the-witness.net/news/2012
|
||||
|
||||
void main() {
|
||||
int textureIndex = textureData[blockType].textureIndices[faceNormal];
|
||||
textureIndex = textureIndex + time / animation[textureIndex].time % animation[textureIndex].frames;
|
||||
vec3 textureCoords = vec3(getTextureCoordsNormal(startPosition/16, faceNormal), textureIndex);
|
||||
float normalVariation = normalVariations[faceNormal];
|
||||
float densityAdjustment = sqrt(dot(mvVertexPos, mvVertexPos))/abs(mvVertexPos.z);
|
||||
|
@ -3,10 +3,12 @@ const std = @import("std");
|
||||
const main = @import("root");
|
||||
const JsonElement = @import("json.zig").JsonElement;
|
||||
const Neighbors = @import("chunk.zig").Neighbors;
|
||||
const SSBO = @import("graphics.zig").SSBO;
|
||||
const Image = @import("graphics.zig").Image;
|
||||
const Color = @import("graphics.zig").Color;
|
||||
const TextureArray = @import("graphics.zig").TextureArray;
|
||||
const graphics = @import("graphics.zig");
|
||||
const Shader = graphics.Shader;
|
||||
const SSBO = graphics.SSBO;
|
||||
const Image = graphics.Image;
|
||||
const Color = graphics.Color;
|
||||
const TextureArray = graphics.TextureArray;
|
||||
const items = @import("items.zig");
|
||||
const models = @import("models.zig");
|
||||
const rotation = @import("rotation.zig");
|
||||
@ -344,7 +346,14 @@ pub const meshes = struct {
|
||||
};
|
||||
|
||||
var animationSSBO: SSBO = undefined;
|
||||
var textureIndexSSBO: SSBO = undefined;
|
||||
var textureDataSSBO: SSBO = undefined;
|
||||
var animatedTextureDataSSBO: SSBO = undefined;
|
||||
|
||||
var animationShader: Shader = undefined;
|
||||
var animationUniforms: struct {
|
||||
time: c_int,
|
||||
size: c_int,
|
||||
} = undefined;
|
||||
|
||||
pub var blockTextureArray: TextureArray = undefined;
|
||||
pub var emissionTextureArray: TextureArray = undefined;
|
||||
@ -356,11 +365,14 @@ pub const meshes = struct {
|
||||
var emptyTexture = [_]Color {black};
|
||||
const emptyImage = Image{.width = 1, .height = 1, .imageData = emptyTexture[0..]};
|
||||
|
||||
pub fn init() void {
|
||||
pub fn init() !void {
|
||||
animationSSBO = SSBO.init();
|
||||
animationSSBO.bind(0);
|
||||
textureIndexSSBO = SSBO.init();
|
||||
textureIndexSSBO.bind(1);
|
||||
textureDataSSBO = SSBO.init();
|
||||
textureDataSSBO.bind(6);
|
||||
animatedTextureDataSSBO = SSBO.init();
|
||||
animatedTextureDataSSBO.bind(1);
|
||||
animationShader = try Shader.initComputeAndGetUniforms("assets/cubyz/shaders/animation_pre_processing.glsl", &animationUniforms);
|
||||
blockTextureArray = TextureArray.init();
|
||||
emissionTextureArray = TextureArray.init();
|
||||
arenaForArrayLists = std.heap.ArenaAllocator.init(main.globalAllocator);
|
||||
@ -373,7 +385,9 @@ pub const meshes = struct {
|
||||
|
||||
pub fn deinit() void {
|
||||
animationSSBO.deinit();
|
||||
textureIndexSSBO.deinit();
|
||||
textureDataSSBO.deinit();
|
||||
animatedTextureDataSSBO.deinit();
|
||||
animationShader.deinit();
|
||||
blockTextureArray.deinit();
|
||||
emissionTextureArray.deinit();
|
||||
arenaForArrayLists.deinit();
|
||||
@ -549,12 +563,21 @@ pub const meshes = struct {
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn preProcessAnimationData(time: u32) void {
|
||||
animationShader.bind();
|
||||
graphics.c.glUniform1i(animationUniforms.time, @bitCast(time));
|
||||
graphics.c.glUniform1i(animationUniforms.size, @intCast(meshes.size));
|
||||
graphics.c.glDispatchCompute(@divFloor(meshes.size + 63, 64), 1, 1); // TODO: Replace with @divCeil once available
|
||||
graphics.c.glMemoryBarrier(graphics.c.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
}
|
||||
|
||||
pub fn generateTextureArray() !void {
|
||||
try blockTextureArray.generate(blockTextures.items, true);
|
||||
try emissionTextureArray.generate(emissionTextures.items, true);
|
||||
|
||||
// Also generate additional buffers:
|
||||
animationSSBO.bufferData(AnimationData, animation.items);
|
||||
textureIndexSSBO.bufferData(TextureData, textureData[0..meshes.size]);
|
||||
textureDataSSBO.bufferData(TextureData, textureData[0..meshes.size]);
|
||||
animatedTextureDataSSBO.bufferData(TextureData, textureData[0..meshes.size]);
|
||||
}
|
||||
};
|
||||
|
@ -399,7 +399,6 @@ pub const meshing = struct {
|
||||
emissionSampler: c_int,
|
||||
reflectionMap: c_int,
|
||||
reflectionMapSize: c_int,
|
||||
time: c_int,
|
||||
visibilityMask: c_int,
|
||||
voxelSize: c_int,
|
||||
zNear: c_int,
|
||||
@ -444,7 +443,7 @@ pub const meshing = struct {
|
||||
faceBuffer.deinit();
|
||||
}
|
||||
|
||||
pub fn bindShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, time: u32) void {
|
||||
pub fn bindShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f) void {
|
||||
shader.bind();
|
||||
|
||||
c.glUniformMatrix4fv(uniforms.projectionMatrix, 1, c.GL_FALSE, @ptrCast(&projMatrix));
|
||||
@ -458,15 +457,13 @@ pub const meshing = struct {
|
||||
|
||||
c.glUniform3f(uniforms.ambientLight, ambient[0], ambient[1], ambient[2]);
|
||||
|
||||
c.glUniform1i(uniforms.time, @as(u31, @truncate(time)));
|
||||
|
||||
c.glUniform1f(uniforms.zNear, renderer.zNear);
|
||||
c.glUniform1f(uniforms.zFar, renderer.zFar);
|
||||
|
||||
c.glBindVertexArray(vao);
|
||||
}
|
||||
|
||||
pub fn bindTransparentShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, time: u32) void {
|
||||
pub fn bindTransparentShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f) void {
|
||||
transparentShader.bind();
|
||||
|
||||
c.glUniform3fv(transparentUniforms.@"fog.color", 1, @ptrCast(&game.fog.color));
|
||||
@ -483,8 +480,6 @@ pub const meshing = struct {
|
||||
|
||||
c.glUniform3f(transparentUniforms.ambientLight, ambient[0], ambient[1], ambient[2]);
|
||||
|
||||
c.glUniform1i(transparentUniforms.time, @as(u31, @truncate(time)));
|
||||
|
||||
c.glUniform1f(transparentUniforms.zNear, renderer.zNear);
|
||||
c.glUniform1f(transparentUniforms.zFar, renderer.zFar);
|
||||
|
||||
|
@ -1110,6 +1110,23 @@ pub const Shader = struct {
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn initCompute(compute: []const u8) !Shader {
|
||||
var shader = Shader{.id = c.glCreateProgram()};
|
||||
try shader.addShader(compute, c.GL_COMPUTE_SHADER);
|
||||
try shader.link();
|
||||
return shader;
|
||||
}
|
||||
|
||||
pub fn initComputeAndGetUniforms(compute: []const u8, ptrToUniformStruct: anytype) !Shader {
|
||||
const self = try Shader.initCompute(compute);
|
||||
inline for(@typeInfo(@TypeOf(ptrToUniformStruct.*)).Struct.fields) |field| {
|
||||
if(field.type == c_int) {
|
||||
@field(ptrToUniformStruct, field.name) = c.glGetUniformLocation(self.id, field.name[0..] ++ "\x00"); // TODO: #16072
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn bind(self: *const Shader) void {
|
||||
c.glUseProgram(self.id);
|
||||
}
|
||||
@ -1753,9 +1770,9 @@ pub fn generateBlockTexture(blockType: u16) !Texture {
|
||||
if(block.transparent()) {
|
||||
c.glBlendEquation(c.GL_FUNC_ADD);
|
||||
c.glBlendFunc(c.GL_ONE, c.GL_SRC1_COLOR);
|
||||
main.chunk.meshing.bindTransparentShaderAndUniforms(projMatrix, .{1, 1, 1}, 0);
|
||||
main.chunk.meshing.bindTransparentShaderAndUniforms(projMatrix, .{1, 1, 1});
|
||||
} else {
|
||||
main.chunk.meshing.bindShaderAndUniforms(projMatrix, .{1, 1, 1}, 0);
|
||||
main.chunk.meshing.bindShaderAndUniforms(projMatrix, .{1, 1, 1});
|
||||
}
|
||||
const uniforms = if(block.transparent()) &main.chunk.meshing.transparentUniforms else &main.chunk.meshing.uniforms;
|
||||
|
||||
|
@ -15,6 +15,7 @@ const GuiComponent = gui.GuiComponent;
|
||||
pub const Samples = enum(u8) {
|
||||
screenbuffer_clear,
|
||||
clear,
|
||||
animation,
|
||||
chunk_rendering,
|
||||
entity_rendering,
|
||||
transparent_rendering,
|
||||
@ -29,6 +30,7 @@ pub const Samples = enum(u8) {
|
||||
const names = [_][]const u8 {
|
||||
"Screenbuffer clear",
|
||||
"Clear",
|
||||
"Pre-processing Block Animations",
|
||||
"Chunk Rendering",
|
||||
"Entity Rendering",
|
||||
"Transparent Rendering",
|
||||
|
@ -686,7 +686,7 @@ pub fn main() !void {
|
||||
try assets.init();
|
||||
defer assets.deinit();
|
||||
|
||||
blocks.meshes.init();
|
||||
try blocks.meshes.init();
|
||||
defer blocks.meshes.deinit();
|
||||
|
||||
try chunk.meshing.init();
|
||||
|
@ -173,8 +173,13 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
||||
|
||||
const time: u32 = @intCast(std.time.milliTimestamp() & std.math.maxInt(u32));
|
||||
|
||||
gpu_performance_measuring.startQuery(.animation);
|
||||
blocks.meshes.preProcessAnimationData(time);
|
||||
gpu_performance_measuring.stopQuery();
|
||||
|
||||
|
||||
// Update the uniforms. The uniforms are needed to render the replacement meshes.
|
||||
chunk.meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight, time);
|
||||
chunk.meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight);
|
||||
|
||||
reflectionCubeMap.bindTo(2);
|
||||
c.glActiveTexture(c.GL_TEXTURE0);
|
||||
@ -202,7 +207,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
||||
MeshSelection.select(playerPos, game.camera.direction);
|
||||
MeshSelection.render(game.projectionMatrix, game.camera.viewMatrix, playerPos);
|
||||
|
||||
chunk.meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight, time);
|
||||
chunk.meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight);
|
||||
|
||||
for(meshes) |mesh| {
|
||||
mesh.render(playerPos);
|
||||
@ -225,7 +230,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
||||
|
||||
gpu_performance_measuring.startQuery(.transparent_rendering);
|
||||
c.glTextureBarrier();
|
||||
chunk.meshing.bindTransparentShaderAndUniforms(game.projectionMatrix, ambientLight, time);
|
||||
chunk.meshing.bindTransparentShaderAndUniforms(game.projectionMatrix, ambientLight);
|
||||
|
||||
c.glBlendEquation(c.GL_FUNC_ADD);
|
||||
c.glBlendFunc(c.GL_ONE, c.GL_SRC1_COLOR);
|
||||
|
Loading…
x
Reference in New Issue
Block a user