当前位置:   article > 正文

Unity HDRP Custom Pass (Post processing) 后处理特效学习(二)总结

hdrp custompass

目录

B站视频

B站视频,录制不易,求关注、一键三连(点赞、投币、收藏)。置顶评论内有PPT(内有优秀参考资源链接)、工程、插件、群号。

官方社区

文字版总结,编写不易,求关注、点赞。手机版阅读困难的,记得是在电脑浏览器中查看 开发者社区

分享背景

突然开始做分享主要2个原因。
  • 有朋友和我说Unity是不是只是手游引擎呀,UE能做的Unity能不能做呀,恰巧看到虚幻官方月神的直播讲后处理,所以就试着也录一期Unity的,证明Unity并不只是手游引擎。
  • 最近被一个Unity官方合作的知名博主up主麦扣的群里的管理员傲娇修酒z侮辱了,发现如果没有粉丝,被人侮辱的时候甚至没有人帮我说话,所以希望吸引一些愿意帮我说话的粉丝。除非麦扣把侮辱人的管理员踢掉,否则这事情永远不会揭过。
另外这可能不是最好的分享,但是绝对是最详细的分享,不会不求甚解的去分享一些一眼就能看明白的东西。

感谢

首先要感谢一下叶月葵(Hazukiaoi),没有他,无法制作这系列视频和分享。

上一期有更新

上一期有更新,补充了很多内容和配图,务必重新阅读一遍。 Unity HDRP Custom Pass (Post processing) 后处理特效学习(一)总结

屏幕尺寸 _ScreenSize

屏幕尺寸_ScreenSize是一个float4,内容分别是(W,H,1/W,1/H)。W和H很好理解,就是屏幕宽高。那么1/W和1/H是什么用途的呢?可以回想上一期视频和分享中提到的PositionInput结构体中的positionNDC跟positionSS,_ScreenSize主要用于这两个坐标之间的转换。
  1. positionNDC
  2. =
  3. positionSS
  4. *
  5. _ScreenSize
  6. .
  7. zw
  8. ;
  9. positionSS
  10. =
  11. positionNDC
  12. *
  13. _ScreenSize
  14. .
  15. xy
  16. ;

ddx/ddy

ddx

返回指定值相对于屏幕空间x坐标的偏导数。

ddy

返回指定值相对于屏幕空间y座标的偏导数。

计算方法

在三角形光栅化过程中,GPU一次运行许多片段着色器的实例,将它们组织成2×2像素的块。dFdx是将块中像素值的差值减去块左侧的像素值和右侧的像素值,dFdy是将底部像素的值减去顶部像素的值。请看下面的图片,其中网格表示渲染的屏幕像素,dFdx、dFdy表达式是为由片段着色器实例在(x、y)屏幕坐标处计算的通用值p提供的,属于2×2块的红色高亮显示的2×2块。导数可以对片段着色器中的每个变量进行计算。 对于向量和矩阵类型,导数是按元素计算的。
值得注意的是图上是以glsl中的dFdx和dFdy进行讲解,实际上Unity中使用的是hlsl中的ddx和ddy,并且是以左下角为坐标原点。其次,既然ddx和ddy是像图中一样,ddx(p(x,y))=p(x+1,y)-p(x,y),ddy(p(x,y))=p(x,y+1)-p(x,y)。对于显卡内部计算这个2x2块,并不知道旁边的2x2块的数据,那么他是怎么计算ddx(p(x+1,y))、ddx(p(x,y+1))、ddx(p(x+1,y+1))、ddy(p(x+1,y))、ddy(p(x,y+1))、ddy(p(x+1,y+1))的呢?
怀着这个疑问,进行了测试与探讨,最终得出结论,2x2块中,4个像素的ddx共享一个值,4个像素的ddy共享一个值。ddx只与p(x,y)、p(x+1,y)有关,ddy只与p(x,y)、p(x,y+1)有关。无论ddx与ddy都与p(x+1,y+1)无关。
可以自行查看工程中的CheckDDX场景进行验证,下面有些截图证明这个结论。
从上面几张图,可以看出,ddx跟左下p(x,y),右下p(x+1,y)有关,跟左上p(x,y+1),右上p(x+1,y+1)无关。看颜色变化,输出的是ddx的值。
从上面几张图,可以看出,ddy跟左下p(x,y),左上p(x,y+1)有关,跟右下p(x+1,y),右上p(x+1,y+1)无关。看颜色变化,输出的是ddy的值。
从上面几张图,可以看出,ddx ddy都跟右上右上p(x+1,y+1)无关。
那为什么一定要搞明白这个ddx和ddy的计算方式呢?那是因为后面介绍的第一种最简单的勾边方式,就是使用ddx、ddy对设备深度、线性深度、世界法线计算来达到勾边的目的。但是你会发现ddx和ddy的方式勾边会有断线的情况,其实这个就是因为这个4个像素共享ddx ddy值导致的,所以如果真的用ddx、ddy进行勾边,一般还会加上一个TAA的抗锯齿。

abs

返回指定值的绝对值。

clamp/saturate

clamp

将指定的值夹在指定的最小和最大范围内。

saturate

将指定的值夹在0到1的范围内。如果你是要夹在0到1的之间的话,应该使用saturate,他基本上是一个硬件级别的函数,几乎无消耗。

使用ddx、ddy进行勾边

使用设备深度

可以看到,简单的使用ddx、ddy就能做到一个简单的勾边。
首先来说计算方法,计算方法就是对设备深度数据进行了ddx、ddy计算后取绝对值相加,然后再通过saturate去把数值夹在0-1之间。
那么再来说说原理,原理就是ddx对ddy分别对每个像素对x、y计算偏导数,得到变化率,变化率高的地方代表设备深度差异大,是边缘。
那么,为什么表面会有亮面一样的效果呢?因为平面并不是平行于摄像机平面,有深度差异,所以变化率并不是0,因此会有微光,如果想去掉可以用后面介绍手动计算勾边的方法里的Contrast方法来增强对比度的方式来去除这些微光。
最后,来说说为什么断线,相信你阅读了前面的分享,你应该已经明白ddx和ddy是2x2块里4个像素共享ddx和ddy的值,因此,除了左下的像素,另外3个像素计算变化率的结果是不准确的,这就是造成断线的原因。
后续在介绍如何手动计算勾边的方法,再介绍如何与原场景融合。
  1. // ddx & ddy outline by device depth
  2. md
  3. =
  4. posInput
  5. .
  6. deviceDepth
  7. *
  8. 1000
  9. ;
  10. finalColor
  11. =
  12. abs
  13. (
  14. ddx
  15. (
  16. md
  17. )
  18. )
  19. +
  20. abs
  21. (
  22. ddy
  23. (
  24. md
  25. )
  26. )
  27. ;
  28. finalColor
  29. =
  30. saturate
  31. (
  32. finalColor
  33. )
  34. ;

使用线性深度

同样的,用相同的原理,通过线性深度使用ddx、ddy做到了一个简单的勾边。
  1. // ddx & ddy outline by linear depth
  2. md
  3. =
  4. posInput
  5. .
  6. linearDepth
  7. *
  8. 10
  9. ;
  10. finalColor
  11. =
  12. abs
  13. (
  14. ddx
  15. (
  16. md
  17. )
  18. )
  19. +
  20. abs
  21. (
  22. ddy
  23. (
  24. md
  25. )
  26. )
  27. ;
  28. finalColor
  29. =
  30. saturate
  31. (
  32. finalColor
  33. )
  34. ;

使用世界法线

同样的,用相同的原理,通过世界法线使用ddx、ddy做到了一个简单的勾边。
那么为什么地上有种脏脏的感觉呢,为什么都被勾上了弱边呢?那是因为地面是凹凸不平的发现,法线变化率有弱小变化。同样的,可以通过后面介绍手动计算勾边的方法里的Contrast方法来增强对比度的方式来去除这些弱边。

distance

返回两个向量之间的距离标量。

lerp

进行线性插值。

max

选择x和y中的较大者。

Contrast

((valueInput - 0.5f) * contrastInput) + 0.5f;
通过简单数值计算,达到增大或者降低对比度的目的。valueInput为原始值,contrastInput为缩放洗漱。
  1. float
  2. Contrast
  3. (
  4. float
  5. contrastInput
  6. ,
  7. float
  8. valueInput
  9. )
  10. {
  11. return
  12. (
  13. (
  14. valueInput
  15. -
  16. 0.5f
  17. )
  18. *
  19. contrastInput
  20. )
  21. +
  22. 0.5f
  23. ;
  24. }

手动计算进行勾边

使用世界法线

我们先来看整段代码,首先这个方法原理上跟ddx和ddy的方式类似,不一样的是,他并不会像ddx、ddy那样2x2块里的4个像素都共享一个值,而是每个像素都会单独计算。
  1. // offset outline by world normal
  2. linearDepth
  3. =
  4. posInput
  5. .
  6. linearDepth
  7. ;
  8. outlineWidth
  9. =
  10. _OutlineWidth
  11. ;
  12. outlineWidth
  13. =
  14. saturate
  15. (
  16. 1
  17. -
  18. linearDepth
  19. /
  20. 1000
  21. )
  22. *
  23. outlineWidth
  24. ;
  25. NormalData
  26. normalData0
  27. ;
  28. NormalData
  29. normalData1
  30. ;
  31. NormalData
  32. normalData2
  33. ;
  34. DecodeFromNormalBuffer
  35. (
  36. posInput
  37. .
  38. positionSS
  39. ,
  40. normalData0
  41. )
  42. ;
  43. DecodeFromNormalBuffer
  44. (
  45. posInput
  46. .
  47. positionSS
  48. +
  49. float2
  50. (
  51. outlineWidth
  52. ,
  53. 0
  54. )
  55. ,
  56. normalData1
  57. )
  58. ;
  59. DecodeFromNormalBuffer
  60. (
  61. posInput
  62. .
  63. positionSS
  64. +
  65. float2
  66. (
  67. 0
  68. ,
  69. outlineWidth
  70. )
  71. ,
  72. normalData2
  73. )
  74. ;
  75. distanceXNormal
  76. =
  77. distance
  78. (
  79. normalData0
  80. .
  81. normalWS
  82. ,
  83. normalData1
  84. .
  85. normalWS
  86. )
  87. ;
  88. distanceYNormal
  89. =
  90. distance
  91. (
  92. normalData0
  93. .
  94. normalWS
  95. ,
  96. normalData2
  97. .
  98. normalWS
  99. )
  100. ;
  101. distanceSumNormal
  102. =
  103. distanceXNormal
  104. +
  105. distanceYNormal
  106. ;
  107. distanceSumNormal
  108. =
  109. distanceSumNormal
  110. /
  111. _DivideFactor
  112. ;
  113. distanceSum
  114. =
  115. distanceSumNormal
  116. ;
  117. distanceSum
  118. =
  119. distanceSum
  120. /
  121. _DivideFactor
  122. ;
  123. distanceSum
  124. =
  125. Contrast
  126. (
  127. _ContrastInput
  128. ,
  129. distanceSum
  130. )
  131. ;
  132. distanceSum
  133. =
  134. saturate
  135. (
  136. distanceSum
  137. )
  138. ;
  139. finalColor
  140. =
  141. lerp
  142. (
  143. color
  144. ,
  145. _OutlineColor
  146. ,
  147. distanceSum
  148. )
  149. ;
  150. //finalColor = color + distanceSum * _OutlineColor;
与ddx、ddy不同的是,ddx、ddy只能跟旁边一个像素对比,自己写的话,可以与偏移好几个像素的进行对比。那么你可以控制勾边的宽度。
  1. linearDepth
  2. =
  3. posInput
  4. .
  5. linearDepth
  6. ;
  7. outlineWidth
  8. =
  9. _OutlineWidth
  10. ;
  11. outlineWidth
  12. =
  13. saturate
  14. (
  15. 1
  16. -
  17. linearDepth
  18. /
  19. 1000
  20. )
  21. *
  22. outlineWidth
  23. ;
那么我们先来看前三行代码,这里的目的是根据远近来控制勾边的宽度。我们这里先获取线性深度。然后,我们给outlineWidth赋值一个初值_OutlineWidth,这是shader定义的属性,可以方便我们通过材质进行控制勾边的宽度。最后,我们的Near是0.3,Far是1000,那么linearDepth/1000可以计算出与我们的远近比例。最近的为0.3/1000=0.0003,最远为1000/1000=1。那么(1-linearDepth/1000)就变成了最近的是0.9997,最远的是0。这里采用saturate是你可以Far设置1000以上,那么通过saturate可以压回到0到1之间,不会导致有负数的勾边的宽度,这里再乘以初始的勾边的宽度,达到近处勾边粗,远处勾边细的目的。
  1. NormalData
  2. normalData0
  3. ;
  4. NormalData
  5. normalData1
  6. ;
  7. NormalData
  8. normalData2
  9. ;
  10. DecodeFromNormalBuffer
  11. (
  12. posInput
  13. .
  14. positionSS
  15. ,
  16. normalData0
  17. )
  18. ;
  19. DecodeFromNormalBuffer
  20. (
  21. posInput
  22. .
  23. positionSS
  24. +
  25. float2
  26. (
  27. outlineWidth
  28. ,
  29. 0
  30. )
  31. ,
  32. normalData1
  33. )
  34. ;
  35. DecodeFromNormalBuffer
  36. (
  37. posInput
  38. .
  39. positionSS
  40. +
  41. float2
  42. (
  43. 0
  44. ,
  45. outlineWidth
  46. )
  47. ,
  48. normalData2
  49. )
  50. ;
接下来我们读取p(x,y)、p(x+oultineWidth,y),p(x,y+outlineWidth)的法线数据,用于后续的对比。
  1. distanceXNormal
  2. =
  3. distance
  4. (
  5. normalData0
  6. .
  7. normalWS
  8. ,
  9. normalData1
  10. .
  11. normalWS
  12. )
  13. ;
  14. distanceYNormal
  15. =
  16. distance
  17. (
  18. normalData0
  19. .
  20. normalWS
  21. ,
  22. normalData2
  23. .
  24. normalWS
  25. )
  26. ;
由于法线是float3的向量,因此这里采取最简单的对比方式,通过distance对比两个向量的距离标量,达到计算变化率的目的。
  1. distanceSumNormal
  2. =
  3. distanceXNormal
  4. +
  5. distanceYNormal
  6. ;
把x跟y的变化率相加,类似ddx、ddy方式里面的计算方式。
  1. distanceSum
  2. =
  3. distanceSumNormal
  4. ;
  5. distanceSum
  6. =
  7. distanceSum
  8. /
  9. _DivideFactor
  10. ;
  11. distanceSum
  12. =
  13. Contrast
  14. (
  15. _ContrastInput
  16. ,
  17. distanceSum
  18. )
  19. ;
  20. distanceSum
  21. =
  22. saturate
  23. (
  24. distanceSum
  25. )
  26. ;
  27. //color = float4(0,0,0,1);
  28. finalColor
  29. =
  30. lerp
  31. (
  32. color
  33. ,
  34. _OutlineColor
  35. ,
  36. distanceSum
  37. )
  38. ;
类似_OulineWidth,我们给一个_DivideFacter的shader属性,因为距离最大可能是2,通过控制_DivideFactor来达到控制勾线强度的目的。用Contrast函数控制对比度,达到把法线导致的脏脏的弱小勾边去除。最后,通过saturate,把值压回到0到1之间。最后,通过lerp在场景颜色和_OutlineColor勾边的颜色之间进行线性差值,达到在原场景颜色上勾边的效果。我们为了观察方便,先把_DivideFactor和_ContrastInput都设置回1,通过去掉color的那行注释可以看到初始勾边效果。 仔细查看,你可以发现工作台上的木棍,上方的勾边没了,那是因为木棍表面刚好平行地面,法线一致,distance为0。所以没能勾出来边,可以通过用设备深度勾边或者混合使用世界法线、设备深度勾边来解决。其次,地面有脏脏的效果,这里,可以通过调节_ContrastInput来增大对比度达到去除这个因为地面呕吐不平法线导致的微小勾边的脏脏的效果去掉。 可以根据场景需要自由调节_ContrastInput和_DivideFactor的值来控制勾边效果。把color那行注释,可以在原场景颜色上勾边了。 除了lerp的勾边方式,还可以使用加法的方式进行勾边,能提亮的效果。
  1. finalColor
  2. =
  3. color
  4. +
  5. distanceSum
  6. *
  7. _OutlineColor
  8. ;

使用线性深度

我们先来看整段代码,首先这个方法和上面使用世界法线不一样的是使用的是设备深度。
  1. // offset outline by device depth
  2. linearDepth
  3. =
  4. posInput
  5. .
  6. linearDepth
  7. ;
  8. outlineWidth
  9. =
  10. _OutlineWidth
  11. ;
  12. outlineWidth
  13. =
  14. saturate
  15. (
  16. 1
  17. -
  18. linearDepth
  19. /
  20. 10000
  21. )
  22. *
  23. outlineWidth
  24. ;
  25. float2
  26. positionCS0
  27. =
  28. varyings
  29. .
  30. positionCS
  31. .
  32. xy
  33. ;
  34. float
  35. depth0
  36. =
  37. LoadCameraDepth
  38. (
  39. positionCS0
  40. )
  41. ;
  42. PositionInputs
  43. posInput0
  44. =
  45. GetPositionInput
  46. (
  47. positionCS0
  48. ,
  49. _ScreenSize
  50. .
  51. zw
  52. ,
  53. depth
  54. ,
  55. UNITY_MATRIX_I_VP
  56. ,
  57. UNITY_MATRIX_V
  58. )
  59. ;
  60. float2
  61. positionCS1
  62. =
  63. varyings
  64. .
  65. positionCS
  66. .
  67. xy
  68. +
  69. float2
  70. (
  71. outlineWidth
  72. ,
  73. 0
  74. )
  75. ;
  76. float
  77. depth1
  78. =
  79. LoadCameraDepth
  80. (
  81. positionCS1
  82. )
  83. ;
  84. PositionInputs
  85. posInput1
  86. =
  87. GetPositionInput
  88. (
  89. positionCS1
  90. ,
  91. _ScreenSize
  92. .
  93. zw
  94. ,
  95. depth1
  96. ,
  97. UNITY_MATRIX_I_VP
  98. ,
  99. UNITY_MATRIX_V
  100. )
  101. ;
  102. float2
  103. positionCS2
  104. =
  105. varyings
  106. .
  107. positionCS
  108. .
  109. xy
  110. +
  111. float2
  112. (
  113. 0
  114. ,
  115. outlineWidth
  116. )
  117. ;
  118. float
  119. depth2
  120. =
  121. LoadCameraDepth
  122. (
  123. positionCS2
  124. )
  125. ;
  126. PositionInputs
  127. posInput2
  128. =
  129. GetPositionInput
  130. (
  131. positionCS2
  132. ,
  133. _ScreenSize
  134. .
  135. zw
  136. ,
  137. depth2
  138. ,
  139. UNITY_MATRIX_I_VP
  140. ,
  141. UNITY_MATRIX_V
  142. )
  143. ;
  144. distanceXDepth
  145. =
  146. distance
  147. (
  148. posInput0
  149. .
  150. linearDepth
  151. ,
  152. posInput1
  153. .
  154. linearDepth
  155. )
  156. ;
  157. distanceYDepth
  158. =
  159. distance
  160. (
  161. posInput0
  162. .
  163. linearDepth
  164. ,
  165. posInput2
  166. .
  167. linearDepth
  168. )
  169. ;
  170. distanceSumDepth
  171. =
  172. distanceXDepth
  173. +
  174. distanceYDepth
  175. ;
  176. distanceSum
  177. =
  178. distanceSumDepth
  179. ;
  180. distanceSum
  181. =
  182. distanceSum
  183. /
  184. _DivideFactor
  185. ;
  186. distanceSum
  187. =
  188. Contrast
  189. (
  190. _ContrastInput
  191. ,
  192. distanceSum
  193. )
  194. ;
  195. distanceSum
  196. =
  197. saturate
  198. (
  199. distanceSum
  200. )
  201. ;
  202. //color = float4(0,0,0,1);
  203. finalColor
  204. =
  205. lerp
  206. (
  207. color
  208. ,
  209. _OutlineColor
  210. ,
  211. distanceSum
  212. )
  213. ;
  214. //finalColor = color + distanceSum * _OutlineColor;
接下来具体看看计算的方法。
  1. float2
  2. positionCS0
  3. =
  4. varyings
  5. .
  6. positionCS
  7. .
  8. xy
  9. ;
  10. float
  11. depth0
  12. =
  13. LoadCameraDepth
  14. (
  15. positionCS0
  16. )
  17. ;
  18. PositionInputs
  19. posInput0
  20. =
  21. GetPositionInput
  22. (
  23. positionCS0
  24. ,
  25. _ScreenSize
  26. .
  27. zw
  28. ,
  29. depth
  30. ,
  31. UNITY_MATRIX_I_VP
  32. ,
  33. UNITY_MATRIX_V
  34. )
  35. ;
  36. float2
  37. positionCS1
  38. =
  39. varyings
  40. .
  41. positionCS
  42. .
  43. xy
  44. +
  45. float2
  46. (
  47. outlineWidth
  48. ,
  49. 0
  50. )
  51. ;
  52. float
  53. depth1
  54. =
  55. LoadCameraDepth
  56. (
  57. positionCS1
  58. )
  59. ;
  60. PositionInputs
  61. posInput1
  62. =
  63. GetPositionInput
  64. (
  65. positionCS1
  66. ,
  67. _ScreenSize
  68. .
  69. zw
  70. ,
  71. depth1
  72. ,
  73. UNITY_MATRIX_I_VP
  74. ,
  75. UNITY_MATRIX_V
  76. )
  77. ;
  78. float2
  79. positionCS2
  80. =
  81. varyings
  82. .
  83. positionCS
  84. .
  85. xy
  86. +
  87. float2
  88. (
  89. 0
  90. ,
  91. outlineWidth
  92. )
  93. ;
  94. float
  95. depth2
  96. =
  97. LoadCameraDepth
  98. (
  99. positionCS2
  100. )
  101. ;
  102. PositionInputs
  103. posInput2
  104. =
  105. GetPositionInput
  106. (
  107. positionCS2
  108. ,
  109. _ScreenSize
  110. .
  111. zw
  112. ,
  113. depth2
  114. ,
  115. UNITY_MATRIX_I_VP
  116. ,
  117. UNITY_MATRIX_V
  118. )
  119. ;
前三行跟使用世界法线的方法一样,略过。同理,这里读取p(x,y)、p(x+oultineWidth,y),p(x,y+outlineWidth)的设备深度,用于后续的对比。
  1. distanceXDepth
  2. =
  3. distance
  4. (
  5. posInput0
  6. .
  7. linearDepth
  8. ,
  9. posInput1
  10. .
  11. linearDepth
  12. )
  13. ;
  14. distanceYDepth
  15. =
  16. distance
  17. (
  18. posInput0
  19. .
  20. linearDepth
  21. ,
  22. posInput2
  23. .
  24. linearDepth
  25. )
  26. ;
类似的通过distance方式获得变化率。
  1. distanceSumNormal
  2. =
  3. distanceXNormal
  4. +
  5. distanceYNormal
  6. ;
类似的把x跟y的变化率相加。
  1. distanceSum
  2. =
  3. distanceSumDepth
  4. ;
  5. distanceSum
  6. =
  7. distanceSum
  8. /
  9. _DivideFactor
  10. ;
  11. distanceSum
  12. =
  13. Contrast
  14. (
  15. _ContrastInput
  16. ,
  17. distanceSum
  18. )
  19. ;
  20. distanceSum
  21. =
  22. saturate
  23. (
  24. distanceSum
  25. )
  26. ;
  27. //color = float4(0,0,0,1);
  28. finalColor
  29. =
  30. lerp
  31. (
  32. color
  33. ,
  34. _OutlineColor
  35. ,
  36. distanceSum
  37. )
  38. ;
最后通过类似的方式把颜色附加到场景颜色中去。我们为了观察方便,先把_DivideFactor和_ContrastInput都设置回1,通过去掉color的那行注释可以看到初始勾边效果。 仔细查看,你可以发现工作台上的木棍,棱角上的边没了,因为这是通过深度来求变化率,对于棱角法线变化率大的地方,深度变化并不大。其次,地面有发光的效果,在ddx、ddy中使用的深度的方法中已经解释过了。这里,可以通过调节_ContrastInput来增大对比度达到去除这个发光效果。 可以根据场景需要自由调节_ContrastInput和_DivideFactor的值来控制勾边效果。把color那行注释,可以在原场景颜色上勾边了。 类似除了lerp的勾边方式,还可以使用加法的方式进行勾边,能提亮的效果。
  1. finalColor
  2. =
  3. color
  4. +
  5. distanceSum
  6. *
  7. _OutlineColor
  8. ;

使用混合世界法线、设备深度

我们先来看整段代码,这个方法兼顾了世界法线和设备深度,可以在法线变化大和深度变化大的地方同时勾上边。
  1. // offset outline by world normal
  2. linearDepth
  3. =
  4. posInput
  5. .
  6. linearDepth
  7. ;
  8. outlineWidth
  9. =
  10. _OutlineWidth
  11. ;
  12. outlineWidth
  13. =
  14. saturate
  15. (
  16. 1
  17. -
  18. linearDepth
  19. /
  20. 1000
  21. )
  22. *
  23. outlineWidth
  24. ;
  25. NormalData
  26. normalData0
  27. ;
  28. NormalData
  29. normalData1
  30. ;
  31. NormalData
  32. normalData2
  33. ;
  34. DecodeFromNormalBuffer
  35. (
  36. posInput
  37. .
  38. positionSS
  39. ,
  40. normalData0
  41. )
  42. ;
  43. DecodeFromNormalBuffer
  44. (
  45. posInput
  46. .
  47. positionSS
  48. +
  49. float2
  50. (
  51. outlineWidth
  52. ,
  53. 0
  54. )
  55. ,
  56. normalData1
  57. )
  58. ;
  59. DecodeFromNormalBuffer
  60. (
  61. posInput
  62. .
  63. positionSS
  64. +
  65. float2
  66. (
  67. 0
  68. ,
  69. outlineWidth
  70. )
  71. ,
  72. normalData2
  73. )
  74. ;
  75. distanceXNormal
  76. =
  77. distance
  78. (
  79. normalData0
  80. .
  81. normalWS
  82. ,
  83. normalData1
  84. .
  85. normalWS
  86. )
  87. ;
  88. distanceYNormal
  89. =
  90. distance
  91. (
  92. normalData0
  93. .
  94. normalWS
  95. ,
  96. normalData2
  97. .
  98. normalWS
  99. )
  100. ;
  101. distanceSumNormal
  102. =
  103. distanceXNormal
  104. +
  105. distanceYNormal
  106. ;
  107. // offset outline by device depth
  108. linearDepth
  109. =
  110. posInput
  111. .
  112. linearDepth
  113. ;
  114. outlineWidth
  115. =
  116. _OutlineWidth
  117. ;
  118. outlineWidth
  119. =
  120. saturate
  121. (
  122. 1
  123. -
  124. linearDepth
  125. /
  126. 10000
  127. )
  128. *
  129. outlineWidth
  130. ;
  131. float2
  132. positionCS0
  133. =
  134. varyings
  135. .
  136. positionCS
  137. .
  138. xy
  139. ;
  140. float
  141. depth0
  142. =
  143. LoadCameraDepth
  144. (
  145. positionCS0
  146. )
  147. ;
  148. PositionInputs
  149. posInput0
  150. =
  151. GetPositionInput
  152. (
  153. positionCS0
  154. ,
  155. _ScreenSize
  156. .
  157. zw
  158. ,
  159. depth
  160. ,
  161. UNITY_MATRIX_I_VP
  162. ,
  163. UNITY_MATRIX_V
  164. )
  165. ;
  166. float2
  167. positionCS1
  168. =
  169. varyings
  170. .
  171. positionCS
  172. .
  173. xy
  174. +
  175. float2
  176. (
  177. outlineWidth
  178. ,
  179. 0
  180. )
  181. ;
  182. float
  183. depth1
  184. =
  185. LoadCameraDepth
  186. (
  187. positionCS1
  188. )
  189. ;
  190. PositionInputs
  191. posInput1
  192. =
  193. GetPositionInput
  194. (
  195. positionCS1
  196. ,
  197. _ScreenSize
  198. .
  199. zw
  200. ,
  201. depth1
  202. ,
  203. UNITY_MATRIX_I_VP
  204. ,
  205. UNITY_MATRIX_V
  206. )
  207. ;
  208. float2
  209. positionCS2
  210. =
  211. varyings
  212. .
  213. positionCS
  214. .
  215. xy
  216. +
  217. float2
  218. (
  219. 0
  220. ,
  221. outlineWidth
  222. )
  223. ;
  224. float
  225. depth2
  226. =
  227. LoadCameraDepth
  228. (
  229. positionCS2
  230. )
  231. ;
  232. PositionInputs
  233. posInput2
  234. =
  235. GetPositionInput
  236. (
  237. positionCS2
  238. ,
  239. _ScreenSize
  240. .
  241. zw
  242. ,
  243. depth2
  244. ,
  245. UNITY_MATRIX_I_VP
  246. ,
  247. UNITY_MATRIX_V
  248. )
  249. ;
  250. distanceXDepth
  251. =
  252. distance
  253. (
  254. posInput0
  255. .
  256. linearDepth
  257. ,
  258. posInput1
  259. .
  260. linearDepth
  261. )
  262. ;
  263. distanceYDepth
  264. =
  265. distance
  266. (
  267. posInput0
  268. .
  269. linearDepth
  270. ,
  271. posInput2
  272. .
  273. linearDepth
  274. )
  275. ;
  276. distanceSumDepth
  277. =
  278. distanceXDepth
  279. +
  280. distanceYDepth
  281. ;
  282. distanceSum
  283. =
  284. _NormalFactor
  285. *
  286. distanceSumNormal
  287. +
  288. (
  289. 1
  290. -
  291. _NormalFactor
  292. )
  293. *
  294. distanceSumDepth
  295. ;
  296. //distanceSum = max(distanceSumDepth, distanceSumNormal);
  297. distanceSum
  298. =
  299. distanceSum
  300. /
  301. _DivideFactor
  302. ;
  303. distanceSum
  304. =
  305. Contrast
  306. (
  307. _ContrastInput
  308. ,
  309. distanceSum
  310. )
  311. ;
  312. distanceSum
  313. =
  314. saturate
  315. (
  316. distanceSum
  317. )
  318. ;
  319. //color = float4(0,0,0,1);
  320. finalColor
  321. =
  322. lerp
  323. (
  324. color
  325. ,
  326. _OutlineColor
  327. ,
  328. distanceSum
  329. )
  330. ;
  331. //finalColor = color + distanceSum * _OutlineColor;
这里对distanceSum有两种方式,一种是通过Shader属性_NormalFactor和(1-_NormalFactor)来控制以哪种勾边为主。
  1. distanceSum
  2. =
  3. _NormalFactor
  4. *
  5. distanceSumNormal
  6. +
  7. (
  8. 1
  9. -
  10. _NormalFactor
  11. )
  12. *
  13. distanceSumDepth
  14. ;
一种是通过取max的方式,来确保两种模式的都勾到边,大家可以自行测试。
  1. //distanceSum = max(distanceSumDepth, distanceSumNormal);

下期预告

下一期分享,将会分享alelievr的HDRP-Custom-Passes库中的TIPS特效,并且介绍其中的原理等。最后,对于本文,求关注、点赞。对于B站视频,求关注、一键三连(点赞、投币、收藏)。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/101657?site
推荐阅读
相关标签
  

闽ICP备14008679号