Unity Shader 学习笔记(27)渲染轮廓线(描边)方法、卡通风格渲染、素描风格渲染
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)渲染轮廓线(描边)方法、卡通风格渲染、素描风格渲染相关推荐
- Unity Shader 学习笔记(33) 全局光照(GI)、反射探针、线性空间和伽马空间、高动态范围(HDR)
Unity Shader 学习笔记(33) 全局光照(GI).反射探针.线性空间和伽马空间.高动态范围(HDR) 参考书籍:<Unity Shader 入门精要> [<Real-Ti ...
- Unity Shader 学习笔记(3)URP渲染管线带阴影PBR-Shader模板(ASE优化版本)
此 Shader 已经不是最新版本,最新版本见本专栏的第四篇文章: Unity Shader 学习笔记(4) 材质面板截图: 功能实现(URP渲染管线下): PBR材质.投射和接收阴影. 代码展示: ...
- Unity Shader学习笔记(5)基于摄像机深度和法线的后处理描边效果
文章目标 : 主要参考书籍为<Unity Shader入门精要>,本文主要注重于整理,方便后续直接调用. 渲染效果图: 主要相关代码: 摄像机脚本文件: using System.Coll ...
- 【Unity】Unity Shader学习笔记(二)渲染管线
文章目录 渲染管线(Randering Pipeline) 渲染流程 可编程渲染管线 应用阶段 把数据加载到显存中 设置渲染状态 调用DrawCall 几何阶段.光栅化阶段 渲染管线(Randerin ...
- 【Unity Shader学习笔记】实现反射与折射模拟水面、使用grabPass与环境贴图
文章目录 写在前面 一个水波效果 大致组成部分与对应的实现方案 交界线与深度贴图 折射效果与GrabPass 使用Cubemap与法线信息来模拟反射 在正确的地点创建对应的cubemap 通过贴图获取 ...
- Unity Shader学习笔记/Urp/水墨风效果
实现简易的水墨风效果大致分为三部分: 1.将原始的rgb贴图转化为灰度图 float4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN ...
- 【Unity Shader学习笔记】(五)使用鼠标绘制自由多边形(附完整工程源码)
前言 在前面的文章中,我们已经了解了怎样使用Unity Shader来绘制简单的点和线,本文将延续上次的话题,讲述一下如何在场景中使用Unity Shader绘制自由多边形. 本文所述的程序,支持在地 ...
- Unity Shader 学习笔记(5)Shader变体、Shader属性定义技巧、自定义材质面板
写在之前 Shader变体.Shader属性定义技巧.自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用 ...
- Unity Shader 学习笔记(4)URP渲染管线带阴影PBR-Shader模板 -- 新增可自定义阴影颜色
材质面板截图 功能实现(URP渲染管线下): 1.进一步优化Shader结构和算法: 2.包含PBR材质: 3.投射和接收阴影,并升级支持自定义阴影颜色: 4.支持点光源照射(但不支持点光源阴影). ...
最新文章
- 学科交叉是科学发展的必然趋势
- 用神经网络做分子模型是不是扯淡,f2,cl2,br2分子模型
- Java NIO之缓冲区
- SoftReference的用法
- 如何汉化美化Citrix的WEB界面
- python测试用例管理模块_Python的单元测试模块如何检测测试用例?
- java程序员的第二编程语言应该选什么?
- C语言——ASCII 码表及分类
- 传真机接收不到传真故障检查思路
- pdf转的html 360看不了,360浏览器看不了pdf
- 梅姐为什么没能拯救雅虎?
- mysql analyze_技术分享 | MySQL EXPLAIN ANALYZE
- mysql密码expired_mysql密码过期的修改方法(your password has expired)
- 网易,这次你让粉丝们失望了
- 软件测试-进阶篇:设计测试用例-文本框
- Win10 下报错 WerFault.exe -解决方法亲测有效
- 华为起诉最新进展,国内航司暂停运行有关客机,收买家庭不得继续抚养被解救儿童,脸书创始人后悔没早学微信,这就是今天的大新闻...
- Nginx正向代理与Client设置代理上网
- python之xlrd
- ultraiso制作iso镜像文件_移动硬盘制作启动盘安装win7系统