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系列降压芯片驱动电路降压芯片驱动电路详解-…

【大模型系列】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-创建工程与创建模拟器

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

在 Spring Boot 中整合 MyBatis-Plus 可以按照以下步骤进行&#xff1a; 一、整合步骤 1. 创建 Spring Boot 项目 首先&#xff0c;使用 Spring Initializr&#xff08;https://start.spring.io/&#xff09;创建一个新的 Spring Boot 项目。在创建过程中&#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)系统已成为医疗机构信息化建设的核心组成部分。电子病历不仅承载着患者的诊疗信息,更是医疗决策、质量控制、科研分析以及医疗管理的重要依据。根据国家卫生健康委发布的《电…

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

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

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 基…

基于AT89C51单片机的可暂停八路抢答器设计

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/90196607?spm1001.2014.3001.5503 C15 部分参考设计如下&#xff1a; 摘要 随着社会进步和科技发展&#xff0c;电子设备在各类活动中的应用日益普遍&#xff0c…

【python】unittest单元测试

文章目录 基本使用不同启动方式的区别 基本使用 下面是根据文档写的一个demo&#xff0c;主要的内容基本都包含了&#xff0c;使用时导入自己的业务类测试类中的方法就行。 import unittest# 测试类不强制test开头&#xff0c;仅作为规范。但必须继承unittest.TestCase class…

从0入门自主空中机器人-4-【PX4与Gazebo入门】

前言: 从上一篇的文章 从0入门自主空中机器人-3-【环境与常用软件安装】 | MGodmonkeyの世界 中我们的机载电脑已经安装了系统和常用的软件&#xff0c;这一篇文章中我们入门一下无人机常用的开源飞控PX4&#xff0c;以及ROS中无人机的仿真 1. PX4的安装 1.1 PX4固件代码的下载…

SqlSession的线程安全问题源码分析

&#x1f3ae; 作者主页&#xff1a;点击 &#x1f381; 完整专栏和代码&#xff1a;点击 &#x1f3e1; 博客主页&#xff1a;点击 文章目录 SqlSession 是线程安全的吗&#xff1f;为什么说是线程不安全的&#xff1f;事务管理问题 数据库连接的共享问题 一级缓存线程安全问题…

Unity Mesh生成Cube

1. 配置一个Cube的每个面的数据 一共是6个面&#xff0c;每个面包含的数据包括4个顶点的相对顶点坐标&#xff08;Cube的中心为原点&#xff09;&#xff0c;法线方向&#xff0c;UV坐标&#xff0c;顶点渲染顺序&#xff0c;以及这个面用到的材质&#xff0c;因为这里是Top&am…

小程序组件 —— 22 组件案例 - 轮播区域绘制

这一节我们实现轮播图最外层的盒子&#xff0c;也就是把轮播图的最外层搭好&#xff0c;先不给轮播图添加图片&#xff0c;因为图片属于新的组件&#xff0c;组件里面有一些知识点&#xff0c;需要单独分开讲&#xff1b; 回顾一下&#xff0c;在进行传统网页开发时&#xff0…

【文献精读笔记】Explainability for Large Language Models: A Survey (大语言模型的可解释性综述)(二)

****非斜体正文为原文献内容&#xff08;也包含笔者的补充&#xff09;&#xff0c;灰色块中是对文章细节的进一步详细解释&#xff01; 3.1.2 基于注意力的解释&#xff08;Attention-Based Explanation&#xff09; 注意力机制可以揭示输入数据中各个部分之间的关系&#…

git reset --hard(重置到当前提交,所有未提交的更改都会被永久丢弃)

git reset --hard 是一个强大的命令&#xff0c;它会将你的工作目录、暂存区和当前分支的 HEAD 指针重置到指定的提交状态&#xff0c;所有未提交的更改都会被永久丢弃。因此&#xff0c;使用这个命令时需要非常小心。 基本用法 重置到当前提交&#xff08;丢弃所有未提交的更…

单元测试入门和mockup

Java 新手入门&#xff1a;Java单元测试利器&#xff0c;Mock详解_java mock-CSDN博客 这个是典型的before when assert三段式&#xff0c;学一下单测思路 这个没有动态代理&#xff0c;所以是直接class(对比下面) Jmockit使用笔记_增加代码覆盖率_覆盖try catch_使用new Mock…

智能化人才招聘系统是怎样的?

随着企业规模的扩大和业务范围的拓展&#xff0c;人才招聘成为了企业发展的关键环节。然而&#xff0c;市面上的人才招聘系统琳琅满目&#xff0c;质量参差不齐&#xff0c;许多企业发现&#xff0c;并非所有系统都能满足他们的需求&#xff0c;特别是智能化的需求。今天&#…