From 9f40a59612951842127c5cf64373bb397facce40 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sat, 8 Nov 2025 21:30:49 +0100 Subject: [PATCH 01/21] working project --- Shaders/Compute.glsl | 55 +++++++------ Shaders/Fragment.glsl | 8 ++ Shaders/Vertex.glsl | 15 ++++ src/Main.cpp | 176 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 211 insertions(+), 43 deletions(-) create mode 100644 Shaders/Fragment.glsl create mode 100644 Shaders/Vertex.glsl diff --git a/Shaders/Compute.glsl b/Shaders/Compute.glsl index 50a1882..8ceed32 100644 --- a/Shaders/Compute.glsl +++ b/Shaders/Compute.glsl @@ -2,31 +2,40 @@ layout(rgba32f, binding = 0) uniform writeonly image2D outputImage; -layout(local_size_x = 16, local_size_y = 16) in; +layout(std430, binding = 3) buffer layoutName +{ + vec2 o_Points[]; +}; + +// 1 -> 1 +// 2 -> 3 +// 3 -> 9 +// 4 -> 27 +// 5 -> 81 +// 6 -> 243 +// ... + +// 4 27 +// 1 + 3 + 9 = 13 + +// Sn = ((3^n)-1)/2 +// S3 = 3^3 - 1 / 2 +// 3^4 + +// gl_NumWorkGroups : This variable contains the number of work groups passed to the dispatch function. +// gl_WorkGroupID : This is the current work group for this shader invocation. Each of the XYZ components will be on the half-open range [0, gl_NumWorkGroups.XYZ). +// gl_LocalInvocationID : This is the current invocation of the shader within the work group. Each of the XYZ components will be on the half-open range [0, gl_WorkGroupSize.XYZ). + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; void main() { - ivec2 pixelCoord = ivec2(gl_GlobalInvocationID.xy); + uint triangleCount = gl_NumWorkGroups.x; + uint currentPoint = gl_WorkGroupID.x; - if (pixelCoord.x >= imageSize(outputImage).x || pixelCoord.y >= imageSize(outputImage).y) - return; + uint offset = (triangleCount - 1) / 2; - ivec2 texSize = imageSize(outputImage); - vec2 fTexSize = vec2(texSize); - vec2 normalizedCoord = vec2(pixelCoord) / vec2(texSize); - - vec4 O = vec4(0, 0, 0, 1); - vec2 I = vec2(pixelCoord); - - float iTime = 2.2; - float i = 0.0, t=iTime; - O *= i; - for(vec2 a=fTexSize.xy, p=(I+I-a)/a.y; i++<20.; - O += (cos(sin(i*.2+t)*vec4(0,4,3,1))+2.) - /(i/1e3+abs(length(a-.5*min(a+a.yx,.1))-.05))) - a.x = abs(a = (fract(.2*t+.3*p*i*mat2(cos(cos(.2*t+.2*i)+vec4(0,11,33,0))))-.5)).x; - - O = tanh(O*O/2e5); - - vec4 color = vec4(normalizedCoord, 0.0, 1.0); - imageStore(outputImage, pixelCoord, O); + uint firstPointIndex = offset * 3 + 1; + o_Points[firstPointIndex + currentPoint * 3 ] = o_Points[offset + currentPoint] / 2 + vec2(0, 0.36); + o_Points[firstPointIndex + currentPoint * 3 + 1] = o_Points[offset + currentPoint] / 2 + vec2(-0.5, -0.5); + o_Points[firstPointIndex + currentPoint * 3 + 2] = o_Points[offset + currentPoint] / 2 + vec2(0.5, -0.5); } \ No newline at end of file diff --git a/Shaders/Fragment.glsl b/Shaders/Fragment.glsl new file mode 100644 index 0000000..835cf1d --- /dev/null +++ b/Shaders/Fragment.glsl @@ -0,0 +1,8 @@ +#version 460 core + +layout (location = 0) out vec4 o_Color; + +void main() +{ + o_Color = vec4(1, 1, 1, 1); +} \ No newline at end of file diff --git a/Shaders/Vertex.glsl b/Shaders/Vertex.glsl new file mode 100644 index 0000000..e8ba39a --- /dev/null +++ b/Shaders/Vertex.glsl @@ -0,0 +1,15 @@ +#version 460 core + +layout(location = 0) in vec2 a_Position; + +layout(std430, binding = 3) buffer layoutName +{ + vec2 data_SSBO[]; +}; + +out vec2 v_TexCoord; + +void main() +{ + gl_Position = vec4(data_SSBO[gl_InstanceID], 0.0, 1.0); +} \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp index 9d473cf..c82cf47 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,25 +1,93 @@ #include #include +#include #include "Shader.h" #include "Renderer.h" -static uint32_t s_ComputeShader = -1; -static const std::filesystem::path s_ComputeShaderPath = "Shaders/Compute.glsl"; +#include -static void ErrorCallback(int error, const char* description) +class Timer +{ +public: + Timer() { Reset(); } + void Reset() { m_Start = std::chrono::high_resolution_clock::now(); } + float Elapsed() const { return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_Start).count() * 0.001f * 0.001f; } + float ElapsedMillis() const { return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_Start).count() * 0.001f; } + +private: + std::chrono::time_point m_Start; +}; + +class ScopedTimer +{ +public: + ScopedTimer(std::string_view name) : m_Name(name) {} + ~ScopedTimer() + { + float time = m_Timer.ElapsedMillis(); + std::cout << m_Name << " - " << time << "ms\n"; + } + +private: + Timer m_Timer; + std::string m_Name; +}; + +static uint32_t s_ComputeShader = -1; +static uint32_t s_GraphicsShader = -1; +static const std::filesystem::path s_ComputeShaderPath = "Shaders/Compute.glsl"; +static const std::filesystem::path s_VertexShaderPath = "Shaders/Vertex.glsl"; +static const std::filesystem::path s_FragmentShaderPath = "Shaders/Fragment.glsl"; + +static void ErrorCallback(int error, const char *description) { std::cerr << "Error: " << description << std::endl; } -static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) +static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) { + if (action != GLFW_PRESS) + return; + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GLFW_TRUE); if (key == GLFW_KEY_R) + { s_ComputeShader = ReloadComputeShader(s_ComputeShader, s_ComputeShaderPath); + s_GraphicsShader = ReloadGraphicsShader(s_GraphicsShader, s_VertexShaderPath, s_FragmentShaderPath); + } +} + +std::vector GenPoints(float x, float y) +{ + x /= 2; + y /= 2; + return { + x, y + 0.36f, + x - 0.5f, y - 0.5f, + x + 0.5f, y - 0.5f}; +} + +std::vector GetPoints(int depth) +{ + std::vector result = {0.0f, 0.0f}; + std::size_t offset = 0; + std::size_t count = 1; + for (std::size_t i = 1; i < depth; i++) + { + for (std::size_t j = 0; j < count; j++) + { + std::size_t index = offset + j * 2; + auto newPoints = GenPoints(result[index], result[index + 1]); + result.insert(result.end(), newPoints.begin(), newPoints.end()); + } + offset += count * 2; + count *= 3; + } + return result; } int main() @@ -35,7 +103,7 @@ int main() int width = 1280; int height = 720; - GLFWwindow* window = glfwCreateWindow(width, height, "Compute", NULL, NULL); + GLFWwindow *window = glfwCreateWindow(width, height, "Compute", NULL, NULL); if (!window) { glfwTerminate(); @@ -55,11 +123,82 @@ int main() return -1; } + s_GraphicsShader = CreateGraphicsShader(s_VertexShaderPath, s_FragmentShaderPath); + if (s_GraphicsShader == -1) + { + std::cerr << "Graphics shader failed\n"; + return -1; + } + Texture computeShaderTexture = CreateTexture(width, height); Framebuffer fb = CreateFramebufferWithTexture(computeShaderTexture); - + + GLuint vertexArray; + glCreateVertexArrays(1, &vertexArray); + + GLuint vertexBuffer; + glCreateBuffers(1, &vertexBuffer); + + constexpr int DEPTH = 13; + + auto vertices = GetPoints(DEPTH); + + glNamedBufferData(vertexBuffer, sizeof(float) * vertices.size(), vertices.data(), GL_STATIC_DRAW); + + glVertexArrayVertexBuffer(vertexArray, 0, vertexBuffer, 0, sizeof(float) * 2); + + glEnableVertexArrayAttrib(vertexArray, 0); + glEnableVertexArrayAttrib(vertexArray, 1); + + glVertexArrayAttribFormat(vertexArray, 0, 2, GL_FLOAT, GL_FALSE, 0); + + glVertexArrayAttribBinding(vertexArray, 0, 0); + glVertexArrayAttribBinding(vertexArray, 1, 0); + + GLuint ssbo; + glGenBuffers(1, &ssbo); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, ssbo); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * vertices.size(), nullptr, GL_DYNAMIC_COPY); // sizeof(data) only works for statically sized C/C++ arrays. + + float lastTime = (float)glfwGetTime(); + + int fps = 0; + float secondsTimer = 0.0f; + + // Compute + glUseProgram(s_ComputeShader); + glBindImageTexture(0, fb.ColorAttachment.Handle, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); + + std::size_t count = 1; + for (std::size_t i = 0; i < DEPTH; i++) + { + glDispatchCompute(count, 1, 1); + + // Ensure all writes to the image are complete + glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + + count *= 3; + } + while (!glfwWindowShouldClose(window)) { + // ScopedTimer timer("Main Loop"); + + float currentTime = (float)glfwGetTime(); + float dt = currentTime - lastTime; + lastTime = currentTime; + + secondsTimer += dt; + if (secondsTimer >= 1.0f) + { + std::string title = "FPS : " + std::to_string(fps); + glfwSetWindowTitle(window, title.c_str()); + + secondsTimer = 0.0f; + fps = 0; + } + glfwGetFramebufferSize(window, &width, &height); // Resize texture @@ -70,22 +209,14 @@ int main() AttachTextureToFramebuffer(fb, computeShaderTexture); } - // Compute - { - glUseProgram(s_ComputeShader); - glBindImageTexture(0, fb.ColorAttachment.Handle, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); + // Graphics + glBindFramebuffer(GL_FRAMEBUFFER, fb.Handle); + glUseProgram(s_GraphicsShader); - const GLuint workGroupSizeX = 16; - const GLuint workGroupSizeY = 16; + glBindVertexArray(vertexArray); + glDrawArraysInstanced(GL_POINTS, 0, 1, vertices.size()); - GLuint numGroupsX = (width + workGroupSizeX - 1) / workGroupSizeX; - GLuint numGroupsY = (height + workGroupSizeY - 1) / workGroupSizeY; - - glDispatchCompute(numGroupsX, numGroupsY, 1); - - // Ensure all writes to the image are complete - glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); - } + glBindFramebuffer(GL_FRAMEBUFFER, 0); // Blit { @@ -94,6 +225,11 @@ int main() glfwSwapBuffers(window); glfwPollEvents(); + + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(0, 0, 0, 1); + + fps++; } glfwDestroyWindow(window); -- 2.49.1 From db1bbd6d0aa4c80d42c9aeb3141a08b396790a81 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sat, 8 Nov 2025 22:23:22 +0100 Subject: [PATCH 02/21] optimize dispatch calls --- Shaders/Compute.glsl | 15 ++++++++++----- Shaders/Vertex.glsl | 4 ---- src/Main.cpp | 14 ++++++++++++-- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Shaders/Compute.glsl b/Shaders/Compute.glsl index 8ceed32..21343d1 100644 --- a/Shaders/Compute.glsl +++ b/Shaders/Compute.glsl @@ -2,6 +2,8 @@ layout(rgba32f, binding = 0) uniform writeonly image2D outputImage; +layout(location = 0) uniform uint triangleCount; + layout(std430, binding = 3) buffer layoutName { vec2 o_Points[]; @@ -26,16 +28,19 @@ layout(std430, binding = 3) buffer layoutName // gl_WorkGroupID : This is the current work group for this shader invocation. Each of the XYZ components will be on the half-open range [0, gl_NumWorkGroups.XYZ). // gl_LocalInvocationID : This is the current invocation of the shader within the work group. Each of the XYZ components will be on the half-open range [0, gl_WorkGroupSize.XYZ). -layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; +// avant : 1 3 9 +// après : 3 9 27 +// count : 1 3 9 +layout(local_size_x = 64) in; void main() { - uint triangleCount = gl_NumWorkGroups.x; - uint currentPoint = gl_WorkGroupID.x; + uint currentPoint = gl_GlobalInvocationID.x; + if (currentPoint >= triangleCount) + return; uint offset = (triangleCount - 1) / 2; - uint firstPointIndex = offset * 3 + 1; - o_Points[firstPointIndex + currentPoint * 3 ] = o_Points[offset + currentPoint] / 2 + vec2(0, 0.36); + o_Points[firstPointIndex + currentPoint * 3] = o_Points[offset + currentPoint] / 2 + vec2(0, 0.36); o_Points[firstPointIndex + currentPoint * 3 + 1] = o_Points[offset + currentPoint] / 2 + vec2(-0.5, -0.5); o_Points[firstPointIndex + currentPoint * 3 + 2] = o_Points[offset + currentPoint] / 2 + vec2(0.5, -0.5); } \ No newline at end of file diff --git a/Shaders/Vertex.glsl b/Shaders/Vertex.glsl index e8ba39a..d86e4b0 100644 --- a/Shaders/Vertex.glsl +++ b/Shaders/Vertex.glsl @@ -1,14 +1,10 @@ #version 460 core -layout(location = 0) in vec2 a_Position; - layout(std430, binding = 3) buffer layoutName { vec2 data_SSBO[]; }; -out vec2 v_TexCoord; - void main() { gl_Position = vec4(data_SSBO[gl_InstanceID], 0.0, 1.0); diff --git a/src/Main.cpp b/src/Main.cpp index c82cf47..03a22ad 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -139,7 +139,7 @@ int main() GLuint vertexBuffer; glCreateBuffers(1, &vertexBuffer); - constexpr int DEPTH = 13; + constexpr int DEPTH = 14; auto vertices = GetPoints(DEPTH); @@ -155,6 +155,8 @@ int main() glVertexArrayAttribBinding(vertexArray, 0, 0); glVertexArrayAttribBinding(vertexArray, 1, 0); + Timer timer; + GLuint ssbo; glGenBuffers(1, &ssbo); glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo); @@ -173,7 +175,13 @@ int main() std::size_t count = 1; for (std::size_t i = 0; i < DEPTH; i++) { - glDispatchCompute(count, 1, 1); + glUniform1ui(0, count); + std::cout << count << std::endl; + + int dispatchCount = (count - 1) / 64 + 1; + std::cout << "DC : " < Date: Sat, 8 Nov 2025 23:55:05 +0100 Subject: [PATCH 03/21] chaos game --- Shaders/Compute.glsl | 60 ++++++++++++++++---------------------------- src/Main.cpp | 47 ++++++++++------------------------ 2 files changed, 35 insertions(+), 72 deletions(-) diff --git a/Shaders/Compute.glsl b/Shaders/Compute.glsl index 21343d1..7b41fe4 100644 --- a/Shaders/Compute.glsl +++ b/Shaders/Compute.glsl @@ -1,46 +1,30 @@ #version 460 core -layout(rgba32f, binding = 0) uniform writeonly image2D outputImage; - -layout(location = 0) uniform uint triangleCount; - -layout(std430, binding = 3) buffer layoutName -{ +layout(std430, binding = 3) buffer layoutName { vec2 o_Points[]; }; -// 1 -> 1 -// 2 -> 3 -// 3 -> 9 -// 4 -> 27 -// 5 -> 81 -// 6 -> 243 -// ... - -// 4 27 -// 1 + 3 + 9 = 13 - -// Sn = ((3^n)-1)/2 -// S3 = 3^3 - 1 / 2 -// 3^4 - -// gl_NumWorkGroups : This variable contains the number of work groups passed to the dispatch function. -// gl_WorkGroupID : This is the current work group for this shader invocation. Each of the XYZ components will be on the half-open range [0, gl_NumWorkGroups.XYZ). -// gl_LocalInvocationID : This is the current invocation of the shader within the work group. Each of the XYZ components will be on the half-open range [0, gl_WorkGroupSize.XYZ). - -// avant : 1 3 9 -// après : 3 9 27 -// count : 1 3 9 layout(local_size_x = 64) in; -void main() -{ - uint currentPoint = gl_GlobalInvocationID.x; - if (currentPoint >= triangleCount) - return; - uint offset = (triangleCount - 1) / 2; - uint firstPointIndex = offset * 3 + 1; - o_Points[firstPointIndex + currentPoint * 3] = o_Points[offset + currentPoint] / 2 + vec2(0, 0.36); - o_Points[firstPointIndex + currentPoint * 3 + 1] = o_Points[offset + currentPoint] / 2 + vec2(-0.5, -0.5); - o_Points[firstPointIndex + currentPoint * 3 + 2] = o_Points[offset + currentPoint] / 2 + vec2(0.5, -0.5); +highp float rand(vec2 co) +{ + highp float a = 12.9898; + highp float b = 78.233; + highp float c = 43758.5453; + highp float dt= dot(co.xy ,vec2(a,b)); + highp float sn= mod(dt,3.14); + return fract(sin(sn) * c); +} + +void main() { + const uint total = gl_NumWorkGroups.x * gl_WorkGroupSize.x; + uint currentPoint = gl_GlobalInvocationID.x; + uint index = uint(rand(o_Points[currentPoint] + currentPoint) * 69); + if (index % 3 == 0) { + o_Points[currentPoint] = o_Points[currentPoint] / 2 + vec2(0, 0.36); + } else if (index % 3 == 1) { + o_Points[currentPoint] = o_Points[currentPoint] / 2 + vec2(-0.5, -0.5); + } else { + o_Points[currentPoint] = o_Points[currentPoint] / 2 + vec2(0.5, -0.5); + } } \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp index 03a22ad..c738ddc 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -139,7 +139,7 @@ int main() GLuint vertexBuffer; glCreateBuffers(1, &vertexBuffer); - constexpr int DEPTH = 14; + constexpr int DEPTH = 6; auto vertices = GetPoints(DEPTH); @@ -157,40 +157,19 @@ int main() Timer timer; + constexpr int PARTICLE_COUNT = 64 * 5000; + GLuint ssbo; glGenBuffers(1, &ssbo); glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, ssbo); - glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * vertices.size(), nullptr, GL_DYNAMIC_COPY); // sizeof(data) only works for statically sized C/C++ arrays. + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * PARTICLE_COUNT, nullptr, GL_DYNAMIC_COPY); // sizeof(data) only works for statically sized C/C++ arrays. float lastTime = (float)glfwGetTime(); int fps = 0; float secondsTimer = 0.0f; - // Compute - glUseProgram(s_ComputeShader); - glBindImageTexture(0, fb.ColorAttachment.Handle, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); - - std::size_t count = 1; - for (std::size_t i = 0; i < DEPTH; i++) - { - glUniform1ui(0, count); - std::cout << count << std::endl; - - int dispatchCount = (count - 1) / 64 + 1; - std::cout << "DC : " < Date: Sun, 9 Nov 2025 00:11:12 +0100 Subject: [PATCH 04/21] big refactor --- .clang-format | 37 ++++++++++ src/Main.cpp | 176 +++++++++++++++++------------------------------ src/Renderer.cpp | 36 ++++------ src/Renderer.h | 6 +- src/Shader.cpp | 38 ++++------ src/Shader.h | 3 +- 6 files changed, 132 insertions(+), 164 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..e993027 --- /dev/null +++ b/.clang-format @@ -0,0 +1,37 @@ +Language: Cpp +BasedOnStyle: LLVM + +AlignAfterOpenBracket: DontAlign +BreakConstructorInitializers: AfterColon +ConstructorInitializerAllOnOneLineOrOnePerLine: true +PointerAlignment: Left +SortIncludes: true +SpacesBeforeTrailingComments: 2 +UseTab: Always +MaxEmptyLinesToKeep: 5 + +TabWidth: 4 +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +IndentWidth: 4 +IndentCaseLabels: true + +ColumnLimit: 135 +AlwaysBreakTemplateDeclarations: Yes + +AllowShortFunctionsOnASingleLine: Empty +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp index c738ddc..82e3657 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -3,36 +3,32 @@ #include #include -#include "Shader.h" #include "Renderer.h" +#include "Shader.h" #include -class Timer -{ -public: - Timer() { Reset(); } - void Reset() { m_Start = std::chrono::high_resolution_clock::now(); } - float Elapsed() const { return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_Start).count() * 0.001f * 0.001f; } - float ElapsedMillis() const { return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_Start).count() * 0.001f; } +constexpr int PARTICLE_COUNT = 64 * 5000; -private: - std::chrono::time_point m_Start; -}; - -class ScopedTimer -{ -public: - ScopedTimer(std::string_view name) : m_Name(name) {} - ~ScopedTimer() - { - float time = m_Timer.ElapsedMillis(); - std::cout << m_Name << " - " << time << "ms\n"; +class Timer { + public: + Timer() { + Reset(); + } + void Reset() { + m_Start = std::chrono::high_resolution_clock::now(); + } + float Elapsed() const { + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_Start).count() * + 0.001f * 0.001f; + } + float ElapsedMillis() const { + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_Start).count() * + 0.001f; } -private: - Timer m_Timer; - std::string m_Name; + private: + std::chrono::time_point m_Start; }; static uint32_t s_ComputeShader = -1; @@ -41,57 +37,51 @@ static const std::filesystem::path s_ComputeShaderPath = "Shaders/Compute.glsl"; static const std::filesystem::path s_VertexShaderPath = "Shaders/Vertex.glsl"; static const std::filesystem::path s_FragmentShaderPath = "Shaders/Fragment.glsl"; -static void ErrorCallback(int error, const char *description) -{ +static void ErrorCallback(int error, const char* description) { std::cerr << "Error: " << description << std::endl; } -static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) -{ +static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (action != GLFW_PRESS) return; if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GLFW_TRUE); - if (key == GLFW_KEY_R) - { + if (key == GLFW_KEY_R) { s_ComputeShader = ReloadComputeShader(s_ComputeShader, s_ComputeShaderPath); s_GraphicsShader = ReloadGraphicsShader(s_GraphicsShader, s_VertexShaderPath, s_FragmentShaderPath); } } -std::vector GenPoints(float x, float y) -{ - x /= 2; - y /= 2; - return { - x, y + 0.36f, - x - 0.5f, y - 0.5f, - x + 0.5f, y - 0.5f}; +static GLuint CreateDummyVAO() { + GLuint vertexArray; + glCreateVertexArrays(1, &vertexArray); + + GLuint vertexBuffer; + glCreateBuffers(1, &vertexBuffer); + + // Buffer with just one point + float vertices[] = {0.0f, 0.0f}; + glNamedBufferData(vertexBuffer, sizeof(vertices), vertices, GL_STATIC_DRAW); + glVertexArrayVertexBuffer(vertexArray, 0, vertexBuffer, 0, sizeof(float) * 2); + glEnableVertexArrayAttrib(vertexArray, 0); + glVertexArrayAttribFormat(vertexArray, 0, 2, GL_FLOAT, GL_FALSE, 0); + glVertexArrayAttribBinding(vertexArray, 0, 0); + + return vertexArray; } -std::vector GetPoints(int depth) -{ - std::vector result = {0.0f, 0.0f}; - std::size_t offset = 0; - std::size_t count = 1; - for (std::size_t i = 1; i < depth; i++) - { - for (std::size_t j = 0; j < count; j++) - { - std::size_t index = offset + j * 2; - auto newPoints = GenPoints(result[index], result[index + 1]); - result.insert(result.end(), newPoints.begin(), newPoints.end()); - } - offset += count * 2; - count *= 3; - } - return result; +static void CreateGpuBuffer(std::size_t a_Size) { + GLuint ssbo; + glGenBuffers(1, &ssbo); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, ssbo); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * a_Size, nullptr, + GL_DYNAMIC_COPY); // sizeof(data) only works for statically sized C/C++ arrays. } -int main() -{ +static GLFWwindow* InitWindow() { glfwSetErrorCallback(ErrorCallback); if (!glfwInit()) @@ -103,9 +93,8 @@ int main() int width = 1280; int height = 720; - GLFWwindow *window = glfwCreateWindow(width, height, "Compute", NULL, NULL); - if (!window) - { + GLFWwindow* window = glfwCreateWindow(width, height, "", NULL, NULL); + if (!window) { glfwTerminate(); exit(EXIT_FAILURE); } @@ -117,61 +106,37 @@ int main() glfwSwapInterval(1); s_ComputeShader = CreateComputeShader(s_ComputeShaderPath); - if (s_ComputeShader == -1) - { + if (s_ComputeShader == -1) { std::cerr << "Compute shader failed\n"; - return -1; + return nullptr; } s_GraphicsShader = CreateGraphicsShader(s_VertexShaderPath, s_FragmentShaderPath); - if (s_GraphicsShader == -1) - { + if (s_GraphicsShader == -1) { std::cerr << "Graphics shader failed\n"; - return -1; + return nullptr; } - Texture computeShaderTexture = CreateTexture(width, height); - Framebuffer fb = CreateFramebufferWithTexture(computeShaderTexture); + return window; +} - GLuint vertexArray; - glCreateVertexArrays(1, &vertexArray); +int main() { + GLFWwindow* window = InitWindow(); + if (!window) + return -1; - GLuint vertexBuffer; - glCreateBuffers(1, &vertexBuffer); + auto vertexArray = CreateDummyVAO(); - constexpr int DEPTH = 6; - - auto vertices = GetPoints(DEPTH); - - glNamedBufferData(vertexBuffer, sizeof(float) * vertices.size(), vertices.data(), GL_STATIC_DRAW); - - glVertexArrayVertexBuffer(vertexArray, 0, vertexBuffer, 0, sizeof(float) * 2); - - glEnableVertexArrayAttrib(vertexArray, 0); - glEnableVertexArrayAttrib(vertexArray, 1); - - glVertexArrayAttribFormat(vertexArray, 0, 2, GL_FLOAT, GL_FALSE, 0); - - glVertexArrayAttribBinding(vertexArray, 0, 0); - glVertexArrayAttribBinding(vertexArray, 1, 0); - - Timer timer; - - constexpr int PARTICLE_COUNT = 64 * 5000; - - GLuint ssbo; - glGenBuffers(1, &ssbo); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, ssbo); - glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * PARTICLE_COUNT, nullptr, GL_DYNAMIC_COPY); // sizeof(data) only works for statically sized C/C++ arrays. + CreateGpuBuffer(PARTICLE_COUNT); float lastTime = (float)glfwGetTime(); int fps = 0; float secondsTimer = 0.0f; - while (!glfwWindowShouldClose(window)) - { + glBindVertexArray(vertexArray); + + while (!glfwWindowShouldClose(window)) { // ScopedTimer timer("Main Loop"); float currentTime = (float)glfwGetTime(); @@ -179,8 +144,7 @@ int main() lastTime = currentTime; secondsTimer += dt; - if (secondsTimer >= 1.0f) - { + if (secondsTimer >= 1.0f) { std::string title = "FPS : " + std::to_string(fps); glfwSetWindowTitle(window, title.c_str()); @@ -188,18 +152,7 @@ int main() fps = 0; } - glfwGetFramebufferSize(window, &width, &height); - - // Resize texture - if (width != computeShaderTexture.Width || height != computeShaderTexture.Height) - { - glDeleteTextures(1, &computeShaderTexture.Handle); - computeShaderTexture = CreateTexture(width, height); - AttachTextureToFramebuffer(fb, computeShaderTexture); - } - // Compute - glUseProgram(s_ComputeShader); glDispatchCompute(PARTICLE_COUNT / 64, 1, 1); @@ -209,7 +162,6 @@ int main() // Graphics glUseProgram(s_GraphicsShader); - glBindVertexArray(vertexArray); glDrawArraysInstanced(GL_POINTS, 0, 1, PARTICLE_COUNT); glfwSwapBuffers(window); diff --git a/src/Renderer.cpp b/src/Renderer.cpp index e518a5f..5892fd5 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -5,8 +5,7 @@ #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" -Texture CreateTexture(int width, int height) -{ +Texture CreateTexture(int width, int height) { Texture result; result.Width = width; result.Height = height; @@ -24,21 +23,17 @@ Texture CreateTexture(int width, int height) return result; } -Texture LoadTexture(const std::filesystem::path& path) -{ +Texture LoadTexture(const std::filesystem::path& path) { int width, height, channels; std::string filepath = path.string(); unsigned char* data = stbi_load(filepath.c_str(), &width, &height, &channels, 0); - if (!data) - { + if (!data) { std::cerr << "Failed to load texture: " << filepath << "\n"; return {}; } - GLenum format = channels == 4 ? GL_RGBA : - channels == 3 ? GL_RGB : - channels == 1 ? GL_RED : 0; + GLenum format = channels == 4 ? GL_RGBA : channels == 3 ? GL_RGB : channels == 1 ? GL_RED : 0; Texture result; result.Width = width; @@ -47,7 +42,7 @@ Texture LoadTexture(const std::filesystem::path& path) glCreateTextures(GL_TEXTURE_2D, 1, &result.Handle); glTextureStorage2D(result.Handle, 1, (format == GL_RGBA ? GL_RGBA8 : GL_RGB8), width, height); - + glTextureSubImage2D(result.Handle, 0, 0, 0, width, height, format, GL_UNSIGNED_BYTE, data); glTextureParameteri(result.Handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -62,14 +57,12 @@ Texture LoadTexture(const std::filesystem::path& path) return result; } -Framebuffer CreateFramebufferWithTexture(const Texture texture) -{ +Framebuffer CreateFramebufferWithTexture(const Texture texture) { Framebuffer result; glCreateFramebuffers(1, &result.Handle); - if (!AttachTextureToFramebuffer(result, texture)) - { + if (!AttachTextureToFramebuffer(result, texture)) { glDeleteFramebuffers(1, &result.Handle); return {}; } @@ -77,12 +70,10 @@ Framebuffer CreateFramebufferWithTexture(const Texture texture) return result; } -bool AttachTextureToFramebuffer(Framebuffer& framebuffer, const Texture texture) -{ +bool AttachTextureToFramebuffer(Framebuffer& framebuffer, const Texture texture) { glNamedFramebufferTexture(framebuffer.Handle, GL_COLOR_ATTACHMENT0, texture.Handle, 0); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - { + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { std::cerr << "Framebuffer is not complete!" << std::endl; return false; } @@ -91,12 +82,11 @@ bool AttachTextureToFramebuffer(Framebuffer& framebuffer, const Texture texture) return true; } -void BlitFramebufferToSwapchain(const Framebuffer framebuffer) -{ +void BlitFramebufferToSwapchain(const Framebuffer framebuffer) { glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer.Handle); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // swapchain + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // swapchain - glBlitFramebuffer(0, 0, framebuffer.ColorAttachment.Width, framebuffer.ColorAttachment.Height, // Source rect - 0, 0, framebuffer.ColorAttachment.Width, framebuffer.ColorAttachment.Height, // Destination rect + glBlitFramebuffer(0, 0, framebuffer.ColorAttachment.Width, framebuffer.ColorAttachment.Height, // Source rect + 0, 0, framebuffer.ColorAttachment.Width, framebuffer.ColorAttachment.Height, // Destination rect GL_COLOR_BUFFER_BIT, GL_NEAREST); } \ No newline at end of file diff --git a/src/Renderer.h b/src/Renderer.h index 139f971..f5c2b69 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -6,15 +6,13 @@ #include -struct Texture -{ +struct Texture { GLuint Handle = 0; uint32_t Width = 0; uint32_t Height = 0; }; -struct Framebuffer -{ +struct Framebuffer { GLuint Handle = 0; Texture ColorAttachment; }; diff --git a/src/Shader.cpp b/src/Shader.cpp index ab51998..f280121 100644 --- a/src/Shader.cpp +++ b/src/Shader.cpp @@ -1,17 +1,15 @@ #include "Shader.h" -#include #include +#include #include #include -static std::string ReadTextFile(const std::filesystem::path& path) -{ +static std::string ReadTextFile(const std::filesystem::path& path) { std::ifstream file(path); - if (!file.is_open()) - { + if (!file.is_open()) { std::cerr << "Failed to open file: " << path.string() << std::endl; return {}; } @@ -21,8 +19,7 @@ static std::string ReadTextFile(const std::filesystem::path& path) return contentStream.str(); } -uint32_t CreateComputeShader(const std::filesystem::path& path) -{ +uint32_t CreateComputeShader(const std::filesystem::path& path) { std::string shaderSource = ReadTextFile(path); GLuint shaderHandle = glCreateShader(GL_COMPUTE_SHADER); @@ -34,8 +31,7 @@ uint32_t CreateComputeShader(const std::filesystem::path& path) GLint isCompiled = 0; glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &isCompiled); - if (isCompiled == GL_FALSE) - { + if (isCompiled == GL_FALSE) { GLint maxLength = 0; glGetShaderiv(shaderHandle, GL_INFO_LOG_LENGTH, &maxLength); @@ -54,14 +50,13 @@ uint32_t CreateComputeShader(const std::filesystem::path& path) GLint isLinked = 0; glGetProgramiv(program, GL_LINK_STATUS, (int*)&isLinked); - if (isLinked == GL_FALSE) - { + if (isLinked == GL_FALSE) { GLint maxLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); std::vector infoLog(maxLength); glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]); - + std::cerr << infoLog.data() << std::endl; glDeleteProgram(program); @@ -74,8 +69,7 @@ uint32_t CreateComputeShader(const std::filesystem::path& path) return program; } -uint32_t ReloadComputeShader(uint32_t shaderHandle, const std::filesystem::path& path) -{ +uint32_t ReloadComputeShader(uint32_t shaderHandle, const std::filesystem::path& path) { uint32_t newShaderHandle = CreateComputeShader(path); // Return old shader if compilation failed @@ -86,8 +80,7 @@ uint32_t ReloadComputeShader(uint32_t shaderHandle, const std::filesystem::path& return newShaderHandle; } -uint32_t CreateGraphicsShader(const std::filesystem::path& vertexPath, const std::filesystem::path& fragmentPath) -{ +uint32_t CreateGraphicsShader(const std::filesystem::path& vertexPath, const std::filesystem::path& fragmentPath) { std::string vertexShaderSource = ReadTextFile(vertexPath); std::string fragmentShaderSource = ReadTextFile(fragmentPath); @@ -102,8 +95,7 @@ uint32_t CreateGraphicsShader(const std::filesystem::path& vertexPath, const std GLint isCompiled = 0; glGetShaderiv(vertexShaderHandle, GL_COMPILE_STATUS, &isCompiled); - if (isCompiled == GL_FALSE) - { + if (isCompiled == GL_FALSE) { GLint maxLength = 0; glGetShaderiv(vertexShaderHandle, GL_INFO_LOG_LENGTH, &maxLength); @@ -127,8 +119,7 @@ uint32_t CreateGraphicsShader(const std::filesystem::path& vertexPath, const std isCompiled = 0; glGetShaderiv(fragmentShaderHandle, GL_COMPILE_STATUS, &isCompiled); - if (isCompiled == GL_FALSE) - { + if (isCompiled == GL_FALSE) { GLint maxLength = 0; glGetShaderiv(fragmentShaderHandle, GL_INFO_LOG_LENGTH, &maxLength); @@ -150,8 +141,7 @@ uint32_t CreateGraphicsShader(const std::filesystem::path& vertexPath, const std GLint isLinked = 0; glGetProgramiv(program, GL_LINK_STATUS, (int*)&isLinked); - if (isLinked == GL_FALSE) - { + if (isLinked == GL_FALSE) { GLint maxLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); @@ -172,8 +162,8 @@ uint32_t CreateGraphicsShader(const std::filesystem::path& vertexPath, const std return program; } -uint32_t ReloadGraphicsShader(uint32_t shaderHandle, const std::filesystem::path& vertexPath, const std::filesystem::path& fragmentPath) -{ +uint32_t ReloadGraphicsShader( + uint32_t shaderHandle, const std::filesystem::path& vertexPath, const std::filesystem::path& fragmentPath) { uint32_t newShaderHandle = CreateGraphicsShader(vertexPath, fragmentPath); // Return old shader if compilation failed diff --git a/src/Shader.h b/src/Shader.h index 491d226..bd33acb 100644 --- a/src/Shader.h +++ b/src/Shader.h @@ -6,4 +6,5 @@ uint32_t CreateComputeShader(const std::filesystem::path& path); uint32_t ReloadComputeShader(uint32_t shaderHandle, const std::filesystem::path& path); uint32_t CreateGraphicsShader(const std::filesystem::path& vertexPath, const std::filesystem::path& fragmentPath); -uint32_t ReloadGraphicsShader(uint32_t shaderHandle, const std::filesystem::path& vertexPath, const std::filesystem::path& fragmentPath); \ No newline at end of file +uint32_t ReloadGraphicsShader( + uint32_t shaderHandle, const std::filesystem::path& vertexPath, const std::filesystem::path& fragmentPath); \ No newline at end of file -- 2.49.1 From e7edf0cf6feecec99c9525c70cc8bda99bc1c2d4 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 11:06:18 +0100 Subject: [PATCH 05/21] fix gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b9478e6..95ba5e5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ *.user # VsCode -.vsCode +.vscode # Xmake .xmake -- 2.49.1 From 9c4894eda266190c3f88728848ce06d6ea7f9e01 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 11:06:44 +0100 Subject: [PATCH 06/21] fix shader buffer size --- src/Main.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index 82e3657..3570c24 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -8,7 +8,10 @@ #include -constexpr int PARTICLE_COUNT = 64 * 5000; +constexpr int WORK_GROUP_SIZE = 64; +constexpr int PARTICLE_COUNT = WORK_GROUP_SIZE * 1000; + +constexpr int SWAP_INTERVAL = 60; class Timer { public: @@ -51,6 +54,7 @@ static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, i if (key == GLFW_KEY_R) { s_ComputeShader = ReloadComputeShader(s_ComputeShader, s_ComputeShaderPath); s_GraphicsShader = ReloadGraphicsShader(s_GraphicsShader, s_VertexShaderPath, s_FragmentShaderPath); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * PARTICLE_COUNT * 2, nullptr, GL_DYNAMIC_COPY); } } @@ -72,12 +76,12 @@ static GLuint CreateDummyVAO() { return vertexArray; } -static void CreateGpuBuffer(std::size_t a_Size) { +static void CreateGpuBuffer() { GLuint ssbo; glGenBuffers(1, &ssbo); glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, ssbo); - glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * a_Size, nullptr, + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * 2 * PARTICLE_COUNT, nullptr, GL_DYNAMIC_COPY); // sizeof(data) only works for statically sized C/C++ arrays. } @@ -103,7 +107,7 @@ static GLFWwindow* InitWindow() { glfwMakeContextCurrent(window); gladLoadGL(); - glfwSwapInterval(1); + glfwSwapInterval(SWAP_INTERVAL); s_ComputeShader = CreateComputeShader(s_ComputeShaderPath); if (s_ComputeShader == -1) { @@ -127,7 +131,7 @@ int main() { auto vertexArray = CreateDummyVAO(); - CreateGpuBuffer(PARTICLE_COUNT); + CreateGpuBuffer(); float lastTime = (float)glfwGetTime(); @@ -154,7 +158,7 @@ int main() { // Compute glUseProgram(s_ComputeShader); - glDispatchCompute(PARTICLE_COUNT / 64, 1, 1); + glDispatchCompute(PARTICLE_COUNT / WORK_GROUP_SIZE, 1, 1); // Ensure all writes to the image are complete glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); -- 2.49.1 From ba6a342c9450ac8c6c567e3a1e3cc9bb57339d48 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 11:09:04 +0100 Subject: [PATCH 07/21] real time --- src/Main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index 3570c24..34b6c2f 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -9,9 +9,9 @@ #include constexpr int WORK_GROUP_SIZE = 64; -constexpr int PARTICLE_COUNT = WORK_GROUP_SIZE * 1000; +constexpr int PARTICLE_COUNT = WORK_GROUP_SIZE * 10000; -constexpr int SWAP_INTERVAL = 60; +constexpr int SWAP_INTERVAL = 1; class Timer { public: -- 2.49.1 From b54bb6a1360e5bef07dbb53265bd76d60d0c1b68 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 11:19:22 +0100 Subject: [PATCH 08/21] matrix multiplcation --- Shaders/Compute.glsl | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Shaders/Compute.glsl b/Shaders/Compute.glsl index 7b41fe4..a94ab8d 100644 --- a/Shaders/Compute.glsl +++ b/Shaders/Compute.glsl @@ -20,11 +20,19 @@ void main() { const uint total = gl_NumWorkGroups.x * gl_WorkGroupSize.x; uint currentPoint = gl_GlobalInvocationID.x; uint index = uint(rand(o_Points[currentPoint] + currentPoint) * 69); - if (index % 3 == 0) { - o_Points[currentPoint] = o_Points[currentPoint] / 2 + vec2(0, 0.36); - } else if (index % 3 == 1) { - o_Points[currentPoint] = o_Points[currentPoint] / 2 + vec2(-0.5, -0.5); - } else { - o_Points[currentPoint] = o_Points[currentPoint] / 2 + vec2(0.5, -0.5); + mat3 transformation; + switch (index % 3) { + case 0: + transformation = mat3(0.5, 0, 0, 0, 0.5, 0, 0, 0.36, 1); + break; + + case 1: + transformation = mat3(0.5, 0, 0, 0, 0.5, 0, -0.5, -0.5, 1); + break; + + case 2: + transformation = mat3(0.5, 0, 0, 0, 0.5, 0, 0.5, -0.5, 1); + break; } + o_Points[currentPoint] = (transformation * vec3(o_Points[currentPoint], 1.0)).xy; } \ No newline at end of file -- 2.49.1 From 6a874a01bb5f9361bbaf47736f9518ae069ff80c Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 11:59:46 +0100 Subject: [PATCH 09/21] now in 3D --- Shaders/Compute.glsl | 28 ++++++++++++++++++++-------- Shaders/Vertex.glsl | 8 ++++++-- src/Main.cpp | 20 +++++++++++++++----- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/Shaders/Compute.glsl b/Shaders/Compute.glsl index a94ab8d..cfa3368 100644 --- a/Shaders/Compute.glsl +++ b/Shaders/Compute.glsl @@ -1,7 +1,7 @@ #version 460 core layout(std430, binding = 3) buffer layoutName { - vec2 o_Points[]; + float o_Points[]; }; layout(local_size_x = 64) in; @@ -16,23 +16,35 @@ highp float rand(vec2 co) return fract(sin(sn) * c); } +vec3 unpack(uint index) { + return vec3(o_Points[index * 3], o_Points[index * 3 + 1], o_Points[index * 3 + 2]); +} + +void store(vec3 vect, uint index) { + o_Points[index * 3] = vect.x; + o_Points[index * 3 + 1] = vect.y; + o_Points[index * 3 + 2] = vect.z; +} + void main() { const uint total = gl_NumWorkGroups.x * gl_WorkGroupSize.x; - uint currentPoint = gl_GlobalInvocationID.x; - uint index = uint(rand(o_Points[currentPoint] + currentPoint) * 69); - mat3 transformation; + uint currentIndex = gl_GlobalInvocationID.x; + vec3 currentPoint = unpack(currentIndex); + uint index = uint(rand(currentPoint.xy + currentPoint.z + currentIndex) * 69); + mat4 transformation; switch (index % 3) { case 0: - transformation = mat3(0.5, 0, 0, 0, 0.5, 0, 0, 0.36, 1); + transformation = mat4(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0.36, 0, 1); break; case 1: - transformation = mat3(0.5, 0, 0, 0, 0.5, 0, -0.5, -0.5, 1); + transformation = mat4(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, -0.5, -0.5, 0, 1); break; case 2: - transformation = mat3(0.5, 0, 0, 0, 0.5, 0, 0.5, -0.5, 1); + transformation = mat4(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0.5, -0.5, 0, 1); break; } - o_Points[currentPoint] = (transformation * vec3(o_Points[currentPoint], 1.0)).xy; + vec3 result = (transformation * vec4(currentPoint, 1.0)).xyz; + store(result, currentIndex); } \ No newline at end of file diff --git a/Shaders/Vertex.glsl b/Shaders/Vertex.glsl index d86e4b0..56fdf50 100644 --- a/Shaders/Vertex.glsl +++ b/Shaders/Vertex.glsl @@ -2,10 +2,14 @@ layout(std430, binding = 3) buffer layoutName { - vec2 data_SSBO[]; + float data_SSBO[]; }; +vec3 unpack(uint index) { + return vec3(data_SSBO[index * 3], data_SSBO[index * 3 + 1], data_SSBO[index * 3 + 2]); +} + void main() { - gl_Position = vec4(data_SSBO[gl_InstanceID], 0.0, 1.0); + gl_Position = vec4(unpack(gl_InstanceID), 1.0); } \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp index 34b6c2f..6488118 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -54,7 +54,7 @@ static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, i if (key == GLFW_KEY_R) { s_ComputeShader = ReloadComputeShader(s_ComputeShader, s_ComputeShaderPath); s_GraphicsShader = ReloadGraphicsShader(s_GraphicsShader, s_VertexShaderPath, s_FragmentShaderPath); - glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * PARTICLE_COUNT * 2, nullptr, GL_DYNAMIC_COPY); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * PARTICLE_COUNT * 3, nullptr, GL_DYNAMIC_COPY); } } @@ -66,11 +66,11 @@ static GLuint CreateDummyVAO() { glCreateBuffers(1, &vertexBuffer); // Buffer with just one point - float vertices[] = {0.0f, 0.0f}; + float vertices[] = {0.0f, 0.0f, 0.0f}; glNamedBufferData(vertexBuffer, sizeof(vertices), vertices, GL_STATIC_DRAW); - glVertexArrayVertexBuffer(vertexArray, 0, vertexBuffer, 0, sizeof(float) * 2); + glVertexArrayVertexBuffer(vertexArray, 0, vertexBuffer, 0, sizeof(float) * 3); glEnableVertexArrayAttrib(vertexArray, 0); - glVertexArrayAttribFormat(vertexArray, 0, 2, GL_FLOAT, GL_FALSE, 0); + glVertexArrayAttribFormat(vertexArray, 0, 3, GL_FLOAT, GL_FALSE, 0); glVertexArrayAttribBinding(vertexArray, 0, 0); return vertexArray; @@ -81,7 +81,7 @@ static void CreateGpuBuffer() { glGenBuffers(1, &ssbo); glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, ssbo); - glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * 2 * PARTICLE_COUNT, nullptr, + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * 3 * PARTICLE_COUNT, nullptr, GL_DYNAMIC_COPY); // sizeof(data) only works for statically sized C/C++ arrays. } @@ -174,6 +174,16 @@ int main() { glClear(GL_COLOR_BUFFER_BIT); glClearColor(0, 0, 0, 1); + // float positions[3 * PARTICLE_COUNT]; + // glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(float) * 3 * PARTICLE_COUNT, positions); + + // std::cout << "Positions :\n"; + // for (size_t i = 0; i < PARTICLE_COUNT; i++) + // { + // std::cout << "\t" << positions[i * 3] << " " << positions[i * 3 + 1] << " " << positions[i * 3 + 2] << "\n"; + // } + + fps++; } -- 2.49.1 From 1be8e337a371068931633b26e327bc7a43271eed Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 12:13:08 +0100 Subject: [PATCH 10/21] matrix values cpu side --- Shaders/Compute.glsl | 20 ++++++-------------- src/Main.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/Shaders/Compute.glsl b/Shaders/Compute.glsl index cfa3368..0052231 100644 --- a/Shaders/Compute.glsl +++ b/Shaders/Compute.glsl @@ -4,6 +4,10 @@ layout(std430, binding = 3) buffer layoutName { float o_Points[]; }; +const uint transformationCount = 3; + +layout(location = 1) uniform mat4 transformations[transformationCount]; + layout(local_size_x = 64) in; highp float rand(vec2 co) @@ -27,24 +31,12 @@ void store(vec3 vect, uint index) { } void main() { - const uint total = gl_NumWorkGroups.x * gl_WorkGroupSize.x; uint currentIndex = gl_GlobalInvocationID.x; vec3 currentPoint = unpack(currentIndex); + uint index = uint(rand(currentPoint.xy + currentPoint.z + currentIndex) * 69); - mat4 transformation; - switch (index % 3) { - case 0: - transformation = mat4(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0.36, 0, 1); - break; + mat4 transformation = transformations[index % transformationCount]; - case 1: - transformation = mat4(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, -0.5, -0.5, 0, 1); - break; - - case 2: - transformation = mat4(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0.5, -0.5, 0, 1); - break; - } vec3 result = (transformation * vec4(currentPoint, 1.0)).xyz; store(result, currentIndex); } \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp index 6488118..b317f02 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -140,6 +140,31 @@ int main() { glBindVertexArray(vertexArray); + std::vector transformations = { + { + 0.5f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.5f, 0.0f, 0.36f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }, + { + 0.5f, 0.0f, 0.0f, -0.5f, + 0.0f, 0.5f, 0.0f, -0.5f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }, + { + 0.5f, 0.0f, 0.0f, 0.5f, + 0.0f, 0.5f, 0.0f, -0.5f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }, + }; + + glUseProgram(s_ComputeShader); + glUniformMatrix4fv(1, transformations.size(), true, glm::value_ptr(transformations[0])); + + while (!glfwWindowShouldClose(window)) { // ScopedTimer timer("Main Loop"); -- 2.49.1 From b5f6e81a7b77fa1eecc5d11998e3f37e4517552a Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 13:27:56 +0100 Subject: [PATCH 11/21] resize viewport --- src/Main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Main.cpp b/src/Main.cpp index b317f02..bf99552 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -199,6 +199,10 @@ int main() { glClear(GL_COLOR_BUFFER_BIT); glClearColor(0, 0, 0, 1); + int width, height; + glfwGetWindowSize(window, &width, &height); + glViewport(0, 0, width, height); + // float positions[3 * PARTICLE_COUNT]; // glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(float) * 3 * PARTICLE_COUNT, positions); -- 2.49.1 From bd81c632deb9e6d41e9e41ad555d9af2d8d94f84 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 13:28:38 +0100 Subject: [PATCH 12/21] procedurally generated transformations --- src/Main.cpp | 139 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 114 insertions(+), 25 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index bf99552..26f9c03 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -7,12 +7,72 @@ #include "Shader.h" #include +#include constexpr int WORK_GROUP_SIZE = 64; constexpr int PARTICLE_COUNT = WORK_GROUP_SIZE * 10000; constexpr int SWAP_INTERVAL = 1; +constexpr int TRANSFORMATION_COUNT = 3; + +static const std::vector SIERPINSKI_TRIANGLE = { + { + 0.5f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.5f, + 0.0f, + 0.36f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + }, + { + 0.5f, + 0.0f, + 0.0f, + -0.5f, + 0.0f, + 0.5f, + 0.0f, + -0.5f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + }, + { + 0.5f, + 0.0f, + 0.0f, + 0.5f, + 0.0f, + 0.5f, + 0.0f, + -0.5f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + }, +}; + class Timer { public: Timer() { @@ -44,6 +104,54 @@ static void ErrorCallback(int error, const char* description) { std::cerr << "Error: " << description << std::endl; } +static void ApplyTransforms(const std::vector& transformations) { + glUseProgram(s_ComputeShader); + glUniformMatrix4fv(1, transformations.size(), true, glm::value_ptr(transformations[0])); +} + +static void GenNewFractal() { + std::random_device randomDevice; + std::mt19937 generator(randomDevice()); + std::uniform_real_distribution distrib(0, 1); + + // scale, rotation, shear, translation + + std::vector transformations(TRANSFORMATION_COUNT); + + for (std::size_t i = 0; i < transformations.size(); i++) { + float scaleX = distrib(generator); + float scaleY = distrib(generator); + float scaleZ = distrib(generator); + + float rotX = distrib(generator) * 2 * 3.14; + float rotY = distrib(generator) * 2 * 3.14; + float rotZ = distrib(generator) * 2 * 3.14; + + float shearXY = distrib(generator) * 0.2f - 0.1f; + float shearXZ = distrib(generator) * 0.2f - 0.1f; + float shearYX = distrib(generator) * 0.2f - 0.1f; + float shearYZ = distrib(generator) * 0.2f - 0.1f; + float shearZX = distrib(generator) * 0.2f - 0.1f; + float shearZY = distrib(generator) * 0.2f - 0.1f; + + float translateX = distrib(generator) * 2.0f - 1.0f; + float translateY = distrib(generator) * 2.0f - 1.0f; + float translateZ = distrib(generator) * 2.0f - 1.0f; + + auto scale = glm::scale(glm::mat4(1), {scaleX, scaleY, scaleZ}); + auto rotateX = glm::rotate(scale, rotX, {1, 0, 0}); + auto rotateY = glm::rotate(rotateX, rotY, {0, 1, 0}); + auto rotateZ = glm::rotate(rotateY, rotZ, {0, 0, 1}); + auto shear = glm::shear(rotateZ, {0, 0, 0}, {shearXY, shearXZ}, {shearYX, shearYZ}, {shearZX, shearZY}); + auto translate = glm::translate(shear, {translateX, translateY, translateZ}); + + transformations[i] = translate; + } + + glUseProgram(s_ComputeShader); + glUniformMatrix4fv(1, transformations.size(), false, glm::value_ptr(transformations[0])); +} + static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (action != GLFW_PRESS) return; @@ -55,6 +163,11 @@ static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, i s_ComputeShader = ReloadComputeShader(s_ComputeShader, s_ComputeShaderPath); s_GraphicsShader = ReloadGraphicsShader(s_GraphicsShader, s_VertexShaderPath, s_FragmentShaderPath); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * PARTICLE_COUNT * 3, nullptr, GL_DYNAMIC_COPY); + ApplyTransforms(SIERPINSKI_TRIANGLE); + } + + if (key == GLFW_KEY_T) { + GenNewFractal(); } } @@ -140,30 +253,7 @@ int main() { glBindVertexArray(vertexArray); - std::vector transformations = { - { - 0.5f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.5f, 0.0f, 0.36f, - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - }, - { - 0.5f, 0.0f, 0.0f, -0.5f, - 0.0f, 0.5f, 0.0f, -0.5f, - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - }, - { - 0.5f, 0.0f, 0.0f, 0.5f, - 0.0f, 0.5f, 0.0f, -0.5f, - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - }, - }; - - glUseProgram(s_ComputeShader); - glUniformMatrix4fv(1, transformations.size(), true, glm::value_ptr(transformations[0])); - + ApplyTransforms(SIERPINSKI_TRIANGLE); while (!glfwWindowShouldClose(window)) { // ScopedTimer timer("Main Loop"); @@ -211,7 +301,6 @@ int main() { // { // std::cout << "\t" << positions[i * 3] << " " << positions[i * 3 + 1] << " " << positions[i * 3 + 2] << "\n"; // } - fps++; } -- 2.49.1 From 78088b2067fed578292e40cc8b6304199a464574 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 13:30:24 +0100 Subject: [PATCH 13/21] auto regenerate every second --- src/Main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Main.cpp b/src/Main.cpp index 26f9c03..e441e77 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -269,6 +269,8 @@ int main() { secondsTimer = 0.0f; fps = 0; + + GenNewFractal(); } // Compute -- 2.49.1 From 0eebe09d47f06f3e5aee6dc63a4acf8eb8b255b6 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 14:00:27 +0100 Subject: [PATCH 14/21] adjust random values --- src/Main.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index e441e77..cb91d06 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -119,9 +119,9 @@ static void GenNewFractal() { std::vector transformations(TRANSFORMATION_COUNT); for (std::size_t i = 0; i < transformations.size(); i++) { - float scaleX = distrib(generator); - float scaleY = distrib(generator); - float scaleZ = distrib(generator); + float scaleX = distrib(generator) * 0.4 + 0.4; + float scaleY = distrib(generator) * 0.4 + 0.4; + float scaleZ = distrib(generator) * 0.4 + 0.4; float rotX = distrib(generator) * 2 * 3.14; float rotY = distrib(generator) * 2 * 3.14; @@ -134,22 +134,21 @@ static void GenNewFractal() { float shearZX = distrib(generator) * 0.2f - 0.1f; float shearZY = distrib(generator) * 0.2f - 0.1f; - float translateX = distrib(generator) * 2.0f - 1.0f; - float translateY = distrib(generator) * 2.0f - 1.0f; - float translateZ = distrib(generator) * 2.0f - 1.0f; + float translateX = distrib(generator) * 1.2f - 0.6f; + float translateY = distrib(generator) * 1.2f - 0.6f; + float translateZ = distrib(generator) * 1.2f - 0.6f; auto scale = glm::scale(glm::mat4(1), {scaleX, scaleY, scaleZ}); auto rotateX = glm::rotate(scale, rotX, {1, 0, 0}); auto rotateY = glm::rotate(rotateX, rotY, {0, 1, 0}); auto rotateZ = glm::rotate(rotateY, rotZ, {0, 0, 1}); auto shear = glm::shear(rotateZ, {0, 0, 0}, {shearXY, shearXZ}, {shearYX, shearYZ}, {shearZX, shearZY}); - auto translate = glm::translate(shear, {translateX, translateY, translateZ}); + auto translate = glm::translate(rotateZ, {translateX, translateY, translateZ}); transformations[i] = translate; } - glUseProgram(s_ComputeShader); - glUniformMatrix4fv(1, transformations.size(), false, glm::value_ptr(transformations[0])); + ApplyTransforms(transformations); } static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { -- 2.49.1 From 10b0b54e7147edb53aecdbcff58ce9df928ac42a Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 14:00:55 +0100 Subject: [PATCH 15/21] 3d projection --- Shaders/Vertex.glsl | 5 ++++- src/Main.cpp | 14 +++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Shaders/Vertex.glsl b/Shaders/Vertex.glsl index 56fdf50..165d3f2 100644 --- a/Shaders/Vertex.glsl +++ b/Shaders/Vertex.glsl @@ -5,11 +5,14 @@ layout(std430, binding = 3) buffer layoutName float data_SSBO[]; }; +layout(location = 0) uniform mat4 viewMatrix; +layout(location = 1) uniform mat4 projectionMatrix; + vec3 unpack(uint index) { return vec3(data_SSBO[index * 3], data_SSBO[index * 3 + 1], data_SSBO[index * 3 + 2]); } void main() { - gl_Position = vec4(unpack(gl_InstanceID), 1.0); + gl_Position = projectionMatrix * viewMatrix * vec4(unpack(gl_InstanceID), 1.0); } \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp index cb91d06..a78fdcf 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -10,7 +10,7 @@ #include constexpr int WORK_GROUP_SIZE = 64; -constexpr int PARTICLE_COUNT = WORK_GROUP_SIZE * 10000; +constexpr int PARTICLE_COUNT = WORK_GROUP_SIZE * 15625; constexpr int SWAP_INTERVAL = 1; @@ -106,7 +106,7 @@ static void ErrorCallback(int error, const char* description) { static void ApplyTransforms(const std::vector& transformations) { glUseProgram(s_ComputeShader); - glUniformMatrix4fv(1, transformations.size(), true, glm::value_ptr(transformations[0])); + glUniformMatrix4fv(1, transformations.size(), false, glm::value_ptr(transformations[0])); } static void GenNewFractal() { @@ -233,6 +233,13 @@ static GLFWwindow* InitWindow() { return nullptr; } + auto viewMatrix = glm::lookAt(glm::vec3{1, 2, 2}, {0, 0, 0}, {0, 1, 0}); + auto projectionMatrix = glm::perspective(70.0f, 2.0f, 0.01f, 10.0f); + + glUseProgram(s_GraphicsShader); + glUniformMatrix4fv(0, 1, false, glm::value_ptr(viewMatrix)); + glUniformMatrix4fv(1, 1, false, glm::value_ptr(projectionMatrix)); + return window; } @@ -252,7 +259,8 @@ int main() { glBindVertexArray(vertexArray); - ApplyTransforms(SIERPINSKI_TRIANGLE); + // ApplyTransforms(SIERPINSKI_TRIANGLE); + GenNewFractal(); while (!glfwWindowShouldClose(window)) { // ScopedTimer timer("Main Loop"); -- 2.49.1 From abb33b6f1f3abb64f546d1a338c92264cda9fb8a Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 14:06:00 +0100 Subject: [PATCH 16/21] gen random device once --- src/Main.cpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index a78fdcf..26c18b5 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -100,6 +100,10 @@ static const std::filesystem::path s_ComputeShaderPath = "Shaders/Compute.glsl"; static const std::filesystem::path s_VertexShaderPath = "Shaders/Vertex.glsl"; static const std::filesystem::path s_FragmentShaderPath = "Shaders/Fragment.glsl"; +static std::random_device s_RandomDevice; +static std::mt19937 s_Generator(s_RandomDevice()); +static std::uniform_real_distribution s_Distrib(0, 1); + static void ErrorCallback(int error, const char* description) { std::cerr << "Error: " << description << std::endl; } @@ -110,33 +114,29 @@ static void ApplyTransforms(const std::vector& transformations) { } static void GenNewFractal() { - std::random_device randomDevice; - std::mt19937 generator(randomDevice()); - std::uniform_real_distribution distrib(0, 1); - // scale, rotation, shear, translation std::vector transformations(TRANSFORMATION_COUNT); for (std::size_t i = 0; i < transformations.size(); i++) { - float scaleX = distrib(generator) * 0.4 + 0.4; - float scaleY = distrib(generator) * 0.4 + 0.4; - float scaleZ = distrib(generator) * 0.4 + 0.4; + float scaleX = s_Distrib(s_Generator) * 0.4 + 0.4; + float scaleY = s_Distrib(s_Generator) * 0.4 + 0.4; + float scaleZ = s_Distrib(s_Generator) * 0.4 + 0.4; - float rotX = distrib(generator) * 2 * 3.14; - float rotY = distrib(generator) * 2 * 3.14; - float rotZ = distrib(generator) * 2 * 3.14; + float rotX = s_Distrib(s_Generator) * 2 * 3.14; + float rotY = s_Distrib(s_Generator) * 2 * 3.14; + float rotZ = s_Distrib(s_Generator) * 2 * 3.14; - float shearXY = distrib(generator) * 0.2f - 0.1f; - float shearXZ = distrib(generator) * 0.2f - 0.1f; - float shearYX = distrib(generator) * 0.2f - 0.1f; - float shearYZ = distrib(generator) * 0.2f - 0.1f; - float shearZX = distrib(generator) * 0.2f - 0.1f; - float shearZY = distrib(generator) * 0.2f - 0.1f; + float shearXY = s_Distrib(s_Generator) * 0.2f - 0.1f; + float shearXZ = s_Distrib(s_Generator) * 0.2f - 0.1f; + float shearYX = s_Distrib(s_Generator) * 0.2f - 0.1f; + float shearYZ = s_Distrib(s_Generator) * 0.2f - 0.1f; + float shearZX = s_Distrib(s_Generator) * 0.2f - 0.1f; + float shearZY = s_Distrib(s_Generator) * 0.2f - 0.1f; - float translateX = distrib(generator) * 1.2f - 0.6f; - float translateY = distrib(generator) * 1.2f - 0.6f; - float translateZ = distrib(generator) * 1.2f - 0.6f; + float translateX = s_Distrib(s_Generator) * 1.2f - 0.6f; + float translateY = s_Distrib(s_Generator) * 1.2f - 0.6f; + float translateZ = s_Distrib(s_Generator) * 1.2f - 0.6f; auto scale = glm::scale(glm::mat4(1), {scaleX, scaleY, scaleZ}); auto rotateX = glm::rotate(scale, rotX, {1, 0, 0}); -- 2.49.1 From da536b8d7d6a8087811c5991532364cce6bd6969 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 14:20:53 +0100 Subject: [PATCH 17/21] update clear color --- src/Main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Main.cpp b/src/Main.cpp index 26c18b5..1d22e3f 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -262,6 +262,8 @@ int main() { // ApplyTransforms(SIERPINSKI_TRIANGLE); GenNewFractal(); + glClearColor(0.4f, 0.4f, 0.4f, 1.0f); + while (!glfwWindowShouldClose(window)) { // ScopedTimer timer("Main Loop"); @@ -296,7 +298,6 @@ int main() { glfwPollEvents(); glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0, 0, 0, 1); int width, height; glfwGetWindowSize(window, &width, &height); -- 2.49.1 From 9e6088f9bfca9468b508f62b2a8ae78cde538ea5 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 14:21:13 +0100 Subject: [PATCH 18/21] refactor Transform --- Shaders/Fragment.glsl | 2 +- src/Main.cpp | 72 +++++++++++++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/Shaders/Fragment.glsl b/Shaders/Fragment.glsl index 835cf1d..bc89c18 100644 --- a/Shaders/Fragment.glsl +++ b/Shaders/Fragment.glsl @@ -4,5 +4,5 @@ layout (location = 0) out vec4 o_Color; void main() { - o_Color = vec4(1, 1, 1, 1); + o_Color = vec4(1, 1, 1, 1); } \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp index 1d22e3f..7a89d8f 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -113,39 +113,65 @@ static void ApplyTransforms(const std::vector& transformations) { glUniformMatrix4fv(1, transformations.size(), false, glm::value_ptr(transformations[0])); } +struct Transform { + float m_ScaleX; + float m_ScaleY; + float m_ScaleZ; + + float m_RotationX; + float m_RotationY; + float m_RotationZ; + + float m_ShearXY; + float m_ShearXZ; + float m_ShearYX; + float m_ShearYZ; + float m_ShearZX; + float m_ShearZY; + + float m_TranslateX; + float m_TranslateY; + float m_TranslateZ; + + glm::mat4 ToMatrix() { + auto scale = glm::scale(glm::mat4(1), {m_ScaleX, m_ScaleY, m_ScaleZ}); + auto rotateX = glm::rotate(scale, m_RotationX, {1, 0, 0}); + auto rotateY = glm::rotate(rotateX, m_RotationY, {0, 1, 0}); + auto rotateZ = glm::rotate(rotateY, m_RotationZ, {0, 0, 1}); + auto shear = glm::shear(rotateZ, {0, 0, 0}, {m_ShearXY, m_ShearXZ}, {m_ShearYX, m_ShearYZ}, {m_ShearZX, m_ShearZY}); + auto translate = glm::translate(rotateZ, {m_TranslateX, m_TranslateY, m_TranslateZ}); + + return translate; + } +}; + static void GenNewFractal() { // scale, rotation, shear, translation std::vector transformations(TRANSFORMATION_COUNT); for (std::size_t i = 0; i < transformations.size(); i++) { - float scaleX = s_Distrib(s_Generator) * 0.4 + 0.4; - float scaleY = s_Distrib(s_Generator) * 0.4 + 0.4; - float scaleZ = s_Distrib(s_Generator) * 0.4 + 0.4; + Transform transform; + transform.m_ScaleX = s_Distrib(s_Generator) * 0.4 + 0.4; + transform.m_ScaleY = s_Distrib(s_Generator) * 0.4 + 0.4; + transform.m_ScaleZ = s_Distrib(s_Generator) * 0.4 + 0.4; - float rotX = s_Distrib(s_Generator) * 2 * 3.14; - float rotY = s_Distrib(s_Generator) * 2 * 3.14; - float rotZ = s_Distrib(s_Generator) * 2 * 3.14; + transform.m_RotationX = s_Distrib(s_Generator) * 2 * 3.14; + transform.m_RotationY = s_Distrib(s_Generator) * 2 * 3.14; + transform.m_RotationZ = s_Distrib(s_Generator) * 2 * 3.14; - float shearXY = s_Distrib(s_Generator) * 0.2f - 0.1f; - float shearXZ = s_Distrib(s_Generator) * 0.2f - 0.1f; - float shearYX = s_Distrib(s_Generator) * 0.2f - 0.1f; - float shearYZ = s_Distrib(s_Generator) * 0.2f - 0.1f; - float shearZX = s_Distrib(s_Generator) * 0.2f - 0.1f; - float shearZY = s_Distrib(s_Generator) * 0.2f - 0.1f; + transform.m_ShearXY = s_Distrib(s_Generator) * 0.2f - 0.1f; + transform.m_ShearXZ = s_Distrib(s_Generator) * 0.2f - 0.1f; + transform.m_ShearYX = s_Distrib(s_Generator) * 0.2f - 0.1f; + transform.m_ShearYZ = s_Distrib(s_Generator) * 0.2f - 0.1f; + transform.m_ShearZX = s_Distrib(s_Generator) * 0.2f - 0.1f; + transform.m_ShearZY = s_Distrib(s_Generator) * 0.2f - 0.1f; - float translateX = s_Distrib(s_Generator) * 1.2f - 0.6f; - float translateY = s_Distrib(s_Generator) * 1.2f - 0.6f; - float translateZ = s_Distrib(s_Generator) * 1.2f - 0.6f; + transform.m_TranslateX = s_Distrib(s_Generator) * 1.2f - 0.6f; + transform.m_TranslateY = s_Distrib(s_Generator) * 1.2f - 0.6f; + transform.m_TranslateZ = s_Distrib(s_Generator) * 1.2f - 0.6f; - auto scale = glm::scale(glm::mat4(1), {scaleX, scaleY, scaleZ}); - auto rotateX = glm::rotate(scale, rotX, {1, 0, 0}); - auto rotateY = glm::rotate(rotateX, rotY, {0, 1, 0}); - auto rotateZ = glm::rotate(rotateY, rotZ, {0, 0, 1}); - auto shear = glm::shear(rotateZ, {0, 0, 0}, {shearXY, shearXZ}, {shearYX, shearYZ}, {shearZX, shearZY}); - auto translate = glm::translate(rotateZ, {translateX, translateY, translateZ}); - - transformations[i] = translate; + transformations[i] = transform.ToMatrix(); } ApplyTransforms(transformations); -- 2.49.1 From e940b670d2ca03eecc7436a08aaabb8dc28d1dcb Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 15:20:13 +0100 Subject: [PATCH 19/21] fix xmake.lua --- xmake.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xmake.lua b/xmake.lua index 68c23e1..8d4ba97 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,3 +1,5 @@ +add_rules("mode.debug", "mode.release") + add_requires("glfw", "glad", "glm", "stb") target("App") -- 2.49.1 From ee93146167c450d7b3d2ff37db7ccf4217ee45ad Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 15:20:36 +0100 Subject: [PATCH 20/21] very cool animation --- src/Main.cpp | 132 ++++++++++++++++++++++++++------------------------- 1 file changed, 68 insertions(+), 64 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index 7a89d8f..960b7d0 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -16,62 +16,8 @@ constexpr int SWAP_INTERVAL = 1; constexpr int TRANSFORMATION_COUNT = 3; -static const std::vector SIERPINSKI_TRIANGLE = { - { - 0.5f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 0.5f, - 0.0f, - 0.36f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - 0.5f, - 0.0f, - 0.0f, - -0.5f, - 0.0f, - 0.5f, - 0.0f, - -0.5f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - 0.5f, - 0.0f, - 0.0f, - 0.5f, - 0.0f, - 0.5f, - 0.0f, - -0.5f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, -}; +constexpr float ANIMATION_TIME = 2; +constexpr float ANIMATION_STILL_TIME = 1; class Timer { public: @@ -143,14 +89,36 @@ struct Transform { return translate; } + + Transform Blend(const Transform& other, const std::function& a_Lerp, float dt) { + return { + a_Lerp(m_ScaleX, other.m_ScaleX, dt), + a_Lerp(m_ScaleY, other.m_ScaleY, dt), + a_Lerp(m_ScaleZ, other.m_ScaleZ, dt), + a_Lerp(m_RotationX, other.m_RotationX, dt), + a_Lerp(m_RotationY, other.m_RotationY, dt), + a_Lerp(m_RotationZ, other.m_RotationZ, dt), + a_Lerp(m_ShearXY, other.m_ShearXY, dt), + a_Lerp(m_ShearXZ, other.m_ShearXZ, dt), + a_Lerp(m_ShearYX, other.m_ShearYX, dt), + a_Lerp(m_ShearYZ, other.m_ShearYZ, dt), + a_Lerp(m_ShearZX, other.m_ShearZX, dt), + a_Lerp(m_ShearZY, other.m_ShearZY, dt), + a_Lerp(m_TranslateX, other.m_TranslateX, dt), + a_Lerp(m_TranslateY, other.m_TranslateY, dt), + a_Lerp(m_TranslateZ, other.m_TranslateZ, dt), + }; + } }; -static void GenNewFractal() { +static std::vector s_T1, s_T2; + +static std::vector GenRandomFractal() { // scale, rotation, shear, translation - std::vector transformations(TRANSFORMATION_COUNT); + std::vector transforms(TRANSFORMATION_COUNT); - for (std::size_t i = 0; i < transformations.size(); i++) { + for (std::size_t i = 0; i < transforms.size(); i++) { Transform transform; transform.m_ScaleX = s_Distrib(s_Generator) * 0.4 + 0.4; transform.m_ScaleY = s_Distrib(s_Generator) * 0.4 + 0.4; @@ -171,10 +139,15 @@ static void GenNewFractal() { transform.m_TranslateY = s_Distrib(s_Generator) * 1.2f - 0.6f; transform.m_TranslateZ = s_Distrib(s_Generator) * 1.2f - 0.6f; - transformations[i] = transform.ToMatrix(); + transforms[i] = transform; } - ApplyTransforms(transformations); + return transforms; +} + +static void GenNewFractal() { + std::swap(s_T1, s_T2); + s_T2 = GenRandomFractal(); } static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { @@ -188,7 +161,7 @@ static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, i s_ComputeShader = ReloadComputeShader(s_ComputeShader, s_ComputeShaderPath); s_GraphicsShader = ReloadGraphicsShader(s_GraphicsShader, s_VertexShaderPath, s_FragmentShaderPath); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * PARTICLE_COUNT * 3, nullptr, GL_DYNAMIC_COPY); - ApplyTransforms(SIERPINSKI_TRIANGLE); + GenNewFractal(); } if (key == GLFW_KEY_T) { @@ -223,6 +196,27 @@ static void CreateGpuBuffer() { GL_DYNAMIC_COPY); // sizeof(data) only works for statically sized C/C++ arrays. } +static std::vector GetTransformMatrixBlended(float dt) { + std::vector result(TRANSFORMATION_COUNT); + + constexpr auto lerp = [](float x, float y, float t){ + return x * (1 - t) + y * t; + }; + + constexpr auto eased = [lerp](float x, float y, float t){ + return lerp(x, y, -(std::cos(3.14 * t) - 1.0f) / 2.0f); + }; + + float blendFactor = std::min(ANIMATION_TIME, dt) / ANIMATION_TIME; + + for (std::size_t i = 0; i < result.size(); i++) { + auto blended = s_T1[i].Blend(s_T2[i], eased, blendFactor); + result[i] = blended.ToMatrix(); + } + + return result; +} + static GLFWwindow* InitWindow() { glfwSetErrorCallback(ErrorCallback); @@ -282,11 +276,13 @@ int main() { int fps = 0; float secondsTimer = 0.0f; + float animationTimer = 0.0f; glBindVertexArray(vertexArray); // ApplyTransforms(SIERPINSKI_TRIANGLE); - GenNewFractal(); + s_T1 = GenRandomFractal(); + s_T2 = GenRandomFractal(); glClearColor(0.4f, 0.4f, 0.4f, 1.0f); @@ -298,18 +294,26 @@ int main() { lastTime = currentTime; secondsTimer += dt; + animationTimer += dt; if (secondsTimer >= 1.0f) { std::string title = "FPS : " + std::to_string(fps); glfwSetWindowTitle(window, title.c_str()); secondsTimer = 0.0f; fps = 0; - + } + + if (animationTimer >= ANIMATION_TIME + ANIMATION_STILL_TIME) { + animationTimer = 0; GenNewFractal(); } // Compute glUseProgram(s_ComputeShader); + + auto matricies = GetTransformMatrixBlended(animationTimer); + glUniformMatrix4fv(1, matricies.size(), false, glm::value_ptr(matricies[0])); + glDispatchCompute(PARTICLE_COUNT / WORK_GROUP_SIZE, 1, 1); // Ensure all writes to the image are complete -- 2.49.1 From a46abca7074e3e6f388a7b745e994a5be7cae760 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Sun, 9 Nov 2025 15:27:23 +0100 Subject: [PATCH 21/21] format ... --- src/Main.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index 960b7d0..4b90fbd 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -199,13 +199,9 @@ static void CreateGpuBuffer() { static std::vector GetTransformMatrixBlended(float dt) { std::vector result(TRANSFORMATION_COUNT); - constexpr auto lerp = [](float x, float y, float t){ - return x * (1 - t) + y * t; - }; + constexpr auto lerp = [](float x, float y, float t) { return x * (1 - t) + y * t; }; - constexpr auto eased = [lerp](float x, float y, float t){ - return lerp(x, y, -(std::cos(3.14 * t) - 1.0f) / 2.0f); - }; + constexpr auto eased = [lerp](float x, float y, float t) { return lerp(x, y, -(std::cos(3.14 * t) - 1.0f) / 2.0f); }; float blendFactor = std::min(ANIMATION_TIME, dt) / ANIMATION_TIME; @@ -302,7 +298,7 @@ int main() { secondsTimer = 0.0f; fps = 0; } - + if (animationTimer >= ANIMATION_TIME + ANIMATION_STILL_TIME) { animationTimer = 0; GenNewFractal(); -- 2.49.1