improve rendering performance even more by using instanced rendering

This commit is contained in:
2026-02-22 02:49:30 +01:00
parent 12a96cba66
commit 9446e1b86c
6 changed files with 125 additions and 17 deletions

View File

@ -4,6 +4,8 @@
#include <raylib.h> #include <raylib.h>
#define PRINT_TIMINGS #define PRINT_TIMINGS
// #define BATCHING
#define INSTANCING // Fastest (so far)
// #define WEB // #define WEB
// Window // Window

View File

@ -49,9 +49,17 @@ private:
RenderTexture klotski_target; RenderTexture klotski_target;
RenderTexture menu_target; RenderTexture menu_target;
Material vertex_mat;
// Batching
float *cube; float *cube;
Mesh graph; Mesh graph;
Material mat;
// Instancing
int transforms_size;
Matrix *transforms;
Mesh cube_instance;
Shader instancing_shader;
public: public:
bool mark_solutions; bool mark_solutions;
@ -60,13 +68,16 @@ public:
public: public:
Renderer() Renderer()
: camera(OrbitCamera3D(Vector3(0, 0, 0), CAMERA_DISTANCE)), : camera(OrbitCamera3D(Vector3(0, 0, 0), CAMERA_DISTANCE)),
mark_solutions(false), connect_solutions(false) { mark_solutions(false), connect_solutions(false), cube(nullptr),
transforms_size(0), transforms(nullptr) {
render_target = LoadRenderTexture(GetScreenWidth() / 2.0, render_target = LoadRenderTexture(GetScreenWidth() / 2.0,
GetScreenHeight() - MENU_HEIGHT); GetScreenHeight() - MENU_HEIGHT);
klotski_target = LoadRenderTexture(GetScreenWidth() / 2.0, klotski_target = LoadRenderTexture(GetScreenWidth() / 2.0,
GetScreenHeight() - MENU_HEIGHT); GetScreenHeight() - MENU_HEIGHT);
menu_target = LoadRenderTexture(GetScreenWidth(), MENU_HEIGHT); menu_target = LoadRenderTexture(GetScreenWidth(), MENU_HEIGHT);
AllocateGraphMesh();
vertex_mat = LoadMaterialDefault();
vertex_mat.maps[MATERIAL_MAP_DIFFUSE].color = VERTEX_COLOR;
} }
Renderer(const Renderer &copy) = delete; Renderer(const Renderer &copy) = delete;
@ -78,9 +89,23 @@ public:
UnloadRenderTexture(render_target); UnloadRenderTexture(render_target);
UnloadRenderTexture(klotski_target); UnloadRenderTexture(klotski_target);
UnloadRenderTexture(menu_target); UnloadRenderTexture(menu_target);
UnloadMesh(graph);
UnloadMaterial(mat); UnloadMaterial(vertex_mat);
// Batching
if (cube != nullptr) {
MemFree(cube); MemFree(cube);
UnloadMesh(graph);
}
// Instancing
if (transforms != nullptr) {
MemFree(transforms);
UnloadMesh(cube_instance);
// I think the shader already gets unloaded with the material?
// UnloadShader(instancing_shader);
}
} }
public: public:
@ -89,10 +114,20 @@ public:
auto UpdateTextureSizes() -> void; auto UpdateTextureSizes() -> void;
auto AllocateGraphMesh() -> void; #ifdef BATCHING
auto AllocateGraphBatching() -> void;
auto ReallocateGraphMeshIfNecessary(const MassSpringSystem &mass_springs) auto ReallocateGraphBatchingIfNecessary(const MassSpringSystem &mass_springs)
-> void; -> void;
#endif
#ifdef INSTANCING
auto AllocateGraphInstancing(const MassSpringSystem &mass_springs) -> void;
auto
ReallocateGraphInstancingIfNecessary(const MassSpringSystem &mass_springs)
-> void;
#endif
auto DrawMassSprings(const MassSpringSystem &mass_springs, auto DrawMassSprings(const MassSpringSystem &mass_springs,
const State &current_state, const State &current_state,

8
instancing_fragment.glsl Normal file
View File

@ -0,0 +1,8 @@
#version 330
uniform vec4 colDiffuse;
out vec4 finalColor;
void main() {
finalColor = colDiffuse;
}

13
instancing_vertex.glsl Normal file
View File

@ -0,0 +1,13 @@
#version 330
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec3 vertexNormal;
in vec4 vertexColor;
in mat4 instanceTransform;
uniform mat4 mvp;
void main() {
gl_Position = mvp * instanceTransform * vec4(vertexPosition, 1.0);
}

View File

@ -43,8 +43,8 @@ auto main(int argc, char *argv[]) -> int {
#endif #endif
// RayLib window setup // RayLib window setup
SetTraceLogLevel(LOG_ERROR); // SetTraceLogLevel(LOG_ERROR);
SetConfigFlags(FLAG_VSYNC_HINT); // SetConfigFlags(FLAG_VSYNC_HINT);
SetConfigFlags(FLAG_MSAA_4X_HINT); SetConfigFlags(FLAG_MSAA_4X_HINT);
SetConfigFlags(FLAG_WINDOW_RESIZABLE); SetConfigFlags(FLAG_WINDOW_RESIZABLE);
SetConfigFlags(FLAG_WINDOW_ALWAYS_RUN); SetConfigFlags(FLAG_WINDOW_ALWAYS_RUN);
@ -105,7 +105,6 @@ auto main(int argc, char *argv[]) -> int {
renderer.UpdateCamera(mass_springs, state.current_state); renderer.UpdateCamera(mass_springs, state.current_state);
renderer.UpdateTextureSizes(); renderer.UpdateTextureSizes();
renderer.ReallocateGraphMeshIfNecessary(mass_springs);
renderer.DrawMassSprings(mass_springs, state.current_state, renderer.DrawMassSprings(mass_springs, state.current_state,
state.winning_states); state.winning_states);

View File

@ -114,7 +114,8 @@ auto Renderer::UpdateTextureSizes() -> void {
menu_target = LoadRenderTexture(width * 2, MENU_HEIGHT); menu_target = LoadRenderTexture(width * 2, MENU_HEIGHT);
} }
auto Renderer::AllocateGraphMesh() -> void { #ifdef BATCHING
auto Renderer::AllocateGraphBatching() -> void {
int vertices = 36; int vertices = 36;
int max_masses = 100000; int max_masses = 100000;
@ -137,13 +138,10 @@ auto Renderer::AllocateGraphMesh() -> void {
} }
UnloadMesh(indexed_cube); UnloadMesh(indexed_cube);
mat = LoadMaterialDefault();
mat.maps[MATERIAL_MAP_DIFFUSE].color = VERTEX_COLOR;
std::cout << "Allocated graph mesh." << std::endl; std::cout << "Allocated graph mesh." << std::endl;
} }
auto Renderer::ReallocateGraphMeshIfNecessary( auto Renderer::ReallocateGraphBatchingIfNecessary(
const MassSpringSystem &mass_springs) -> void { const MassSpringSystem &mass_springs) -> void {
if (graph.vertexCount / 3 > mass_springs.masses.size()) { if (graph.vertexCount / 3 > mass_springs.masses.size()) {
return; return;
@ -165,6 +163,35 @@ auto Renderer::ReallocateGraphMeshIfNecessary(
std::cout << "Reallocated graph mesh." << std::endl; std::cout << "Reallocated graph mesh." << std::endl;
} }
#endif
#ifdef INSTANCING
auto Renderer::AllocateGraphInstancing(const MassSpringSystem &mass_springs)
-> void {
cube_instance = GenMeshCube(VERTEX_SIZE, VERTEX_SIZE, VERTEX_SIZE);
instancing_shader =
LoadShader("instancing_vertex.glsl", "instancing_fragment.glsl");
instancing_shader.locs[SHADER_LOC_MATRIX_MVP] =
GetShaderLocation(instancing_shader, "mvp");
instancing_shader.locs[SHADER_LOC_VECTOR_VIEW] =
GetShaderLocation(instancing_shader, "viewPos");
vertex_mat.shader = instancing_shader;
transforms = (Matrix *)MemAlloc(mass_springs.masses.size() * sizeof(Matrix));
transforms_size = mass_springs.masses.size();
}
auto Renderer::ReallocateGraphInstancingIfNecessary(
const MassSpringSystem &mass_springs) -> void {
if (transforms_size != mass_springs.masses.size()) {
transforms = (Matrix *)MemRealloc(transforms, mass_springs.masses.size() *
sizeof(Matrix));
transforms_size = mass_springs.masses.size();
}
}
#endif
auto Renderer::DrawMassSprings(const MassSpringSystem &mass_springs, auto Renderer::DrawMassSprings(const MassSpringSystem &mass_springs,
const State &current_state, const State &current_state,
@ -186,7 +213,30 @@ auto Renderer::DrawMassSprings(const MassSpringSystem &mass_springs,
} }
rlEnd(); rlEnd();
// Draw masses (instanced)
#ifdef INSTANCING
if (transforms == nullptr) {
AllocateGraphInstancing(mass_springs);
}
ReallocateGraphInstancingIfNecessary(mass_springs);
int i = 0;
for (const auto &[state, mass] : mass_springs.masses) {
transforms[i] =
MatrixTranslate(mass.position.x, mass.position.y, mass.position.z);
++i;
}
DrawMeshInstanced(cube_instance, vertex_mat, transforms,
mass_springs.masses.size());
#endif
// Draw masses (batched) // Draw masses (batched)
#ifdef BATCHING
if (cube == nullptr) {
AllocateGraphBatching();
}
ReallocateGraphBatchingIfNecessary(mass_springs);
int vertices = 36; int vertices = 36;
int current_size = mass_springs.masses.size(); int current_size = mass_springs.masses.size();
int i = 0; int i = 0;
@ -208,11 +258,12 @@ auto Renderer::DrawMassSprings(const MassSpringSystem &mass_springs,
graph.vertexCount = current_size * vertices; graph.vertexCount = current_size * vertices;
graph.triangleCount = current_size * 12; graph.triangleCount = current_size * 12;
DrawMesh(graph, mat, MatrixIdentity()); DrawMesh(graph, vertex_mat, MatrixIdentity());
// Restore the vertex count // Restore the vertex count
graph.vertexCount = full_size; graph.vertexCount = full_size;
graph.triangleCount = full_size / 3; graph.triangleCount = full_size / 3;
#endif
// Mark current state // Mark current state
const Mass &current_mass = mass_springs.GetMass(current_state); const Mass &current_mass = mass_springs.GetMass(current_state);