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 startPosition;
|
||||||
in vec3 direction;
|
in vec3 direction;
|
||||||
|
|
||||||
uniform int time;
|
|
||||||
uniform vec3 ambientLight;
|
uniform vec3 ambientLight;
|
||||||
uniform sampler2DArray texture_sampler;
|
uniform sampler2DArray texture_sampler;
|
||||||
uniform sampler2DArray emissionSampler;
|
uniform sampler2DArray emissionSampler;
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
struct AnimationData {
|
|
||||||
int frames;
|
|
||||||
int time;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define modelSize 16
|
#define modelSize 16
|
||||||
struct VoxelModel {
|
struct VoxelModel {
|
||||||
ivec4 minimum;
|
ivec4 minimum;
|
||||||
@ -37,10 +31,6 @@ struct TextureData {
|
|||||||
uint fogColor;
|
uint fogColor;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(std430, binding = 0) buffer _animation
|
|
||||||
{
|
|
||||||
AnimationData animation[];
|
|
||||||
};
|
|
||||||
layout(std430, binding = 1) buffer _textureData
|
layout(std430, binding = 1) buffer _textureData
|
||||||
{
|
{
|
||||||
TextureData textureData[];
|
TextureData textureData[];
|
||||||
@ -237,7 +227,6 @@ void main() {
|
|||||||
}
|
}
|
||||||
if(!result.hitAThing) discard;
|
if(!result.hitAThing) discard;
|
||||||
int textureIndex = textureData[blockType].textureIndices[result.textureDir];
|
int textureIndex = textureData[blockType].textureIndices[result.textureDir];
|
||||||
textureIndex = textureIndex + time / animation[textureIndex].time % animation[textureIndex].frames;
|
|
||||||
float normalVariation = normalVariations[result.normal];
|
float normalVariation = normalVariations[result.normal];
|
||||||
float lod = getLod(result.voxelPosition, result.normal, direction, variance);
|
float lod = getLod(result.voxelPosition, result.normal, direction, variance);
|
||||||
ivec2 textureCoords = getTextureCoords(result.voxelPosition, result.textureDir);
|
ivec2 textureCoords = getTextureCoords(result.voxelPosition, result.textureDir);
|
||||||
|
@ -9,7 +9,6 @@ flat in int ditherSeed;
|
|||||||
in vec3 startPosition;
|
in vec3 startPosition;
|
||||||
in vec3 direction;
|
in vec3 direction;
|
||||||
|
|
||||||
uniform int time;
|
|
||||||
uniform vec3 ambientLight;
|
uniform vec3 ambientLight;
|
||||||
uniform sampler2DArray texture_sampler;
|
uniform sampler2DArray texture_sampler;
|
||||||
uniform sampler2DArray emissionSampler;
|
uniform sampler2DArray emissionSampler;
|
||||||
@ -26,11 +25,6 @@ struct Fog {
|
|||||||
float density;
|
float density;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AnimationData {
|
|
||||||
int frames;
|
|
||||||
int time;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TextureData {
|
struct TextureData {
|
||||||
int textureIndices[6];
|
int textureIndices[6];
|
||||||
uint absorption;
|
uint absorption;
|
||||||
@ -39,10 +33,6 @@ struct TextureData {
|
|||||||
uint fogColor;
|
uint fogColor;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(std430, binding = 0) buffer _animation
|
|
||||||
{
|
|
||||||
AnimationData animation[];
|
|
||||||
};
|
|
||||||
layout(std430, binding = 1) buffer _textureData
|
layout(std430, binding = 1) buffer _textureData
|
||||||
{
|
{
|
||||||
TextureData textureData[];
|
TextureData textureData[];
|
||||||
@ -143,7 +133,6 @@ vec4 fixedCubeMapLookup(vec3 v) { // Taken from http://the-witness.net/news/2012
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
int textureIndex = textureData[blockType].textureIndices[faceNormal];
|
int textureIndex = textureData[blockType].textureIndices[faceNormal];
|
||||||
textureIndex = textureIndex + time / animation[textureIndex].time % animation[textureIndex].frames;
|
|
||||||
vec3 textureCoords = vec3(getTextureCoordsNormal(startPosition/16, faceNormal), textureIndex);
|
vec3 textureCoords = vec3(getTextureCoordsNormal(startPosition/16, faceNormal), textureIndex);
|
||||||
float normalVariation = normalVariations[faceNormal];
|
float normalVariation = normalVariations[faceNormal];
|
||||||
float densityAdjustment = sqrt(dot(mvVertexPos, mvVertexPos))/abs(mvVertexPos.z);
|
float densityAdjustment = sqrt(dot(mvVertexPos, mvVertexPos))/abs(mvVertexPos.z);
|
||||||
|
@ -3,10 +3,12 @@ const std = @import("std");
|
|||||||
const main = @import("root");
|
const main = @import("root");
|
||||||
const JsonElement = @import("json.zig").JsonElement;
|
const JsonElement = @import("json.zig").JsonElement;
|
||||||
const Neighbors = @import("chunk.zig").Neighbors;
|
const Neighbors = @import("chunk.zig").Neighbors;
|
||||||
const SSBO = @import("graphics.zig").SSBO;
|
const graphics = @import("graphics.zig");
|
||||||
const Image = @import("graphics.zig").Image;
|
const Shader = graphics.Shader;
|
||||||
const Color = @import("graphics.zig").Color;
|
const SSBO = graphics.SSBO;
|
||||||
const TextureArray = @import("graphics.zig").TextureArray;
|
const Image = graphics.Image;
|
||||||
|
const Color = graphics.Color;
|
||||||
|
const TextureArray = graphics.TextureArray;
|
||||||
const items = @import("items.zig");
|
const items = @import("items.zig");
|
||||||
const models = @import("models.zig");
|
const models = @import("models.zig");
|
||||||
const rotation = @import("rotation.zig");
|
const rotation = @import("rotation.zig");
|
||||||
@ -344,7 +346,14 @@ pub const meshes = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var animationSSBO: SSBO = undefined;
|
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 blockTextureArray: TextureArray = undefined;
|
||||||
pub var emissionTextureArray: TextureArray = undefined;
|
pub var emissionTextureArray: TextureArray = undefined;
|
||||||
@ -356,11 +365,14 @@ pub const meshes = struct {
|
|||||||
var emptyTexture = [_]Color {black};
|
var emptyTexture = [_]Color {black};
|
||||||
const emptyImage = Image{.width = 1, .height = 1, .imageData = emptyTexture[0..]};
|
const emptyImage = Image{.width = 1, .height = 1, .imageData = emptyTexture[0..]};
|
||||||
|
|
||||||
pub fn init() void {
|
pub fn init() !void {
|
||||||
animationSSBO = SSBO.init();
|
animationSSBO = SSBO.init();
|
||||||
animationSSBO.bind(0);
|
animationSSBO.bind(0);
|
||||||
textureIndexSSBO = SSBO.init();
|
textureDataSSBO = SSBO.init();
|
||||||
textureIndexSSBO.bind(1);
|
textureDataSSBO.bind(6);
|
||||||
|
animatedTextureDataSSBO = SSBO.init();
|
||||||
|
animatedTextureDataSSBO.bind(1);
|
||||||
|
animationShader = try Shader.initComputeAndGetUniforms("assets/cubyz/shaders/animation_pre_processing.glsl", &animationUniforms);
|
||||||
blockTextureArray = TextureArray.init();
|
blockTextureArray = TextureArray.init();
|
||||||
emissionTextureArray = TextureArray.init();
|
emissionTextureArray = TextureArray.init();
|
||||||
arenaForArrayLists = std.heap.ArenaAllocator.init(main.globalAllocator);
|
arenaForArrayLists = std.heap.ArenaAllocator.init(main.globalAllocator);
|
||||||
@ -373,7 +385,9 @@ pub const meshes = struct {
|
|||||||
|
|
||||||
pub fn deinit() void {
|
pub fn deinit() void {
|
||||||
animationSSBO.deinit();
|
animationSSBO.deinit();
|
||||||
textureIndexSSBO.deinit();
|
textureDataSSBO.deinit();
|
||||||
|
animatedTextureDataSSBO.deinit();
|
||||||
|
animationShader.deinit();
|
||||||
blockTextureArray.deinit();
|
blockTextureArray.deinit();
|
||||||
emissionTextureArray.deinit();
|
emissionTextureArray.deinit();
|
||||||
arenaForArrayLists.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 {
|
pub fn generateTextureArray() !void {
|
||||||
try blockTextureArray.generate(blockTextures.items, true);
|
try blockTextureArray.generate(blockTextures.items, true);
|
||||||
try emissionTextureArray.generate(emissionTextures.items, true);
|
try emissionTextureArray.generate(emissionTextures.items, true);
|
||||||
|
|
||||||
// Also generate additional buffers:
|
// Also generate additional buffers:
|
||||||
animationSSBO.bufferData(AnimationData, animation.items);
|
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,
|
emissionSampler: c_int,
|
||||||
reflectionMap: c_int,
|
reflectionMap: c_int,
|
||||||
reflectionMapSize: c_int,
|
reflectionMapSize: c_int,
|
||||||
time: c_int,
|
|
||||||
visibilityMask: c_int,
|
visibilityMask: c_int,
|
||||||
voxelSize: c_int,
|
voxelSize: c_int,
|
||||||
zNear: c_int,
|
zNear: c_int,
|
||||||
@ -444,7 +443,7 @@ pub const meshing = struct {
|
|||||||
faceBuffer.deinit();
|
faceBuffer.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bindShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, time: u32) void {
|
pub fn bindShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f) void {
|
||||||
shader.bind();
|
shader.bind();
|
||||||
|
|
||||||
c.glUniformMatrix4fv(uniforms.projectionMatrix, 1, c.GL_FALSE, @ptrCast(&projMatrix));
|
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.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.zNear, renderer.zNear);
|
||||||
c.glUniform1f(uniforms.zFar, renderer.zFar);
|
c.glUniform1f(uniforms.zFar, renderer.zFar);
|
||||||
|
|
||||||
c.glBindVertexArray(vao);
|
c.glBindVertexArray(vao);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bindTransparentShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, time: u32) void {
|
pub fn bindTransparentShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f) void {
|
||||||
transparentShader.bind();
|
transparentShader.bind();
|
||||||
|
|
||||||
c.glUniform3fv(transparentUniforms.@"fog.color", 1, @ptrCast(&game.fog.color));
|
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.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.zNear, renderer.zNear);
|
||||||
c.glUniform1f(transparentUniforms.zFar, renderer.zFar);
|
c.glUniform1f(transparentUniforms.zFar, renderer.zFar);
|
||||||
|
|
||||||
|
@ -1110,6 +1110,23 @@ pub const Shader = struct {
|
|||||||
return self;
|
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 {
|
pub fn bind(self: *const Shader) void {
|
||||||
c.glUseProgram(self.id);
|
c.glUseProgram(self.id);
|
||||||
}
|
}
|
||||||
@ -1753,9 +1770,9 @@ pub fn generateBlockTexture(blockType: u16) !Texture {
|
|||||||
if(block.transparent()) {
|
if(block.transparent()) {
|
||||||
c.glBlendEquation(c.GL_FUNC_ADD);
|
c.glBlendEquation(c.GL_FUNC_ADD);
|
||||||
c.glBlendFunc(c.GL_ONE, c.GL_SRC1_COLOR);
|
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 {
|
} 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;
|
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) {
|
pub const Samples = enum(u8) {
|
||||||
screenbuffer_clear,
|
screenbuffer_clear,
|
||||||
clear,
|
clear,
|
||||||
|
animation,
|
||||||
chunk_rendering,
|
chunk_rendering,
|
||||||
entity_rendering,
|
entity_rendering,
|
||||||
transparent_rendering,
|
transparent_rendering,
|
||||||
@ -29,6 +30,7 @@ pub const Samples = enum(u8) {
|
|||||||
const names = [_][]const u8 {
|
const names = [_][]const u8 {
|
||||||
"Screenbuffer clear",
|
"Screenbuffer clear",
|
||||||
"Clear",
|
"Clear",
|
||||||
|
"Pre-processing Block Animations",
|
||||||
"Chunk Rendering",
|
"Chunk Rendering",
|
||||||
"Entity Rendering",
|
"Entity Rendering",
|
||||||
"Transparent Rendering",
|
"Transparent Rendering",
|
||||||
|
@ -686,7 +686,7 @@ pub fn main() !void {
|
|||||||
try assets.init();
|
try assets.init();
|
||||||
defer assets.deinit();
|
defer assets.deinit();
|
||||||
|
|
||||||
blocks.meshes.init();
|
try blocks.meshes.init();
|
||||||
defer blocks.meshes.deinit();
|
defer blocks.meshes.deinit();
|
||||||
|
|
||||||
try chunk.meshing.init();
|
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));
|
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.
|
// 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);
|
reflectionCubeMap.bindTo(2);
|
||||||
c.glActiveTexture(c.GL_TEXTURE0);
|
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.select(playerPos, game.camera.direction);
|
||||||
MeshSelection.render(game.projectionMatrix, game.camera.viewMatrix, playerPos);
|
MeshSelection.render(game.projectionMatrix, game.camera.viewMatrix, playerPos);
|
||||||
|
|
||||||
chunk.meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight, time);
|
chunk.meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight);
|
||||||
|
|
||||||
for(meshes) |mesh| {
|
for(meshes) |mesh| {
|
||||||
mesh.render(playerPos);
|
mesh.render(playerPos);
|
||||||
@ -225,7 +230,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
|||||||
|
|
||||||
gpu_performance_measuring.startQuery(.transparent_rendering);
|
gpu_performance_measuring.startQuery(.transparent_rendering);
|
||||||
c.glTextureBarrier();
|
c.glTextureBarrier();
|
||||||
chunk.meshing.bindTransparentShaderAndUniforms(game.projectionMatrix, ambientLight, time);
|
chunk.meshing.bindTransparentShaderAndUniforms(game.projectionMatrix, ambientLight);
|
||||||
|
|
||||||
c.glBlendEquation(c.GL_FUNC_ADD);
|
c.glBlendEquation(c.GL_FUNC_ADD);
|
||||||
c.glBlendFunc(c.GL_ONE, c.GL_SRC1_COLOR);
|
c.glBlendFunc(c.GL_ONE, c.GL_SRC1_COLOR);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user