improve rendering performance even more by using instanced rendering
This commit is contained in:
@ -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
|
||||||
|
|||||||
@ -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 ©) = delete;
|
Renderer(const Renderer ©) = 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 ¤t_state,
|
const State ¤t_state,
|
||||||
|
|||||||
8
instancing_fragment.glsl
Normal file
8
instancing_fragment.glsl
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#version 330
|
||||||
|
|
||||||
|
uniform vec4 colDiffuse;
|
||||||
|
out vec4 finalColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
finalColor = colDiffuse;
|
||||||
|
}
|
||||||
13
instancing_vertex.glsl
Normal file
13
instancing_vertex.glsl
Normal 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);
|
||||||
|
}
|
||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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 ¤t_state,
|
const State ¤t_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 ¤t_mass = mass_springs.GetMass(current_state);
|
const Mass ¤t_mass = mass_springs.GetMass(current_state);
|
||||||
|
|||||||
Reference in New Issue
Block a user