ComputeParticlesTest: Improve test to actually use Nazara logo

This commit is contained in:
SirLynix 2023-07-21 18:30:47 +02:00
parent 0c6ca52af0
commit 1d3190ac24
3 changed files with 76 additions and 25 deletions

View File

@ -22,7 +22,7 @@ fn main(input: Input)
let outputColor = vec4[f32] let outputColor = vec4[f32]
( (
(pow(1.0 - length(uv), 10.0)).xxx, (pow(1.0 - length(uv), 14.0)).xxx,
1.0 1.0
); );

View File

@ -6,6 +6,7 @@ struct Particle
{ {
color: vec3[f32], color: vec3[f32],
position: vec2[f32], position: vec2[f32],
targetPosition: vec2[f32],
velocity: vec2[f32] velocity: vec2[f32]
} }
@ -20,7 +21,8 @@ struct ParticleData
struct SceneData struct SceneData
{ {
deltaTime: f32, deltaTime: f32,
mousePos: vec2[f32] mousePos: vec2[f32],
effectRadius: f32
} }
external external
@ -42,12 +44,20 @@ fn main(input: Input)
if (index >= data.particle_count) if (index >= data.particle_count)
return; return;
let damping = pow(0.5, sceneData.deltaTime); // Gets pushed by the cursor
let attract_pos = sceneData.mousePos; let attract_pos = sceneData.mousePos;
let dist = length(attract_pos - data.particles[index].position); 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; data.particles[index].velocity *= damping;
// Move particle
data.particles[index].position += data.particles[index].velocity * sceneData.deltaTime; data.particles[index].position += data.particles[index].velocity * sceneData.deltaTime;
} }

View File

@ -60,36 +60,77 @@ int main()
nzsl::FieldOffsets particleLayout(nzsl::StructLayout::Std140); nzsl::FieldOffsets particleLayout(nzsl::StructLayout::Std140);
std::size_t particleColorOffset = particleLayout.AddField(nzsl::StructFieldType::Float3); std::size_t particleColorOffset = particleLayout.AddField(nzsl::StructFieldType::Float3);
std::size_t particlePosOffset = particleLayout.AddField(nzsl::StructFieldType::Float2); 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 particleVelOffset = particleLayout.AddField(nzsl::StructFieldType::Float2);
std::size_t particleSize = particleLayout.GetAlignedSize(); std::size_t particleSize = particleLayout.GetAlignedSize();
constexpr std::size_t maxParticleCount = 10'000; std::shared_ptr<Nz::Image> logo = Nz::Image::LoadFromFile(resourceDir / "Logo.png");
constexpr std::size_t initialParticleCount = maxParticleCount; if (!logo)
{
std::cerr << "failed to load logo" << std::endl;
return EXIT_FAILURE;
}
std::vector<std::pair<Nz::Vector2ui, Nz::Color>> 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); nzsl::FieldOffsets bufferLayout(nzsl::StructLayout::Std140);
std::size_t particleCountOffset = bufferLayout.AddField(nzsl::StructFieldType::UInt1); 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::size_t bufferSize = bufferLayout.GetAlignedSize();
std::vector<Nz::UInt8> particleBufferInitialData(bufferSize); std::vector<Nz::UInt8> particleBufferInitialData(bufferSize);
Nz::AccessByOffset<Nz::UInt32&>(particleBufferInitialData.data(), particleCountOffset) = initialParticleCount; Nz::AccessByOffset<Nz::UInt32&>(particleBufferInitialData.data(), particleCountOffset) = particleCount;
std::mt19937 rand(std::random_device{}()); std::mt19937 rand(std::random_device{}());
std::uniform_real_distribution<float> colorDis(0.f, 1.f); std::uniform_real_distribution<float> colorDis(0.f, 1.f);
std::uniform_real_distribution<float> posXDis(0.f, float(windowSize.x)); std::uniform_real_distribution<float> posXDis(-float(windowSize.x), windowSize.x * 2.f);
std::uniform_real_distribution<float> posYDis(0.f, float(windowSize.y)); std::uniform_real_distribution<float> posYDis(-float(windowSize.y), windowSize.y * 2.f);
std::uniform_real_distribution<float> velDis(-20.f, 20.f); std::uniform_real_distribution<float> 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<Nz::Vector2f> particlePosPtr(particleBasePtr + particlePosOffset, particleSize);
Nz::SparsePtr<Nz::Vector2f> particleTargetPosPtr(particleBasePtr + particleTargetPosOffset, particleSize);
Nz::SparsePtr<Nz::Vector3f> particleColorPtr(particleBasePtr + particleColorOffset, particleSize);
Nz::SparsePtr<Nz::Vector2f> 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<Nz::Vector3f&>(particleBufferInitialData.data(), baseOffset + particleColorOffset) = Nz::Vector3f(colorDis(rand), colorDis(rand), colorDis(rand)); particlePosPtr[i] = Nz::Vector2f(posXDis(rand), posYDis(rand));
//Nz::AccessByOffset<Nz::Vector3f&>(particleBufferInitialData.data(), baseOffset + particleColorOffset) = (i > 2500) ? Nz::Vector3f(0.f, 1.f, 0.f) : Nz::Vector3f(0.f, 0.f, 1.f); particleTargetPosPtr[i] = posScale * Nz::Vector2f(pos) + posOffset;
Nz::AccessByOffset<Nz::Vector2f&>(particleBufferInitialData.data(), baseOffset + particlePosOffset) = Nz::Vector2f(posXDis(rand), posYDis(rand)); particleColorPtr[i] = Nz::Vector3f(color.r, color.g, color.b) * color.a;
Nz::AccessByOffset<Nz::Vector2f&>(particleBufferInitialData.data(), baseOffset + particleVelOffset) = Nz::Vector2f(velDis(rand), velDis(rand)); particleVelPtr[i] = Nz::Vector2f(velDis(rand), velDis(rand));
} }
std::shared_ptr<Nz::RenderBuffer> particleBuffer = device->InstantiateBuffer(Nz::BufferType::Storage, bufferSize, Nz::BufferUsage::DeviceLocal, particleBufferInitialData.data()); std::shared_ptr<Nz::RenderBuffer> particleBuffer = device->InstantiateBuffer(Nz::BufferType::Storage, bufferSize, Nz::BufferUsage::DeviceLocal, particleBufferInitialData.data());
@ -97,6 +138,7 @@ int main()
nzsl::FieldOffsets sceneBufferLayout(nzsl::StructLayout::Std140); nzsl::FieldOffsets sceneBufferLayout(nzsl::StructLayout::Std140);
std::size_t deltaTimeOffset = sceneBufferLayout.AddField(nzsl::StructFieldType::Float1); std::size_t deltaTimeOffset = sceneBufferLayout.AddField(nzsl::StructFieldType::Float1);
std::size_t mousePosOffset = sceneBufferLayout.AddField(nzsl::StructFieldType::Float2); std::size_t mousePosOffset = sceneBufferLayout.AddField(nzsl::StructFieldType::Float2);
std::size_t effectRadiusOffset = sceneBufferLayout.AddField(nzsl::StructFieldType::Float1);
std::size_t sceneBufferSize = sceneBufferLayout.GetAlignedSize(); std::size_t sceneBufferSize = sceneBufferLayout.GetAlignedSize();
@ -157,18 +199,15 @@ int main()
hasNewPipeline = true; hasNewPipeline = true;
}); });
std::string windowTitle = "Compute test"; std::string windowTitle = "Particle test (" + std::to_string(particleCount) + " particles)";
Nz::Window window; 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::cout << "Failed to create Window" << std::endl;
std::abort(); std::abort();
} }
Nz::WindowSwapchain windowSwapchain(device, window); Nz::WindowSwapchain windowSwapchain(device, window);
constexpr float textureSize = 512.f;
float margin = (windowSize.y - textureSize) * 0.5f;
nzsl::FieldOffsets viewerLayout(nzsl::StructLayout::Std140); nzsl::FieldOffsets viewerLayout(nzsl::StructLayout::Std140);
std::size_t projectionMatrixOffset = viewerLayout.AddMatrix(nzsl::StructFieldType::Float1, 4, 4, true); std::size_t projectionMatrixOffset = viewerLayout.AddMatrix(nzsl::StructFieldType::Float1, 4, 4, true);
@ -228,6 +267,7 @@ int main()
auto& allocation = uploadPool.Allocate(sceneBufferSize); auto& allocation = uploadPool.Allocate(sceneBufferSize);
Nz::AccessByOffset<float&>(allocation.mappedPtr, deltaTimeOffset) = deltaTime; Nz::AccessByOffset<float&>(allocation.mappedPtr, deltaTimeOffset) = deltaTime;
Nz::AccessByOffset<Nz::Vector2f&>(allocation.mappedPtr, mousePosOffset) = Nz::Vector2f(mousePos.x, windowSize.y - mousePos.y); Nz::AccessByOffset<Nz::Vector2f&>(allocation.mappedPtr, mousePosOffset) = Nz::Vector2f(mousePos.x, windowSize.y - mousePos.y);
Nz::AccessByOffset<float&>(allocation.mappedPtr, effectRadiusOffset) = (Nz::Mouse::IsButtonPressed(Nz::Mouse::Button::Left)) ? 10000.f : 100.f;
builder.PreTransferBarrier(); builder.PreTransferBarrier();
builder.CopyBuffer(allocation, sceneDataBuffer.get()); builder.CopyBuffer(allocation, sceneDataBuffer.get());
@ -239,7 +279,7 @@ int main()
{ {
builder.BindComputePipeline(*computePipeline); builder.BindComputePipeline(*computePipeline);
builder.BindComputeShaderBinding(0, *computeBinding); builder.BindComputeShaderBinding(0, *computeBinding);
builder.Dispatch(maxParticleCount / 64 + 1, 1, 1); builder.Dispatch(particleCount / 64 + 1, 1, 1);
} }
builder.EndDebugRegion(); builder.EndDebugRegion();
@ -261,7 +301,7 @@ int main()
builder.BindVertexBuffer(0, *spriteRenderData1.vertexBuffer); builder.BindVertexBuffer(0, *spriteRenderData1.vertexBuffer);
builder.BindRenderShaderBinding(0, *spriteRenderData1.shaderBinding); builder.BindRenderShaderBinding(0, *spriteRenderData1.shaderBinding);
builder.Draw(4, initialParticleCount); builder.Draw(4, particleCount);
} }
builder.EndRenderPass(); builder.EndRenderPass();
} }
@ -325,6 +365,7 @@ struct Particle
{ {
color: vec3[f32], color: vec3[f32],
position: vec2[f32], position: vec2[f32],
target_position: vec2[f32],
velocity: vec2[f32] velocity: vec2[f32]
} }