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

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

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

在这样的情况下,我在网上搜索到了

url=MdQtjaqp8bvHYEOM4K4VqLke2R_Uqgg3feCxNWFonYigyqOwcRQA7sR9LmyjxwiwEnTpA5a0GllnW_FAmHv3cK&wd=opengl%20%E6%8F%8F%E8%BE%B9&issp=1&f=3&ie=utf-8&tn=baiduhome_pg&oq=OpenGL&rsp=1&inputT=1055406">一篇文章。介绍了提取轮廓的方法:

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

Qt 3D的研究(十):描边渲染(轮廓渲染)以及Silhouette Shader的更多相关文章

  1. 使用Qt 3D Studio 2.4显着提升性能(渲染速度提高了565%)

    发布于2019年6月18日星期二11评论Qt 3D Studio 2.4显着改善性能 发表于Biz Circuit&Dev Loop,设计,图形,性能,Qt 3D Studio 除了有效使用系 ...

  2. Qt 3D研究(九):尝试第二边缘检测方法

    Qt 3D研究(九):尝试第二边缘检测方法 三维应用程序,通过FBO.将3D图像渲染成纹理,然后对渲染成的纹理进行图像处理,终于显示在屏幕上的.是风格化后的图案.上一次我使用了一种普通的图像处理方法: ...

  3. 从0开发3D引擎(十二):使用领域驱动设计,从最小3D程序中提炼引擎(第三部分)

    目录 上一篇博文 继续实现 实现"DirectorJsAPI.init" 实现"保存WebGL上下文"限界上下文 实现"初始化所有Shader&quo ...

  4. 【十天自制软渲染器】DAY 01:图形学学习建议与环境搭建

    推荐直接阅读博客原文,更新更及时,阅读体验更佳 「十天自制软渲染器」这个标题我承认标题党了.在对图形学一无所知的情况下想十天自制一个软渲染器,就好似一节课没上过却试图一个晚上看完<30 天精通 ...

  5. Qt 3D Studio 1.0 Resleased

    Qt 这家伙又整出一个新东西了,Qt 3D Studio 1.0 新闻链接:https://blog.qt.io/blog/2017/11/30/qt-3d-studio-1-0-released/ ...

  6. Qt 3D教程(三)实现对模型材质參数的控制

    Qt 3D教程(三)实现对模型材质參数的控制 蒋彩阳原创文章,首发地址:http://blog.csdn.net/gamesdev/article/details/47131841.欢迎同行前来探讨. ...

  7. 基于物理渲染的渲染器Tiberius计划

    既然决定实现一个光栅化软件渲染器,我又萌生了一个念头:实现一个基于物理渲染的渲染器.

  8. 微信小程序学习笔记二 列表渲染 + 条件渲染

    1. 列表渲染 1.1 wx:for 在组件上使用wx:for控制属性绑定一个数组, 即可使用数组中各项的数据重复渲染该组件 默认数组的当前项的下标变量名默认为 index, 数组当前项的变量名默认为 ...

  9. Qt 2D绘图之二:抗锯齿渲染和坐标系统

    一.抗锯齿渲染 1.1 逻辑绘图 图形基元的大小(宽度和高度)始终与其数学模型相对应,下图示意了忽略其渲染时使用的画笔的宽度的样子. 1.2 物理绘图(默认情况) 在默认的情况下,绘制会产生锯齿,并且 ...

随机推荐

  1. php循环跳出

    PHP中的循环结构大致有for循环,while循环,do{} while 循环以及foreach循环几种,不管哪种循环中,在PHP中跳出循环大致有这么几种方式: 代码: <?php $i = 1 ...

  2. thinkphp的ip地址定位

    在WEB应用中,根据IP地址定位和记录相关访问日志也是非常常见的需求,在ThinkPHP中你可以轻松的实现IP地址获取和定位. 获取扩展类库 可以在官网的http://www.thinkphp.cn/ ...

  3. javascript之模块加载方案

    前言 主要学习一下四种模块加载规范: AMD CMD CommonJS ES6 模块 历史 前端模块化开发那点历史 require.js requirejs 为全局添加了 define 函数,你只要按 ...

  4. go之map

    一.概念 简述 1.map 是一种无序的键值对的集合.(类似于python的字典dict) 2.map 的key 与 value 都是有类型的,且定义阶段时就已经统一 定义方式 # 方式一 var m ...

  5. Cannot find module 'crc'

    这个时候你只需要打开你nodejs安装的目录,在其中执行 npm install crc(这里查什么模块(module)就安装什么模块).

  6. Go中的main函数和init函数

    Go里面有两个保留的函数:init函数(能够应用于所有的package)和main函数(只能应用于package main).这两个函数在定义时不能有任何的参数和返回值.虽然一个package里面可以 ...

  7. 偶尔遇到的“The request was aborted:Could not create SSL/TLS secure channel.”怎么解决?

    项目中涉及到调用第三方的Https的WebService,我使用的是原始的HttpWebRequest. 代码中已经考虑到是Https,加上了SSL3协议,加上了委托调用.但偶尔还是会碰到 The r ...

  8. php数据库分页

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. dubbo之事件通知

    事件通知 在调用之前.调用之后.出现异常时,会触发 oninvoke.onreturn.onthrow 三个事件,可以配置当事件发生时,通知哪个类的哪个方法 1. 服务提供者与消费者共享服务接口 in ...

  10. myeclipse中代码不显示SVN版本号

    打开 : windows ->preferences->General->Appearance->Lable Decoration s 勾选其中的 SVN 项即可. 如果以上方 ...