UnityShader——屏幕空间的能量罩(模拟守望先锋温斯顿的能量罩)

前言:

因为是第一次写技术博客可能有些不到位请谅解,废话不多说就先上最终效果图了(PS.可以看出效果图和游戏中还是有差距的,因为Shader刚入门所以有什么不足望指出)。主要的原理是:屏幕空间深度图,纹理动画,遮罩纹理,Blinn-Phong光照模型。(Ps,代码思路主要参考腾讯大神Mya喵神写过的一个的Shader)



所需数学知识:

模型空间到裁剪空间的变换,详情请见冯乐乐的Shader入门到精通4.6.7章节,因为冯乐乐在自己的github上已经放出了第四章的pdf所以这里直接粘一个链接了。


主要的原理:

首先我们要先了解UnityShaderLab中的深度图是如何渲染出来的,在Unity中会直接获取深度缓存或是着色器替换技术,深度图的渲染是需要通过ShadowCaster的Pass来渲染的,也就是说如果没有这个Pass的物体是不会被渲染到深度图中的,而通常透明的物体是没有ShadowCaster这个Pass的(也可以让透明物体有,但是透明物体也会投射阴影),所以只要设置好RenderType(也就是"RenderType"="Transparent"),就可以让我们的能量罩不出现在深度图中,我们可以从下面的图中看出在LinearEyeDepth中的深度图如图所示,深度图中没有出现能量罩(看着是一片黑仔细看,还不行的话再仔细→ →)。


然而只是这样是不够的,我们还可以通过Unity内置的函数o.scrPos = ComputeScreenPos ( o.pos )来得到Clip Space的深度值了,但是需要注意的是Clip Space空间的z值的大小是从-Near至Far的(详情见下图),而深度图中LinearEyeDepth后的范围是Near至Far的,所以我们要再次借助便利的Unity内置函数COMPUTE_EYEDEPTH(o.scrPos.z),来将o.scrPos.z的值转化到Near至Far。

机智的小伙伴应该已经看出来了,在深度图中没有显示出来的能量罩的深度值,却可以通过获取Clip Space的z值来获取,所以我们只要比较这两个值就可以判断出能量罩与别的物体的交汇位置,也就是当深度图中的深度值等于Clip Space的z值的时候是交汇的,于是我们就可以通过这个来做出相交高光的效果了(也就是能量罩与别的物体相交的时候边缘会有蓝白色)。

因为这个文章主要是讲深度图部分,所以纹理动画,Mask和Blinn-Phong就不提了(其实是懒得打字了orz)。


源码:

首先我们需要一个C#脚本来设置相机的深度图模式。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour {
    

    private Camera myCamera;
    public Camera camera
    {
        get
        {
            if (myCamera == null)
            {
                myCamera = GetComponent<Camera>();
            }
            return myCamera;
        }
    }

    void OnEnable()
    {
        camera.depthTextureMode |= DepthTextureMode.Depth;
    }
    
}
其次到了我们的主角Shader部分。

Shader "MyShader/XiangJiaoGaoGuang" {
	Properties {
		_MainColor ("Color" , Color) = (1,1,1,1)
		_HighlightColor("HighlightColor" ,Color) = (0,0,1,1)
		_EdgePow("Threshold" , Range(0 , 5)) = 0.5
		_RimNum("Rim" , Range(0 , 5)) = 1
		_MainTex("Main Tex" , 2D) = "white"{}
		_MaskTex("Mask Tex" ,  2D) = "white" {}
		_speed("Speed" ,Range(0 , 2)) = 1.0
	}

	SubShader {

	Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}
	
	Pass{
		Tags { "LightMode"="ForwardBase" }	
		
		Blend One One
		ZWrite Off
		Cull Off
		
		CGPROGRAM

		#include "UnityCG.cginc"

		#pragma vertex vert
		#pragma fragment frag

		#define UNITY_PASS_FORWARDBASE
        #pragma multi_compile_fwdbase

		float4 _MainColor;
		float4 _HighlightColor;
		sampler2D _CameraDepthTexture;
		float _EdgePow;
		sampler2D _MainTex;
		float4 _MainTex_ST;
		sampler2D _MaskTex;
		float _speed;
		float _RimNum;

		struct a2v{
			float4 vertex:POSITION;
			float3 normal:NORMAL;
			float2 tex:TEXCOORD0;
		};

		struct v2f{
			float4 pos:POSITION;
			float4 scrPos:TEXCOORD0;
			half3 worldNormal:TEXCOORD1;
			half3 worldViewDir:TEXCOORD2;
			float2 uv:TEXCOORD3;
		};

		v2f vert (a2v v )
		{
			v2f o;

			o.pos = UnityObjectToClipPos ( v.vertex );

			o.scrPos = ComputeScreenPos ( o.pos );

			float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; 
		
			o.worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));
			o.worldNormal = UnityObjectToWorldNormal(v.normal); 

			o.uv = TRANSFORM_TEX(v.tex , _MainTex);

			COMPUTE_EYEDEPTH(o.scrPos.z);
			return o;
		}
	
		fixed4 frag ( v2f i ) : SV_TARGET
		{
			//纹理动画和Mask部分,主要作用是实现扫描效果还有六边形图案
			fixed mainTex = 1 - tex2D(_MainTex , i.uv).a;
			fixed mask = tex2D(_MaskTex , i.uv + float2(0 , (_Time.y)*_speed)).r;
			fixed4 finalColor = lerp(_MainColor , _HighlightColor , mainTex);
			finalColor=lerp(fixed4(0,0,0,1),finalColor,mask);
		
			//获取深度图和clip space的深度值
			float sceneZ = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.scrPos)));
			float partZ = i.scrPos.z;

			//diff为比较两个深度值,rim为Phong:在边缘位置加上一层_HighlightColor的颜色
 			float diff = 1-saturate((sceneZ-i.scrPos.z)*4 - _EdgePow);
			half rim = pow(1 - abs(dot(normalize(i.worldNormal),normalize(i.worldViewDir))) , _RimNum);

			//最后通过插值混合颜色
			finalColor = lerp(finalColor, _HighlightColor, diff);
			finalColor = lerp(finalColor, _HighlightColor, rim);
			return finalColor;
		}

		ENDCG
		}
	}
}

源文件:

https://github.com/Porco24/UnityShaderEnergyShield

  • 9
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
<!DOCTYPE html> <html> <head> <title>电影介绍</title> <meta charset="utf-8"> <style> body { font-family: Arial, sans-serif; background-color: #f1f1f1; } h1 { text-align: center; margin-top: 50px; font-size: 36px; color: #333; } .container { max-width: 800px; margin: 0 auto; padding: 20px; background-color: #fff; box-shadow: 0px 0px 10px rgba(0,0,0,0.2); } .poster { float: left; margin-right: 20px; } .poster img { width: 300px; height: 450px; object-fit: cover; box-shadow: 0px 0px 10px rgba(0,0,0,0.2); } .summary { margin-top: 20px; font-size: 18px; line-height: 1.5; color: #666; } .cast { margin-top: 20px; font-size: 18px; color: #333; } .cast ul { margin: 0; padding: 0; list-style: none; } .cast li { margin-bottom: 10px; } .cast li span { font-weight: bold; } </style> </head> <body> <h1>《肖申克的救赎》</h1> <div class="container"> <div class="poster"> <img src="https://img1.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg" alt="肖申克的救赎"> </div> <div class="summary"> <p>导演: 弗兰克·德拉邦特 Frank Darabont</p> <p>主演: 蒂姆·罗宾斯 Tim Robbins / 摩根·弗里曼 Morgan Freeman / 鲍勃·冈顿 Bob Gunton</p> <p>类型: 剧情 / 犯罪</p> <p>制片国家/地区: 美国</p> <p>语言: 英语</p> <p>上映日期: 1994-09-10(多伦多电影节) / 1994-10-14(美国)</p> <p>片长: 142分钟</p> <p>又名: 月黑高飞(港) / 刺激1995(台) / 地狱诺言 / 铁窗岁月 / 消香克的救赎 / 万箭攒心 / 美国往事 / 微笑正义</p> <p>IMDb链接: <a href="https://www.imdb.com/title/tt0111161/" target="_blank">tt0111161</a></p> <p>豆瓣评分: 9.7</p> <p>简介: 本片根据斯蒂芬·金同名小说改编。故事发生在上世纪四十年代末的美国,主人公安迪(蒂姆·罗宾斯 Tim Robbins 饰)因被诬告杀害妻子和她的情人而被判终身监禁。在肖申克监狱,安迪遇到了狱中老大瑞德(摩根·弗里曼 Morgan Freeman 饰),两人成为了密友。在瑞德的帮助下,安迪逐渐适应了狱中的生活,并成为了监狱长的得力助手。然而,安迪却一直没有放弃自己的信念,他暗中策划着逃狱的计划。经过多年的努力,安迪终于成功越狱,并揭露了罪犯集团的真正面目。</p> </div> <div class="cast"> <h2>主要演员</h2> <ul> <li><span>蒂姆·罗宾斯</span> 饰 安迪·杜佛兰</li> <li><span>摩根·弗里曼</span> 饰 瑞德</li> <li><span>鲍勃·冈顿</span> 饰 温斯顿·哈德斯利</li> <li><span>威廉·赛德勒</span> 饰 拉里·布兰登伯格</li> <li><span>克兰西·布朗</span> 饰 布鲁克斯</li> <li><span>吉尔·贝罗斯</span> 饰 托马斯·“汤姆斯”·威廉姆斯</li> </ul> </div> </div> </body> </html>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值