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

原创 2015年03月01日 22:58:45

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.0
import Qt3D.Render 2.0

Entity
{
    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: texPalette

	TextureImage
	{
		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

Qt基础与Qt on Android入门

本课程起始于基础的开发环境搭建和Qt Creator快速介绍,帮助初学者入门;着力于Qt的内在机制,由浅入深介绍信号与槽、Qt模板库、事件、文件处理、XML、网络、多线程、各种GUI控件、布局管理器等各种Qt基础主题(这些主题可同时在Qt桌面编程和Android平台上使用),同时辅以简洁有效有针对性的实例程序(每个示例程序都可以在 Android 平台上运行)。
  • 2014年11月27日 10:53

通过GLSL来实现绘制像素的裁剪

GLSL中含有内置的变量gl_FragCoord,其描述片段着色器的片段(对应像素)所在的坐标。基于上次的GLSL纹理贴图,我们可以增加像素的过滤,例如,我们要过滤掉片段坐标小于100的像素,则可以写...
  • davidsu33
  • davidsu33
  • 2013-12-16 16:31:52
  • 1475

Qt 3D的研究(六):Toon Shader

在上次的实验中,我们实现了Gooch Shader,并给出了通过调色板进行个性化的Gooch Shader设置。Toon Shader又称Cell Shader,是以离散的颜色来表示光照的强弱。很多动...
  • jiangcaiyang123
  • jiangcaiyang123
  • 2015-03-05 16:00:37
  • 2850

Qt 3D的研究(四):指定渲染的材质以及效果

在上一篇文章中我了解到了怎样简单地显示模型。Qt3D内置了一个obj模型的解析器,这样可以将简单的obj模型载入并且显示出来。其实Qt3D对于渲染的配置还是很厉害的,通过设定材质,我们可以得到很不错的...
  • jiangcaiyang123
  • jiangcaiyang123
  • 2015-02-28 11:16:29
  • 4273

qt3d中基于opengles编写shader

项目需要基于嵌入式的板子上加载三维模型并实现特定的效果 首先,QT3D是第一选择,在window系统上实现了相应的功能,然而进行交叉编译时,出现问题了 原因是嵌入式的板子显卡支持的是OpenglE...
  • zengfeichuan
  • zengfeichuan
  • 2016-04-15 17:48:08
  • 259

Qt 3D Overview

Qt3D建立的目标是能够让开发者快速地创建3D场景,通过各式各样的渲染技术来达到3D交互的场景。Qt3D除了和Qt一样跨平台之外,还能够选择OpenGL的具体实现,定制GLSL,从而能够根据不同性能的...
  • lizhenneng
  • lizhenneng
  • 2016-05-10 16:06:35
  • 4215

Qt 3D的研究(二)

上一篇文章给大家看了很多Qt 3D的例子,如果大家有Qt3D的源代码,就会发现,开发这些例子,花费的代码还真不少。这就是不一样的地方,Qt 3D毕竟和三维图形打交道,多了一个维度,问题的难度变得更大了...
  • jiangcaiyang123
  • jiangcaiyang123
  • 2015-02-13 21:47:48
  • 5539

Qt 3D的研究(一)

Qt 3D是有可能即将在Qt 5.5中正式启用的模块之一。它建立的目标是能够让开发者快速地创建3D场景,通过各式各样的渲染技术来达到3D交互的场景。Qt3D除了和Qt一样跨平台之外,还能够选择Open...
  • jiangcaiyang123
  • jiangcaiyang123
  • 2015-02-13 20:45:33
  • 8848

Qt 3D的研究(三):显示3D模型

上一篇文章介绍了如何使用最少的代码创建一个Qt 3D的应用。和大家最初接触的glut一样,对于3D应用来说,需要做的准备工作还真不少,不过呢,Qt 3D把一些窗口相关的琐碎事情解决了,剩下的,该由我们...
  • jiangcaiyang123
  • jiangcaiyang123
  • 2015-02-27 09:59:09
  • 11306

Qt 3D的研究(七):渲染至纹理

最近几天都没有怎么研究Qt 3D了,但是随着Qt5.5发布的日子一天天的靠近,我也不能懈怠,希望利用Qt 3D,将能够实现的功能进行实现,并且对Qt 3D获取一个新的认识。两天多没有研究了,现在信心却...
  • jiangcaiyang123
  • jiangcaiyang123
  • 2015-03-09 16:44:10
  • 2958
收藏助手
不良信息举报
您举报文章:Qt 3D的研究(五):Gooch Shader
举报原因:
原因补充:

(最多只允许输入30个字)