Unity Shader模板测试描边效果,常用于 rpg 项目中主角被遮挡的情况,将被遮挡的部分的轮廓描边绘制出来,这样可以在任何情况都能知道主角在哪里。(还有另外一种就是使用X光效果,但这种效果不需要用到模板测试,所以这里用 描边效果 举例子)

 
效果如下:
 
思路
 
实现这种效果需要两个pass
1、正常绘制,即深度测试 LEqual,正常遮挡,同时往 模板缓冲区 写入一个 参考值 Ref=1(即使深度测试失败的值也要写入,保证 角色所有像素在模板缓冲区的值 都是 参考值 Ref=1)
 
2、只绘制被遮挡部分的描边
  • 先把模型的 顶点 往 法线方向 偏移一个值(这个就是描边的宽度值,可以理解为将模型放大了),可以在观察空间 或者 世界空间、模型空间 偏移,只要和 法线 在同一空间下。
  • 对比 模板缓冲区 的参考值 Ref=1,因为第一个 pass 写入的参考值是 1,所以这个pass中就要不等1才让它通过,这样就能得到一个 差值区域,即描边的区域。
  • 深度测试,让被遮挡部分才让它通过,即 ZTest Greater,done!
 
shader代码:
Shader "Custom/Unlit-Texture-Outline" {
Properties{
_MainTex("Base (RGB)", 2D) = "white" {}
_OutlineColor("Outline Color", Color) = (1,1,0,1) //描边颜色
_Outline("Outline width", Range(0.0, 0.5)) = 0.03 // 描边宽度

CGINCLUDE
#include "UnityCG.cginc"
struct appdata_t {
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f {
float4 vertex : SV_POSITION;
half2 texcoord : TEXCOORD0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Outline;
float4 _OutlineColor;
v2f vert(appdata_t v)

v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;

v2f vert_outline(appdata_t v)

v2f o;
// 方式一,观察空间 下往法线偏移顶点
float4 viewPos = mul(UNITY_MATRIX_MV, v.vertex);
//float3 viewNorm = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
float3 viewNorm = mul(v.normal, (float3x3)UNITY_MATRIX_T_MV);
float3 offset = normalize(viewNorm) * _Outline;
viewPos.xyz += offset;
o.vertex = mul(UNITY_MATRIX_P, viewPos);
//方式二,世界空间 下往法线偏移顶点
//float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
//float3 worldNormal = UnityObjectToWorldNormal(v.normal);
//float3 offset = normalize(worldNormal) * _Outline;
//worldPos.xyz += offset;
//o.vertex = mul(UNITY_MATRIX_VP, worldPos);
return o;

ENDCG
SubShader{
Tags{ "Queue" = "Transparent" "RenderType" = "Opaque" }
Pass{ // 正常绘制
Stencil

Ref 1
Comp Always
Pass Replace
ZFail Replace

ZTest LEqual
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
fixed4 frag(v2f i) : SV_Target

fixed4 col = tex2D(_MainTex, i.texcoord);
return col;

ENDCG

Pass{ // 遮挡部分绘制描边
ZTest Greater
ZWrite Off
//Blend DstAlpha OneMinusDstAlpha
Stencil{
Ref 1
Comp NotEqual

CGPROGRAM
#pragma vertex vert_outline
#pragma fragment frag
half4 frag(v2f i) :COLOR

return _OutlineColor;

ENDCG


 
使用 剔除Cull 的方式 描边
 
这种方式的描边不适合做遮挡部分描边,且不遮挡部分的效果也没有 模板测试 那种方式好,他的原理也是使用两个pass,一个pass正常渲染,剔除背面 (Cull Back),另外一个pass 也需要顶点外拉,然后 剔除正面(Cull Front),偏移深度。这种方式会在人体内也有描边,不像 模板测试 那种方式在人体完全没有描边。
 
效果
 
shader代码
// 这种方式的描边不适合做遮挡部分描边,且不遮挡部分的效果也没有 模板测试 那种方式好
Shader "ITS/test/testOutline_cull" {
Properties{
_MainTex("Base (RGB)", 2D) = "white" {}
_OutlineColor("Outline Color", Color) = (1,1,0,1)
_Outline("Outline width", Range(0.0, 0.5)) = 0.03

CGINCLUDE
#include "UnityCG.cginc"
struct appdata_t {
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f {
float4 vertex : SV_POSITION;
half2 texcoord : TEXCOORD0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Outline;
float4 _OutlineColor;
v2f vert(appdata_t v)

v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;

v2f vert_outline(appdata_t v)

v2f o;
// 方式一,观察空间 下往法线偏移顶点
float4 viewPos = mul(UNITY_MATRIX_MV, v.vertex);
//float3 viewNorm = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
float3 viewNorm = mul(v.normal, (float3x3)UNITY_MATRIX_T_MV);
float3 offset = normalize(viewNorm) * _Outline;
viewPos.xyz += offset;
o.vertex = mul(UNITY_MATRIX_P, viewPos);
//方式二,世界空间 下往法线偏移顶点
//float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
//float3 worldNormal = UnityObjectToWorldNormal(v.normal);
//float3 offset = normalize(worldNormal) * _Outline;
//worldPos.xyz += offset;
//o.vertex = mul(UNITY_MATRIX_VP, worldPos);
return o;

ENDCG
SubShader{
Tags{ "Queue" = "Transparent" "RenderType" = "Opaque" }
Pass{
ZTest LEqual
Cull Back
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
fixed4 frag(v2f i) : SV_Target

fixed4 col = tex2D(_MainTex, i.texcoord);
return col;

ENDCG

Pass{
// ZTest Greater
ZWrite Off
Cull Front
Offset 100,0
CGPROGRAM
#pragma vertex vert_outline
#pragma fragment frag
half4 frag(v2f i) : COLOR

return _OutlineColor;

ENDCG


 
ps: 还有其他描边处理的方式,比如 后处理
来自:https://blog.csdn.net/yangxuan0261/article/details/79686192

Unity Shader模板测试-描边的更多相关文章

  1. Unity Shader入门精要读书笔记(二)UnityShader概述

    第三章<UnityShader概述>的读书笔记: 1.Unity Shader模板提供了几种选择: 标准光照模型(新添加的基于物理的渲染方法) 不含光照的基本的顶点.片元着色器 屏幕后处理 ...

  2. Unity Shader概述

    一.概述 在Unity中需要配合使用材质和Unity Shader才能达到需要的效果.常见的流程:(1)创建一个材质:(2)创建一个Unity Shader,并把它赋给创建的材质:(3)把材质赋给要渲 ...

  3. Unity Shader之模板测试

    Unity Shader之模板测试 一沙一世界,一花一天堂 一.Stencil testing 渲染管线     当片段着色器处理完一个片段之后,模板测试(Stencil Test)会开始执行,和深度 ...

  4. Unity Shader实现描边效果

    http://gad.qq.com/article/detail/28346 描边效果是游戏里面非常常用的一种效果,一般是为了凸显游戏中的某个对象,会给对象增加一个描边效果.本篇文章和大家介绍下利用S ...

  5. Shader 模板缓冲和模板测试

    http://blog.sina.com.cn/s/blog_6e159df70102xa67.html 模板缓冲的概念 Unity官方的Shader文档根本没有提到这个玩意,这个概念也是看到了UGU ...

  6. 关于Unity中的模型描边与Shader切换(专题二)

    模型描边 1: LOL里面的模型描边效果,点击防御塔会有描边的效果,被攻击的时候模型也要描边凸显一下2: 网上可以找到模型描边的Shader,可以直接下载使用,一组第三方的Shader, 帮我们解决了 ...

  7. Unity Shader 卡通渲染 基于退化四边形的实时描边

    从csdn转移过来,顺便把写过的文章改写一下转过来. 一.边缘检测算法 3D模型描边有两种方式,一种是基于图像,即在所有3D模型渲染完成一张图片后,对这张图片进行边缘检测,最后得出描边效果.一种是基于 ...

  8. Unity Shader 知识点总结(一)

    在学习了一段时间的Unity Shader后,打算写一些知识总结,便于今后的查找.如有错误,希望大家指出更改. 本文参照的unity入门精要一书,做一个知识归纳,如有兴趣可以看看其开源的部分,是一本比 ...

  9. 【转】《Unity Shader入门精要》冯乐乐著 书中彩图

    为方便个人手机学习时候查阅,从网上转来这些彩图. 如属过当行为,联系本人删除. 勘错表 http://candycat1992.github.io/unity_shaders_book/unity_s ...

  10. Unity Shader入门精要读书笔记(一)序章

    本系列的博文是笔者读<Unity Shader入门精要>的读书笔记,这本书的章节框架是: 第一章:着手准备. 第二章:GPU流水线. 第三章:Shader基本语法. 第四章:Shader数 ...

随机推荐

  1. nginx平台初探-4

    模块开发高级篇(30%)   变量(80%)   综述 在Nginx中同一个请求需要在模块之间数据的传递或者说在配置文件里面使用模块动态的数据一般来说都是使用变量,比如在HTTP模块中导出了host/ ...

  2. 基于C#实现多线程启动停止暂停继续

    大家好!我是付工. 大部分初学者在学习C#上位机编程时,多线程是一个很难逾越的鸿沟,不合理地使用多线程,会导致经常出现各种奇怪的问题,这也是很多初学者不敢使用多线程的原因.但是在实际开发中,多线程是一 ...

  3. oracle使用存储过程返回游标实现报表查询

    最近在oracle中通过存储过程实现一个报表查询,查询涉及到数据计算这里使用了临时表和存储过程实现输出查询,java接受游标变量返回结果集 第一步.创建统计使用的临时表 CREATE GLOBAL T ...

  4. 小程序之confirm-type改变键盘右下角的内容和input按钮详解

    confirm-type的介绍 confirm-type 在什么时候使用呢? 如果说搜索框的时候,当用户输入完了之后,我们就需要 将confirm-type="search"的值设 ...

  5. Schreier–Sims 算法

    好看的实现. #include<bits/stdc++.h> using namespace std; #define int long long const int maxn=105; ...

  6. 线性空间与线性基(待整修,现在是史,OIwiki上的史。)

    各代数结构定义 群 对于一个集合 \(G\) 和运算 \(\times\),若其满足:封闭性.结合律,具有单位元,对于每个元素都有逆元,则称呼 \((G,\times)\) 为一个群. 阿贝尔群,或交 ...

  7. Atcoder ABC387F Count Arrays 题解 [ 绿 ] [ 基环树 ] [ 树形 dp ] [ 前缀和优化 ]

    Count Arrays:一眼秒的计数题. 思路 显然,把小于等于的条件化为大的向小的连单向边,每个数的入度都是 \(1\),就会形成一个基环树森林. 那么考虑这个环上能填什么数.因为所有数都小于等于 ...

  8. FreeSql学习笔记——7.分组聚合

    前言   分组就是将元数据通过某些条件划分为组,而聚合就是对这些组进行整合操作:在sqlserver数据库中使用的关键字group by使符合条件的集合通过某些字段分好组,再使用聚合函数(如max() ...

  9. 大数据之路Week10_day01 (Hbase总结 II)

    Hbase是数据库 特点: 1.面向列:Hbase是面向列的存储和权限控制,并支持独立索引.列式存储,其数据在表中是按照某列存储的,这样在查询只需要少数几个字段时,能大大减少读取的数据量. 2.多版本 ...

  10. 【自荐】Catime v1.0.4 一款贼好用的计时器

    Github: https://github.com/vladelaina/Catime 仅1.3MB!!!!! 特点 极简设计: 透明界面.点击穿透.可调大小和位置.多语言支持 丰富字体: 47种字 ...