-
-
Notifications
You must be signed in to change notification settings - Fork 29
Canny edge detector
Romain Milbert edited this page Dec 8, 2022
·
5 revisions
As the time of writing (2022-12-08, commit b3646d3), the following files give the result shown in this video:
#include <RaZ/Application.hpp>
#include <RaZ/Data/Mesh.hpp>
#include <RaZ/Data/ObjFormat.hpp>
#include <RaZ/Math/Transform.hpp>
#include <RaZ/Render/Camera.hpp>
#include <RaZ/Render/GaussianBlurRenderProcess.hpp>
#include <RaZ/Render/Material.hpp>
#include <RaZ/Render/MeshRenderer.hpp>
#include <RaZ/Render/RenderSystem.hpp>
#include <RaZ/Render/SobelFilterRenderProcess.hpp>
using namespace Raz::Literals;
using namespace std::literals;
int main() {
Raz::Application app;
Raz::World& world = app.addWorld(2);
auto& renderSystem = world.addSystem<Raz::RenderSystem>(1280, 720, "RaZ");
Raz::Window& window = renderSystem.getWindow();
window.addKeyCallback(Raz::Keyboard::ESCAPE, [&app] (float) noexcept { app.quit(); });
window.setCloseCallback([&app] () noexcept { app.quit(); });
Raz::Entity& camera = world.addEntity();
auto& cameraComp = camera.addComponent<Raz::Camera>(window.getWidth(), window.getHeight());
auto& cameraTrans = camera.addComponent<Raz::Transform>(Raz::Vec3f(0.f, 5.f, 20.f));
Raz::Entity& mesh = world.addEntity();
auto& meshRenderComp = mesh.addComponent<Raz::MeshRenderer>(Raz::ObjFormat::load("crytek_sponza.obj").second);
mesh.addComponent<Raz::Transform>(Raz::Vec3f(0.f), Raz::Quaternionf(90_deg, Raz::Axis::Y), Raz::Vec3f(0.04f));
// Changing the material so that no lighting is computed
for (Raz::Material& mat : meshRenderComp.getMaterials())
mat.loadType(Raz::MaterialType::SINGLE_TEXTURE_2D);
Raz::RenderGraph& renderGraph = renderSystem.getRenderGraph();
Raz::RenderPass& geometryPass = renderSystem.getGeometryPass();
const auto depthBuffer = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::DEPTH);
const auto colorBuffer = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::RGB);
geometryPass.setWriteDepthTexture(depthBuffer);
geometryPass.addWriteColorTexture(colorBuffer, 0);
auto& blur = renderGraph.addRenderProcess<Raz::GaussianBlurRenderProcess>();
blur.setInputBuffer(colorBuffer);
blur.addParent(geometryPass);
auto colorBuffer2 = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::RGB);
auto& sobel = renderGraph.addRenderProcess<Raz::SobelFilterRenderProcess>();
sobel.setInputBuffer(colorBuffer2);
sobel.addParent(blur);
blur.setOutputBuffer(colorBuffer2);
auto sobelGradBuffer = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::GRAY);
auto sobelGradDirBuffer = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::GRAY);
sobel.setOutputGradientBuffer(sobelGradBuffer);
sobel.setOutputGradientDirectionBuffer(sobelGradDirBuffer);
auto& canny = renderGraph.addNode(Raz::FragmentShader::loadFromSource(R"(
in vec2 fragTexcoords;
uniform sampler2D uniSobelGradients;
uniform sampler2D uniSobelGradDirs;
uniform vec2 uniInvBufferSize;
layout(location = 0) out vec4 fragColor;
void main() {
vec3 gradient = texture(uniSobelGradients, fragTexcoords).rgb;
vec3 gradDir = texture(uniSobelGradDirs, fragTexcoords).rgb;
vec3 rightGrad = texture(uniSobelGradients, fragTexcoords + vec2( 1.0, 0.0) * uniInvBufferSize).rgb;
vec3 leftGrad = texture(uniSobelGradients, fragTexcoords + vec2(-1.0, 0.0) * uniInvBufferSize).rgb;
vec3 downGrad = texture(uniSobelGradients, fragTexcoords + vec2( 0.0, -1.0) * uniInvBufferSize).rgb;
vec3 upGrad = texture(uniSobelGradients, fragTexcoords + vec2( 0.0, 1.0) * uniInvBufferSize).rgb;
vec3 lowerRightGrad = texture(uniSobelGradients, fragTexcoords + vec2( 1.0, -1.0) * uniInvBufferSize).rgb;
vec3 upperLeftGrad = texture(uniSobelGradients, fragTexcoords + vec2(-1.0, 1.0) * uniInvBufferSize).rgb;
vec3 lowerLeftGrad = texture(uniSobelGradients, fragTexcoords + vec2(-1.0, -1.0) * uniInvBufferSize).rgb;
vec3 upperRightGrad = texture(uniSobelGradients, fragTexcoords + vec2( 1.0, 1.0) * uniInvBufferSize).rgb;
for (int i = 0; i < 3; ++i) {
// Merging the two halves together; we want to check opposite direction, and both will be combined that way
gradDir[i] -= 0.5 * step(0.5, gradDir[i]);
if (gradDir[i] <= 0.0625 || gradDir[i] > 0.4375) { // Right or left
if (gradient[i] < rightGrad[i] || gradient[i] < leftGrad[i])
gradient[i] = 0.0;
} else if (gradDir[i] > 0.1875 && gradDir[i] <= 0.3125) { // Down or up
if (gradient[i] < downGrad[i] || gradient[i] < upGrad[i])
gradient[i] = 0.0;
} else if (gradDir[i] > 0.0625 && gradDir[i] <= 0.1875) { // Lower-right or upper-left
if (gradient[i] < lowerRightGrad[i] || gradient[i] < upperLeftGrad[i])
gradient[i] = 0.0;
} else if (gradDir[i] > 0.3125 && gradDir[i] <= 0.4375) { // Lower-left or upper-right
if (gradient[i] < lowerLeftGrad[i] || gradient[i] < upperRightGrad[i])
gradient[i] = 0.0;
}
}
const float lowerBound = 0.1;
const float upperBound = 0.25;
for (int i = 0; i < 3; ++i) {
if (gradient[i] <= lowerBound) {
gradient[i] = 0.0;
} else if (gradient[i] >= upperBound) {
gradient[i] = 1.0;
} else {
if (rightGrad[i] >= upperBound || leftGrad[i] >= upperBound || downGrad[i] >= upperBound || upGrad[i] >= upperBound
|| lowerRightGrad[i] >= upperBound || upperLeftGrad[i] >= upperBound || lowerLeftGrad[i] >= upperBound || upperRightGrad[i] >= upperBound) {
gradient[i] = 1.0;
} else {
gradient[i] = 0.0;
}
}
}
fragColor = vec4(gradient, 1.0);
}
)"sv));
canny.getProgram().use();
canny.getProgram().sendUniform("uniInvBufferSize", Raz::Vec2f(1.f / window.getWidth(), 1.f / window.getHeight()));
canny.addReadTexture(sobelGradBuffer, "uniSobelGradients");
canny.addReadTexture(sobelGradDirBuffer, "uniSobelGradDirs");
sobel.addChild(canny);
app.run();
return EXIT_SUCCESS;
}
- Home
- How to build RaZ
- Getting started
- General usage knowledge
- Some examples...
- Playground
- Tutorials
- File formats
- Modules
- Debug