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

原创 2015年03月19日 13:28:56

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运行之。

【NPR】漫谈轮廓线的渲染

写在前面 好久没写文章。最近在看《Real Time Rendering, third edition》这本书,看到了NPR这一章就想顺便记录下一些常见的轮廓线渲染的方法。在非真实感渲染中,对轮廓线...
  • candycat1992
  • candycat1992
  • 2015年05月10日 12:28
  • 12509

三言两语说shader(五)轮廓描边

这也是个常见的shader,可以实现类似动漫《枪之国度》的那种轮廓描边卡通画风。 在我手头的项目里用来给怪物加“霸体”效果,所谓霸体意思是怪物此时无法被击倒。 用途诸如此类。 下面放效果图: ...
  • obmar45
  • obmar45
  • 2016年04月03日 14:10
  • 3301

通过卡通渲染描边shader来学习Unity的Shader写法

Unity自带了很多shader,其中就包含卡通渲染和描边的shader。但是我在实际开发游戏的过程中还是遇到了这些shader无法解决的问题。         于是,我们需要理解如何写Unit...
  • cq886le
  • cq886le
  • 2014年11月14日 12:05
  • 455

Unity Shader 物体外轮廓 描边

Shader "AX/Outline1" { // 漫反射光照模型(环境光+方向光) Properties { _MainTex("MainTex", 2D) = "white"{} ...
  • wxlguitar
  • wxlguitar
  • 2014年09月23日 17:32
  • 9721

几种卡通渲染方法的解析

代码全部出自RenderMonkey的样例文件NPR.rfx,下载地址: http://developer.amd.com/tools-and-sdks/archive/games-cgi/re...
  • YgritteSnow
  • YgritteSnow
  • 2016年08月24日 20:02
  • 2340

Unity Shader入门精要学习笔记 - 第14章非真实感渲染

转载自 冯乐乐的 《Unity Shader 入门精要》 尽管游戏渲染一般都是以照相写实主义作为主要目标,但也有许多游戏使用了非真实感渲染(NPR)的方法来渲染游戏画面。非真实感渲染的一个主要目标是,...
  • u010848412
  • u010848412
  • 2017年06月25日 13:56
  • 410

【Unity Shader实战】卡通风格的Shader(二)

写在前面好久没写博客了,一定是因为课程作业比较多,一定不是因为我懒,恩恩。三个月以前,在一篇讲卡通风格的Shader的最后,我们说到在Surface Shader中实现描边效果的弊端,也就是只对表面平...
  • candycat1992
  • candycat1992
  • 2014年11月14日 17:58
  • 19146

卡通渲染及其相关技术总结

卡通渲染是图形学中一个有趣的话题,属于非真实感计算机图形学(NPR)的范畴,在NPR领域中也最多地被应用到实际游戏中,近年来流行的《守望先锋》,《英雄联盟》,《DOTA2》,《崩坏3》等游戏中都或多或...
  • UWA4D
  • UWA4D
  • 2017年06月15日 10:05
  • 1081

卡通渲染Cocos2d-x中的实现(描边与对物体表面颜色的色阶化)

卡通渲染Cocos2d-x中的实现 在一些类型的游戏中,使用卡通渲染能够将原有模型的一些细节剥离,使原本比较写实的模型变得卡通化。在这里,我向大家介绍简单介绍一下如何在Cocos2d-x中实现卡通渲...
  • u012419410
  • u012419410
  • 2015年02月11日 16:30
  • 669

UE4实现描边效果

描边效果属于常见常用的功能,现VR项目中,也需要射线选中一个物体,使物体高亮。 于是在网上找了部分资料,同时也感谢群里的一位大神的提点,总算将描边的功能实现了,这里也写一个简单的示例步骤。 1.我并不...
  • qq992817263
  • qq992817263
  • 2016年07月06日 13:34
  • 7182
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Qt 3D的研究(十):描边渲染(轮廓渲染)以及Silhouette Shader
举报原因:
原因补充:

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