Chapter11让画面动起来——Shader入门精要学习笔记

Chapter11让画面动起来

  • 一、Unity Shader中的内置变量(时间篇)
  • 二、纹理动画
    • 1.序列帧动画
    • 2.滚动背景
  • 三、顶点动画
    • 1.流动的河流
    • 2.广告牌
    • 3.注意事项
      • ①批处理问题
      • ②阴影投射问题

一、Unity Shader中的内置变量(时间篇)

Unity Shader 提供了一系列时间变量来允许我们方便地在Shader中访问运行时间
在这里插入图片描述

二、纹理动画

1.序列帧动画

  • 原理:依次播放关键帧图像,形成连续动画
 Properties{_Color ("Color Tint", Color) = (1,1,1,1)_MainTex ("Image Sequence", 2D) = "white"{}_HorizontalAmount ("Horizontal Amount", Float) = 4_VerticalAmount ("Vertical Amount", Float) = 4_Speed ("Speed", Range(1,100)) = 3}
  • _MainTex 就是包含了所有关键帧图像的纹理
  • _HorizontalAmount 和 _VerticalAmount 分别代表了该图像在水平方向和竖直方向包含的关键帧图像的个数
  • _Speed 用于控制序列帧动画的播放速度
SubShader
{Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}Pass {Tags {"LightMode" = "ForwardBase"}Zwrite OffBlend SrcAlpha OneMinusSrcAlpha
  • 序列帧通常是透明纹理,可以被当成一个半透明对象
v2f vert(a2v v)
{v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);return o;
}
  • 把顶点纹理坐标存储到了v2f中
            fixed4 frag(v2f i):SV_Target {float time = floor(_Time.y * _Speed);float row = floor(time / _HorizontalAmount);float column = time - row * _HorizontalAmount;//				half2 uv = float2(i.uv.x /_HorizontalAmount, i.uv.y / _VerticalAmount);
//				uv.x += column / _HorizontalAmount;
//				uv.y -= row / _VerticalAmount;half2 uv = i.uv + half2(column, -row);uv.x /= _HorizontalAmount;uv.y /= _VerticalAmount;fixed4 c = tex2D(_MainTex, uv);c.rgb *= _Color;return c;}
  • 前三行计算了行列数
    • _Time.y * _Speed 相乘得到模拟的时间,floor函数用来对结果取整
    • time / _HorizontalAmount 商作为当前对应的行索引,余数是列索引
  • 使用行列索引值来构建真正的采样坐标 (注释的)
    • 我们可以首先把原纹理坐标 i.uv 按行数和列数进行等分, 得到每个子图像的纹理坐标范围
    • 使用当前的行列数对上面的结果进行偏移,得到当前子图像的纹理坐标范围
    • 竖直方向坐标偏移需要使用减法,因为Unity纹理坐标竖直方向顺序是从上到下,序列帧的图像是从下到上的,相反的
  • 将原纹理坐标 i.uv 加上一个向量 (column, -row),然后分别除以水平方向和竖直方向关键帧数量,得到当前子图像的纹理坐标范围。这种方法更加通用,即使关键帧图像大小不同也可以使用。

2.滚动背景

Properties
{_MainTex ("Base Layer (RGB)", 2D) = "white" {}_DetailTex ("2nd Layer (RGB)", 2D) = "white" {}_ScrollX ("Base layer Scroll Speed", Float) = 1.0_Scroll2X ("2nd layer Scroll Speed", Float) = 1.0_Multiplier ("Layer Multiplier", Float) = 1
}
  • _MainTex 表示第一层(较远),_DetailTex 表示第二层(较近)
  • _ScrollX 和 _Scroll2X 对应了各自的水平滚动速度
  • _Multiplier 控制整体亮度
v2f vert (a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex) + frac(float2(_ScrollX, 0.0) * _Time.y);o.uv.zw = TRANSFORM_TEX(v.texcoord, _DetailTex) + frac(float2(_Scroll2X, 0.0) * _Time.y);return o;
}
  • 最基本的顶点变换,把顶点变换到裁剪空间
  • 首先利用 TRANSFORM_TEX() 得到初始纹理坐标,再使用内置的_Time.y 变量在水平方向上对纹理坐标进行偏移
  • 把两张纹理存在一个uv中
fixed4 frag (v2f i) : SV_Target {fixed4 firstLayer = tex2D(_MainTex, i.uv.xy);fixed4 secondLayer = tex2D(_DetailTex, i.uv.zw);fixed4 c = lerp(firstLayer, secondLayer, secondLayer.a);c.rgb *= _Multiplier;return c;
}
  • 使用 i.uv.xy 和 i.uv.zw 对两张背景纹理进行采样

  • 使用第二层纹理的透明通道来混合两张纹理

  • 远处的背景应该移动的比近处的慢

三、顶点动画

1.流动的河流

  • 原理就是使用正弦函数来模拟水流波动效果
Properties {_MainTex ("Main Tex", 2D) = "white" {}_Color ("Color Tint", Color) = (1, 1, 1, 1)_Magnitude ("Distortion Magnitude", Float) = 1_Frequency ("Distortion Frequency", Float) = 1_InvWaveLength ("Distortion Inverse Wave Length", Float) = 10_Speed ("Speed", Float) = 0.5
}
  • _MainTex 是河流纹理, _Color 控制整体颜色,_Magnitude 控制水波流动的幅度,_Frequency 控制波动频率,_InvWaveLength 控制波长的倒数,_Speed 控制速度
SubShader {// Need to disable batching because of the vertex animationTags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}
  • “DisableBatching”=“True” 通过该标签来直接指明是否对该SubShader使用批处理(需要特殊处理的Shader就包含了模型空间的顶点动画),批处理会合并所有相关模型,而这些模型各自的模型空间就会丢失,在本例中,需要在物体模型空间下对顶点进行位置偏移,因此需要取消批处理操作
v2f vert(a2v v) {v2f o;float4 offset;offset.yzw = float3(0.0, 0.0, 0.0);offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;o.pos = UnityObjectToClipPos(v.vertex + offset);o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);o.uv +=  float2(0.0, _Time.y * _Speed);return o;
}
  • 先计算顶点位移量,我们只希望顶点x方向进行位移,所以yzw都被设置为0
  • 利用_Frequency 属性和内置的 _Time.y 来控制正弦函数的频率
  • 为了让不同位置有不同的位移,我们对上述结果加上了模型空间下的位置分量,并×_InvWaveLength 来控制波长
  • 最后×_Magnitude 控制波动幅度,得到最终位移
  • 然后把位移量添加到顶点上,再进行顶点变换即可
fixed4 frag(v2f i) : SV_Target {fixed4 c = tex2D(_MainTex, i.uv);c.rgb *= _Color.rgb;return c;
} 
  • 直接对纹理进行采样再添加颜色即可

2.广告牌

  • 广告牌技术:会根据视角方向来旋转一个被纹理着色的多边形,使得好像总是面对着相机
  • 本质就是构建旋转矩阵
  • 一个变换矩阵需要3个基向量,广告牌技术使用的通常是 表面法线、指向上的方向、指向右的方向,除此之外,还需要指定一个 锚点(在旋转过程中固定不变的,以此来确认多边形在空间中的位置)
  • 计算基向量(相互正交的):
    • 法线方向: 通常为视角方向或固定方向
    • 指向上的方向: 通常为 (0, 1, 0) 或固定方向
    • 指向右的方向: 通过法线方向和指向上的方向计算得到 r i g h t = u p × n o r m a l right = up\times normal right=up×normal 叉积
    • r i g h t right right 归一化后,再由法线方向和指向右的方向计算出正交的指向上的方向 u p ′ = n o r a m l × r i g h t up' = noraml \times right up=noraml×right
      在这里插入图片描述
	Properties {_MainTex ("Main Tex", 2D) = "white" {}_Color ("Color Tint", Color) = (1, 1, 1, 1)_VerticalBillboarding ("Vertical Restraints", Range(0, 1)) = 1 }
  • _MainTex 是广告牌的透明纹理,_Color 控制整体颜色,_VerticalBillboarding 调整是固定法线还是固定指向上的方向(0是向上,1是法线)
SubShader {// Need to disable batching because of the vertex animationTags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}
  • 在广告牌技术中,我们需要使用物体模型空间下的位置来作为模电进行计算,所以要取消批处理
v2f vert (a2v v) {v2f o;// Suppose the center in object space is fixedfloat3 center = float3(0, 0, 0);float3 viewer = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos, 1));float3 normalDir = viewer - center;// If _VerticalBillboarding equals 1, we use the desired view dir as the normal dir// Which means the normal dir is fixed// Or if _VerticalBillboarding equals 0, the y of normal is 0// Which means the up dir is fixednormalDir.y =normalDir.y * _VerticalBillboarding;normalDir = normalize(normalDir);// Get the approximate up dir// If normal dir is already towards up, then the up dir is towards frontfloat3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0, 1) : float3(0, 1, 0);float3 rightDir = normalize(cross(upDir, normalDir));upDir = normalize(cross(normalDir, rightDir));// Use the three vectors to rotate the quadfloat3 centerOffs = v.vertex.xyz - center;float3 localPos = center + rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z;o.pos = UnityObjectToClipPos(float4(localPos, 1));o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);return o;
}
  • 所有的计算都是在模型空间下计算的 (下面解释顶点着色器内容)
  • 首先选择模型空间的原点作为广告牌的锚点,利用内置变量 mul(unity_WorldToObject,float4(_WorldSpaceCameraPos, 1)) 获取模型空间下的视角位置
  • 然后开始计算三个正交基
float3 normalDir = viewer - center;// If _VerticalBillboarding equals 1, we use the desired view dir as the normal dir// Which means the normal dir is fixed// Or if _VerticalBillboarding equals 0, the y of normal is 0// Which means the up dir is fixednormalDir.y =normalDir.y * _VerticalBillboarding;normalDir = normalize(normalDir);
  • 根据观察位置和锚点计算目标法线方向,并使用_VerticalBillboarding 来控制垂直方向上的约束度
  • 1时法线方向固定为视角方向,0时向上方向固定为(0,1,0)
float3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0, 1) : float3(0, 1, 0);
  • 接着粗略地得到向上方向,为了放置法线方向和向上方向平行,对法线方向的y分量进行判断
float3 rightDir = normalize(cross(upDir, normalDir));
  • 然后得到了向右方向,并进行归一化
upDir = normalize(cross(normalDir, rightDir));
  • 在根据准确的法线方向和向右方向得到最后向上方向
// Use the three vectors to rotate the quadfloat3 centerOffs = v.vertex.xyz - center;float3 localPos = center + rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z;
  • 根据三个正交基矢量和原始位置相对于锚点的偏移量,计算得到新顶点的位置
o.pos = UnityObjectToClipPos(float4(localPos, 1));o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
  • 最后把模型空间的顶点位置变换到裁剪空间
  • 片元着色器只需要对纹理进行采样,再与颜色相乘即可
fixed4 frag (v2f i) : SV_Target {fixed4 c = tex2D (_MainTex, i.uv);c.rgb *= _Color.rgb;return c;
}

3.注意事项

①批处理问题

  • 因为批处理会 合并模型,导致模型空间丢失,而顶点动画又需要依赖模型空间的位置进行计算
    • 合并模型:将所有使用同一 Shader 的材质的模型合并成一个批次进行渲染,每个模型都被转换到了一个统一的坐标系中
  • 解决方法
    • 禁用批处理:通过在 SubShader 标签中 使用 “DisableBatching” 标签,可以强制禁用对该 Shader 的批处理,从而避免动画效果被破坏,但这样做会降低性能,因为会增加 Draw Call
    • 使用相对位置和方向:尽量避免使用模型空间下的绝对位置和方向进行计算,例如,使用顶点颜色存储每个顶点到锚点的距离,而不是直接使用模型空间的中心作为锚点
      • 为模型的每个顶点设置一个顶点颜色值,该颜色值表示该顶点到模型中心点的距离,以将颜色值的 R 分量设置为距离值,G、B 分量设置为 0
      • 读取每个顶点的顶点颜色值,并从中提取出距离值

②阴影投射问题

  • 内置的 ShadowCaster Pass 无法处理顶点动画: Unity 的内置阴影投射 Pass 没有进行顶点动画的处理,因此会导致阴影与物体的实际位置不匹配
  • 解决方法:自定义ShadowCaster Pass (见书)

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

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

相关文章

东北财税之星:董女士的家乡创业记

乐财业智慧财税赋能平台,是一个帮助财税机构专业提升、业务增长,让财税生意更好做的综合赋能平台。聚焦财税公司业绩增长,预计2027年帮助2000家财税合伙人利润增长300%,致力打造轻量化、批量化、智能化的”业财税“一体财税服务生…

ARCGIS PRO 要素标注

一、普通模式 1、标注:名称和面积(无分数线) 语言:Arcade $feature.QLR \nRound($feature.Shape_Area,2) 语言:vbscript [QLR] & " " & Round([Shape_Area],2) 2、标注:名称…

ChatGPT如何提升论文写作(附指令集合)

先讲前提: ChatGPT无论是3.5还是4.0都存在非常严重的幻觉问题,目前ChatGPT无法替代搜索引擎。 如果你希望得到更加优质的体验,请用GPT-4.0,幻觉问题上比3.5大幅降低 ChatGPT中文版,一站式AI创作平台​aibox365.com …

Python | Leetcode Python题解之第203题移除链表元素

题目: 题解: # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val val # self.next next class Solution:def removeElements(self, head: ListNode, val: int) -> Li…

因版本冲突导致logback的debug日志不打印

因框架调整,降级了logback的版本号,由1.3.12降级为1.2.11(因框架限制,只能采用1.2版本),降级后发现debug日志无法打印出来,logback.xml配置文件不生效。后排查发现是与slf4j的版本兼容问题 依赖…

一种频偏估计与补偿方法

一种简易的频偏估计补偿方法,使用QAM等信号。估计精度受FFT长度限制,可以作为粗频偏估计。 Nfft 1024; % FFT长度 N 10*Nfft; % 仿真符号数 M 16; % 调制QAM16 freq 1e…

如何选择视频号矩阵系统源码:关键要素与决策指南

在短视频和直播内容迅速崛起的今天,视频号矩阵系统源码成为了企业和个人创作者高效管理视频内容的重要工具。选择合适的视频号矩阵系统源码,可以极大提升内容发布的效率和质量,同时优化用户体验。本文将提供一套选择视频号矩阵系统源码的指南…

MYSQL篇二:数据库的操作

文章目录 1. 创建数据库1.1 查看数据库列表1.2 创建与删除数据库 2. 数据的编码问题3. 字符集和校验规则3.1 查看系统默认字符集以及校验规则3.2 查看数据库支持的字符集3.3 查看数据库支持的字符集校验规则3.4 校验规则对数据库的影响 4. 操纵数据库4.1 查看当前是哪一个数据库…

小程序渗透测试的两种方法——burpsuite、yakit

首先呢主要是配置proxifier,找到小程序的流量,然后使用burpsuite或者yakit去抓包。 一、使用burpsuiteproxifier的抓包测试 1、先配置proxifier,开启http流量转发 勾选确定 2、配置burp对应代理端口,选择profile,点…

《梦醒蝶飞:释放Excel函数与公式的力量》8.7 STDEV函数

8.7 STDEV函数 STDEV函数是Excel中用于计算一组数值的标准偏差的函数。标准偏差是统计学中的一个重要指标,用于衡量数据集中各数值偏离平均值的程度。它反映了数据的离散程度或波动大小。 8.7.1 函数简介 STDEV函数用于返回样本数据的标准偏差,标准偏…

软件测试面试1000问(含答案)

1、自动化代码中,用到了哪些设计模式? 单例设计模式工厂模式PO设计模式数据驱动模式面向接口编程设计模式 2、什么是断言( Assert) ? 断言Assert用于在代码中验证实际结果是不是符合预期结果,如果测试用例执行失败会抛出异常并提供断言日志 3、什么是web自动化…

地图下载工具

1 概述 做仿真的,一般都要用到地图。各大地图厂商,都提供了地图测试接口。只不过,这些接口有限制,用多了就容易被封IP。于是我写了一个瓦片地图下载工具,把地图下载到本地,就可以愉快的玩耍了。 2 操作 …

文字识别技术升级:Airtest与PaddleOCR模型的协作小技巧

一、前言 在进行自动化测试的过程中,ocr文字识别一直是大家最想要实现以及最需要的能力,今天就来介绍一个由百度飞浆提供的一个免费的ocr识别库——PaddleOCR,以及探讨一下,PaddleOCR与Airtest协作能擦出怎么样的火花~ 二、Padd…

打包 最新血液净化器制作技术和资料

网盘 https://pan.baidu.com/s/1fm3LF20dCvy4iSMQklHpug?pwd4je2 便携可穿戴可血液净化用器件及其制备方法和应用.pdf 基于贻贝仿生化学的血液净化材料及其制备方法.pdf 膜分离式一体化血液净化系统.pdf 血液净化器固定夹.pdf 血液净化膜及其制备方法和应用.pdf 评估血液净化…

【手机取证】如何使用360加固助手给apk加固

文章关键词:手机取证、电子数据取证、数据恢复 一、前言 APP加固是对APP代码逻辑的一种保护。原理是将应用文件进行某种形式的转换,包括不限于隐藏,混淆,加密等操作,进一步保护软件的利益不受损坏,下面给…

生成式人工智能如何改变软件开发:助手还是取代者?

生成式人工智能如何改变软件开发:助手还是取代者? 生成式人工智能(AIGC)正在引领软件开发领域的技术变革。从代码生成、错误检测到自动化测试,AI工具在提高开发效率的同时,也引发了对开发者职业前景的讨论…

Java面试八股之MySQL的pconenct和connect有什么区别

MySQL的pconenct和connect有什么区别 在PHP中,mysql_pconnect() 和 mysql_connect() 是用来建立与MySQL数据库服务器连接的两个函数,它们的主要区别在于连接的持久性。 mysql_connect(): 这个函数每次调用都会尝试创建一个新的数据库连接。 当PHP脚本…

天猫超市卡怎么用

猫超卡是在天猫超市里面消费用的卡 但是我们现在买东西都喜欢货比三家,肯定是哪家划算在哪买,要是淘宝其他店铺或京东卖的更便宜,猫超卡自然就用不上了 这种情况的话,还不如直接把猫超卡的余额提出来,买东西也不受限…

【网络安全】漏洞挖掘之Spring Cloud注入漏洞

漏洞描述 Spring框架为现代基于java的企业应用程序(在任何类型的部署平台上)提供了一个全面的编程和配置模型。 Spring Cloud 中的 serveless框架 Spring Cloud Function 中的 RoutingFunction 类的 apply 方法将请求头中的“spring.cloud.function.routing-expression”参数…

【Python学习笔记】菜鸟教程Scrapy案例 + B站amazon案例视频

背景前摇(省流可以跳过这部分) 实习的时候厚脸皮请教了一位办公室负责做爬虫这块的老师,给我推荐了Scrapy框架。 我之前学过一些爬虫基础,但是用的是比较常见的BeautifulSoup和Request,于是得到Scrapy这个关键词后&am…