1 前言

屏幕深度和法线纹理简介中对深度和法线纹理的来源、使用及推导过程进行了讲解,激光雷达特效中讲述了一种重构屏幕像素点世界坐标的方法,本文将沿用激光雷达特效中重构像素点世界坐标的方法,实现平面光罩特效。

假设平面光罩的高度为 shieldHeight,高亮线的宽度为 lineWidth,待检测像素点对应的世界坐标的高度值为 height,则该点的着色分以下三种情况:

  • height < shieldHeight - lineWidth:渲染背景颜色,即 tex2D(_MainTex, i.uv);
  • height > shieldHeight + lineWidth:渲染遮罩与背景的混合颜色;
  • abs(height - shieldHeight) <= lineWidth:渲染高亮线的颜色。

本文完整资源见→Unity3D平面光罩特效。

2 平面光罩实现

PlaneShield.cs

using UnityEngine;[RequireComponent(typeof(Camera))] // 需要相机组件
public class PlaneShield : MonoBehaviour {public Color shieldColor = Color.green; // 平面光罩的颜色[Range(0.01f, 0.5f)]public float lineWidth = 0.05f; // 线条宽度(交叉线高光)[Range(0.01f, 1f)]public float minAlpha = 0.2f; // 平面光罩的最小alpha值[Range(0.01f, 5f)]public float speed = 1f; // 平面光罩的移动速度[Range(0, 1)]public float minHeight = 0; // 平面光罩的最小高度[Range(3, 4)]public float maxHeight = 4; // 平面光罩的最大高度private Camera cam; // 相机private Material material = null; // 材质private void Awake() {cam = GetComponent<Camera>();material = new Material(Shader.Find("MyShader/PlaneShield"));material.hideFlags = HideFlags.DontSave;}private void OnEnable() {cam.depthTextureMode |= DepthTextureMode.Depth;}private void OnRenderImage(RenderTexture src, RenderTexture dest) {if (material != null) {Matrix4x4 frustumCorners = GetFrustumCornersRay();material.SetMatrix("_FrustumCornersRay", frustumCorners);material.SetColor("_ShieldColor", shieldColor);material.SetFloat("_LineWidth", lineWidth);material.SetFloat("_MinAlpha", minAlpha);material.SetFloat("_Speed", speed);material.SetFloat("_MinHeight", minHeight);material.SetFloat("_MaxHeight", maxHeight);Graphics.Blit(src, dest, material);} else {Graphics.Blit(src, dest);}}private Matrix4x4 GetFrustumCornersRay() { // 获取插值射线向量(由相机指向近平面上四个角点的向量除以near后的坐标)Matrix4x4 frustumCorners = Matrix4x4.identity;float fov = cam.fieldOfView;float near = cam.nearClipPlane;float aspect = cam.aspect;float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);Vector3 toRight = cam.transform.right * halfHeight * aspect; // 指向右方的向量Vector3 toTop = cam.transform.up * halfHeight; // 指向上方的向量Vector3 toForward = cam.transform.forward * near; // 指向前方的向量Vector3 bottomLeft = (toForward - toTop - toRight) / near; // 指向左下角的射线Vector3 bottomRight = (toForward + toRight - toTop) / near; // 指向右下角的射线Vector3 topRight = (toForward + toRight + toTop) / near; // 指向右上角的射线Vector3 topLeft = (toForward + toTop - toRight) / near; // 指向左上角的射线frustumCorners.SetRow(0, bottomLeft);frustumCorners.SetRow(1, bottomRight);frustumCorners.SetRow(2, topRight);frustumCorners.SetRow(3, topLeft);return frustumCorners;}
}

PlaneShield.shader

Shader "MyShader/PlaneShield" { // 平面罩特效Properties{_MainTex("MainTex", 2D) = "white" {} // 主纹理_ShieldColor("ShieldColor", Color) = (0, 1, 0, 1) // 平面光罩的颜色_LineWidth("LineWidth", Float) = 0.05 // 线条宽度(交叉线高光)_MinAlpha("MinAlpha", Float) = 0.2 // 平面光罩的最小alpha值_Speed("Speed", Float) = 1 // 平面罩的移动速度_MinHeight("MinHeight", Float) = 0.1 // 平面光罩的最小高度_MaxHeight("MaxHeight", Float) = 4 // 平面光罩的最大高度}SubShader{Pass {// 深度测试始终通过, 关闭深度写入ZTest Always ZWrite OffCGPROGRAM#include "UnityCG.cginc"#pragma vertex vert#pragma fragment fragsampler2D _MainTex; // 主纹理sampler2D _CameraDepthTexture; // 深度纹理float4x4 _FrustumCornersRay; // 视锥体四角射线向量(由相机指向近平面上四个角点的向量除以near后的坐标)float4 _ShieldColor; // 平面光罩的颜色float _LineWidth; // 线条光宽度(交叉线高光)float _MinAlpha; //平面光罩的最小alpha值float _Speed; // 平面光罩的移动速度float _MinHeight; // 平面光罩的最小高度float _MaxHeight; // 平面光罩的最大高度struct v2f {float4 pos : SV_POSITION; // 裁剪空间顶点坐标half2 uv : TEXCOORD0; // 纹理uv坐标, float4 interpolatedRay : TEXCOORD1; // 插值射线向量(由相机指向近平面上点的向量除以near后的坐标)};float4 getInterpolatedRay(half2 uv) { // 获取插值射线向量(由相机指向近平面上四个角点的向量除以near后的坐标)int index = 0;if (uv.x < 0.5 && uv.y < 0.5) {index = 0;} else if (uv.x > 0.5 && uv.y < 0.5) {index = 1;} else if (uv.x > 0.5 && uv.y > 0.5) {index = 2;} else {index = 3;}return _FrustumCornersRay[index];}v2f vert(appdata_img v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex); // 计算裁剪坐标系中顶点坐标, 等价于: mul(unity_MatrixMVP, v.vertex)o.uv = v.texcoord;o.interpolatedRay = getInterpolatedRay(v.texcoord); // 获取插值射线向量(由相机指向近平面上四个角点的向量除以near后的坐标)return o;}fixed4 frag(v2f i) : SV_Target {float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv); // 非线性的深度, tex2D(_CameraDepthTexture, i.uv).rfloat linearDepth = LinearEyeDepth(depth); // 线性的深度//if (linearDepth > _ProjectionParams.z - 2) {// return tex2D(_MainTex, i.uv); // 天空不参与平面光罩特效//}float3 worldPos = _WorldSpaceCameraPos + linearDepth * i.interpolatedRay.xyz; // 顶点世界坐标float range = _MaxHeight - _MinHeight; // 高度范围float shieldHeight = _MinHeight + abs(range - fmod(_Time.y * _Speed, range + range)); // 使平面光罩由上往下、再由下往上周期性运动if (worldPos.y < shieldHeight - _LineWidth) {return tex2D(_MainTex, i.uv);}float delta = abs(worldPos.y - shieldHeight);float factor = 1 - smoothstep(0, _LineWidth, delta) * (1 - _MinAlpha);fixed4 tex = tex2D(_MainTex, i.uv);fixed4 color = lerp(tex, _ShieldColor, factor);return color;}ENDCG}}FallBack off
}

3 平面光罩实现

【Unity3D】平面光罩特效相关推荐

  1. 【Unity3D】水波特效

    1 水波特效原理 水波特效属于 Unity3D 后处理特效,其原理是:对渲染后的纹理进行局部挤压和拉升变换,即对局部 uv 坐标进行周期性的偏移运动,实现波纹效果. 1)波形方程 为简化水波模型,我们 ...

  2. Unity3D之刀光剑影特效的实现

    我们来看几张图片吧: 可以看到,在这部游戏中,前两部是半即时制RPG,第三部则完全是即时制RPG.整个配乐大气磅礴,一招一式都有不错的打击感,而且武器的特效十分华丽.那么,到这里,就到了我们今天的主题 ...

  3. Unity3D图像后处理特效——Grayscale image effect

    Grayscale is a simple image effect that changes colors to grayscale by default. It can also use a Te ...

  4. 【Shader】扭曲能量罩特效

    Shader "Custom/ForceField" { Properties {_Color("Color", Color) = (0,0,0,0)_Nois ...

  5. 【Unity3D】动态路径特效

    1 前言 本文通过导航系统(NavMeshAgent)和线段渲染器(LineRenderer)实现了角色走迷宫和绘制路径功能,同时实现动态路径特效. 导航系统的介绍详见博客:导航系统.分离路面导航.动 ...

  6. Unity3D如何快速入门?

    一句话说明下Unity是什么,Unity是一个开发游戏,主要用于手机游戏开发的引擎,什么是引擎,引擎就是工具的意思. 想学习一门课程,最有效直接的方法是什么?从网上找各种相关资料,最后你会发现看了很多 ...

  7. Unity3d-制作粒子光环特效

    利用Unity3d制作一个特效,与这个网站效果类似: 首先,在Unuty3d下面建立了一个object,命名为Particle. 然后建立一个脚本:并挂在刚刚建立的gameobject下面 然后然后依 ...

  8. [Unity3D]Unity资料大全免费分享

    都是网上找的连七八糟的资料了,整理好分享的,有学习资料,视频,源码,插件--等等 东西比较多,不是所有的都是你需要的,可以按  ctrl+F 来搜索你要的东西,如果有广告,不用理会,关掉就可以了,如果 ...

  9. 【unity shader】unity游戏特效-简简单单的能量护罩

    本文参考文章: [1]Unity shader护盾特效,作者:qq_16982323 [2]UnityShader--屏幕空间的能量罩(模拟守望先锋温斯顿的能量罩),作者:Porco_ 玩过崩坏3没? ...

最新文章

  1. 解决博客园模版错误排版的一个问题
  2. DataFrame表样式设置(一)
  3. python logging模块的作用_【python】【logging】python日志模块logging常用功能
  4. 一次较为完整的原生JavaScript AJAX与Java的前后端数据交互
  5. 【离散期末复习】:集合论
  6. CISCO 路由器启动自动配置
  7. 设计模式-结构型软件设计模式(二)
  8. springboot 多任务并行执行
  9. 现代OpenGL教程(六):鼠标和键盘(imgui+OpenGL3.3)
  10. 正则表达式(BREs,EREs,PREs)差异比较
  11. MBA心路历程第一天 —— 开始行动
  12. 4.实操(Credit Card Fraud Detection)
  13. 2021年芒种是几月几号?芒种习俗有哪些 ?
  14. [lintcode]入门
  15. 【内网学习笔记】10、ew 的使用
  16. 小小知识点(二十八)开环空间复用和闭环空间复用
  17. Ksz8081目前为MICROCHIP主推的PHY芯片之一,原为MICREL公司设计;芯片分为MII接口型号,RMII接口型号,分了两种不同的产品型号。enc28j60集成了MAC和PHY芯片
  18. 数学知识整理:不定积分
  19. Excel如何对多个格式相同的工作表快速汇总求和
  20. Linux文件管理、查找与光盘挂载

热门文章

  1. 想通过培训转行软件测试可以吗
  2. 解决SELinux is preventing *** 的问题
  3. 一个word文档中,多个表格的批量调整(根据窗口调整表格和添加表格水平线)
  4. 记录一次不成功的换手机屏幕经历。
  5. 游戏装备强化java机制,原神装备强化经验继承机制
  6. 微软IE8新功能对谷歌广告模式造成威胁
  7. 服务器需要cpu性能吗,CPU性能的要求_服务器知识学堂-中关村在线
  8. 如何使用PathFileExists
  9. HTML5 Canvas爱心表白动画特效
  10. cookie简介(前端)