• Qt 3D研究(九):尝试第二边缘检测方法


    Qt 3D研究(九):尝试第二边缘检测方法

           三维应用程序,通过FBO。将3D图像渲染成纹理,然后对渲染成的纹理进行图像处理,终于显示在屏幕上的。是风格化后的图案。上一次我使用了一种普通的图像处理方法:索贝尔边缘检測法,与我们的卡通渲染结合起来,实现了这种效果。接着。我将採用第二种边缘检測方法——普雷维特(Prewitt)边缘检測方法来又一次渲染图案。

    蒋彩阳原创文章。首发地址:http://blog.csdn.net/gamesdev/article/details/44405219。

    欢迎同行前来探讨。

           首先让我们看看上一次的截图:

           我们看到,本不应该是边缘的机身部分。因为离散的调色,被索贝尔算子边缘检測一算,也被误觉得是边缘了,同一时候,在背景与机身颜色不明显的部分,也因为採用不适当的阈值,不被觉得是边缘。

    所以我想有没有一种方法可以解决问题呢?于是我採取了这个方案:

    1、 第一遍的render pass,取的不是卡通着色的颜色图,而是深度图。

    2、 将深度图渲染至纹理;

    3、 对该纹理进行边缘检測;

    4、 与卡通着色的图进行叠加,做成效果图。

    怎样在GLSL中将片元的深度信息提取出来?这里我參考了前辈的博客,然后写出了这种GLSL代码:

    // Depth.vert
    #version 100
    
    // Qt 3D默认提供的參数
    attribute vec3 vertexPosition;
    uniform mat4 modelView;
    uniform mat4 mvp;
    
    void main( void )
    {
        gl_Position = mvp * vec4( vertexPosition, 1.0 );
    }
    
    // Depth.frag
    #version 110
    
    // 自己提供的參数
    
    bool inBetween( float v, float min, float max )
    {
        return v > min && v < max;
    }
    
    void main( void )
    {
        float exp = 256.0;
        gl_FragColor = vec4( vec3( pow( gl_FragCoord.z, exp ) ), 1.0);
    }

           由于gl_FragCoord.z表示的片元深度信息相互之间很接近。我们须要一个指数乘幂操作将这种差别放大,这样才干区分不同的深度的值。

           紧接着,我们将Prewitt算子替换掉Sobel算子,终于的着色器代码例如以下:

    // Ouput.vert
    #version 100
    
    // Qt 3D默认提供的參数
    attribute vec4 vertexPosition;
    uniform mat4 modelMatrix;
    
    // 自己提供的參数
    
    void main( void )
    {
        gl_Position = modelMatrix * vertexPosition;
    }
    
    // Output.frag
    #version 100
    
    // 自己提供的參数
    uniform sampler2D colorAttachTex;
    //uniform sampler2D depthAttachTex;
    uniform vec2 texSize;
    uniform float texOffsetX;
    uniform float texOffsetY;
    
    float gray( vec4 color )
    {
        return dot( color.xyz, vec3( 0.299, 0.587, 0.114 ) );
    }
    
    void main( void )
    {
        vec4 texColor[9];
        texColor[0] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( -texOffsetX, texOffsetY ) );
        texColor[1] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( 0.0, -texOffsetY ) );
        texColor[2] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( texOffsetX, texOffsetY ) );
        texColor[3] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( -texOffsetX, 0 ) );
        texColor[4] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( 0.0, 0.0 ) );
        texColor[5] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( texOffsetX, 0 ) );
        texColor[6] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( -texOffsetX, -texOffsetY ) );
        texColor[7] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( 0.0, -texOffsetY ) );
        texColor[8] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( texOffsetX, -texOffsetY ) );
    
        // 普雷维特算子
        float prewitt_x[9];
        prewitt_x[0] = -1.0;
        prewitt_x[1] = 0.0;
        prewitt_x[2] = 1.0;
        prewitt_x[3] = -1.0;
        prewitt_x[4] = 0.0;
        prewitt_x[5] = 1.0;
        prewitt_x[6] = -1.0;
        prewitt_x[7] = 0.0;
        prewitt_x[8] = 1.0;
    
        float prewitt_y[9];
        prewitt_y[0] = 1.0;
        prewitt_y[1] = 1.0;
        prewitt_y[2] = 1.0;
        prewitt_y[3] = 0.0;
        prewitt_y[4] = 0.0;
        prewitt_y[5] = 0.0;
        prewitt_y[6] = -1.0;
        prewitt_y[7] = -1.0;
        prewitt_y[8] = -1.0;
    
        // 卷积操作
        vec4 edgeX = vec4( 0.0 );
        vec4 edgeY = vec4( 0.0 );
        for ( int i = 0; i < 9; ++i )
        {
            edgeX += texColor[i] * prewitt_x[i];
            edgeY += texColor[i] * prewitt_y[i];
        }
    
        vec4 edgeColor = sqrt( ( edgeX * edgeX ) + ( edgeY * edgeY ) );
        float edgeIntensity = gray( edgeColor );
        const float threshold = 0.05;
    
        if ( edgeIntensity > threshold )
            gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
        else discard;
    }

           因为代码相对较长,我必须把来github在。

    有需要的同行和朋友,从能github有资格代替代码。

    地址:这里

  • 相关阅读:
    软件工程课程总结
    c++第五次作业
    软件工程第四次作业
    c++第四次作业
    软件工程第三次作业
    c++第三次作业
    软件工程基础第二次作业
    c++第二次作业
    c++第一次作业
    软件工程基础第一次作业
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5031713.html
Copyright © 2020-2023  润新知