• Qt 3D的研究(十):描边渲染(轮廓渲染)以及Silhouette Shader


    Qt 3D的研究(十):描边渲染(轮廓渲染)以及Silhouette Shader

           之前写了两篇文章,介绍了我在边缘检測上面的研究。实际上。使用GPU对渲染图像进行边缘检測。前提是须要进行两遍渲染。前一遍渲染的结果作为后一遍结果的输入纹理。接着在第二遍渲染的时候,对二维图像做一些图像处理,终于得出带轮廓的描边渲染效果,接着和正常渲染混合在一起。就成为渲染的终于图像。但是,这种做法,是对二维图像做的图像处理,即使像上次对提取的深度进行图像处理,也无法准确地依据深度的突变来提取我们须要的边缘。所以我们须要新的方法来提取模型的边缘。


    蒋彩阳原创文章,首发地址:http://blog.csdn.net/gamesdev/article/details/44455901。欢迎同行前来探讨。

           在这样的情况下,我在网上搜索到了一篇文章。介绍了提取轮廓的方法:

    1、顶点着色阶段,计算在view视角下的顶点到视点原点向量与在顶点位置向量的法向量。

    2、对顶点到视点原点向量与法向量归一化,然后进行点积,表示夹角θ的cos值

    3、假设cosθ>0,那么意味着θ<90°。能够代表这个顶点所在的面(当然也有可能是面面相交的棱上的点)朝向视点。表示正面,既然是正面,就显示原顶点位置;假设cosθ<0,那么意味着90°<θ<180°。能够代表这个面是背面。于是须要将顶点沿着法线偏移一定的距离,形成silhouette(轮廓)。

    4、片断着色阶段,假设是正面的话,那么显示的是正常的片元颜色,否则显示的是黑色(或者是其他暗色)。

           依据这种流程,我写了一个简单的着色器:

    // Silhouette.vert
    #version 100
    
    // Qt 3D默认提供的參数
    attribute vec3 vertexPosition;
    attribute vec3 vertexNormal;
    uniform mat4 modelView;
    uniform mat3 modelViewNormal;
    uniform mat4 modelNormalMatrix;
    uniform mat4 mvp;
    
    // 自己提供的參数
    uniform vec3 lightPosition;
    varying float lightIntensity;
    
    float getLightIntensity( )
    {
        vec3 ecPos = vec3( modelView * vec4( vertexPosition, 1.0 ) );
        vec3 normal = modelViewNormal * vertexNormal;
        ecPos = normalize( ecPos );
        normal = normalize( normal );
        return dot( -ecPos, normal );
    }
    
    void main( void )
    {
        const float bias = 0.2;
        vec3 silhouettePosition = vertexPosition + normalize( vertexNormal ) * bias;
        lightIntensity = getLightIntensity( );
        if ( lightIntensity > 0.0 ) gl_Position = mvp * vec4( vertexPosition, 1.0 );
        else gl_Position = mvp * vec4( silhouettePosition, 1.0 );
    }
    
    // Silhouette.frag
    #version 110
    
    // 自己提供的參数
    varying float lightIntensity;
    
    void main( void )
    {
        vec4 light = vec4( 0.9, 0.7, 0.5, 1.0 );
        vec4 dark = vec4( 0.0, 0.0, 0.0, 1.0 );
        gl_FragColor = lightIntensity > 0.0? light: dark;
    }

    执行的结果例如以下:

    这里须要开启深度測试,測试公式是lessOrEqual。代码例如以下:

    DepthTest { func: DepthTest.LessOrEqual }

           看来基本轮廓已经显示出来了,接下来要结合前段时间制作的卡通渲染效果。来一个结合。终于制作的ToonSilhouette着色器例如以下:

    // ToonSilhouette.vert
    #version 100
    
    // Qt 3D默认提供的參数
    attribute vec3 vertexPosition;
    attribute vec3 vertexNormal;
    uniform mat4 modelView;
    uniform mat3 modelViewNormal;
    uniform mat4 modelNormalMatrix;
    uniform mat4 mvp;
    
    // 自己提供的參数
    uniform vec3 lightPosition;
    varying float lightIntensity;
    
    float getLightIntensity( )
    {
        vec3 ecPos = vec3( modelView * vec4( vertexPosition, 1.0 ) );
        vec3 normal = modelViewNormal * vertexNormal;
        ecPos = normalize( ecPos );
        normal = normalize( normal );
        return dot( -ecPos, normal );
    }
    
    void main( void )
    {
        const float bias = 0.1;
        vec3 silhouettePosition = vertexPosition + normalize( vertexNormal ) * bias;
        lightIntensity = getLightIntensity( );
        if ( lightIntensity > 0.0 ) gl_Position = mvp * vec4( vertexPosition, 1.0 );
        else gl_Position = mvp * vec4( silhouettePosition, 1.0 );
    }
    
    // ToonSilhouette.frag
    #version 110
    
    // 自己提供的參数
    uniform sampler2D texPalette;
    varying float lightIntensity;
    
    void main( void )
    {
        vec4 light = vec4( 0.9, 0.7, 0.5, 1.0 );
        vec4 dark = vec4( 0.0, 0.0, 0.0, 1.0 );
        vec4 toon = texture2D( texPalette, vec2( lightIntensity, 1.0 ) );
        gl_FragColor = lightIntensity > 0.0? toon: dark;
    }
    
    

           演示程序的截图例如以下:

           这样看起来饱满多了。

           因为程序较长。我将全部代码放在了github中。有须要的同行朋友们能够从这个地址上clone执行之。

  • 相关阅读:
    Linux用户态程序计时方式详解
    我的代码重构经验
    基于链表的C语言堆内存检测
    C语言内存使用的常见问题及解决之道
    1151 LCA in a Binary Tree (30 分)
    1150 Travelling Salesman Problem (25 分)
    1149 Dangerous Goods Packaging (25 分)
    1148 Werewolf
    1155 Heap Paths (30 分)
    1154 Vertex Coloring (25 分)
  • 原文地址:https://www.cnblogs.com/yxysuanfa/p/6970499.html
Copyright © 2020-2023  润新知