Unity Shader 学习笔记(27)渲染轮廓线(描边)方法、卡通风格渲染、素描风格渲染

参考书籍:《Unity Shader 入门精要》


渲染轮廓线(描边)

五种方法:

  • 基于观察角度和表面法线。即视角方向和表面法线点乘结果判断(接近0,表示面接近垂直与视角)。
  • 过程式几何。两个Pass:第一个Pass渲染背面并且让轮廓可见(顶点外扩);第二个Pass正常渲染正面。适应于大多数表面平滑的模型,不适合立方体等平整模型。
  • 基于图像处理。前面两种边缘检测就是了:直接用算子判断和使用深度和法线纹理。但如果一些深度和法线变化很小的无法检测出来,如桌子上一张纸。
  • 基于轮廓边。检测方法:相邻两个三角是否一个面向视角,另一个背向视角,就是边。即 (n0·v > 0) ≠ (n1·v > 0)。 缺点是轮廓是逐帧单独提取的,帧与帧之间会出现跳跃性。
  • 混合上述方法。首先找到轮廓线(方法4),把模型和轮廓边渲染到纹理中,再使用图像处理识别轮廓线(方法3),在图像空间进行风格化渲染。

卡通风格渲染

使用描边方法2,以及卡通风格的高光反射光照模型实现。
描边注意:在背面顶点扩展时,可能有正面的面,这时会出错。可想象一个半实心球,内部有个面向视角的面,顶点外扩时,内部的面会超出外表面,遮挡了外表面。解决办法是先让背面法线z值减0.5再归一化(背面压扁)。
高光实现:镜面反射使用Blinn模型,计算(n·h)时,做阈值比较,小于的就是高光部分。

Shader "Custom/Chapter 14/Toon Shading" {Properties {_Color ("Color Tint", Color) = (1, 1, 1, 1)_MainTex ("Main Tex", 2D) = "white" {}_Ramp ("Ramp Texture", 2D) = "white" {}                     // 漫反射渐变纹理_Outline ("Outline", Range(0, 1)) = 0.1                        // 轮廓线宽度_OutlineColor ("Outline Color", Color) = (0, 0, 0, 1)        // 轮廓线颜色_Specular ("Specular", Color) = (1, 1, 1, 1)_SpecularScale ("Specular Scale", Range(0, 0.1)) = 0.01       // 高光反射的阈值}SubShader {Tags { "RenderType"="Opaque" "Queue"="Geometry"}// 第一个Pass,延展背面顶点,实现描边。Pass {NAME "OUTLINE"Cull Front       // 剔除正面,只渲染正面...v2f vert (a2v v) {v2f o;// 顶点和法线变换到视角空间下,让描边可以在观察空间达到最好的效果float4 pos = mul(UNITY_MATRIX_MV, v.vertex); float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);  normal.z = -0.5;  // 让法线向视角方向外扩,避免物体有背面遮挡正面pos = pos + float4(normalize(normal), 0) * _Outline;      //对外扩展,出现轮廓o.pos = mul(UNITY_MATRIX_P, pos);return o;}...}// 第二个Pass,基于Blinn光照模型,使用自定义高光光照模型,实现高光。Pass {Tags { "LightMode"="ForwardBase" }Cull Back...float4 frag(v2f i) : SV_Target { ...fixed spec = dot(worldNormal, worldHalfDir);// 高光区域抗锯齿操作,fwidth:邻域像素的近似导数。fixed w = fwidth(spec) * 2.0;     // _SpecularScale为0会完全消除高光反射,smoothstep:小于-w为0,大于w为1,否则在0到1之间插值。fixed3 specular = _Specular.rgb * lerp(0, 1, smoothstep(-w, w, spec + _SpecularScale - 1)) * step(0.0001, _SpecularScale);      return fixed4(ambient + diffuse + specular, 1.0);}ENDCG}}FallBack "Diffuse"
}

素描风格渲染

通过判断不同光照下漫反射值,使用不同的渲染纹理。纹理组成一个色调艺术映射(Tonal Art Map, TAM)。




// 素描风格
Shader "Custom/Chapter 14/Hatching" {Properties {_Color ("Color Tint", Color) = (1, 1, 1, 1)_TileFactor ("Tile Factor", Float) = 1  // 平铺系数_Outline ("Outline", Range(0, 1)) = 0.1_Hatch0 ("Hatch 0", 2D) = "white" {}  // 6张素描纹理,模拟不同阴影使用的纹理_Hatch1 ("Hatch 1", 2D) = "white" {}_Hatch2 ("Hatch 2", 2D) = "white" {}_Hatch3 ("Hatch 3", 2D) = "white" {}_Hatch4 ("Hatch 4", 2D) = "white" {}_Hatch5 ("Hatch 5", 2D) = "white" {}}SubShader {Tags { "RenderType"="Opaque" "Queue"="Geometry"}UsePass "Custom/Chapter 14/Toon Shading/OUTLINE"   // 使用前面的描边渲染PassPass {...struct v2f {float4 pos : SV_POSITION;float2 uv : TEXCOORD0;fixed3 hatchWeights0 : TEXCOORD1;   // 6张纹理存在两个fixed3中fixed3 hatchWeights1 : TEXCOORD2;float3 worldPos : TEXCOORD3;SHADOW_COORDS(4)};v2f vert(a2v v) {...o.hatchWeights0 = fixed3(0, 0, 0);o.hatchWeights1 = fixed3(0, 0, 0);float hatchFactor = diff * 7.0; // 放大7倍,便于分成7块,混合权重。if (hatchFactor > 6.0) {// 纯白} else if (hatchFactor > 5.0) {o.hatchWeights0.x = hatchFactor - 5.0;} else if (hatchFactor > 4.0) {o.hatchWeights0.x = hatchFactor - 4.0;o.hatchWeights0.y = 1.0 - o.hatchWeights0.x;} else if (hatchFactor > 3.0) {o.hatchWeights0.y = hatchFactor - 3.0;o.hatchWeights0.z = 1.0 - o.hatchWeights0.y;} else if (hatchFactor > 2.0) {o.hatchWeights0.z = hatchFactor - 2.0;o.hatchWeights1.x = 1.0 - o.hatchWeights0.z;} else if (hatchFactor > 1.0) {o.hatchWeights1.x = hatchFactor - 1.0;o.hatchWeights1.y = 1.0 - o.hatchWeights1.x;} else {o.hatchWeights1.y = hatchFactor;o.hatchWeights1.z = 1.0 - o.hatchWeights1.y;}o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;TRANSFER_SHADOW(o);return o; }fixed4 frag(v2f i) : SV_Target {           fixed4 hatchTex0 = tex2D(_Hatch0, i.uv) * i.hatchWeights0.x;fixed4 hatchTex1 = tex2D(_Hatch1, i.uv) * i.hatchWeights0.y;fixed4 hatchTex2 = tex2D(_Hatch2, i.uv) * i.hatchWeights0.z;fixed4 hatchTex3 = tex2D(_Hatch3, i.uv) * i.hatchWeights1.x;fixed4 hatchTex4 = tex2D(_Hatch4, i.uv) * i.hatchWeights1.y;fixed4 hatchTex5 = tex2D(_Hatch5, i.uv) * i.hatchWeights1.z;// 全白和最浅的纹理混合。fixed4 whiteColor = fixed4(1, 1, 1, 1) * (1 - i.hatchWeights0.x - i.hatchWeights0.y - i.hatchWeights0.z - i.hatchWeights1.x - i.hatchWeights1.y - i.hatchWeights1.z);fixed4 hatchColor = hatchTex0 + hatchTex1 + hatchTex2 + hatchTex3 + hatchTex4 + hatchTex5 + whiteColor;UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);return fixed4(hatchColor.rgb * _Color.rgb * atten, 1.0);}ENDCG}}FallBack "Diffuse"
}

Unity Shader 学习笔记(27)渲染轮廓线(描边)方法、卡通风格渲染、素描风格渲染相关推荐

  1. Unity Shader 学习笔记(33) 全局光照(GI)、反射探针、线性空间和伽马空间、高动态范围(HDR)

    Unity Shader 学习笔记(33) 全局光照(GI).反射探针.线性空间和伽马空间.高动态范围(HDR) 参考书籍:<Unity Shader 入门精要> [<Real-Ti ...

  2. Unity Shader 学习笔记(3)URP渲染管线带阴影PBR-Shader模板(ASE优化版本)

    此 Shader 已经不是最新版本,最新版本见本专栏的第四篇文章: Unity Shader 学习笔记(4) 材质面板截图: 功能实现(URP渲染管线下): PBR材质.投射和接收阴影. 代码展示: ...

  3. Unity Shader学习笔记(5)基于摄像机深度和法线的后处理描边效果

    文章目标 : 主要参考书籍为<Unity Shader入门精要>,本文主要注重于整理,方便后续直接调用. 渲染效果图: 主要相关代码: 摄像机脚本文件: using System.Coll ...

  4. 【Unity】Unity Shader学习笔记(二)渲染管线

    文章目录 渲染管线(Randering Pipeline) 渲染流程 可编程渲染管线 应用阶段 把数据加载到显存中 设置渲染状态 调用DrawCall 几何阶段.光栅化阶段 渲染管线(Randerin ...

  5. 【Unity Shader学习笔记】实现反射与折射模拟水面、使用grabPass与环境贴图

    文章目录 写在前面 一个水波效果 大致组成部分与对应的实现方案 交界线与深度贴图 折射效果与GrabPass 使用Cubemap与法线信息来模拟反射 在正确的地点创建对应的cubemap 通过贴图获取 ...

  6. Unity Shader学习笔记/Urp/水墨风效果

    实现简易的水墨风效果大致分为三部分: 1.将原始的rgb贴图转化为灰度图 float4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN ...

  7. 【Unity Shader学习笔记】(五)使用鼠标绘制自由多边形(附完整工程源码)

    前言 在前面的文章中,我们已经了解了怎样使用Unity Shader来绘制简单的点和线,本文将延续上次的话题,讲述一下如何在场景中使用Unity Shader绘制自由多边形. 本文所述的程序,支持在地 ...

  8. Unity Shader 学习笔记(5)Shader变体、Shader属性定义技巧、自定义材质面板

    写在之前 Shader变体.Shader属性定义技巧.自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用 ...

  9. Unity Shader 学习笔记(4)URP渲染管线带阴影PBR-Shader模板 -- 新增可自定义阴影颜色

    材质面板截图 功能实现(URP渲染管线下): 1.进一步优化Shader结构和算法: 2.包含PBR材质: 3.投射和接收阴影,并升级支持自定义阴影颜色: 4.支持点光源照射(但不支持点光源阴影). ...

最新文章

  1. 学科交叉是科学发展的必然趋势
  2. 用神经网络做分子模型是不是扯淡,f2,cl2,br2分子模型
  3. Java NIO之缓冲区
  4. SoftReference的用法
  5. 如何汉化美化Citrix的WEB界面
  6. python测试用例管理模块_Python的单元测试模块如何检测测试用例?
  7. java程序员的第二编程语言应该选什么?
  8. C语言——ASCII 码表及分类
  9. 传真机接收不到传真故障检查思路
  10. pdf转的html 360看不了,360浏览器看不了pdf
  11. 梅姐为什么没能拯救雅虎?
  12. mysql analyze_技术分享 | MySQL EXPLAIN ANALYZE
  13. mysql密码expired_mysql密码过期的修改方法(your password has expired)
  14. 网易,这次你让粉丝们失望了
  15. 软件测试-进阶篇:设计测试用例-文本框
  16. Win10 下报错 WerFault.exe -解决方法亲测有效
  17. 华为起诉最新进展,国内航司暂停运行有关客机,收买家庭不得继续抚养被解救儿童,脸书创始人后悔没早学微信,这就是今天的大新闻...
  18. Nginx正向代理与Client设置代理上网
  19. python之xlrd
  20. ultraiso制作iso镜像文件_移动硬盘制作启动盘安装win7系统

热门文章

  1. 2019最新Windows上安装并启动ElasticSearch6.5.4
  2. 几种常见触发器简介分析
  3. 数据分析面试【一】—— SQL基础知识
  4. 在软件测试中如何利用fiddler抓app的包
  5. 荣耀x30 Max算不算市场中的“异类”?
  6. 《创意人-创意思考的自我训练》 (学习笔记)
  7. 相机参数标定:张正友标定法
  8. Tinkpad E450 U盘启动
  9. 项目源码--Android美图秀秀源码
  10. 通俗理解线性回归(一)