-
-
Notifications
You must be signed in to change notification settings - Fork 29
Falling sand
Romain Milbert edited this page Aug 28, 2023
·
5 revisions
As the time of writing (2022-11-23, commit ff435d0), the following file give the result shown in this video:
Using this code, you can perform several actions:
- Add "sand" pixels with the left mouse click;
- Add "stone" pixels (which remain in place) with the right mouse click;
- Add "dirt" pixels with the middle mouse click.
#include <RaZ/Application.hpp>
#include <RaZ/Math/Transform.hpp>
#include <RaZ/Render/Camera.hpp>
#include <RaZ/Render/RenderSystem.hpp>
constexpr int sceneWidth = 1280;
constexpr int sceneHeight = 720;
int main() {
Raz::Application app;
Raz::World& world = app.addWorld(1);
auto& render = world.addSystem<Raz::RenderSystem>(sceneWidth, sceneHeight, "RaZ");
render.getWindow().addKeyCallback(Raz::Keyboard::ESCAPE, [&app] (float) noexcept { app.quit(); });
render.getWindow().setCloseCallback([&app] () noexcept { app.quit(); });
world.addEntityWithComponent<Raz::Transform>().addComponent<Raz::Camera>(sceneWidth, sceneHeight);
Raz::Texture2DPtr texture = Raz::Texture2D::create(sceneWidth, sceneHeight, Raz::TextureColorspace::RGBA, Raz::TextureDataType::BYTE);
Raz::Renderer::bindImageTexture(0, texture->getIndex(), 0, false, 0, Raz::ImageAccess::READ_WRITE, Raz::ImageInternalFormat::RGBA8);
Raz::ComputeShaderProgram compute(Raz::ComputeShader::loadFromSource(R"(
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(rgba8, binding = 0) uniform image2D uniBuffer;
uniform bool uniMouseLeftClick = false;
uniform bool uniMouseRightClick = false;
uniform bool uniMouseMiddleClick = false;
uniform ivec2 uniMousePos;
const vec3 dirtColor = vec3(0.608, 0.463, 0.325);
const vec3 sandColor = vec3(0.761, 0.698, 0.502);
const vec3 stoneColor = vec3(0.35);
void main() {
ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy);
vec2 invImgDims = 1.0 / vec2(imageSize(uniBuffer));
vec3 currentFrag = imageLoad(uniBuffer, pixelCoords).rgb;
if (currentFrag == vec3(0.0) && uniMousePos == pixelCoords) {
if (uniMouseLeftClick) {
currentFrag = sandColor;
} else if (uniMouseRightClick) {
imageStore(uniBuffer, pixelCoords + ivec2(-1, 0), vec4(stoneColor, 1.0));
imageStore(uniBuffer, pixelCoords + ivec2(1, 0), vec4(stoneColor, 1.0));
imageStore(uniBuffer, pixelCoords + ivec2(0, -1), vec4(stoneColor, 1.0));
imageStore(uniBuffer, pixelCoords + ivec2(0, 1), vec4(stoneColor, 1.0));
imageStore(uniBuffer, pixelCoords + ivec2(-1, -1), vec4(stoneColor, 1.0));
imageStore(uniBuffer, pixelCoords + ivec2(1, 1), vec4(stoneColor, 1.0));
imageStore(uniBuffer, pixelCoords + ivec2(1, -1), vec4(stoneColor, 1.0));
imageStore(uniBuffer, pixelCoords + ivec2(-1, 1), vec4(stoneColor, 1.0));
currentFrag = stoneColor;
} else if (uniMouseMiddleClick) {
currentFrag = dirtColor;
}
imageStore(uniBuffer, pixelCoords, vec4(currentFrag, 1.0));
return;
}
if (abs(dot(currentFrag, currentFrag) - dot(stoneColor, stoneColor)) <= 0.01)
return;
ivec2 belowCoords = pixelCoords - ivec2(0, 1);
vec3 belowFrag = imageLoad(uniBuffer, belowCoords).rgb;
if (belowFrag == vec3(0.0) && belowCoords.y >= 0) {
imageStore(uniBuffer, belowCoords, vec4(currentFrag, 1.0));
currentFrag = vec3(0.0);
} else {
belowCoords = pixelCoords - ivec2(0, 5);
belowFrag = imageLoad(uniBuffer, belowCoords).rgb;
if (belowFrag != vec3(0.0) && belowCoords.y >= 5) {
if (imageLoad(uniBuffer, pixelCoords - ivec2(1, 1)).rgb == vec3(0.0)) {
imageStore(uniBuffer, pixelCoords - ivec2(1, 1), vec4(currentFrag, 1.0));
currentFrag = vec3(0.0);
} else if (imageLoad(uniBuffer, pixelCoords - ivec2(-1, 1)).rgb == vec3(0.0)) {
imageStore(uniBuffer, pixelCoords - ivec2(-1, 1), vec4(currentFrag, 1.0));
currentFrag = vec3(0.0);
}
}
}
imageStore(uniBuffer, pixelCoords, vec4(currentFrag, 1.0));
}
)"));
render.getWindow().addMouseButtonCallback(Raz::Mouse::LEFT_CLICK, [&compute, &render] (float) {
compute.use();
compute.sendUniform("uniMouseLeftClick", true);
const Raz::Vec2f mousePos = render.getWindow().recoverMousePosition();
compute.sendUniform("uniMousePos", Raz::Vec2i(static_cast<int>(mousePos.x()), sceneHeight - static_cast<int>(mousePos.y())));
}, Raz::Input::ALWAYS, [&compute] () {
compute.use();
compute.sendUniform("uniMouseLeftClick", false);
});
render.getWindow().addMouseButtonCallback(Raz::Mouse::RIGHT_CLICK, [&compute, &render] (float) {
compute.use();
compute.sendUniform("uniMouseRightClick", true);
const Raz::Vec2f mousePos = render.getWindow().recoverMousePosition();
compute.sendUniform("uniMousePos", Raz::Vec2i(static_cast<int>(mousePos.x()), sceneHeight - static_cast<int>(mousePos.y())));
}, Raz::Input::ALWAYS, [&compute] () {
compute.use();
compute.sendUniform("uniMouseRightClick", false);
});
render.getWindow().addMouseButtonCallback(Raz::Mouse::MIDDLE_CLICK, [&compute, &render] (float) {
compute.use();
compute.sendUniform("uniMouseMiddleClick", true);
const Raz::Vec2f mousePos = render.getWindow().recoverMousePosition();
compute.sendUniform("uniMousePos", Raz::Vec2i(static_cast<int>(mousePos.x()), sceneHeight - static_cast<int>(mousePos.y())));
}, Raz::Input::ALWAYS, [&compute] () {
compute.use();
compute.sendUniform("uniMouseMiddleClick", false);
});
auto& displayPass = render.getRenderGraph().addNode(Raz::FragmentShader::loadFromSource(R"(
in vec2 fragTexcoords;
uniform sampler2D uniBuffer;
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = vec4(texture(uniBuffer, fragTexcoords).rgb, 1.0);
}
)"));
displayPass.addParents(render.getGeometryPass());
displayPass.addReadTexture(texture, "uniBuffer");
app.run([&compute] (float) {
for (int i = 0; i < 15; ++i)
compute.execute(sceneWidth, sceneHeight);
});
}
- Home
- How to build RaZ
- Getting started
- General usage knowledge
- Some examples...
- Playground
- Tutorials
- File formats
- Modules
- Debug