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

1. 顶点动画的原理

顶点动画的原理是,在顶点着色器中按照一定的规则或函数计算得到一段偏移量对顶点进行移动,最后将改变位置后的顶点变换到裁剪空间进行后续的渲染工作。

可见,与纹理动画只是改变从纹理中哪一部分开始显示图案不同,顶点动画的原理是通过移动顶点改变物体的形状。

当我们在模型空间中操作顶点实现顶点动画时,如果使用顶点的绝对位置和方向,就需要将SubShader的 “DisableBatching” 标签设置为“True”,否可会因为合批丢失模型空间信息。更好的做法是避免使用绝对位置和方向,通过颜色通道存储顶点到模型原点的距离,这样就可以不必打断合批。

另外,由于顶点动画移动了顶点位置,因此在用到 ShadowCaster 相关的效果时(比如生成阴影),都会出现错误。如果由这种需求,就需要在 Shader 中手动实现对应的 ShadowCaster 的Pass。

2. 流动的河流

下面的例子通过顶点动画实现简单的河流的效果。原理为利用正弦函数的图形变换:f(X)= Asin(ωX+φ),于每一时刻计算正弦函数的值作为当前顶点的偏移量。

例子中使用了书里类似的模型网格,如下图所示:
在这里插入图片描述
代码中有两处不容易理解的地方,其实都跟使用的网格有关:

  1. 为什么偏移量是加到顶点的x分量上而不是y分量上?
    因为代码中移动顶点的操作是在模型空间里进行的,因此需要按照模型空间的坐标轴决定移动哪一个分量,由上图可以看到,例子中使用的网格,控制上下起伏的轴是模型空间的x轴而不是y轴。
  2. 为什么代码中将顶点的xyz分量都乘以了 _InvWaveLen 后加到一起来进行平移效果?
    流动效果需要在表示河流方向的轴上做正弦函数的平移,书中三个分量都处理是为了使代码在任意方向上流动都生效,其实在这个例子中没必要,观察上图可以看到,河流网格是在Z轴方向上延申的(依然要看模型空间的轴),因此实际只需要将 Z 分量乘以 _InvWaveLen 作为函数平移即可。

测试Shader如下:

Shader "MyShader/Chapter_11/Chapter_11_Flow_Shader"
{Properties{_MainTex("MainTex", 2D) = "white"{}_Color("Color",  Color) = (1, 1, 1, 1)_Magnitude("Magnituede", Float) = 1_Frequency("Frequency", Float) = 1_InvWaveLen("InvWaveLen", Float) = 1_UVSpeed("UVSpeed", Float) = 1}SubShader{Tags{"Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "true" "DisableBatching" = "True"}Pass{Tags{"LightMode" = "ForwardBase"}Cull OffZWrite OffBlend SrcAlpha OneMinusSrcAlphaCGPROGRAM#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;fixed4 _Color;half _Magnitude;half _Frequency;half _InvWaveLen;half _UVSpeed;v2f vert(a2v v){v2f o;float4 _offset = float4(0, 0, 0, 0);//_offset.x = _Magnitude * sin(_Frequency * _Time.y + _InvWaveLen * v.vertex.x + _InvWaveLen * v.vertex.y + _InvWaveLen * v.vertex.z);_offset.x = _Magnitude * sin(_Frequency * _Time.y + _InvWaveLen * v.vertex.z);o.pos = UnityObjectToClipPos(v.vertex + _offset);o.uv = TRANSFORM_TEX(v.uv, _MainTex) + float2(0, frac(_UVSpeed * _Time.y));return o;}fixed4 frag(v2f i) : SV_Target{fixed4 _samplerColor = tex2D(_MainTex, i.uv);return fixed4(_samplerColor.rgb * _Color.rgb, _samplerColor.a);}ENDCG}}
}

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

3. 广告牌技术

广告牌(Billboarding)是在实际项目中经常被使用到的一种技术,原理是通过摄像机与当前物体的连线方向,实时修改顶点位置,使物体整体发生旋转,从而做到让物体的某一面始终朝向摄像机。

在实际游戏中,Billboarding 通常分为两种效果:

  • 一种是Y轴固定,即物体的Y轴不发生倾斜永远指向上方,只是在XZ平面跟随摄像机旋转,比如地上的草。
  • 另一种是朝向固定,即物体的Z轴永远指向摄像机,使物体永远都保持正面正对摄像机,此时Y轴不再固定指向上方,有可能发生倾斜,比如天上的云。

要计算顶点旋转后的位置,我们只需要得到旋转后的模型空间,然后按照新模型空间在XYZ分量上分别做平移再加上新模型空间的原点偏移即可,因此最重要的便是构建旋转后的模型空间。

根据上面提到的两种效果,构建模型空间也有两种情况:

  • Y轴固定
    在这里插入图片描述
    此时 Y 轴固定为(0,1, 0),我们可以用摄像机与物体的连线方向作为 Z’,通过 cross(Y, Z’) 得到 X 轴方向,然后用 cross(X, Y) 得到真正的 Z 轴方向。

  • 朝向固定
    在这里插入图片描述
    此时 摄像机与物体的连线方向即为 Z 轴,我们可以取(0, 1, 0)也就是图中的 Y‘ 作为参考轴,通过 cross(Y’, Z) 得到 X 轴方向,然后用 cross(Z, X) 得到真正的 Y 轴方向。

但其中会有一种特殊的情况,即 Z’ 于 Y 轴重合时,如下图:
在这里插入图片描述
这时候在计算时, Y(或Y‘)轴就不能直接用(0, 1, 0)而要改成用(0,0,1):
在这里插入图片描述

另外需要注意的一点是,在计算Z轴的时候,要以模型空间的原点与摄像机的连线作为方向,而不能直接取ObjSpaceViewDir,否则就变成每个顶点单独算出一个Z轴,导致各个顶点最后不在同一个坐标空间下,显示就会出错。

测试Shader如下:

Shader "MyShader/Chapter_11/Chapter_11_Billboarding_Shader"
{Properties{_MainTex("MainTex", 2D) = "white"{}_BillboardingFixZ("_BillboardingFixZ", Range(0, 1)) = 1}SubShader{Tags{"Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "true" "DisableBatching" = "True"}Pass{Tags{"LightMode" = "ForwardBase"}Cull OffZWrite OffBlend SrcAlpha OneMinusSrcAlphaCGPROGRAM#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;//为 0 时相当于把Z轴放平了,因此后续不需要改变叉乘的顺序,依然保持Y轴向上,从而实现Y轴固定的效果//为 1 时就是正常的固定朝向fixed _BillboardingFixZ;v2f vert(a2v v){v2f o;float3 _camDir = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1)).xyz;_camDir.y *= _BillboardingFixZ;float3 _z = normalize(_camDir);float3 _y = abs(_z.y) > 0.999 ? float3(0, 0, 1) : float3(0, 1, 0);float3 _x = normalize(cross(_y, _z));_y = normalize(cross(_z, _x));float3 _pos = v.vertex.x * _x + v.vertex.y * _y + v.vertex.z * _z;o.pos = UnityObjectToClipPos(float4(_pos, 1));o.uv = TRANSFORM_TEX(v.uv, _MainTex);return o;}fixed4 frag(v2f i) : SV_Target{return tex2D(_MainTex, i.uv);}ENDCG}}
}

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

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

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

相关文章

visual studis 安装教程

1、下载软件 2、直接安装。根据自己的需求选择需要的模板类型。 如果是.net环境,可以选择.net项目; 如果是c环境,可以选择c项目模板,多个模板可以同时并存。 3、选择C模板,然后重新启动项目。 我是小路,一枚…

使用小猪APP分发打造高效的App封装工具

你是否曾经因为App封装和分发的复杂性而头疼不已?在这个移动应用迅速发展的时代,开发人员不仅需要专注于应用的功能和用户体验,还必须面对繁琐的封装和分发过程。幸运的是,小猪APP分发www.appzhu.cn正好为我们提供了一个简便而高效…

手绘任意波

更多内容,请访问我的网站:https://jiangge12.github.io/ 上位机发送手绘波形数据,下位机接收并输出。 支持 STM32 STC arduino Pico 等多种单片机,内置或外置 DAC 实现。

【学习Day1】计算机基础

✍🏻记录学习过程中的输出,坚持每天学习一点点~ ❤️希望能给大家提供帮助~欢迎点赞👍🏻收藏⭐评论✍🏻指点🙏 1.1 中央处理单元CPU 中央处理器(CPU,central processing unit&…

在全志H616核桃派开发板上进行音频配置的方法详解

耳机口​ 核桃派板载的3.5mm音频输出口,该接口有一定的输出功率,可以使用耳机或者带功放的扬声器都可以播放声音。 查看音频设备​ 可以使用下面指令来查看音频信息: aplay -l音频播放测试​ 播放系统自带wav音频文件测试, 下面指令的au…

控制台生产厂家生产流程详解

控制台生产厂家的生产流程是一个复杂而精细的过程,它涉及多个环节,从原材料的准备到最终产品的出厂检验,每一步都至关重要。以下是控制台生产厂家的一般生产流程: 厂家会根据客户的需求和市场趋势进行产品设计。设计师会综合考虑控…

闪电加载:Hexo博客性能优化全攻略

巴索罗缪大熊 前言 这些年积累了很多前端性能优化的知识点和思路,日常工作很少涉及技术层极限优化,近期终于一点点把博客独立搭建并部署了,对之前的一些技术点进行了深度探索,最终结果也达到了预期效果,由于水平有限&…

河北奥润顺达集团研究院PMO经理常江南受邀为第十三届中国PMO大会演讲嘉宾

全国PMO专业人士年度盛会 河北奥润顺达集团研究院PMO经理、研发部运营管理办负责人常江南先生受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾,演讲议题为“初建PMO的体系宣贯和人员培养实践总结”。大会将于6月29-30日在北京举办,敬请关注&#xf…

如何利用云平台上更好地规划安全生产教育与培训

在平台上进行安全教育和培训,可以采取以下步骤和策略,以确保教育的有效性和参与度: 一、明确教育目标和培训内容 确定教育目标:明确希望员工通过培训达到的安全意识和技能水平。 制定培训内容:根据行业特点、岗位需求…

centos7安装python-gdal环境

python3 yum install python3 python3-pip -y gdal-3.6.2 参考编译postgis python安装gdal export CPLUS_INCLUDE_PATH/usr/local/gdal-3.6.2/include export C_INCLUDE_PATH/usr/local/gdal-3.6.2/include export LDFLAGS"-L/usr/local/gdal-3.6.2/lib64" pip3…

wordpress子比主题文章付费发卡插件

插件仅适用于子比主题 插件演示 免费下载 :子比主题文章付费发卡插件_麦田吧 如下图,添加卡密支持批量添加,按照卡号(英文逗号/空格/—-)密码的格式输入,一行一条,可以直接添加数据&#xff0…

​​人工智能_大模型083_大模型时代机遇02_提示词优化开发工具_立项_计量模式_真实需求_5why法---人工智能工作笔记0218

上一节我们提供了一个非常好用的提示词,优化开发的,调试工具 vellum 可以看到是这个工具 使用的时候,写完一段提示词,可以选择不同的模型,看看给出的效果情况 对应的模型非常多. ### 立项在立项阶段,要对这三个要素有初步的答案:1. 真实需求是什么? 2. 商业模式是什么? 3…

Tomcat端口配置和网页浏览

安装完成Tomcat后,到安装目录里看到内容如下: 各文件夹作用 bin:可执行文件(启动文件startup.bat、关闭文件shutdown.bat)conf:配置文件(修改端口号:server.xml,建议将s…

[自动驾驶技术]-5 Tesla自动驾驶方案之算法(AI Day 2021)

有朋友问我,如何有效学习一个新技术。笔者这么多年的经验是:1)了解国内外产业应用和标准法规现状,先建立宏观知识图谱及技术系统框架;2)根据系统框架逐块进行深入研究(横向、纵向)&a…

【html+css(大作业)】二级菜单导航栏

目录 实现效果 代码及其解释 html部分 CSS部分 hello&#xff0c;hello好久不见&#xff01; 今天我们来写二级导航栏&#xff0c;所谓二级导航栏&#xff0c;简单来说就是鼠标放上去就有菜单拉出&#xff1a; 实现效果 代码及其解释 html部分 <!DOCTYPE html> &l…

嵌入式进阶——矩阵键盘

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 矩阵按键原理图按键状态检测单行按键状态检测多行按键状态检测 状态记录状态优化循环优化 矩阵按键 矩阵键盘是一种常见的数字输入…

Databend 开源周报第 146 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 支持 Expressio…

网络编程基础知识

一、网络的相关概念 二、Ip 对于ipv4&#xff0c;是由4个字节&#xff08;32位&#xff09;表示&#xff0c;一个字节的范围是0~255&#xff0c;采用的是十进制表示ipv6的地址长度位128位&#xff0c;是ipv4的4倍&#xff0c;采用的是16进制表示查看ip地址&#xff1a;在命令行…

windows 下载redis (通过redis-server.exe启动服务)

下载链接&#xff1a; https://github.com/MicrosoftArchive/redis/releases 启动&#xff1a; 查看&#xff1a; 人工智能学习网站 https://chat.xutongbao.top

玩转STM32-I2C通信协议(详细-慢工出细活)

文章目录 一、I2C总线原理&#xff08;掌握&#xff09;1.1 硬件构成1.2 传输位1.3数据传输格式 二、STM32的I2C特性和结构三、STM32的I2C通信实现&#xff08;硬件实现方式&#xff09;3.1 I2C主模式 四、应用实例 一、I2C总线原理&#xff08;掌握&#xff09; 1.1 硬件构成…