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

三维应用程序,通过FBO。将3D图像渲染成纹理,然后对渲染成的纹理进行图像处理,终于显示在屏幕上的。是风格化后的图案。上一次我使用了一种普通的图像处理方法:索贝尔边缘检測法,与我们的卡通渲染结合起来,实现了这种效果。接着。我将採用第二种边缘检測方法——普雷维特(Prewitt)边缘检測方法来又一次渲染图案。

蒋彩阳原创文章。首发地址:http://blog.csdn.net/gamesdev/article/details/44405219。

欢迎同行前来探讨。

首先让我们看看上一次的截图:

我们看到,本不应该是边缘的机身部分。因为离散的调色,被索贝尔算子边缘检測一算,也被误觉得是边缘了,同一时候,在背景与机身颜色不明显的部分,也因为採用不适当的阈值,不被觉得是边缘。

所以我想有没有一种方法可以解决问题呢?于是我採取了这个方案:

1、 第一遍的render pass,取的不是卡通着色的颜色图,而是深度图。

2、 将深度图渲染至纹理;

3、 对该纹理进行边缘检測;

4、 与卡通着色的图进行叠加,做成效果图。

怎样在GLSL中将片元的深度信息提取出来?这里我參考了前辈的博客,然后写出了这种GLSL代码:

  1. // Depth.vert
  2. #version 100
  3.  
  4. // Qt 3D默认提供的參数
  5. attribute vec3 vertexPosition;
  6. uniform mat4 modelView;
  7. uniform mat4 mvp;
  8.  
  9. void main( void )
  10. {
  11. gl_Position = mvp * vec4( vertexPosition, 1.0 );
  12. }
  13.  
  14. // Depth.frag
  15. #version 110
  16.  
  17. // 自己提供的參数
  18.  
  19. bool inBetween( float v, float min, float max )
  20. {
  21. return v > min && v < max;
  22. }
  23.  
  24. void main( void )
  25. {
  26. float exp = 256.0;
  27. gl_FragColor = vec4( vec3( pow( gl_FragCoord.z, exp ) ), 1.0);
  28. }

由于gl_FragCoord.z表示的片元深度信息相互之间很接近。我们须要一个指数乘幂操作将这种差别放大,这样才干区分不同的深度的值。

紧接着,我们将Prewitt算子替换掉Sobel算子,终于的着色器代码例如以下:

  1. // Ouput.vert
  2. #version 100
  3.  
  4. // Qt 3D默认提供的參数
  5. attribute vec4 vertexPosition;
  6. uniform mat4 modelMatrix;
  7.  
  8. // 自己提供的參数
  9.  
  10. void main( void )
  11. {
  12. gl_Position = modelMatrix * vertexPosition;
  13. }
  14.  
  15. // Output.frag
  16. #version 100
  17.  
  18. // 自己提供的參数
  19. uniform sampler2D colorAttachTex;
  20. //uniform sampler2D depthAttachTex;
  21. uniform vec2 texSize;
  22. uniform float texOffsetX;
  23. uniform float texOffsetY;
  24.  
  25. float gray( vec4 color )
  26. {
  27. return dot( color.xyz, vec3( 0.299, 0.587, 0.114 ) );
  28. }
  29.  
  30. void main( void )
  31. {
  32. vec4 texColor[9];
  33. texColor[0] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( -texOffsetX, texOffsetY ) );
  34. texColor[1] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( 0.0, -texOffsetY ) );
  35. texColor[2] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( texOffsetX, texOffsetY ) );
  36. texColor[3] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( -texOffsetX, 0 ) );
  37. texColor[4] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( 0.0, 0.0 ) );
  38. texColor[5] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( texOffsetX, 0 ) );
  39. texColor[6] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( -texOffsetX, -texOffsetY ) );
  40. texColor[7] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( 0.0, -texOffsetY ) );
  41. texColor[8] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( texOffsetX, -texOffsetY ) );
  42.  
  43. // 普雷维特算子
  44. float prewitt_x[9];
  45. prewitt_x[0] = -1.0;
  46. prewitt_x[1] = 0.0;
  47. prewitt_x[2] = 1.0;
  48. prewitt_x[3] = -1.0;
  49. prewitt_x[4] = 0.0;
  50. prewitt_x[5] = 1.0;
  51. prewitt_x[6] = -1.0;
  52. prewitt_x[7] = 0.0;
  53. prewitt_x[8] = 1.0;
  54.  
  55. float prewitt_y[9];
  56. prewitt_y[0] = 1.0;
  57. prewitt_y[1] = 1.0;
  58. prewitt_y[2] = 1.0;
  59. prewitt_y[3] = 0.0;
  60. prewitt_y[4] = 0.0;
  61. prewitt_y[5] = 0.0;
  62. prewitt_y[6] = -1.0;
  63. prewitt_y[7] = -1.0;
  64. prewitt_y[8] = -1.0;
  65.  
  66. // 卷积操作
  67. vec4 edgeX = vec4( 0.0 );
  68. vec4 edgeY = vec4( 0.0 );
  69. for ( int i = 0; i < 9; ++i )
  70. {
  71. edgeX += texColor[i] * prewitt_x[i];
  72. edgeY += texColor[i] * prewitt_y[i];
  73. }
  74.  
  75. vec4 edgeColor = sqrt( ( edgeX * edgeX ) + ( edgeY * edgeY ) );
  76. float edgeIntensity = gray( edgeColor );
  77. const float threshold = 0.05;
  78.  
  79. if ( edgeIntensity > threshold )
  80. gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
  81. else discard;
  82. }

因为代码相对较长,我必须把来github在。

有需要的同行和朋友,从能github有资格代替代码。

地址:这里

Qt 3D研究(九):尝试第二边缘检测方法的更多相关文章

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

    Qt 3D的研究(十):描边渲染(轮廓渲染)以及Silhouette Shader 之前写了两篇文章,介绍了我在边缘检測上面的研究.实际上.使用GPU对渲染图像进行边缘检測.前提是须要进行两遍渲染.前 ...

  2. Qt中中文字符 一劳永逸的解决方法

    QT中中文字符问题,有没有一劳永逸的解决方法? 目前遇到有以下问题 1.字符串中有中文时,编译提示"常量中含有换行符" 2.在控制台窗口输出中文时无法正常显示,中文全部显示为? 目 ...

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

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

  4. Unity 3D游戏开发学习路线(方法篇)

    Unity 3D本来是由德国的一些苹果粉丝开发的一款游戏引擎,一直只能用于Mac平台,所以一直不被业外人士所知晓.但是后来也推出了2.5版,同时发布了PC版本,并将其发布方向拓展到手持移动设备.Uni ...

  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. 修改Chem 3D模型的化学键属性的方法有哪些

    很多的用户在绘制化学图形过程中发现很多的图形都是立体结构的,这个时候就需要用Chem3D,它是ChemOffice的核心组件之一,在绘制立体模型和计算化学数据方面具有不可替代的作用.虽然ChemDra ...

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

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

  8. monkey工具使用中遇到的问题之二:尝试了各种方法通过adb都无法找到设备

    测试环境: 1.用的是adt-bundle-windows-x86_64-20140702里面的adb 2.用的是手机模拟器(夜神) 问题描述: 已搭建好adb的环境,输入adb,可以看到以下相关信息 ...

  9. ios更新UI时请尝试使用performSelectorOnMainThread方法

    最近开发项目时发现联网获取到数据后,使用通知方式让列表刷新会存在死机的问题. 经过上网查找很多文章,都建议使用异步更新的方式,可是依然崩溃. 最后尝试使用performSelectorOnMainTh ...

随机推荐

  1. Android读取网络图片

    本文是自己学习所做笔记,欢迎转载,但请注明出处:http://blog.csdn.net/jesson20121020 在android4.0之后,已不同意在主线程中进行网络请求操作了, 否则会出现N ...

  2. THashMD5,THashSHA1,THashBobJenkins,TIdHashMessageDigest5的用法

    [delphi] view plain copy unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils ...

  3. android怎样查看当前project哪些profile是打开的

    代码project里面有三仅仅文件都是涉及到各个profile的宏的,各自是:featureoption.java.common/ProjectConfig.mk.product/ProjectCon ...

  4. make 2>&1 | tee log.txt之小析

    前言 接触过linux的人,或多或少都会了解一点make 2>&1 | tee log.txt这个命令. 1. make是什么? make是linux下一个非常强大的命令,简单点就是你要 ...

  5. 给一个非常长的字符串str 另一个字符集比方{a,b,c} 找出str 里包括{a,b,c}的最短子串。要求O(n)

    给一个非常长的字符串str 另一个字符集比方{a,b,c} 找出str 里包括{a,b,c}的最短子串.要求O(n). 比方,字符集是a,b,c,字符串是abdcaabcx,则最短子串为abc. 设置 ...

  6. 知识网之C++总结

    米老师常说的一句话:构造知识网. 立即要考试了.就让我们构造一下属于C++的知识网.首先从总体上了解C++: 从图中能够了解到,主要有五部分.而当我们和之前的知识联系的话,也就剩下模板和运算符重载以及 ...

  7. python语言学习8——字符串和编码

    Unicode编码 计算机只能处理数字,如果要处理文本,就必须把文本转化为数字才能处理 有许多编码标准,但是不同的编码标准有时候会混乱,所以Unicode应运而生 Unicode把所有语言统一到一套编 ...

  8. [置顶] think in java interview-高级开发人员面试宝典(七)

    上两周研发任务太紧了,所以担搁了一下,我们继续我们的面试之旅. 下面是一个基于图书系统的15道SQL问答,供大家参考 问题描述:本题用到下面三个关系表:CARD     借书卡.   CNO 卡号,N ...

  9. 《算法导论》 — Chapter 7 高速排序

    序 高速排序(QuickSort)也是一种排序算法,对包括n个数组的输入数组.最坏情况执行时间为O(n^2). 尽管这个最坏情况执行时间比較差.可是高速排序一般是用于排序的最佳有用选择.这是由于其平均 ...

  10. Nginx 进程间通信

    Linux下的IPC非常多,nginx的进程都是有亲缘关系的进程,对于他们的通信我们选择TCP socket进行通信.   TCP socket 用来做进程通信的优点有,   1.socket是文件描 ...