当前位置: 首页 > article >正文

【Unity Shader URP】序列帧动画(Sprite Sheet)实战教程

文章目录0. 效果预览1. 原理简述2. 功能点3. 完整 Shader可直接用4. 使用方法5. 参数说明6. 变体与扩展6.1 带 Billboard 的顶点着色器Shader 内置面向摄像机6.2 外部控制帧索引C# 驱动6.3 Additive 混合火焰/光效7. 常见问题8. 性能建议0. 效果预览序列帧动画是特效制作的基本功把一组连续帧画面排列在一张贴图上Shader 按时间依次采样每一帧实现火焰、爆炸、烟雾、魔法阵等循环动画。不需要骨骼、不需要粒子系统一张图 一个 Shader 就能跑。1. 原理简述序列帧动画的本质把 UV 坐标限制在贴图的某一格内随时间推移切换到下一格。一张 4×4 的序列帧贴图有 16 帧。每一帧占据 1/4 宽度、1/4 高度的 UV 区域。Shader 要做的事// 1. 算出当前是第几帧 int frameIndex floor(_Time.y * _Speed) % totalFrames; // 2. 算出这一帧在第几行第几列 int col frameIndex % _Columns; int row frameIndex / _Columns; // 3. 把 UV 缩放到单帧大小再偏移到对应格子 float2 uv (uv float2(col, row)) / float2(_Columns, _Rows);注意贴图的 UV 原点在左下角但序列帧通常从左上角开始排列所以行号需要翻转。2. 功能点自动播放基于_Time驱动无需 C# 脚本即可循环播放行列可配支持任意 N×M 的序列帧布局4×4、8×8、2×4 等速度可调_Speed控制每秒播放帧数FPS帧间插值可选开启两帧之间的线性混合消除跳帧感透明支持Alpha Blend 渲染适合叠加在场景上的特效Billboard 可选配合顶点着色器实现始终面向摄像机GPU Instancing支持多实例渲染3. 完整 Shader可直接用Shader Custom/SpriteSheet_URP { Properties { // 序列帧贴图一张包含所有帧的图集 _MainTex (Sprite Sheet, 2D) white {} // 主颜色叠乘可用于调色或控制整体透明度 _BaseColor (Base Color, Color) (1,1,1,1) // 列数水平方向有几帧 _Columns (Columns, Int) 4 // 行数垂直方向有几帧 _Rows (Rows, Int) 4 // 播放速度每秒帧数 _Speed (Speed (FPS), Range(1, 60)) 10 // 总帧数如果最后一行没排满填实际帧数 _TotalFrames (Total Frames, Int) 16 // 帧间插值开关1 开启混合0 硬切 [Toggle] _Interpolate (Frame Interpolation, Float) 0 } SubShader { Tags { RenderPipeline UniversalRenderPipeline Queue Transparent RenderType Transparent } Pass { Name SpriteSheetPass Tags { LightMode UniversalForward } Cull Off ZWrite Off Blend SrcAlpha OneMinusSrcAlpha HLSLPROGRAM #pragma vertex vert #pragma fragment frag // GPU Instancing 支持 #pragma multi_compile_instancing #include Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl // // 贴图声明 // TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); // // 材质属性与 Properties 一一对应 // float4 _MainTex_ST; float4 _BaseColor; int _Columns; int _Rows; float _Speed; int _TotalFrames; float _Interpolate; struct Attributes { float4 positionOS : POSITION; // 模型空间顶点 float2 uv : TEXCOORD0; // UV 坐标 UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionHCS : SV_POSITION; // 裁剪空间位置 float2 uv : TEXCOORD0; // 传递 UV UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; // // 计算某一帧的 UV将原始 UV 缩放并偏移到对应格子 // float2 GetFrameUV(float2 uv, int frameIndex) { // 列号 帧索引 % 列数 int col frameIndex % _Columns; // 行号 帧索引 / 列数从上往下数 int row frameIndex / _Columns; // UV 原点在左下角但序列帧从左上角排列 // 翻转行号实际行 总行数 - 1 - row int flippedRow _Rows - 1 - row; // 每帧占据的 UV 尺寸 float2 frameSize float2(1.0 / _Columns, 1.0 / _Rows); // 缩放 UV 到单帧大小再偏移到目标格子 return uv * frameSize float2(col, flippedRow) * frameSize; } // // 顶点着色器 // Varyings vert(Attributes v) { Varyings o; UNITY_SETUP_INSTANCE_ID(v); UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.positionHCS TransformObjectToHClip(v.positionOS.xyz); o.uv TRANSFORM_TEX(v.uv, _MainTex); return o; } // // 片元着色器核心序列帧采样 // half4 frag(Varyings i) : SV_Target { UNITY_SETUP_INSTANCE_ID(i); // 1) 计算当前时间对应的帧进度浮点数 // _Time.y 自场景加载以来的秒数 float frameProgress _Time.y * _Speed; // 2) 当前帧索引取模实现循环 int currentFrame ((int)floor(frameProgress)) % _TotalFrames; // 3) 采样当前帧 float2 currentUV GetFrameUV(i.uv, currentFrame); half4 currentColor SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, currentUV); // 4) 帧间插值可选 half4 finalColor currentColor; if (_Interpolate 0.5) { // 下一帧索引 int nextFrame (currentFrame 1) % _TotalFrames; float2 nextUV GetFrameUV(i.uv, nextFrame); half4 nextColor SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, nextUV); // 用小数部分作为混合权重 float blend frac(frameProgress); finalColor lerp(currentColor, nextColor, blend); } // 5) 叠乘基础颜色 finalColor * (half4)_BaseColor; return finalColor; } ENDHLSL } } }4. 使用方法在Assets/Shaders/下新建文件SpriteSheet_URP.shader粘贴上方完整代码。新建材质Create → MaterialShader 选择Custom/SpriteSheet_URP。准备序列帧贴图一张包含所有帧的图集帧按从左到右、从上到下排列常见来源特效软件导出Houdini、EmberGen、手绘帧动画、Unity 粒子录制贴图导入设置Texture Type DefaultAlpha Source Input Texture Alpha关闭Generate Mip Maps避免帧边缘渗色将贴图拖到材质的Sprite Sheet槽位。设置参数Columns/Rows与贴图的实际行列数一致如 4×4 就填 4 和 4Total Frames实际帧数如果最后一行没排满填真实帧数而不是行×列Speed每秒播放帧数10~15 适合火焰20~30 适合爆炸创建一个 Quad3D Object → Quad赋上材质在 Game 视图中即可看到动画循环播放。如果需要特效面向摄像机给 Quad 挂一个简单的 Billboard 脚本usingUnityEngine;publicclassBillboard:MonoBehaviour{voidLateUpdate(){// 让物体始终面向摄像机transform.forwardCamera.main.transform.forward;}}5. 参数说明参数类型范围/默认值说明_MainTex2Dwhite序列帧贴图所有帧排列在一张图上_BaseColorColor(1,1,1,1)颜色叠乘可用于调色或控制整体透明度_ColumnsInt4贴图水平方向的帧数_RowsInt4贴图垂直方向的帧数_SpeedRange(1,60)10播放速度每秒帧数FPS_TotalFramesInt16实际总帧数最后一行没排满时填真实值_InterpolateToggle0帧间插值开启后两帧之间线性混合动画更平滑6. 变体与扩展6.1 带 Billboard 的顶点着色器Shader 内置面向摄像机不需要 C# 脚本直接在顶点着色器中实现 BillboardVaryings vert(Attributes v) { Varyings o; UNITY_SETUP_INSTANCE_ID(v); UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); // Billboard用摄像机的右方向和上方向替换模型的 X/Y 轴 float3 centerWS TransformObjectToWorld(float3(0, 0, 0)); float3 camRight UNITY_MATRIX_V[0].xyz; // 摄像机右方向 float3 camUp UNITY_MATRIX_V[1].xyz; // 摄像机上方向 // 用模型空间的 xy 作为偏移量沿摄像机平面展开 float3 positionWS centerWS camRight * v.positionOS.x * unity_ObjectToWorld._m00 // 保留缩放 camUp * v.positionOS.y * unity_ObjectToWorld._m11; o.positionHCS TransformWorldToHClip(positionWS); o.uv TRANSFORM_TEX(v.uv, _MainTex); return o; }6.2 外部控制帧索引C# 驱动有时需要精确控制播放进度如技能释放到某个阶段播放特定帧段// 在 Properties 中加一个手动帧索引// _ManualFrame (Manual Frame, Range(0, 64)) -1// 负值 自动播放非负值 锁定到指定帧// C# 端material.SetFloat(_ManualFrame,5);// 锁定到第 5 帧material.SetFloat(_ManualFrame,-1);// 恢复自动播放// frag 中替换帧索引计算 int currentFrame; if (_ManualFrame 0) currentFrame clamp((int)_ManualFrame, 0, _TotalFrames - 1); else currentFrame ((int)floor(_Time.y * _Speed)) % _TotalFrames;6.3 Additive 混合火焰/光效火焰、闪电等发光特效用 Additive 混合比 Alpha Blend 更自然// 把 Pass 中的 Blend 模式改为 Blend SrcAlpha One // Additive源色 × Alpha 加到目标上效果亮的部分叠加发光暗的部分黑色自然消失不需要精确的 Alpha 通道。7. 常见问题Q: 动画播放顺序反了从右到左或从下到上A: 检查两个地方① 贴图的帧排列方向是否是左到右、上到下——这是本 Shader 的默认约定② 如果贴图是左到右、下到上排列把GetFrameUV中的flippedRow改为int flippedRow row;去掉翻转。Q: 帧与帧之间有明显的接缝/渗色A: 两个原因① Mip Maps 导致相邻帧的像素渗透——在贴图导入设置中关闭 Generate Mip Maps② 贴图的 Wrap Mode 设为Clamp而不是Repeat避免边缘采样到对面的帧。Q: 开启帧间插值后画面变模糊A: 正常现象——两帧线性混合本质上就是叠加运动剧烈的帧之间会产生重影。如果不能接受关闭_Interpolate用更高的帧率更多帧来弥补平滑度。Q: 贴图最后一行没排满比如 4×4 但只有 14 帧播放到空白帧A: 把Total Frames设为实际帧数14Shader 会在第 14 帧后循环回第 0 帧不会播放到空白格子。Q: 多个使用同一材质的 Quad 动画完全同步A: 因为它们共享同一个_Time值。解决方案用MaterialPropertyBlock给每个实例设置不同的时间偏移或者在 Shader 中加一个_TimeOffset属性C# 端随机赋值。8. 性能建议贴图尺寸控制4×4 的序列帧贴图每帧 256×256 → 整张图 1024×1024这是移动端的舒适区。8×8 每帧 128×128 也是 1024×1024帧数更多但单帧精度降低按需取舍。关闭 Mip Maps序列帧贴图不需要 Mip MapsUI/特效通常在固定距离观看关掉可以节省 33% 显存。Additive 优于 Alpha Blend如果视觉上允许Additive 混合不需要排序GPU 友好。帧间插值的代价开启插值 每个像素采样两次贴图。如果特效数量多几十个同屏关闭插值可以减半采样开销。合批注意多个使用相同材质的 Quad 可以被 SRP Batcher / GPU Instancing 合批。如果用了MaterialPropertyBlock设置不同参数GPU Instancing 仍然有效但 SRP Batcher 会被打断。

相关文章:

【Unity Shader URP】序列帧动画(Sprite Sheet)实战教程

文章目录0. 效果预览1. 原理简述2. 功能点3. 完整 Shader(可直接用)4. 使用方法5. 参数说明6. 变体与扩展6.1 带 Billboard 的顶点着色器(Shader 内置面向摄像机)6.2 外部控制帧索引(C# 驱动)6.3 Additive …...

别再纠结了!用Nuitka一键打包你的Python项目(含PyTorch依赖处理)

深度解析Nuitka:Python项目打包与PyTorch依赖处理实战指南 在Python生态中,项目打包一直是个令人头疼的问题——尤其是当你需要处理像PyTorch这样的复杂依赖时。传统的PyInstaller虽然简单易用,但在处理深度学习框架时常常会遇到各种兼容性问…...

2026最权威的十大降AI率网站解析与推荐

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 意在协助用户降低文本重复所占比率的降重网站,借助同义词取代、句式重新组合以及…...

2025届毕业生推荐的五大降重复率工具横评

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 当下,人工智能内容生成技术被广泛应用,此时,AIGC检测系统…...

记一次系统环境变量更改后在IDEA中无法读取新值的排查过程

问题背景本人在测试Protocol buffers序列化工具时,将项目设置为了 JDK 22 版本,如图所示:问题现象但在执行时,因为涉及到需要手动执行 mvn clean compile 命令,但是我的本地 JDK 环境是为了兼容之前项目而设置的1.8版本…...

终极指南:如何快速解决AI绘图中的维度冲突:3种实用方案指南

终极指南:如何快速解决AI绘图中的维度冲突:3种实用方案指南 【免费下载链接】ComfyUI-BrushNet ComfyUI BrushNet nodes 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-BrushNet 在AI图像生成领域,ComfyUI BrushNet作为一款强…...

深度拆解 GEO 服务商收费标准及影响因素|北京聚微文化传媒

深度拆解 GEO 服务商收费标准及影响因素|北京聚微文化传媒作者:北京聚微文化传媒GEO 优化专家团队在生成式引擎优化(GEO)领域,传统 “按关键词排名” 计费已不再适用。GEO 的核心是让大模型(LLM&#xff09…...

算法与心智的双重反噬:为何亚马逊品牌延伸会“污染”搜索标签与用户预期

大众汽车的兴衰史,是品牌定位与延伸战略的经典悲剧,其在亚马逊的商业战场上有着精确的映射。一个品牌凭借极致聚焦的定位(如“微型车”)获得巨大成功,在消费者心智和平台算法中注册了清晰的“价值标签”;然…...

农村与中小城市的数字化,藏着被忽略的技术蓝海

被忽视的数字新大陆当一线城市的数字化转型趋于饱和,农村与中小城市正悄然成为技术落地的"价值洼地"。这片蓝海蕴藏着庞大的场景创新空间,却因基础设施薄弱、用户群体特殊、生态体系未成型等痛点被长期忽视。对软件测试从业者而言,…...

职业倦怠解药:软件测试从业者如何保持长期动力

测试工程师的倦怠困局在敏捷开发与持续交付的浪潮中,软件测试工程师长期面临三重压力:技术迭代焦虑(AI测试工具每月更新)、价值隐形化(自动化脚本掩盖人工贡献)和责任错配(线上事故归咎测试环节…...

Spring事务基础知识+使用方法+源码拆解

下面我会简单介绍一下 Spring 事务的基础知识,以及使用方法,然后直接对源码进行拆解。 不 BB,上文章目录。 1. 1. 项目准备 需要搭建环境的同学,代码详见:https://github.com/lml200701158/program_demo/tree/main/s…...

Unity游戏接入Steam成就系统:从Steamworks配置到C# API调用的保姆级避坑指南

Unity游戏接入Steam成就系统全流程实战指南 当独立游戏开发者决定将作品发布到Steam平台时,成就系统往往是提升玩家留存和互动的重要功能。不同于简单的API调用,一个健壮的Steam成就实现需要前后端配置、统计逻辑绑定和代码架构的完整配合。本文将带你从…...

2026年AI企业怎么选?深度评测解析,新手也能精准避坑

一、摘要据IDC 2026年上半年中国AI行业发展报告显示,国内AI企业数量突破3000家,但具备核心技术自研能力、可实现规模化商业落地的企业不足20%,同质化竞争导致用户选型失误率高达45%。无论是企业用户寻求AI解决方案赋能业务,还是个…...

YOLOv8在Jetson上实时推理的终极优化:从.pt到INT8/FP16量化TensorRT引擎全流程

YOLOv8在Jetson平台上的极致性能优化:从模型量化到TensorRT部署实战 当你在Jetson边缘设备上部署YOLOv8模型时,是否遇到过这样的困境——明明使用了GPU加速,推理速度却依然无法满足实时视频分析的需求?这可能是由于你没有充分利用…...

C99与C11模式下解决for循环初始化声明错误的实用指南

1. 为什么你的for循环会报错? 最近有个朋友在用CodeBlocks写C代码时遇到了一个奇怪的错误。他在for循环里声明变量时,编译器直接报错:"[Error] for loop initial declarations are only allowed in C99 or C11 mode"。这让他很困惑…...

天尊传奇「剑神密藏」全攻略

核心玩法:消耗灵符 / 剑神密钥抽奖,享高倍加成,可 100 连抽,目标拿飞剑、神装等稀缺战力资源天尊传奇。一、核心规则与折扣消耗:灵符或剑神密钥(密钥可通过活动 / 商城获取,优先用密钥保底&…...

课题申请:如何预判评审潜台词并从容应对?

在基金申报的激烈竞争中,许多科研人员常常陷入一个误区:将申请书单纯地视为一份“任务说明书”。我们习惯于在文中详细罗列“要做什么”、“打算怎么做”,却往往忽略了评审专家在阅读时的心理活动。当一份申请书只停留在陈述层面,…...

【爬虫实战对比】Requests vs Scrapy 笔趣阁小说爬虫,从单线程到高效并发的全方位升级

【爬虫实战对比】Requests vs Scrapy 笔趣阁小说爬虫,从单线程到高效并发的全方位升级 近期完成了笔趣阁小说爬虫的重构,从最初的Requests单线程版本,升级为Scrapy框架版本,过程中深刻体会到两者在开发效率、运行性能、代码可维护…...

1644万,无锡市“一网统管”城市运行管理平台

4月3日,无锡市“一网统管”城市运行管理平台(扩续建2025)采购公告,项目预算金额:1644.439万元,提交投标文件截止时间:2026-04-29 09:30 (北京时间)。一、项目信息&#x…...

智元GO-2:具身基座大模型新突破

智元机器人正式推出新一代具身基座大模型Genie Operator-2(GO-2),它在GO-1基础上进化,弥合语义‑运动鸿沟,在多个基准测试中刷新行业SOTA。进化亮点:弥合语义‑运动鸿沟GO-2在GO-1基础上进化,致…...

Qwen-Ranker Pro效果展示:‘猫洗澡’vs‘狗洗澡’语义陷阱精准识别案例

Qwen-Ranker Pro效果展示:‘猫洗澡’vs‘狗洗澡’语义陷阱精准识别案例 1. 引言:当搜索遇到语义陷阱 你有没有遇到过这样的情况:在搜索引擎中输入"猫洗澡的注意事项",结果却给你推荐了一大堆"给狗洗澡"的内…...

西门子博途1500SCL程序和梯形图两者结合编程,包括西门子v90伺服profinet通讯控制

西门子博途1500SCL程序和梯形图两者结合编程,包括西门子v90伺服profinet通讯控制,发那科机器人profinet通讯控制,多profinet io从站,扫码枪串口通讯,触摸屏类似配方功能多行参数显示,模块化结构化编程方式&…...

OpenClaw技能扩展:基于千问3.5-9B的内容处理自动化实践

OpenClaw技能扩展:基于千问3.5-9B的内容处理自动化实践 1. 为什么需要内容处理自动化 作为一个经常需要产出技术文档的开发者,我发现自己每天要重复处理大量内容相关的琐碎工作:从收集资料、整理笔记到生成初稿、调整格式,最后还…...

那些你不知道自己需要监控的 Linux 暗坑期

我为什么会发出这个疑问呢?是因为我研究Web开发中的一个问题时,HTTP请求体在 Filter(过滤器)处被读取了之后,在 Controller(控制层)就读不到值了,使用 RequestBody 的时候。 无论是字…...

【实践】Dify文件下载功能实现与优化指南

1. Dify文件下载功能实现全流程解析 第一次接触Dify文件下载功能时,我也被它独特的存储机制绕晕了。和常见的直接返回文件流的做法不同,Dify的存储类实现更像是"黑箱操作"——文件明明被下载到了指定目录,却找不到返回内容的出口。…...

strlen 和 sizeof 的核心区别

strlen 和 sizeof 的核心区别(超清晰版)这是 C 语言最常考、最易错的知识点,我用最简单的方式给你讲明白:一句话总结sizeof:算内存大小(占多少字节),编译器算,不看内容st…...

智能医学影像分析系统 手骨X光影像的骨折检测与分类任务 手骨x光识别10653期(数据集+模型+界面+代码)

手骨x光识别10653期 README 项目概述 类别 远端指间关节 掌指关节 近端指间关节 桡骨 尺骨 腕部/手腕手骨X光影像数据集分析数据概览关键信息总数量及类别8900,类别:6数据集数量(取整)8900数据格式与应用价值YoloVOC,适…...

JLink 添加国产芯片手把手教程(雅特力 + 华大)

大家好,我是嵌入式学习菌,一名在上海嘉定打拼的嵌入式开发工程师。2023 年 7 月硕士毕业,现深耕嵌入式软件开发,日常和 MCU、调试器打交道。现在项目都在做国产 MCU 替代,雅特力 AT32、华大 HC32 用得越来越多,但 JLink 默认不自带这两家芯片支持,每次都要手动添加。 今…...

AI原生研发ROI断崖预警:2024Q2实测数据揭示——超61%项目在MVP后陷入“伪敏捷成本陷阱”

第一章:AI原生软件研发成本优化实战技巧 2026奇点智能技术大会(https://ml-summit.org) AI原生软件的研发成本常被模型训练开销主导,但实际可观测的浪费更多来自推理服务冗余、提示工程低效、向量数据库未压缩索引及本地开发环境重复构建。聚焦真实生产…...

西安 GEO 服务商有哪些?在到店引流方案中提供哪些关键数据和支持?

在西安,GEO服务商的有效选择直接影响到到店引流方案的实施效果。这些服务商能够提供关键数据支持,比如曝光量、咨询量和转化率,这些数据对于企业评估市场推广效果和优化策略至关重要。企业需要关注服务商的数据透明度,确保其反馈的…...