Unity Shader:从基础使用到动画实现全解析

在Unity的精彩世界里,Shader(着色器)堪称打造独特视觉效果的魔法棒。无论是绚丽的光影、奇幻的材质,还是生动的动画,Shader都能助你一臂之力。今天,就让我们一同深入探索Unity中Shader的使用方法,以及如何调用Shader实现令人惊叹的动画效果。

一、Shader基础:开启图形渲染的大门

(一)Shader是什么

Shader本质上是运行在GPU上的小程序,专门负责控制渲染过程中每个像素或顶点的外观。想象一下,GPU就像一个高效的工厂,Shader则是工厂里的技术工人,精确地塑造着每个图形元素的模样。通过编写Shader,我们可以实现从简单的颜色变化到复杂的光照模拟、反射折射等各种效果。

(二)Shader的类型

  1. 顶点着色器(Vertex Shader):主要处理顶点数据,包括位置、法线、纹理坐标等。它如同一位空间魔法师,能够对顶点进行平移、旋转、缩放等变换,还能将顶点从模型空间巧妙地转换到世界空间、视空间等不同的坐标系统。
  2. 片段着色器(Fragment Shader):也叫像素着色器,在顶点着色器完成对顶点的处理后,片段着色器闪亮登场。它专注于计算每个像素的最终颜色,通过颜色混合、光照计算、纹理采样等操作,为画面赋予丰富的色彩和细节。

二、编写Shader:用代码描绘绚丽世界

(一)ShaderLab语法初窥

在Unity中,编写Shader通常借助ShaderLab语法。下面是一个简单Shader的基本结构:

// 定义一个名为Custom/MyShader的Shader
Shader "Custom/MyShader" {// 定义属性,这些属性会在材质面板中显示,方便用户在不修改代码的情况下调整Shader效果Properties {// 定义一个名为_MainColor的颜色属性,在材质面板中显示名称为“Main Color”,默认值为白色(1, 1, 1, 1)_MainColor ("Main Color", Color) = (1,1,1,1) // 定义一个名为_FloatValue的浮点型属性,在材质面板中显示名称为“Float Value”,默认值为0.5_FloatValue ("Float Value", Float) = 0.5 // 定义一个名为_RangeValue的范围型属性,在材质面板中显示名称为“Range Value”,范围是0到1,默认值为0.5_RangeValue ("Range Value", Range(0, 1)) = 0.5 // 定义一个名为_MainTexture的二维纹理属性,在材质面板中显示名称为“Main Texture”,默认值为白色纹理_MainTexture ("Main Texture", 2D) = "white" {} // 定义一个名为_VectorValue的向量属性,在材质面板中显示名称为“Vector Value”,默认值为(1, 1, 1, 1)_VectorValue ("Vector Value", Vector) = (1, 1, 1, 1) // 定义一个名为_CubeMap的立方体贴图属性,在材质面板中显示名称为“Cube Map”,默认值为白色立方体贴图_CubeMap ("Cube Map", Cube) = "white" {} }SubShader {// 定义显卡支持的渲染代码区域,这里设置渲染类型为不透明Tags { "RenderType" = "Opaque" } Pass {CGPROGRAM// 声明顶点着色器函数为vert#pragma vertex vert // 声明片段着色器函数为frag#pragma fragment frag // 声明与Properties中定义的属性对应的变量,以便在着色器代码中使用uniform fixed4 _MainColor; uniform sampler2D _MainTexture; // 输入结构体(appdata),用于存储从模型中读取的顶点数据struct appdata {// 顶点的位置信息,POSITION语义表示这是顶点位置float4 vertex : POSITION; // 顶点的纹理坐标,TEXCOORD0语义表示这是第一个纹理坐标集float2 uv : TEXCOORD0; };// 输出结构体(v2f),用于将顶点着色器的计算结果传递给片段着色器struct v2f {// 经过变换后顶点在裁剪空间中的位置,SV_POSITION语义表示这是输出到裁剪空间的位置float4 pos : SV_POSITION; // 传递给片段着色器的纹理坐标float2 uv : TEXCOORD0; };// 顶点函数(vert),处理顶点数据v2f vert (appdata v) {v2f o;// 将顶点从模型空间转换到裁剪空间o.pos = UnityObjectToClipPos(v.vertex); // 将顶点的纹理坐标传递给输出结构体o.uv = v.uv; return o;}// 片段着色器(Fragment Shader),计算每个像素的最终颜色fixed4 frag (v2f i) : SV_Target {// 通过纹理采样获取纹理颜色,并与主颜色相乘fixed4 col = tex2D(_MainTexture, i.uv) * _MainColor; return col;}ENDCG}}// 备用Shader,当主SubShader在目标硬件上不被支持时使用,这里使用内置的Diffuse ShaderFallBack "Diffuse" 
}
  1. Properties块:这是我们与Shader交互的桥梁,通过定义属性,如颜色、纹理等,我们可以在材质的Inspector面板中轻松调整这些参数。
    例如:

     `_MainColor`定义了一个颜色属性_FloatValue定义了一个浮点属性`_MainTexture`定义了一个纹理属性。_RangeValue定义了一个范围 属性。_VectorValue 定义了一个向量属性_CubeMap定义了一个立方体贴图属性
    
  2. SubShader块:这里面包含一个或多个Pass,每个Pass代表一次渲染操作
    Tags用于设置渲染队列等重要信息,比如:

     RenderType:定义渲染类型,常见值有"Opaque"(不透明)、"Transparent"(透明)、"TransparentCutout"(透明裁剪)等。Queue:指定渲染队列,决定物体的渲染顺序。常见队列有"Background"(背景队列,最早渲染)、"Geometry"(几何体队列,默认用于不透明物体)、"AlphaTest"(透明度测试队列)、"Transparent"(透明队列,后渲染以保证透明效果正确)等。
    

Pass块:核心的渲染代码部分,使用CGPROGRAM和ENDCG包围的是Cg/HLSL代码。

	顶点着色器(Vertex Shader):处理顶点数据,如位置变换、纹理坐标传递等。
v2f vert (appdata v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = v.uv;return o;
}
	片段着色器(Fragment Shader):计算每个像素的最终颜色。
fixed4 frag (v2f i) : SV_Target {fixed4 col = tex2D(_MainTexture, i.uv) * _MainColor;return col;
}
  1. FallBack:当当前SubShader在目标硬件上不被支持时,Unity会自动使用这里指定的备用Shader,比如FallBack "Diffuse"表示使用内置的Diffuse Shader。

三、使用Shader:让材质绽放光彩

(一)创建材质并应用Shader

  1. 在Unity的Project面板中,右键点击,选择Create -> Material,创建一个全新的材质。
  2. 选中新创建的材质,在Inspector面板的Shader下拉菜单中,找到我们刚刚编写的Shader(例如Custom/MyShader)并选择它。此时,材质就如同被赋予了神奇的力量,开始按照Shader定义的方式展现独特的外观。
  3. 根据Shader中定义的属性,在材质的Inspector面板中进行调整。比如,对于上述Shader,我们可以轻松调整Main Color的颜色,选择心仪的Main Texture纹理,从而打造出千变万化的材质效果。

(二)调试Shader

  1. 帧调试器(Frame Debugger):通过Window -> Analysis 分析-> Frame Debugger 调式器打开这个强大的工具。它就像一个时间放大镜,让我们能够逐帧查看渲染过程,包括每个Pass的详细渲染结果。通过分析这些信息,我们可以精准定位Shader在哪个环节出现问题,是顶点变换异常,还是纹理采样错误,一目了然。
  2. ShaderLab Profiler:在Window -> Analysis -> ShaderLab Profiler着色器实验室分析器中,我们可以获取Shader的性能数据,如绘制调用次数、GPU内存使用情况等。这些数据是优化Shader性能的关键依据,帮助我们发现性能瓶颈,进行针对性的优化。
  3. 添加调试输出:在Shader代码中,我们可以巧妙地使用UnityEngine.Debug.LogDebug.LogWarning等函数输出调试信息。在Cg/HLSL代码中,clip函数不仅可以丢弃不符合条件的像素,还能输出调试信息,例如:
fixed4 frag (v2f i) : SV_Target {if (i.uv.x < 0.5) {clip(-1); // 丢弃左半部分像素}fixed4 col = tex2D(_MainTexture, i.uv) * _MainColor;return col;
}

四、Shader动画:赋予场景灵动之美

(一)在Shader中创建可动画属性

假设我们要打造一个迷人的闪烁效果Shader,通过巧妙改变颜色的透明度来实现闪烁的梦幻效果。

Shader "Custom/FlickerShader" {Properties {_MainColor ("Main Color", Color) = (1,1,1,1)_FlickerSpeed ("Flicker Speed", Range(0.1, 10)) = 1_FlickerAmount ("Flicker Amount", Range(0, 1)) = 0.5}SubShader {Tags { "RenderType" = "Transparent" "Queue" = "Transparent" }Pass {CGPROGRAM#pragma vertex vert#pragma fragment fraguniform fixed4 _MainColor;uniform float _FlickerSpeed;uniform float _FlickerAmount;struct appdata {float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f {float4 pos : SV_POSITION;float2 uv : TEXCOORD0;};v2f vert (appdata v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = v.uv;return o;}fixed4 frag (v2f i) : SV_Target {float flicker = sin(_Time.y * _FlickerSpeed) * _FlickerAmount;fixed4 col = _MainColor;col.a = col.a + flicker;return col;}ENDCG}}FallBack "Transparent/Diffuse"
}

在这个Shader中:

  • _FlickerSpeed属性如同节奏大师,掌控着闪烁的速度。
  • _FlickerAmount属性则像一个调色盘,控制着闪烁的幅度。
  • frag函数中,我们利用sin(_Time.y * _FlickerSpeed) * _FlickerAmount这个神奇的公式计算出闪烁值,并将其巧妙地应用到颜色的透明度上,从而实现迷人的闪烁效果。

(二)在脚本中动态调整Shader属性

为了让闪烁效果更加生动多变,我们创建一个C#脚本,在运行时动态调整Shader的属性。

using UnityEngine;// 定义一个名为FlickerController的脚本类,继承自MonoBehaviour,以便该脚本可以挂载到游戏对象上
public class FlickerController : MonoBehaviour
{// 定义最小闪烁速度,默认为1public float minFlickerSpeed = 1;// 定义最大闪烁速度,默认为5public float maxFlickerSpeed = 5;// 定义最小闪烁幅度,默认为0.2public float minFlickerAmount = 0.2f;// 定义最大闪烁幅度,默认为0.8public float maxFlickerAmount = 0.8f;// 声明一个Material类型的变量,用于存储游戏对象的材质private Material material;// Start方法在脚本实例化后的第一帧更新之前调用void Start(){// 获取挂载该脚本的游戏对象的Renderer组件,并从中获取其材质,赋值给material变量material = GetComponent<Renderer>().material;}// Update方法在每帧都会调用void Update(){// 使用Mathf.PingPong函数,该函数会在0到1之间往返取值,随着时间的推移,// 这个值会在0和1之间不断循环变化,Time.time是一个随时间不断增加的浮点数// Mathf.Lerp函数则根据PingPong函数返回的值,在minFlickerSpeed和maxFlickerSpeed之间进行线性插值,// 从而得到一个在最小和最大闪烁速度之间动态变化的新的闪烁速度float newFlickerSpeed = Mathf.Lerp(minFlickerSpeed, maxFlickerSpeed, Mathf.PingPong(Time.time, 1));// 将新的闪烁速度值传递给材质的_FlickerSpeed属性,该属性应该在对应的Shader中定义material.SetFloat("_FlickerSpeed", newFlickerSpeed);// 与上面计算闪烁速度类似,这里通过改变Time.time的倍数(乘以2),使得闪烁幅度的变化频率更快// 然后在minFlickerAmount和maxFlickerAmount之间进行线性插值,得到新的闪烁幅度float newFlickerAmount = Mathf.Lerp(minFlickerAmount, maxFlickerAmount, Mathf.PingPong(Time.time * 2, 1));// 将新的闪烁幅度值传递给材质的_FlickerAmount属性,该属性同样应该在对应的Shader中定义material.SetFloat("_FlickerAmount", newFlickerAmount);}
}

在这个脚本中:

  • minFlickerSpeedmaxFlickerSpeed设定了闪烁速度的变化范围,就像为闪烁节奏设定了快慢边界。
  • minFlickerAmountmaxFlickerAmount定义了闪烁幅度的区间,决定了闪烁效果的明显程度。
  • Update函数中,我们运用Mathf.LerpMathf.PingPong这两个函数的魔法,动态地改变_FlickerSpeed_FlickerAmount的值,并通过material.SetFloat方法将新的值传递给Shader,从而让闪烁效果随着时间不断变化,充满生机。

(三)应用与测试

  1. 创建材质并应用Shader:在Project面板中创建一个新的材质,将上述Custom/FlickerShader应用到该材质上,赋予材质闪烁的潜力。
  2. 挂载脚本:将FlickerController脚本挂载到带有渲染器的游戏对象上,并将刚才创建的材质赋给该游戏对象的渲染器,建立起脚本与材质之间的紧密联系。
  3. 运行测试:激动人心的时刻到了,运行游戏,你将看到游戏对象的颜色如同夜空中闪烁的繁星,按照设定的方式欢快地闪烁起来,为场景增添独特的魅力。

(四)其他动画方式

  1. 顶点动画:在Shader的顶点函数中,我们可以创造出奇妙的顶点动画效果。比如,让物体表面的顶点像波浪一样起伏波动。通过三角函数或噪声函数,我们能够精准地修改顶点的位置,实现类似水面波光粼粼、旗帜随风飘扬等令人惊叹的效果。
v2f vert (appdata v) {v2f o;float wave = sin(v.vertex.x * 5 + _Time.y) * 0.1;v.vertex.y += wave;o.pos = UnityObjectToClipPos(v.vertex);o.uv = v.uv;return o;
}
  1. 纹理动画:通过巧妙地改变纹理的采样坐标,我们可以实现生动的纹理动画。想象一下,让纹理像潺潺流水一样滚动,模拟出水流的动态效果。
fixed4 frag (v2f i) : SV_Target {float2 uv = i.uv + float2(_Time.y * 0.1, 0);fixed4 col = tex2D(_MainTexture, uv);return col;
}

希望通过这篇博客,你能对Unity中Shader的使用和动画实现有更深入的理解和掌握,在游戏开发的世界里创造出更加绚丽多彩的视觉效果!

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

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

相关文章

单片机复位电路基本理解教程文章·含上拉电阻理解电容开路理解!!!

目录 常见复位电路种类 复位电路电阻上拉理解 电容储能断路理解 ​​​​​​​ ​​​​​​​ 编写不易&#xff0c;仅供学习&#xff0c;请勿搬运&#xff0c;感谢理解 常见元器件驱动电路文章专栏连接 LM7805系列降压芯片驱动电路降压芯片驱动电路详解-…

2501d,d.110

原文 更改编译器 禁止使用-previewfixImmutableConv从const(void)[]复制到void[] 如果const(void)[]数据包含尾常指针,则复制到void[],随后可能会违反常数据: void f(int*[] a, const int*[] b) {void[] va a;const void[] vb b;va[] vb[]; //用常指针填充*a[0] 0; //更…

深入聊聊typescript、ES6和JavaScript的关系与前瞻技术发展

什么是typescript&#xff0c;为什么项目当中你可能没见过&#xff1f; TypeScript由微软发布于2012年&#xff0c;在发布之初并没有立即获得广泛的采用&#xff0c;但随着它的逐步发展和流行的框架&#xff08;如 Angular 和 React&#xff09;的支持&#xff0c;TypeScript …

Linux(Centos 7.6)网卡信息没有了问题处理

1.问题现象 虚拟机打开后&#xff0c;使用ifconfig查看IP信息&#xff0c;虚拟机默认的网卡名称是ens33&#xff0c;ifconfig没有看到相关问题&#xff0c;远程连接工具Xshell也不能正常访问该虚拟机。 [rootnode1 ~]# ifconfig lo: flags73<UP,LOOPBACK,RUNNING> mtu…

【大模型系列】Mobile-Agent(2024.04)

Paper: https://arxiv.org/pdf/2401.16158Github: https://github.com/X-PLUG/MobileAgentAuthor: Junyang Wang et al. 北交、阿里巴巴 Mobile-agent核心工作&#xff1a; 首先使用视觉感知工具(检测和OCR模型)识别前端界面中文本和图像元素的精确位置 检测图标&#xff1a;…

Android Studio学习笔记

01-课程前面的话 02-Android 发展历程 03-Android 开发机器配置要求 04-Android Studio与SDK下载安装 05-创建工程与创建模拟器

数据的简单处理——pandas模块——数据结构(Series和DataFrame对象)

pandas模块是基于Numpy模块开发的。在pandas模块中有两个重要的数据结构对象——Series和DataFrame。使用这两个对象可以在计算机的内存中构建虚拟的数据库。对于Series和DataFrame对象主要有三类&#xff0c;都是包括普通默认的方式、添加行列标签的方式、采用字典创建数据结构…

Linux 服务器启用 DNS 加密

DNS 加密的常用协议包括 DNS over HTTPS (DoH)、DNS over TLS (DoT) 和 DNSCrypt。以下是实现这些加密的步骤和工具建议&#xff1a; 1. 使用 DoH (DNS over HTTPS) 工具推荐&#xff1a; cloudflared&#xff08;Cloudflare 提供的客户端&#xff09;doh-client&#xff08;…

【three.js】材质(Material)

基础网格材质&#xff08;MeshBasicMaterial&#xff09;【常用】 一个以简单着色&#xff08;平面或线框&#xff09;方式来绘制几何体的材质&#xff0c;这种材质不受光照的影响。常用于背影、2D图形等场景。 参数&#xff1a; color&#xff1a;材质颜色。 opacity&#x…

【数据库系列】Spring Boot 中整合 MyBatis-Plus详细步骤

在 Spring Boot 中整合 MyBatis-Plus 可以按照以下步骤进行&#xff1a; 一、整合步骤 1. 创建 Spring Boot 项目 首先&#xff0c;使用 Spring Initializr&#xff08;https://start.spring.io/&#xff09;创建一个新的 Spring Boot 项目。在创建过程中&#xff0c;选择以…

naive ui 使用地址记录

naive ui 地址Naive UI Naive UI 是一个 Vue3 的组件库。 要了解如何安装&#xff0c;参见安装。 它比较完整&#xff0c;主题可调&#xff0c;用 TypeScript 写的&#xff0c;快

CVSS漏洞评分系统曝出严重缺陷

在网络安全领域&#xff0c;漏洞的管理和评估是企业防御的重要一环。然而&#xff0c;随着技术的快速发展和攻击手段的不断演变&#xff0c;传统的漏洞评分系统显露出了不可忽视的弊端。在近期的Black Hat欧洲大会上&#xff0c;摩根大通的网络安全专家警告称&#xff0c;通用漏…

深入剖析MySQL数据库架构:核心组件、存储引擎与优化策略(一)

sql语句分为两大类&#xff1a;查询&#xff08;select&#xff09;、增删改----修改&#xff08;update&#xff09; select语句的执行流程 执行sql语句的流程&#xff1a;连接数据库、缓存查询、解析器、优化器、执行器、存储引擎操作数据 客户端&#xff1a;图形界面工具…

电子病历四级视角下SQL语句的优化策略与实践用例研究

一、引言 1.1 研究背景与意义 在当今数智化医疗时代,电子病历(Electronic Medical Record,EMR)系统已成为医疗机构信息化建设的核心组成部分。电子病历不仅承载着患者的诊疗信息,更是医疗决策、质量控制、科研分析以及医疗管理的重要依据。根据国家卫生健康委发布的《电…

如何借助 AI 提升工作效率

AI让工作更高效 引言 你是否曾在忙碌的工作中感到力不从心&#xff0c;无法高效完成任务&#xff1f;在如今这个信息爆炸的时代&#xff0c;时间似乎总是不够用。而幸运的是&#xff0c;人工智能&#xff08;AI&#xff09;的崛起让这一切发生了变化。AI的应用正日益深入我们…

C++简明教程(14)动态库和静态库的内存共享机制

总结&#xff0c;动态库共享内存&#xff0c;静态库独占一份内存。

NextCloud服务安装与配置教程

NextCloud服务安装与配置教程 什么是 NextCloud: Nextcloud 是一款开源的私有云存储和协作平台,允许用户在自己的服务器上托管数据并管理团队协作。它可以作为一个功能丰富、安全可靠的替代方案,与商业云服务(如 Google Drive、Dropbox)相比提供更多控制和隐私保护。简单来…

Elasticsearch向量检索需要的数据集以及768维向量生成

Elasticsearch8.17.0在mac上的安装 Kibana8.17.0在mac上的安装 Elasticsearch检索方案之一&#xff1a;使用fromsize实现分页 快速掌握Elasticsearch检索之二&#xff1a;滚动查询(scrool)获取全量数据(golang) Elasticsearch检索之三&#xff1a;官方推荐方案search_after…

CSS2笔记

一、CSS基础 1.CSS简介 2.CSS的编写位置 2.1 行内样式 2.2 内部样式 2.3 外部样式 3.样式表的优先级 4.CSS语法规范 5.CSS代码风格 二、CSS选择器 1.CSS基本选择器 通配选择器元素选择器类选择器id选择器 1.1 通配选择器 1.2 元素选择器 1.3 类选择器 1.4 ID选择器 1.5 基…

Prometheus 专栏 —— Prometheus安装、配置

配置文件基本结构 global: 全局配置 scrape_interval: 抓取目标指标的频率,默认为 1minevaluation_interval: 评估告警规则的频率,默认为 1minscrape_timeout: 抓取目标指标数据拉取超时,默认为 10s,如果出现 context deadline exceeded 错误时需要在特定的 job 下配置该字…