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+OpenGL 3ds模型的导入

Qt是一个跨平台的C++图形用户界面应用程序框架。它提供给应用程序开发者建立艺术级的图形用户界面所需的所有功能。Qt很容易扩展,并且允许真正地组件编程。基本上,Qt同 X Window 上的 Moti...
  • u010118469
  • u010118469
  • 2014年03月26日 19:39
  • 2764

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

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

Qt3D的研究

Qt3D
  • tony2278
  • tony2278
  • 2016年09月13日 17:46
  • 691

Qt3D for QT 5

http://blog.sina.com.cn/s/blog_88e2dbbf0101hzx7.html
  • chenyijun
  • chenyijun
  • 2014年09月29日 00:11
  • 1719

Shader的语法

Shader的语法 Shader "name" { [Properties] Subshaders [Fallback] } (1)Properties:{ Property [Property .....
  • heyuchang666
  • heyuchang666
  • 2016年02月25日 14:18
  • 1720

qt3d中基于opengles编写shader

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

Qt下学习OpenGL之OBJ模型

我这里的OBJ格式不是c++代码产生的中间文件,而是那个g什么wave公司的OBJ格式,格式很简单,作用就是拿来存储3D模型的一些基本信息。以前在VS2005下能很轻松读取,这次换QT了,幸好QT公司...
  • stilling2006
  • stilling2006
  • 2010年05月02日 00:00
  • 4211

3D Slicer+Qt-easy-build+VS2013

废话: 科研菜鸟终于要走出敲代码这一步了,只是离心水的机器学习越来越远,不过走进可视化这个领域还是蛮令人激动的。 需要用到3D Slicer这个开源库,需要自己写一个程序来读取医学数据模型等来做可视化...
  • u011310341
  • u011310341
  • 2016年04月07日 18:30
  • 1722

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

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

Unity3D -- 语法内置函数(Shader学习之三)

该篇是Unity Shader中HLSL的内置函数,主要是一些数学方面的计算函数。在写Shader的时候可以直接使用。abs //计算输入值的绝对值。 ...
  • honey199396
  • honey199396
  • 2017年01月16日 20:34
  • 667
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Qt 3D的研究(五):Gooch Shader
举报原因:
原因补充:

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