Qt 3D的研究(五):Gooch Shader

来源:互联网 发布:nba2k17乔丹动作数据 编辑:程序博客网 时间:2024/04/18 22:26

Qt 3D的研究(五):Gooch Shader

       Qt 3D的一个很大的优势就是采用数据驱动的方式,将C++和GLSL使用QML来表示,动态语言的优势尽显。在上一次的研究中,我实现了一个非常简单的着色器,接下来,我们可以在此基础上,通过设定着色器的数据,制作出更加绚丽的着色效果。作为开始,我们先从几个非真实渲染(Non-Photorealistic Rendering,NPR)开始吧。

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

       首先我们开始研究Gooch着色器。Gooch着色器是Phong着色器的一个变种,一般用于技术插图中,比如说下面这张插图的效果就可以使用Gooch着色器完成。


       接下来我们将上一篇文章的QML代码稍微修改一下,以支持我们的Gooch着色器。下面是新增的代码:

import Qt3D 2.0import Qt3D.Render 2.0Entity{    id: root    Camera    {        id: camera        position: Qt.vector3d( 0.0, 0.0, 40.0 )        projectionType: CameraLens.PerspectiveProjection        fieldOfView: 45        aspectRatio: 16.0 / 9.0        nearPlane : 0.1        farPlane : 1000.0        upVector: Qt.vector3d( 0.0, 1.0, 0.0 )        viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )    }    components: FrameGraph    {        ForwardRenderer        {            clearColor: Qt.rgba( 1.0, 0.8, 0.2, 1 )            camera: camera        }    }    Entity    {        Mesh        {            id: mesh            source: "qrc:/toyplane.obj"        }        Material        {            id: material            effect: effect            Effect            {                id: effect                techniques: [ technique ]                Technique                {                    id: technique                    openGLFilter                    {                        api: OpenGLFilter.Desktop                        profile: OpenGLFilter.None                        majorVersion: 2                        minorVersion: 0                    }                    renderPasses: [ renderPass ]                    //! [5]                    parameters:                    [                        Parameter                        {                            name: "lightPosition"                            value: camera.position                        },                        Parameter                        {                            name: "surfaceColor"                            value: Qt.rgba( 0.9, 0.9, 0.9, 1 )                        },                        Parameter                        {                            name: "warmColor"                            value: Qt.rgba( 0.8, 0.3, 0.0, 1 )                        },                        Parameter                        {                            name: "coolColor"                            value: Qt.rgba( 0.0, 0.3, 0.2, 1 )                        },                        Parameter                        {                            name: "diffuseWarm"                            value: 0.4                        },                        Parameter                        {                            name: "diffuseCool"                            value: 0.6                        }                    ]                    //! [5]                    RenderPass                    {                        id: renderPass                        shaderProgram: goochSP                        ShaderProgram                        {                            id: goochSP                            vertexShaderCode: loadSource( "qrc:/Gooch.vert" )                            fragmentShaderCode: loadSource( "qrc:/Gooch.frag" )                        }                    }                }            }        }        components: [ mesh, material ]    }    Configuration    {        controlledCamera: camera    }}

       在//! [5]中我们定义了一些需要传入的参数。它们是lightPosition、surfaceColor、warmColor、coolColor、diffuseWarm和diffuseCool。这些是要在着色器中定义的uniform参数,所以我们必须要在QML中显示地指定它。其实Parameter定义在哪里,Qt 3D是有讲究的。Qt 3D是这样一个规律:Parameter定义在外层的,会覆盖在内层的同名Parameter,也就是说,内层的Parameter作为一个默认的参数,可以通过外层的Parameter进行修改。目前,Qt3D的覆盖优先顺序是:Material→Effect→Technique→RenderPass→GLSL默认值。

       介绍完了这些,让我们看看GLSL是如何的吧。

// Gooch.vert#version 100// Qt 3D默认提供的参数attribute vec3 vertexPosition;attribute vec3 vertexNormal;uniform mat4 modelView;uniform mat4 modelNormalMatrix;uniform mat4 mvp;// 自己提供的参数uniform vec3 lightPosition;varying vec3 reflectVec;varying vec3 viewVec;varying float NdotL;void main( void ){    vec3 ecPos = ( modelView * vec4( vertexPosition, 1.0 ) ).xyz;    vec3 normal = normalize( modelNormalMatrix * vec4( vertexNormal, 1.0 ) ).xyz;    vec3 lightVec = normalize( lightPosition - ecPos );    reflectVec = normalize( reflect( -lightVec, normal ) );    viewVec = normalize( -ecPos );    NdotL = ( dot( lightVec, normal ) + 1.0 ) * 0.5;    gl_Position = mvp * vec4( vertexPosition, 1.0 );}

       顶点着色器中我们仍然像Phong光照模型一样,求出NdotL,在片断着色器中使用;然后我们算出reflectVec,和viewVec,作为反射和视向量的单位向量,留到片断着色器中使用。

// Gooch.frag#version 100// 自己提供的参数uniform vec3 surfaceColor;uniform vec3 warmColor;uniform vec3 coolColor;uniform float diffuseWarm;uniform float diffuseCool;varying vec3 reflectVec;varying vec3 viewVec;varying float NdotL;void main( void ){    vec3 kcool    = min( coolColor + diffuseCool * surfaceColor, 1.0 );    vec3 kwarm    = min( warmColor + diffuseWarm * surfaceColor, 1.0 );    vec3 kfinal   = mix( kcool, kwarm, NdotL );    float spec = max( dot( reflectVec, viewVec ), 0.0 );    spec = pow( spec, 32.0 );    gl_FragColor = vec4( min( kfinal + spec, 1.0 ), 1.0 );}

在片断着色器中,我们定义了平面颜色、暖色调颜色、冷色调颜色以及他们相应的参数。这些参数需要我们通过mix函数(线性插值函数)最终得出基本的颜色,紧接着我们计算镜面反射光,让模型飞机具有光泽效果,最后将这些值添加起来,得到的是片断颜色。

       演示程序截图如下:

       嗯,通过调节参数来获取更好的效果,不过呢,更好的方法是定义一个颜色版纹理来得到一些更有趣的渲染效果:

       方法是:首先我们定义一个颜色调色版的纹理:

       然后在QML中添加这样一个参数以及相应的纹理对象:

 

parameters:[Parameter{name: "lightPosition"value: camera.position},Parameter{name: "surfaceColor"value: Qt.rgba( 0.9, 0.9, 0.9, 1 )},Parameter{name: "warmColor"value: Qt.rgba( 0.8, 0.3, 0.0, 1 )},Parameter{name: "coolColor"value: Qt.rgba( 0.0, 0.3, 0.2, 1 )},Parameter{name: "diffuseWarm"value: 0.4},Parameter{name: "diffuseCool"value: 0.6},//! [6]Parameter{name: "texPalette"value: texPalette}]Texture2D{id: texPaletteTextureImage{source: "qrc:/texturePalette.png"}}//! [6]

       这里定义了Texture2D类以及TextureImage类。TextureImage类作为纹理的载入者,可以接受QImage能够载入的图片类型,接着作为Texture2D类的默认属性被生成一个纹理采样器(texture sampler2D),作为一个uniform变量载入到GLSL中。

GLSL中顶点着色器不变,片断着色器作如下的修改:

// Gooch.frag#version 100// 自己提供的参数uniform vec3 surfaceColor;uniform vec3 warmColor;uniform vec3 coolColor;uniform float diffuseWarm;uniform float diffuseCool;varying vec3 reflectVec;varying vec3 viewVec;varying float NdotL;uniform sampler2D texPalette;void main( void ){    vec3 kcool    = min( coolColor + diffuseCool * surfaceColor, 1.0 );    vec3 kwarm    = min( warmColor + diffuseWarm * surfaceColor, 1.0 );    //! [6]    vec3 kfinal   = texture2D( texPalette, vec2( NdotL, 1.0 ) ).xyz;    //! [6]    float spec = max( dot( reflectVec, viewVec ), 0.0 );    spec = pow( spec, 32.0 );    gl_FragColor = vec4( min( kfinal + spec, 1.0 ), 1.0 );}

这里添加了texturePalette这个sampler2D变量,并且修改了kfinal的值。

 

参考文献:

http://www.jonatron.ca/tag/shader/

http://shiba.hpe.sh.cn/jiaoyanzu/wuli/showArticle.aspx?articleId=333&classId=4

0 0