【Unity Shader入门精要 第11章】让画面动起来(一)

1. Unity Shader中的时间变量

Shader控制这物体的显示,当向Shader中引入时间变量后,就可以让物体的显示效果随时间发生变化,以实现动画效果。

Unity中常见的时间变量如下表:

变量类型描述
_Timefloat4(t/20, t, 2t, 3t),其中 t 为自该场景加载开始所经过的时间
_SinTimefloat4(t/8, t/4, t/4, t),其中 t 为时间的正弦值
_CosTimefloat4(t/8, t/4, t/4, t),其中 t 为时间的余弦值
unity_DeltaTimefloat4(dt, 1/dt, smoothDt, 1/smoothDt),其中 dt 为时间增量

通过Shader实现的动画效果,最常见的可以分为两种形式:

  • 纹理动画——通过时间改变纹理采样的位置
  • 顶点动画——通过时间改变顶点的位置

2. 纹理动画

2.1 序列帧动画

序列帧动画是常见的一类纹理动画。将一个动画效果中的关键帧图像按顺序保存到一张纹理上,在游戏中根据时间推移,计算当前应该显示关键帧中的哪一帧,并计算其在纹理上的位置,修改采样坐标后进行采样,即可达到动画显示的效果。

另外,由于序列帧动画,特别是特效动画,往往包含半透效果,因此这类动画需要按照透明度混合的方式进行渲染。

下面的例子展示了一个简单的序列帧动画。

使用的序列帧纹理如下:
在这里插入图片描述

测试Shader如下:

Shader "MyShader/Chapter_11/Chapter_11_Boom_Shader"
{
    Properties
    {
        _MainTex("MainTex", 2D) = "white"{}
        _NumInRow("NumInRow", Int) = 3
        _NumInColumn("NumInColumn", Int) = 5
        _Speed("Speed", float) = 10
    }
    SubShader
    {
        Tags{"Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "true"}
    
        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase
            #include "UnityCG.cginc"
            
            struct a2v
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
            
            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
            };
            
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _NumInRow;
            fixed _NumInColumn;
            fixed _Speed;
            
            v2f vert(a2v v)
            {
               v2f o;
               o.pos = UnityObjectToClipPos(v.vertex);
               o.uv = TRANSFORM_TEX(v.uv, _MainTex);
               return o;
            }
            
            fixed4 frag(v2f i) : SV_Target
            {
                
                //计算当前应该显示的关键帧(第几行第几列)
                float _num = floor(_Time.y * _Speed);
                float _row = floor(_num / _NumInRow);
                float _column = _num - _row * _NumInRow; 
                
                //原始的uv是针对整张纹理的采样坐标,由于我们只需要显示其中的一个关键帧,因此需要将uv转换为针对这一帧图像的坐标
                //整张纹理被等分成了 _NumInColumn 行、_NumInRow 列,因此只需要与总行数和总列数相除,即可将原始uv缩放到单帧图像的uv
                //i.uv = float2(i.uv.x / _NumInRow, i.uv.y / _NumInColumn);
                //针对第_row行、_column列的关键帧图像计算偏移
                //同样因为整张纹理被等分成了 _NumInColumn 行、_NumInRow 列,且纹理坐标的范围为[0,1]
                //因此行中每一个图像的偏移为 1/_NumInRow,列中每一个图像的偏移为 -1/_NumInColumn(图像是从上向下排列的)
                //i.uv += float2(_column / _NumInRow, - _row / _NumInColumn);
                
                //对上面的计算过程整理合并,可以减少除法的次数
                i.uv += float2(_column, -_row);
                i.uv.x /= _NumInRow;
                i.uv.y /= _NumInColumn;
                
                return tex2D(_MainTex, i.uv);
            }
            
            ENDCG
        }
    }
}

效果如下:
在这里插入图片描述

2.2 滚动背景

无限滚动背景的原理是以一张在某方向上可以与自身进行拼接的图片作为纹理,在每个时刻下计算当前时刻在该方向上的UV偏移,并进行采样显示。

下面的例子通过两张图片(一张背景图,一张前景图)的纹理动画实现分层滚动背景的效果。

例子中用到了 frac 方法,其作用是返回参数的小数部分,从而做到循环采样。

Shader如下:

Shader "MyShader/Chapter_11/Chapter_11_BackGround_Shader"
{
    Properties
    {
        _BackTex("BackTex", 2D) = "white"{}
        _FrontTex("FrontTex", 2D) = "white"{}
        _Speed_1("Speed1", float) = 0.2
        _Speed_2("Speed2", float) = 0.3
    }
    SubShader
    {
        Tags{"Queue" = "BackGround" "RenderType" = "Opaque" "IgnoreProjector" = "true"}
    
        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase
            #include "UnityCG.cginc" 
            
            struct a2v
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
            
            struct v2f
            {
                float4 pos : SV_POSITION;
                float4 uv : TEXCOORD0;
            };
            
            sampler2D _BackTex;
            float4 _BackTex_ST;
            sampler2D _FrontTex;
            float4 _FrontTex_ST;
            half _Speed_1;
            half _Speed_2;
            
            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv.xy = TRANSFORM_TEX(v.uv, _BackTex) + frac(float2(_Speed_1, 0 ) * _Time.y);
                o.uv.zw = TRANSFORM_TEX(v.uv, _FrontTex) + frac(float2(_Speed_2, 0 ) * _Time.y);
                return o;
            }
            
            fixed4 frag(v2f i) : SV_Target
            {
                fixed4 _backColor = tex2D(_BackTex, i.uv.xy);
                fixed4 _frontColor = tex2D(_FrontTex, i.uv.zw);

                fixed3 _finalColor = lerp(_backColor.rgb, _frontColor.rgb, _frontColor.a);
                return fixed4(_finalColor, 1);
            }
            
            ENDCG
        }
    }
}

效果如下:

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

二维数组传参时不用二级指针接收

先放结论: 1. 二维数组数组名指向的类型是 int [x] 类型,int** 指针指向类型是 int* ,如果用二级指针接收会导致访问错误,因为 int [x] 类型和 int* 类型不同。 2. 指向什么类型的指针1就按照该类型的字节数1移动。 最近在学…

unity2D跑酷游戏

项目成果 项目网盘 导入资源包 放入Assets文件Assets资源文件 游戏流程分析 摄像机size调小,让图片占满屏幕 人跑本质,相对运动,图片无限向右滚动 图片720,缩小100倍第二个图片x为7.2每unit px100两张图片刚好挨着连贯 空对象Bg…

Cloudflare的增长正在放缓,股价过高,未来将进一步下跌

来源:猛兽财经 作者:猛兽财经 一、Cloudflare公司介绍 1.1、Cloudflare(NET)是一家全球性云平台,总部位于美国旧金山,在英国伦敦亦设有办事处。 Cloudflare以向客户提供网站安全管理、性能优化及相关的技术支持为主要业务。通过基…

职场中,那些35岁以上的测试猿到底去哪了?

🔥 交流讨论:欢迎加入我们一起学习! 🔥 资源分享:耗时200小时精选的「软件测试」资料包 🔥 教程推荐:火遍全网的《软件测试》教程 📢欢迎点赞 👍 收藏 ⭐留言 &#x1…

收银系统源码--商超水果生鲜店收银硬件要怎么选择?

新零售时代,越来越多的商家开始明白,除了要做好店铺定位、店面装潢和商品的设定,还要选购最适合店铺运营需求的收银机和硬件,好的收银机和收银系统可以帮助商家做好收支统计、库存管理、人员配置。客户服务等工作。现在的智能收银…

解决bind error: Address already in use

是端口复用问题 产生原因 程序突然退出系统但是没有释放端口 问题解决 首先通过 //显示进程信息 ps -la //杀死相关进程 kill -9 xxxx然后添加socket设置 int on1; if(setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0){perror("setsockopt")…

RocketMQ学习(2) 深入学习

RokcetMQ的介绍和基础知识见这篇博客——RocketMQ学习(1) 快速入门 本篇为上一篇的深入学习&#xff0c;很多基础知识不再赘述。 目录 消息重复消费问题(去重;幂等)布隆过滤器 重试机制死信消息 SpringBoot集成RocketMQ集成SpringBoot发送不同消息模式(同步消息)异步消息单向消…

Kafka系列之高频面试题

基础 简介 特点&#xff1a; 高吞吐、低延迟&#xff1a;kafka每秒可以处理几十万条消息&#xff0c;延迟最低只有几毫秒&#xff0c;每个Topic可以分多个Partition&#xff0c;Consumer Group对Partition进行Consumer操作可扩展性&#xff1a;Kafka集群支持热扩展持久性、可…

OFA one-for-all 通用多模态预训练模型

使用简单的序列到序列的学习框架 统一模态 &#xff08;跨模态、视觉、语言等模态&#xff09;和任务&#xff08;如图片生成、视觉定位、图片描述、图片分类、文本生成等&#xff09; ICML 2022&#xff1a; 《OFA: Unifying Architectures, Tasks, and Modalities Through a…

2024最新 Jenkins + Docker 实战教程(六)- Jenkins配置邮箱接收构建通知

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

Redis常用命令大全

目录 1、五大数据类型的基本命令 1.1 字符串 1.2 列表 1.3 哈希 1.4 集合 1.5 有序集合 2、与key相关 2.1 查看redis数据的类型 2.2 查看当前redis库中的所有key命令 3、除了五大数据类型外常见命令 3.1 键操作 3.2 服务器操作 3.3 连接操作 3.4 发布/订阅 3.5 事…

vue canvas绘制信令图二、

需求:根据信令图标题的每2个区域之间有无内容来给宽度,无内容区域的间隔要小一些。有内容区域的间隔大一些。 先上效果图: 从上面的效果图可以看出无内容区域的间隔宽度变小了很多。 1、先设置一个最先间隔的宽度:minGapX: 200, 2、然后设置一个 存放有计算后的间隔数据:…

【爱空间_登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞 …

尝试用智谱机器人+知识库,制作pytorch测试用例生成器

尝试用智谱机器人知识库,制作pytorch测试用例生成器 1 保存pytorch算子文档到txt2 创建知识库3 创建聊天机器人4 测试效果5 分享 背景:是否能将API的接口文档和sample放到RAG知识库,让LLM编写API相关的程序呢 小结:当前的实验效果并不理想,可以生成代码,但几乎都存在BUG 1 保存…

SpringCloud Feign用法

1.在目标应用的启动类上添加开启远程fein调用注解&#xff1a; 2.添加一个feign调用的interface FeignClient("gulimall-coupon") public interface CouponFeignService {PostMapping("/coupon/spubounds/save")R save(RequestBody SpuBondTo spuBounds);…

数据结构的快速排序(c语言版)

一.快速排序的概念 1.快排的基本概念 快速排序是一种常用的排序算法,它是基于分治策略的一种高效排序算法。它的基本思想如下: 从数列中挑出一个元素作为基准(pivot)。将所有小于基准值的元素放在基准前面,所有大于基准值的元素放在基准后面。这个过程称为分区(partition)操作…

期末速成 ——计算机组成原理(2)数值的表示与运算

目录 一、定点数的表示 &#xff08;一&#xff09;无符号数和有符号数的表示 &#xff08;二&#xff09;机器数的定点表示 &#xff08;三&#xff09;原码、补码、反码、移码 (1)原码表示法 二、浮点数的表示 三、溢出判断 (一)采用一位符号位 (二)采用双符号位 四…

重学java 53. 集合 二叉树查找树红黑树

少焦虑 多睡觉 常开心 —— 24.5.30 二叉树&#xff1a; 分支不能超过两个 平衡树&#xff1a; 左孩子和右孩子数量相等 不平衡树&#xff1a; 左孩子数量不等于右孩子 排序树/查找树: 在二又树的基础上元素是有大小排序的 左子树小,右子树大 红黑树&#xff1a; 1.每一个节点…

conda与pip的镜像源与代理设置

conda与pip的镜像源与代理设置 一、前言二、conda镜像源设置2.1conda默认镜像源介绍2.2通过终端设置镜像源2.3通过配置文件设置镜像源 三、pip镜像源设置3.1pip默认镜像源介绍3.2通过终端临时设置镜像源3.3通过配置文件设置一个或多个镜像源 四、conda代理设置4.1通过终端设置代…

SpringBoot 基于jedis实现Codis高可用访问

codis与redis的关系 codis与redis之间关系就是codis是基于多个redis实例做了一层路由层来进行数据的路由&#xff0c;每个redis实例承担一定的数据分片。 codis作为开源产品&#xff0c;可以很直观的展示出codis运维成本低&#xff0c;扩容平滑最核心的优势. 其中&#xff0…