From 1d3190ac245121c1470ab81dff5bea3db490f26d Mon Sep 17 00:00:00 2001 From: SirLynix Date: Fri, 21 Jul 2023 18:30:47 +0200 Subject: [PATCH] ComputeParticlesTest: Improve test to actually use Nazara logo --- .../compute/compute_particle_texture.nzsl | 2 +- assets/shaders/compute/compute_particles.nzsl | 18 ++++- tests/ComputeParticlesTest/main.cpp | 81 ++++++++++++++----- 3 files changed, 76 insertions(+), 25 deletions(-) diff --git a/assets/shaders/compute/compute_particle_texture.nzsl b/assets/shaders/compute/compute_particle_texture.nzsl index fc9b97410..844e8b438 100644 --- a/assets/shaders/compute/compute_particle_texture.nzsl +++ b/assets/shaders/compute/compute_particle_texture.nzsl @@ -22,7 +22,7 @@ fn main(input: Input) let outputColor = vec4[f32] ( - (pow(1.0 - length(uv), 10.0)).xxx, + (pow(1.0 - length(uv), 14.0)).xxx, 1.0 ); diff --git a/assets/shaders/compute/compute_particles.nzsl b/assets/shaders/compute/compute_particles.nzsl index 769f02f4b..cce7f2009 100644 --- a/assets/shaders/compute/compute_particles.nzsl +++ b/assets/shaders/compute/compute_particles.nzsl @@ -6,6 +6,7 @@ struct Particle { color: vec3[f32], position: vec2[f32], + targetPosition: vec2[f32], velocity: vec2[f32] } @@ -20,7 +21,8 @@ struct ParticleData struct SceneData { deltaTime: f32, - mousePos: vec2[f32] + mousePos: vec2[f32], + effectRadius: f32 } external @@ -42,12 +44,20 @@ fn main(input: Input) if (index >= data.particle_count) return; - let damping = pow(0.5, sceneData.deltaTime); - + // Gets pushed by the cursor let attract_pos = sceneData.mousePos; let dist = length(attract_pos - data.particles[index].position); - data.particles[index].velocity += 10000.0 * (attract_pos - data.particles[index].position) * sceneData.deltaTime / (dist * dist); + data.particles[index].velocity -= 10000.0 * sceneData.effectRadius / min(dist, sceneData.effectRadius) * sceneData.deltaTime * (attract_pos - data.particles[index].position) / (dist * dist * dist * dist); + + // But want to return to their original position + let dist = length(data.particles[index].targetPosition - data.particles[index].position); + let shouldUseDir = dist < 1.0; + data.particles[index].velocity += 100.0 * sceneData.deltaTime * select(shouldUseDir, normalize(data.particles[index].targetPosition - data.particles[index].position), vec2[f32](0.0, 0.0)); + + // Lose speed with time + let damping = pow(0.5, sceneData.deltaTime); data.particles[index].velocity *= damping; + // Move particle data.particles[index].position += data.particles[index].velocity * sceneData.deltaTime; } diff --git a/tests/ComputeParticlesTest/main.cpp b/tests/ComputeParticlesTest/main.cpp index 12456c10e..37bf38e43 100644 --- a/tests/ComputeParticlesTest/main.cpp +++ b/tests/ComputeParticlesTest/main.cpp @@ -60,36 +60,77 @@ int main() nzsl::FieldOffsets particleLayout(nzsl::StructLayout::Std140); std::size_t particleColorOffset = particleLayout.AddField(nzsl::StructFieldType::Float3); std::size_t particlePosOffset = particleLayout.AddField(nzsl::StructFieldType::Float2); + std::size_t particleTargetPosOffset = particleLayout.AddField(nzsl::StructFieldType::Float2); std::size_t particleVelOffset = particleLayout.AddField(nzsl::StructFieldType::Float2); std::size_t particleSize = particleLayout.GetAlignedSize(); - constexpr std::size_t maxParticleCount = 10'000; - constexpr std::size_t initialParticleCount = maxParticleCount; + std::shared_ptr logo = Nz::Image::LoadFromFile(resourceDir / "Logo.png"); + if (!logo) + { + std::cerr << "failed to load logo" << std::endl; + return EXIT_FAILURE; + } + + std::vector> logoParticles; + for (unsigned int y = 0; y < logo->GetHeight(); ++y) + { + for (unsigned int x = 0; x < logo->GetWidth(); ++x) + { + Nz::Color color = logo->GetPixelColor(x, y); + if (color.a == 0) + continue; + + logoParticles.push_back({ + { x, y }, + color + }); + } + } + + std::size_t particleCount = logoParticles.size(); nzsl::FieldOffsets bufferLayout(nzsl::StructLayout::Std140); std::size_t particleCountOffset = bufferLayout.AddField(nzsl::StructFieldType::UInt1); - std::size_t particlesOffset = bufferLayout.AddStructArray(particleLayout, maxParticleCount); + std::size_t particlesOffset = bufferLayout.AddStructArray(particleLayout, particleCount); std::size_t bufferSize = bufferLayout.GetAlignedSize(); std::vector particleBufferInitialData(bufferSize); - Nz::AccessByOffset(particleBufferInitialData.data(), particleCountOffset) = initialParticleCount; + Nz::AccessByOffset(particleBufferInitialData.data(), particleCountOffset) = particleCount; std::mt19937 rand(std::random_device{}()); std::uniform_real_distribution colorDis(0.f, 1.f); - std::uniform_real_distribution posXDis(0.f, float(windowSize.x)); - std::uniform_real_distribution posYDis(0.f, float(windowSize.y)); - std::uniform_real_distribution velDis(-20.f, 20.f); + std::uniform_real_distribution posXDis(-float(windowSize.x), windowSize.x * 2.f); + std::uniform_real_distribution posYDis(-float(windowSize.y), windowSize.y * 2.f); + std::uniform_real_distribution velDis(-50.f, 50.f); - for (std::size_t i = 0; i < initialParticleCount; ++i) + Nz::Vector2f logoImageSize(Nz::Vector2ui(logo->GetSize())); + Nz::Vector2f logoSize = Nz::Vector2f(windowSize) * 0.8f; + + // Center the logo in the canvas + Nz::Vector2f posScale = logoSize / logoImageSize; + + Nz::Vector2f posOffset = (Nz::Vector2f(windowSize) - logoSize) * 0.5f; + + // from image space to world space (topleft Y down to bottomleft Y up) + posScale.y *= -1.f; + posOffset.y += logoSize.y; + + // Build particles + Nz::UInt8* particleBasePtr = particleBufferInitialData.data() + particlesOffset; + Nz::SparsePtr particlePosPtr(particleBasePtr + particlePosOffset, particleSize); + Nz::SparsePtr particleTargetPosPtr(particleBasePtr + particleTargetPosOffset, particleSize); + Nz::SparsePtr particleColorPtr(particleBasePtr + particleColorOffset, particleSize); + Nz::SparsePtr particleVelPtr(particleBasePtr + particleVelOffset, particleSize); + for (std::size_t i = 0; i < particleCount; ++i) { - std::size_t baseOffset = particlesOffset + particleSize * i; + auto&& [pos, color] = logoParticles[i]; - Nz::AccessByOffset(particleBufferInitialData.data(), baseOffset + particleColorOffset) = Nz::Vector3f(colorDis(rand), colorDis(rand), colorDis(rand)); - //Nz::AccessByOffset(particleBufferInitialData.data(), baseOffset + particleColorOffset) = (i > 2500) ? Nz::Vector3f(0.f, 1.f, 0.f) : Nz::Vector3f(0.f, 0.f, 1.f); - Nz::AccessByOffset(particleBufferInitialData.data(), baseOffset + particlePosOffset) = Nz::Vector2f(posXDis(rand), posYDis(rand)); - Nz::AccessByOffset(particleBufferInitialData.data(), baseOffset + particleVelOffset) = Nz::Vector2f(velDis(rand), velDis(rand)); + particlePosPtr[i] = Nz::Vector2f(posXDis(rand), posYDis(rand)); + particleTargetPosPtr[i] = posScale * Nz::Vector2f(pos) + posOffset; + particleColorPtr[i] = Nz::Vector3f(color.r, color.g, color.b) * color.a; + particleVelPtr[i] = Nz::Vector2f(velDis(rand), velDis(rand)); } std::shared_ptr particleBuffer = device->InstantiateBuffer(Nz::BufferType::Storage, bufferSize, Nz::BufferUsage::DeviceLocal, particleBufferInitialData.data()); @@ -97,6 +138,7 @@ int main() nzsl::FieldOffsets sceneBufferLayout(nzsl::StructLayout::Std140); std::size_t deltaTimeOffset = sceneBufferLayout.AddField(nzsl::StructFieldType::Float1); std::size_t mousePosOffset = sceneBufferLayout.AddField(nzsl::StructFieldType::Float2); + std::size_t effectRadiusOffset = sceneBufferLayout.AddField(nzsl::StructFieldType::Float1); std::size_t sceneBufferSize = sceneBufferLayout.GetAlignedSize(); @@ -157,18 +199,15 @@ int main() hasNewPipeline = true; }); - std::string windowTitle = "Compute test"; + std::string windowTitle = "Particle test (" + std::to_string(particleCount) + " particles)"; Nz::Window window; - if (!window.Create(Nz::VideoMode(1280, 720), windowTitle)) + if (!window.Create(Nz::VideoMode(windowSize.x, windowSize.y), windowTitle)) { std::cout << "Failed to create Window" << std::endl; std::abort(); } Nz::WindowSwapchain windowSwapchain(device, window); - constexpr float textureSize = 512.f; - float margin = (windowSize.y - textureSize) * 0.5f; - nzsl::FieldOffsets viewerLayout(nzsl::StructLayout::Std140); std::size_t projectionMatrixOffset = viewerLayout.AddMatrix(nzsl::StructFieldType::Float1, 4, 4, true); @@ -228,6 +267,7 @@ int main() auto& allocation = uploadPool.Allocate(sceneBufferSize); Nz::AccessByOffset(allocation.mappedPtr, deltaTimeOffset) = deltaTime; Nz::AccessByOffset(allocation.mappedPtr, mousePosOffset) = Nz::Vector2f(mousePos.x, windowSize.y - mousePos.y); + Nz::AccessByOffset(allocation.mappedPtr, effectRadiusOffset) = (Nz::Mouse::IsButtonPressed(Nz::Mouse::Button::Left)) ? 10000.f : 100.f; builder.PreTransferBarrier(); builder.CopyBuffer(allocation, sceneDataBuffer.get()); @@ -239,7 +279,7 @@ int main() { builder.BindComputePipeline(*computePipeline); builder.BindComputeShaderBinding(0, *computeBinding); - builder.Dispatch(maxParticleCount / 64 + 1, 1, 1); + builder.Dispatch(particleCount / 64 + 1, 1, 1); } builder.EndDebugRegion(); @@ -261,7 +301,7 @@ int main() builder.BindVertexBuffer(0, *spriteRenderData1.vertexBuffer); builder.BindRenderShaderBinding(0, *spriteRenderData1.shaderBinding); - builder.Draw(4, initialParticleCount); + builder.Draw(4, particleCount); } builder.EndRenderPass(); } @@ -325,6 +365,7 @@ struct Particle { color: vec3[f32], position: vec2[f32], + target_position: vec2[f32], velocity: vec2[f32] }