Unity 引擎做残影效果——3、顶点偏移方式

Unity实现残影效果


  大家好,我是阿赵。
  继续讲Unity引擎的残影做法。这次的残影效果和之前两种不太一样,是通过顶点偏移来实现的。
  具体的效果是这样:
在这里插入图片描述 在这里插入图片描述

  与其说是残影,这种效果更像是移动速度很快时造成的速度线,所以在移动过程中的效果还是非常好的,截图的感觉没有视频的感觉那么有冲击力。

一、原理介绍

1、顶点偏移

  这个做法很简单,在c#里面对比当前帧和上一帧的坐标,如果坐标有变化,就把两个坐标相减,算出一个世界空间坐标的向量出来,并做标准化处理。
  得到了这么一个向量之后,就可以把它传入到shader里面了。
  既然是顶点偏移,那么肯定是在顶点着色器程序里面做修改了。不过这里有个比较值得注意的问题。一般写shader的时候,如果没有特殊的需要,我们都是直接把顶点坐标从物体局部坐标直接就转换到裁剪空间了,比如使用Untiy提供的方法:

UnityObjectToClipPos(v.vertex);

  但在这个例子里面,我们从c#传入的是世界空间坐标的向量,所以我们不能通过模型局部坐标或者裁剪空间去叠加这个偏移向量,而应该在同样的世界坐标上面去偏移。

float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
worldPos += _MoveDir * _MoveDis;

  其中_MoveDir就是标准化后的移动向量, _MoveDis是用于控制偏移距离的变量。
  这个时候,可以看到,整个模型都在拉伸了
在这里插入图片描述

  但这种效果明显不是我们想要的。

2.控制偏移的范围

  我们想要的效果是怎样的呢?是不是应该是移动的过程中,前面的部分是不变形的,只有最后一点位置出现拉伸?
  怎么去控制拉伸的范围呢?其实很简单,假如我们把刚才那个移动的向量想象成是灯光,就可以求出这样的一个效果:
在这里插入图片描述

  很明显的,模型高亮的部分,其实就是我们想拉伸的方向了。所以,其实很简单,把移动方向和模型的法线做点乘,就可以求出一个我们想偏移的范围了。
  不过现在高亮的部分还是有点多,所以我们用一个power运算,让对比度变得更高,就变成了下面这个情况。
在这里插入图片描述

  现在,白色的部分只有很小的范围了。接下来就对这个白色的范围做顶点偏移:
在这里插入图片描述

  基本上就出现了我们想要的效果了。

二、优缺点

1、优点

  首先,之前介绍的不管是BakeMesh还是屏幕后处理,都是基于对模型的多次渲染上的,所以性能上并不那么友好。
  用顶点偏移的方式,并没有太多额外的计算量,所以从性能上来说,它是比前两种方式都要好的。
  然后,顶点偏移这种手段,其实是一种非常简单的技术含量比较低的手段,难点是在于你怎样想出这个办法而已,所以知道了方法之后,其实非常容易就能实现了。

2、缺点

  这个做法的缺点也是很明显的。
  首先,它不是真正的残影效果,只是速度线的类似效果,所以我个人感觉只适合用于特定的风格里面,比如卡通之类。如果写实风格的游戏用这种效果可能不太行。
  然后,由于是要对模型做顶点偏移,那么就要意味着需要修改模型原有的Shader了。对于比较正规的团队来说,这问题不大,因为项目里面每个Shader都应该是经过TA的定制的,需要统一加入一些元素是很简单的。
  但对于不那么正规的团队,甚至是纯美术人员组成的团队来说,说不定已经在用的Shader都是从不知道哪个网站上面复制下来的,要统一修改,难度会非常大。
  所以,如果想使用这种技术手段,还是要先考虑一下自己的实际情况的。

三、代码

  同样的,只是demo,所以代码只是在于实现部分,没有过多优化。

1、C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class MoveVertexOffsetCtrl : MonoBehaviour
{public float moveDis = 1;private bool isMove = false;private Vector3 oldPos = Vector3.zero;public GameObject role;private Vector3 moveDir = Vector3.zero;private List<Material> matList;public float pow = 1;// Start is called before the first frame updatevoid Start(){matList = new List<Material>();if(role){SkinnedMeshRenderer[] renders = role.GetComponentsInChildren<SkinnedMeshRenderer>();for(int i = 0;i<renders.Length;i++){for(int j = 0;j<renders[i].materials.Length;j++){Material mat = renders[i].materials[j];if (matList.IndexOf(mat) < 0){matList.Add(mat);}}}}}// Update is called once per framevoid Update(){CheckMove();SetMaterial();}private void CheckMove(){if(role){if(Vector3.Distance(role.transform.position,oldPos)>0){moveDir =  oldPos - role.transform.position;moveDir = moveDir.normalized;oldPos = role.transform.position;isMove = true;}else{isMove = false;}}else{isMove = false;}}private void SetMaterial(){if(matList!=null&&matList.Count>0){for(int i = 0;i<matList.Count;i++){if(isMove==false){matList[i].SetFloat("_MoveDis", 0);}else{matList[i].SetFloat("_MoveDis", moveDis);matList[i].SetVector("_MoveDir", moveDir);matList[i].SetFloat("_MovePow", pow);}}}}
}

2、Shader

Shader "azhao/MoveVertexBase"
{Properties{_MainTex ("Texture", 2D) = "white" {}_MoveDir("MoveDir",Vector) = (0,0,0,0)_MoveDis("MoveDis",float) = 0_MovePow("MovePow",float) = 1}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;half3 normal : NORMAL;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;float4 _MoveDir;float _MoveDis;float _MovePow;v2f vert (appdata v){v2f o;o.uv = TRANSFORM_TEX(v.uv, _MainTex);float4 worldPos = mul(unity_ObjectToWorld, v.vertex);float3 worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);float ndotl = saturate(dot(worldNormal, _MoveDir));ndotl = pow(ndotl, _MovePow);worldPos += _MoveDir * _MoveDis*ndotl;//世界空间顶点坐标转观察空间坐标float4 viewPos = mul(UNITY_MATRIX_V, worldPos);//观察空间坐标转裁剪空间坐标float4 clipPos = mul(UNITY_MATRIX_P, viewPos);o.vertex = clipPos;return o;}half4 frag (v2f i) : SV_Target{// sample the texturehalf4 col = tex2D(_MainTex, i.uv);return col;}ENDCG}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/20984.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于前后端分离

关于前后端分离 接下来&#xff0c;你将进入 前后端分离项目开发 模块。 这也是企业中比较常见的开发模式。 疑问&#xff1a; 什么是前后端分离&#xff1f;与之前的开发模式有什么区别&#xff1f;企业为什么要用前后端分离&#xff1f; 1. 什么是前后端分离&#xff1f;…

基于人工智能的状态监测帮助结束冷却塔的维护“噩梦”

冷却塔是将水蒸气冷却成较低温的水、将系统的废热排到大气层的排热装置&#xff0c;在工业生产中扮演着不可或缺的关键角色。大型工业冷却塔的主要用途是用来冷却在水冷系统中的循环水。这些水冷系统广泛应用于发电厂、炼油厂、石化厂、天然气制造厂、食品加工厂、半导体厂等工…

ARP断网攻击及防御

ARP断网攻击及防御 攻击防御 攻击 PC1的IP地址 10.9.136.222 PC2的IP地址 10.9.136.55在局域网里通信 需要有IP地址和MAC地址 两台电脑PC1和PC2要想相互通信&#xff0c;PC1在连接PC2的时候&#xff0c;PC1会先查看自己的ARP缓存表&#xff08;命令&#xff1a;arp -a &#xf…

校园跑腿小程序运营攻略

作为一名校园跑腿小程序的运营者&#xff0c;你可能会面临诸如用户获取、平台推广、服务质量保证等挑战。在本篇推文中&#xff0c;我将为你提供一些关键的运营策略&#xff0c;帮助你成功运营校园跑腿小程序。 1. 用户获取和留存 用户是校园跑腿小程序成功的关键。以下是一些…

C++如何用OpenCV中实现图像的边缘检测和轮廓提取?

最近有个项目需要做细孔定位和孔距测量&#xff0c;需要做边缘检测和轮廓提取&#xff0c;先看初步效果图&#xff1a; 主要实现代码&#xff1a; int MainWindow::Test() {// 2.9 单个像素长度um 5倍double dbUnit 2.9/(1000*5);// 定义显示窗口namedWindow("src"…

VR实景导航——开启3D可视化实景导航新体验

数字化时代&#xff0c;我们大家出门在外都是离不开各种导航软件&#xff0c;人们对导航的需求也越来越高&#xff0c;而传统的导航软件由于精度不够&#xff0c;无法满足人们对真实场景的需求&#xff0c;这个时候就需要VR实景导航为我们实景指引目的地的所在。 VR实景导航以其…

跨境多商户中日韩英多语言商城搭建(PC+小程序+H5),搭建方案

随着全球化的推进&#xff0c;跨境电商正变得越来越普遍。在本文中&#xff0c;我们将介绍跨境电商系统开发中多语言商城独立站的部署搭建方案。 准备工作 在开始部署搭建之前&#xff0c;需要准备以下环境&#xff1a; 服务器&#xff0c;确保服务器具备足够的性能和稳定性。 …

RF手机天线仿真介绍(一):金属边框天线和LDS天线

目录 简介LDS天线LDS天线仿真 金属边框天线金属边框天线仿真 简介 最早的手机是外置式天线&#xff0c;从NOKIA开始采用内置式天线&#xff0c;开始采用内置金属片&#xff08;一般是0.1MM厚的不锈钢片冲压而成&#xff09;&#xff0c;随后为降低成本&#xff0c;后来改用FPC…

powershell脚本写一个托盘图标

1、准备ico格式图标 star_bethlehem_icon 文件名改为star.ico 2、安装VSCode 如何下载安装VSCode 扩展&#xff1a;PowerShell扩展 3、创建项目 1、运行PowerShell命令 mkdir trayicon_ps1;cd trayicon_ps1;New-Item trayicon.ps1;code .2、将star.ico放入trayicon_ps1文…

DDS中间件设计

OpenDDS、FastDDS数据分发服务中间件设计 软件架构 应用层DDS层RTPS层传输层 软件层次 FastDDS整体架构如下&#xff0c;这里可以看到DDS和RTPS的关系。另外缺少一部分IDL&#xff08;统一描述语言&#xff09;&#xff0c;其应该是Pub、Sub的反序列化、序列化工具。 在RT…

Ubuntu安装harbor(http模式)并随便上传一个

Ubuntu安装harbor&#xff08;http模式&#xff09; docker和harbor的介绍就免了&#xff0c;都不知道啥东西&#xff0c;还安装搞毛 先安装docker环境 不要问&#xff0c;软件源之类的配置&#xff0c;挨个梭就行 sudo apt update sudo apt install apt-transport-https ca…

Python3 高级教程 | Python3 CGI编程(二)

目录 一、什么是CGI 二、网页浏览 三、CGI架构图 四、Web服务器支持及配置 五、第一个CGI程序 六、HTTP头部 七、CGI环境变量 八、GET和POST方法 &#xff08;一&#xff09;使用GET方法传输数据 &#xff08;二&#xff09;简单的url实例&#xff1a;GET方法 &#x…

快速排序——“数据结构与算法”

各位CSDN的uu们好呀&#xff0c;今天又是小雅兰的数据结构与算法专栏啦&#xff0c;下面&#xff0c;就让我们进入快速排序的世界吧&#xff01;&#xff01;&#xff01; 快速排序 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法&#xff0c;其基本思想为&…

【Docker】Docker容器与虚拟机的对比、三要素、架构和镜像加速器的详细讲解

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;目前学习C/C、算法、Python、Java等方向&#xff0c;一个正在慢慢前行的普通人。 &#x1f3c0;系列专栏&#xff1a;陈童学的日记 &#x1f4a1;其他专栏&#xff1a;CSTL&…

什么?你还没有用过JPA Buddy,那么你工作肯定没5年

1. 概述 JPA Buddy是一个广泛使用的IntelliJ IDEA插件&#xff0c;面向使用JPA数据模型和相关技术&#xff08;如Spring DataJPA&#xff0c;DB版本控制工具&#xff08;Flyway&#xff0c;Liquibase&#xff09;&#xff0c;MapStruct等&#xff09;的新手和有经验的开发人员…

《Java-SE-第二十七章》之常见的锁策略

前言 在你立足处深挖下去,就会有泉水涌出!别管蒙昧者们叫嚷:“下边永远是地狱!” 博客主页&#xff1a;KC老衲爱尼姑的博客主页 博主的github&#xff0c;平常所写代码皆在于此 共勉&#xff1a;talk is cheap, show me the code 作者是爪哇岛的新手&#xff0c;水平很有限&…

RD算法(四)登堂入室 —— 成像完成

SAR成像专栏目录_lightninghenry的博客-CSDN博客https://lightning.blog.csdn.net/article/details/122393577?spm=1001.2014.3001.5502先放RD算法最终的成像结果: 经简单的地距投影后为(地距投影的内容在后面的几何校正章节中讲解): 温哥华这地形还真像是一张怪兽的巨嘴呀…

方差分析||判断数据是否符合正态分布

方差分析练习题 练习学习笔记&#xff1a; &#xff08;1&#xff09; 标准差和标准偏差、均方差是一个东西。标准误差和标准误是一个东西。这两个东西有区别。 &#xff08;2&#xff09;单因素方差分析&#xff08;MATLAB求解&#xff09; &#xff08;3&#xff09;使用an…

【雕爷学编程】MicroPython动手做(28)——物联网之Yeelight

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

同比环比使用方法

一、解释&#xff1a; 1.同比&#xff1a;本期与去年同期相比 &#xff0c;如2023年8月 比 2022年8月 2.环比&#xff1a;本期与上期相比 &#xff0c;如2023年8月 比 2023年7月 二、应用&#xff1a; 1.场景&#xff1a;统计日报、周报、月报、年报下进店客流的同比和环…