OpenGL - 对象轮廓

Arc*_* Pi 7 c++ opengl graphics outlining highlight

我正在尝试实现选择轮廓功能.这就是我现在所要做的.

在此输入图像描述

如您所见,当鼠标悬停并在所选对象周围绘制轮廓时,可以正确选择对象.

我现在想做的是以这种方式勾勒出对象的可见边缘

在此输入图像描述

左边的图像是我现在拥有的,右边的图像是我想要实现的.

这是我现在使用的程序.

void paintGL()
{
    /* ... */

    int w = geometry().width();
    int h = geometry().height();

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    glEnable(GL_STENCIL_TEST);
    glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
    glStencilMask(0xFF);

    setClearColor(Qt::GlobalColor::darkGray);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    glStencilMask(0x00);
    DrawGeometry();

    if (HoveredSphere != RgbFromColorToString(Qt::GlobalColor::black))
    {
        glBindFramebuffer(GL_FRAMEBUFFER, addFBO(FBOIndex::OUTLINE));
        {
            glStencilFunc(GL_ALWAYS, 1, 0xFF);
            glStencilMask(0xFF);

            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

            DrawOutline(HoveredSphere, 1.0f - 0.025f);
        }
        glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject());

        glBindFramebuffer(GL_READ_FRAMEBUFFER, addFBO(FBOIndex::OUTLINE));
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebufferObject());
        {
            // copy stencil buffer
            GLbitfield mask = GL_STENCIL_BUFFER_BIT;
            glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, mask, GL_NEAREST);

            glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
            glStencilMask(0x00);

            glDepthFunc(GL_LEQUAL);
            DrawOutline(HoveredSphere, 1.0f);
        }
        glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject());
    }

    update();
}
Run Code Online (Sandbox Code Playgroud)

其中DrawGeometry绘制的所有对象,并DrawOutline绘制由作为第二个参数传递的因子按比例缩放所选择的对象.

谢谢你的任何建议.

Arc*_* Pi 6

按照@MichaelMahn的提示,我找到了解决方案.

首先,我在纹理中绘制所选对象的可见部分的轮廓.

IMG

然后我使用这个纹理通过检查相邻像素来计算轮廓,以确定我是否站在轮廓的边缘.

在此输入图像描述

大纲片段着色器

#version 450

uniform sampler2D silhouette;

in FragData
{
    smooth vec2 coords;
} frag;

out vec4 PixelColor;

void main()
{
    // if the pixel is black (we are on the silhouette)
    if (texture(silhouette, frag.coords).xyz == vec3(0.0f))
    {
        vec2 size = 1.0f / textureSize(silhouette, 0);

        for (int i = -1; i <= +1; i++)
        {
            for (int j = -1; j <= +1; j++)
            {
                if (i == 0 && j == 0)
                {
                    continue;
                }

                vec2 offset = vec2(i, j) * size;

                // and if one of the neighboring pixels is white (we are on the border)
                if (texture(silhouette, frag.coords + offset).xyz == vec3(1.0f))
                {
                    PixelColor = vec4(vec3(1.0f), 1.0f);
                    return;
                }
            }
        }
    }

    discard;
}
Run Code Online (Sandbox Code Playgroud)

paintgl

void paintGL()
{
    int w = geometry().width();
    int h = geometry().height();

    setClearColor(Qt::GlobalColor::darkGray);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    DrawGeometry();

    // if we hover a sphere
    if (HoveredSphere != RgbFromColorToString(Qt::GlobalColor::black))
    {
        glBindFramebuffer(GL_READ_FRAMEBUFFER, defaultFramebufferObject());
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, addFBO(FBOIndex::SILHOUETTE));
        {
            // copy depth buffer
            GLbitfield mask = GL_DEPTH_BUFFER_BIT;
            glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, mask, GL_NEAREST);

            // set clear color
            setClearColor(Qt::GlobalColor::white);
            // enable depth test
            glEnable(GL_DEPTH_TEST);
            glDepthFunc(GL_LEQUAL);
            // clear color buffer
            glClear(GL_COLOR_BUFFER_BIT);

            // draw silhouette
            DrawSilhouette(HoveredSphere);
        }
        glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject());

        // clear depth buffer
        glClear(GL_DEPTH_BUFFER_BIT);

        // draw outline
        DrawOutline();
    }
}
Run Code Online (Sandbox Code Playgroud)

问题 ::现在我想参数化轮廓的宽度,其厚度当前固定为1像素.

非常感谢您的任何建议!