【OpenGL】Shader实例分析(五)- 边缘检测

转发请保持地址:http://blog.csdn.net/stalendp/article/details/23139953

这里将介绍基于法线的边缘检测方法,这里的shader是参考官方的:http://wiki.unity3d.com/index.php/Outlined_Diffuse_3;运行效果如下:

代码如下:

 

  1. Shader "Outlined/Diffuse" { // see http://wiki.unity3d.com/index.php/Outlined_Diffuse_3  
  2.     Properties {  
  3.         _Color ("Main Color", Color) = (.5,.5,.5,1)  
  4.         _OutlineColor ("Outline Color", Color) = (0,0,0,1)  
  5.         _Outline ("Outline width", Range (.002, 0.03)) = .005  
  6.         _MainTex ("Base (RGB)", 2D) = "white" { }  
  7.     }  
  8.    
  9.     CGINCLUDE  
  10.     #include "UnityCG.cginc"  
  11.        
  12.     struct appdata {  
  13.         float4 vertex : POSITION;  
  14.         float3 normal : NORMAL;  
  15.     };  
  16.        
  17.     struct v2f {  
  18.         float4 pos : POSITION;  
  19.         float4 color : COLOR;  
  20.     };  
  21.        
  22.     uniform float _Outline;  
  23.     uniform float4 _OutlineColor;  
  24.        
  25.     v2f vert(appdata v) {  
  26.         // just make a copy of incoming vertex data but scaled according to normal direction  
  27.         v2f o;  
  28.         o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
  29.        
  30.         float3 norm   = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);  
  31.         float2 offset = TransformViewToProjection(norm.xy);  
  32.           
  33.         o.pos.xy += offset * o.pos.z * _Outline;  
  34.         // following please refer to : http://unitygems.com/noobs-guide-shaders-6-toon-shader/  
  35.         // o.pos = mul( UNITY_MATRIX_MVP, v.vertex + (float4(v.normal,0) * _Outline));   
  36.         o.color = _OutlineColor;  
  37.         return o;  
  38.     }  
  39.     ENDCG  
  40.    
  41.     SubShader {  
  42.         //Tags {"Queue" = "Geometry+100" }  
  43.         CGPROGRAM  
  44.         #pragma surface surf Lambert  
  45.            
  46.         sampler2D _MainTex;  
  47.         fixed4 _Color;  
  48.            
  49.         struct Input {  
  50.             float2 uv_MainTex;  
  51.         };  
  52.            
  53.         void surf (Input IN, inout SurfaceOutput o) {  
  54.             fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;  
  55.             o.Albedo = c.rgb;  
  56.             o.Alpha = c.a;  
  57.         }  
  58.         ENDCG  
  59.    
  60.         // note that a vertex shader is specified here but its using the one above  
  61.         Pass {  
  62.             Name "OUTLINE"  
  63.             Tags { "LightMode" = "Always" }  
  64.             Cull Front  
  65.             ZWrite On  
  66.             ColorMask RGB  
  67.             Blend SrcAlpha OneMinusSrcAlpha  
  68.             //Offset 50,50  
  69.    
  70.             CGPROGRAM  
  71.             #pragma vertex vert  
  72.             #pragma fragment frag  
  73.             half4 frag(v2f i) :COLOR { return i.color; }  
  74.             ENDCG  
  75.         }  
  76.     }  
  77.    
  78.     SubShader {  
  79.         CGPROGRAM  
  80.         #pragma surface surf Lambert  
  81.            
  82.         sampler2D _MainTex;  
  83.         fixed4 _Color;  
  84.            
  85.         struct Input {  
  86.             float2 uv_MainTex;  
  87.         };  
  88.            
  89.         void surf (Input IN, inout SurfaceOutput o) {  
  90.             fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;  
  91.             o.Albedo = c.rgb;  
  92.             o.Alpha = c.a;  
  93.         }  
  94.         ENDCG  
  95.    
  96.         Pass {  
  97.             Name "OUTLINE"  
  98.             Tags { "LightMode" = "Always" }  
  99.             Cull Front  
  100.             ZWrite On  
  101.             ColorMask RGB  
  102.             Blend SrcAlpha OneMinusSrcAlpha  
  103.    
  104.             CGPROGRAM  
  105.             #pragma vertex vert  
  106.             #pragma exclude_renderers gles xbox360 ps3  
  107.             ENDCG  
  108.             SetTexture [_MainTex] { combine primary }  
  109.         }  
  110.     }  
  111.    
  112.     Fallback "Diffuse"  
  113. }  


原理介绍:

 

分两个pass进行渲染,第一个渲染边框,第二个渲染实物。

1)边框的渲染

在vertex Shader阶段,吧顶点按照法线的方向进行扩展, 这样物体就比原来要膨胀(关于膨胀效果,请参考Surface Shader Example中的Normal Extrusion with Vertex Modifier)。

 

  1. o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
  2. float3 norm   = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);  
  3. float2 offset = TransformViewToProjection(norm.xy);  //计算法线的方向  
  4. o.pos.xy += offset * o.pos.z * _Outline; //按照法线的方向进行偏移  

效果如下:

 

边框盖住里原始物体,这里只要设置只渲染背面,就可以达到效果,在渲染边框的Pass中设置“Cull Front”就可以了。

2)渲染实物

当然这个只是适用于3d物体,图像的边缘检测,还有canny算法等,以后再补充,这里给个Canny的地址:Canny Edge Detection Tutorial

另外一篇:http://en.wikipedia.org/wiki/Edge_detection;  还有: http://en.wikipedia.org/wiki/Canny_edge_detector

关于图像的边缘检测,可以运用在Deferred shading中的anti-aliasing

======

相关的文章:http://unitygems.com/noobs-guide-shaders-6-toon-shader/

Silhouette-Outlined Diffuse

OutlinedDiffuse

Lighted Bumped Outline

基于法线的边缘检测

Code Snippet: Edge Detector/Antialiasing Shader

posted @ 2014-04-18 17:59  酷小卡  阅读(1247)  评论(0编辑  收藏  举报