提要:基于Emission,使用多个模块分别实现细分效果并最终组装成完整护盾效果;使用Rigidbody进行碰撞检测,通过脚本将位置传进Shader,播放由参数控制的冲击效果。

https://vdn6.vzuu.com/SD/42d88158-3209-11ec-9482-5205fb48cbf7.mp4?pkey=AAXAIWf3cO_MEnH9vjnMdBS2Cj0Gsx_gZ7dVOmdPAwN9kgAmkvxOjauU-0HouER0jkcXjmiA8-kMRg0vz-Ac-OI9&c=avc.0.0&f=mp4&pu=078babd7&bu=078babd7&expiration=1679475988&v=ks6

v1.0 效果图


着色器部分

着色器部分包括了护盾主要的表现效果和护盾受击效果。这里主要使用ASE实现,重在讲解思路,降低学习成本。

编写准备

开始正式编写之前,我们需要首先完成基本开发环境的部署。无需从头开始的小伙伴可以直接越过这部分内容,从工程文件创建开始浏览。

Unity安装

从Unity官方网站上下载Unity Hub并按照自己需求安装一个版本。推荐安装不低于2018的任一LTS版本,就本工程来说,社区版本也是完全足够的。

具体步骤较为简单,网络上教程也比较丰富,这里就不做进一步展开。

ASE插件安装

如前所说,我们需要安装ASE插件来创建ASE着色器,以获得图形界面支持。Unity的Asset Store里面上架了ASE插件,可以直接从里面获取。与通常Package的下载相同,点击Download并下载完成后,点击Import自动导入即可。

如果是从非Asset Store途径获取的ASE,双击ASE.unitypackage即可在安装了Unity的前提下自动导入插件。

ASE插件安装完成后会弹出ASE初始化界面,关闭即可。

工程文件创建

与创建普通着色器类似,我们依然是在Asset界面使用右键菜单创建ASE Shader,ASE插件通过编辑器脚本为我们在右键菜单中添加了额外的选项:

选择Surface来以表面着色器为模板,来创建一个ASE Shader。

创建完毕后将文件名改为ASE_ForceShield(或者是你喜欢的其他名字),我们就完成了工程的准备工作,可以开始正式编写着色器了。

Albedo&Normal(反射和法线部分)

对于Albedo和Normal,我们不做过多处理,简单地留出接口并输入shader即可。如果有需要,可以自行改写。

Emission(自发光部分)

在这部分,我们将逐个完成护盾的各方面表现效果,并最终将它们组合到一起。

模块划分

闭上眼睛,想象一下,一个护盾应该是什么样的?你能在最近玩过的游戏,看过的影视作品中找到参考吗?
当你确定之后,思考一下,可以把这个效果进行划分吗?它由哪些细分效果组成?

在本案例中,我们主要将护盾简单划分为护盾波纹,护盾纹理,护盾光晕和护盾受击四个模块。通过组合这四个模块,我们就能够实现一个最基本的护盾效果。

准备时间参数

如果我们想让我们的特效动起来,我们就需要一个时间参数,用于标识时间的流逝,并且我们应当能通过一个外接的参数对时间流逝速度进行控制,从而间接地控制动画播放的速率。

Unity为我们提供了这个基本参数,它是一个由四个浮点数组成的浮点数组。在ASE中我们可以以节点的形式直接引用它,就像在代码中使用宏。

Time Parameters
即时间参数,以秒为单位输出Unity内部流逝的时间,这个参数组包括4不同的预设缩放值。

序号

成员

描述

类型

0

t/20

返回t值的二十分之一放缩值

Float

1

t

返回t值原始值

Float

2

t*2

返回t值的二倍放缩值

Float

3

t*3

返回t值的三倍放缩值

*部分ASE版本中可能包含一个Output的额外输出端口,输出包括所有成员的原始时间向量。

我们首先将节点给出的四个成员重新组合与原始时间向量一致的Float4数组,然后将它与我们定义的参数相乘,最后将输出结果注册为本地变量待用。

护盾波纹——外色值光波效果

我们引入纹理坐标节点,通过向这个节点输入参数来决定我们的护盾网格纹理以什么方式映射到我们的物体上。

在坐标偏移参数中,我们使用了之前准备的时间参数,并对其进行了适当的缩放,作为UV坐标的Y偏移值,使我们的纹理能够动起来,形成动画。

Texture Coordinates
“纹理坐标”节点(快捷键:U键)使用网格UV并根据纹理平铺和偏移参数对其进行操作,以定义如何将纹理映射到3d资产上。如果Tex端口连接到纹理对象,或者如果在节点属性面板中引用了Tex端口,则它们将通过材质检查器中的该纹理字段进行转换。否则,将使用节点的参数或输入来转换坐标。

端口

描述

类型

Tex

该端口接受一个纹理对象,该对象允许使用其纹理UV参数。覆盖节点填充和偏移量,而改用物料检查器

Sampler2D

Tilling

参数Tilling的动态版本。仅当Reference设置为None时可用,否则将被锁定以指示其使用了材质检查器中的Texture属性的填充

Float2

Offset

参数Offset的动态版本。仅当Reference设置为None时可用,否则将被锁定以指示其使用了材质检查器中的Texture属性的偏移

Float2

UV(WT)

在vector2的情况下,返回分别包含U和V坐标的vector2,vector3或vector4,vector3的UVW坐标,vector4的UVWT

Float2(34)

可以通过修改Tilling常量的值来决定纹理是否重复拼接;如果将Tilling常量的值设为0,0,纹理事实上将用于修改物体的整体颜色。

护盾网格——外图案纹理效果

类似地,我们为网格纹理设置动画效果,并同时引入护盾基色和护盾强度参数。

护盾受击——护盾冲击效果

这里我们为了尽可能地简化系统,仅对护盾受击效果做了颜色上的简单模拟,更加深入的内容我们将放在后续笔记中。

总的思路是,使用受击点位置与顶点位置得出冲击距离,然后对距离进行判断,分三段表现受击效果,各边界值由参数控制。

首先,我们使用Distance节点获取受击点与顶点之间的距离。

Distance
Distance节点输出两个值或向量 A和 B之间的欧式距离,可以将其视为以下运算 Sqrt ( Dot (B-A,B-A))。 如果将不同的数据类型连接到每个端口,则将始终对大多数通道的端口类型执行强制转换。

然后将得出的距离值引入Compare节点,与边界值进行比较,以决定是否启用冲击效果,应用哪种效果。

Compare Node
The Compare 节点比较其A和B上设置的值,根据运算符类型获得对应布尔值,并根据该值输出对应参数
注意:无论 True and False输入端口可以有不同的数据类型,但投将与渠道的量最多的类型进行。所选类型还将定义输出类型,并定义在比较操作中将使用的A和B通道数量。

端口

描述

类型

A

第一个比较值

Float [1]

B

第二个比较值

Float [1]

True

如果逻辑表达式为真,输出该值

Float [1]

False

如果逻辑表达式为假,输出该值

Float [1]

此外,这里的受击效果使用的是受击颜色与顶点颜色的插值,由受击点逐渐过渡至基色;但如果我们将Lerp节点的输入对调,只需要一些简单的调整我们就能实现一个看起来完全不同的效果。

https://vdn6.vzuu.com/SD/d424671e-321b-11ec-9eab-22e7ec068dc6.mp4?pkey=AAWoCrBiCIvpcIYnibTaEMcGC42DFF0T2D-_YTo5cym8iFwyFS3iZnX9J7IzqOgD9TpaWGouWcQJ8Z3Mn7agPGOu&c=avc.0.0&f=mp4&pu=078babd7&bu=078babd7&expiration=1679476107&v=ks6

护盾光晕——菲涅尔边缘光效果

如果想要让我们的护盾看起来晶莹剔透,加一点点边缘光是个不错的主意。这里我们使用了Fresnel节点来实现边缘光效果,并使用参数控制其反射强度。

Fresnel节点的原理是大名鼎鼎的菲涅尔光照模型,描述了光线在不同折射率材料交界处的行为。如果读者对此节点背后的机理感兴趣,可以自行查阅相关资料,这里不过多展开叙述。

Fresnel Node
菲涅耳节点输出菲涅耳效果的结果。它定义了光到达具有不同折射率的两种材料之间的界面时的行为,反射和折射的量。 该节点在与该反射部分特定的交易,并计算其由下面的表达式定义的菲涅耳反射系数:

Reflection Coefficient = Bias + Scale x ( 1 + N·I )^Power

方程的每个成员都可以修改,但 I 变量除外,该变量定义了从摄像机到对象的入射向量,并在节点内部将其计算为反向的世界方向向量。

端口

描述

类型

Normal

要使用的法线向量。如果未连接,则将使用Surface World法线

Float 3

Bias

定义菲涅耳方程式的Bias变量

Float

Scale

定义菲涅耳方程式的Scale变量

Float

Power

定义菲涅耳方程式的幂变量

Float

自发光总装——护盾效果混合

接下来就是激动人心的总装时刻。在这一部分,我们将把之前制作的模块效果一一引入并进行混合,以得到最终的护盾效果。

首先,我们将边缘光与护盾纹理进行叠加。

然后,引入护盾波纹。

需要注意的是,引入时使用的运算符不同,会极大地影响引入结果。读者可以自行尝试不同的运算符节点,查看效果。

现在我们的护盾效果已经初具雏形,接下来我们要为护盾效果上色,引入护盾基色和受击效果。

由于受击效果同样涉及顶点颜色的变更,所以我们在引入之前,首先对护盾基色和受击效果进行合并处理。

然后,我们再将其引入到护盾效果上。

接下来,我们需要制造一点层次感。这里使用Depth Fade节点处理过的参数对护盾效果和护盾深度色进行插值,使护盾效果在与其他几何体交错时实现颜色的平滑渐变。

值得注意的一点是,Depth Fade本身输出的值并不是映射在[0,1]内的,因此我们需要一个Clamp对其进行进一步处理,以用于插值。

然后将其引入,用于深度色和护盾效果的插值。

Depth Fade
Depth Fade 节点输出一个线性渐变值,表示对象表面与其后面的几何体之间的距离。渐变范围或渐变距离可以通过调整Distance参数来设置。
更具体地说,Distance参数的作用是在对象表面与其后面的几何体之间的距离小于等于Distance值时将其距离一一映射为 [0,1] 范围内的值。

端口

描述

类型

Vertex Position

可自定义的顶点位置,默认时使用当前顶点位置

Float 3

Distance

允许映射的距离上界

Float

Out

输出的线性渐变值

Float

最后一步,引入一个总参数用于控制整体表现,然后我们就可以将整个效果输出到Emission了!

大功告成!如果读者正确完成了之前的步骤,应该能获得以下结果:

细心的读者可能注意到,在我们的冲击效果前方还有一个未使用的本地变量。这个变量输出的是改进后的冲击效果,在后续笔记中才会涉及。

护盾的主体工程已经结束,我们接下来将对透明度进行简单的处理,并添加一个顶点动画。

Opacity(透明度部分)

在处理透明度之前,读者应当检查自己的Shader配置,确保Blend Mode是Transparent状态,否则很多节点可能无法正常工作。

然后,我们简单地加入一个参数用于控制护盾曲面整体的透明度。

上图中,我们对反照、法线和透明度都只做了预留接口的简单处理,主要功能模块集中在Emission部分。
下方输出到顶点偏移接口的正是我们接下来要做的顶点动画。

Vertex Offset(顶点偏移部分)

在这一部分,我们将实现一个简单的抖动顶点动画,让我们的护盾像布丁一样看起来富有弹性。

首先,再次引入之前制备的时间参数,并对其进行缩放。

然后,将结果与顶点位置相加。

这个随时间变化的顶点位置将作为UV坐标供Noise Generator生成我们想要的随机噪声值。

Noise Generator
“噪声生成器”节点使用 Type指定的方法根据 UV处指定的值在 [-1 1]范围内创建 浮动噪声值。
注意:输入数据必须在整个几何图形上变化,因为相等的值会产生相同的噪声。一种简单的方法是将“ 纹理坐标”节点连接到其输入。

端口

描述

类型

UV

用于产生噪声的值。相同的输入值始终会产生相同的噪声值。仅在未连接相应的输入端口时可见。

Float2/3

Scale

用于缩放通过UV端口给定的输入的值。仅在未连接相应的输入端口时可见。

Float

参数

描述

默认值

Type

噪声生成选项

Simplex 2D:使用Simplex方法从Vector2创建噪声值

Simplex 3D: 使用Simplex 方法从Vector3创建噪声值

Gradient: :使用Gradient方法从Vector 2创建噪声值

Simplex 2D

0-1 Range

如果打开,则输出值为[0 1]范围;如果关闭,则为[-1 1]范围。

True

最后,引入一个参数,控制其抖动幅度。

具体控制方式是通过将噪声重映射至正负参数范围来控制其所能出现的偏移值范围。

如果一切顺利,我们在最终的输出上能够看到如下的噪声:

脚本部分

在这部分中,我们将在脚本实现碰撞检测、着色器赋值,并基于碰撞检测实现简单的射弹,用于受击效果的测试。

首先,在场景中创建一个球,一个使用我们的护盾着色器的材质,然后将材质赋给这个球,并将球重命名为Force Shield(或者你喜欢的其他名字)。

然后在球上新建一个CS脚本,并重命名为Force Shield Manager。

接下来,我们将着手实现碰撞检测。

碰撞检测

碰撞检测依赖于碰撞盒和刚体。因此,我们首先需要在球上增加一个Rigid Body组件。

在设置中取消了默认勾选的 Use Gravity,并勾选了Freeze Position的所有方向。这是为了更好的观察效果而进行的处理

UNITY提供了预设事件OnCollisionEnter(),这个事件将在挂载物体被其他刚体碰撞时触发。我们在脚本中公共类下创建该事件:

voidOnCollisionEnter(Collisioncollision){Debug.Log("triggered");}

我们可以将另一个拥有Rigid Body的物体扔向挂载了脚本的球,如果console弹出了debug信息,则说明碰撞检测已经正常运作。

赋值着色器

我们向着色器传递参数的方法是通过物体挂载的Material组件的.SetFloat方法,因此我们需要声明一个材质私有变量,并在Start()中获取物体挂载的材质:

privateMaterialmat;voidStart(){mat=GetComponent<Renderer>().material;// 储存挂载的材质引用
}

另外我们需要一个参数控制轰击的强度:

[Range(0,1)]publicfloatbasicImpactFactor=1;privatefloathitTime;//计算当前效果强度

这个强度将随时间衰减,实现受击效果的淡出:

voidUpdate(){// 受击效果淡出
if(hitTime>0){hitTime-=Time.deltaTime;if(hitTime<0){hitTime=0;}mat.SetFloat("_HitTime",hitTime);}}

为了使之前编写的护盾受击效果派上用场,我们需要遍历collision中的所有接触点.contacts,为着色器获取碰撞位置和碰撞强度:

voidOnCollisionEnter(Collisioncollision){foreach(ContactPointcontactincollision.contacts){Debug.Log("triggered");mat.SetVector("_HitPosition",transform.InverseTransformPoint(contact.point));//将受击点坐标从世界空间坐标系转换为本地坐标系
hitTime=basicImpactFactor;mat.SetFloat("_HitTime",hitTime);//通过材质传参
}}

这里需要注意的地方是,这里设置参数所使用的名称务必与着色器中用于接收撞击位置的参数名称保持一致。

完成如上脚本后,我们再使护盾球与其他具有刚体的物体碰撞时,就应当能看到护盾受击效果。

到这里,事实上整个护盾效果的功能我们就已经完成了实现。后面的内容只是为了更好的展示效果而添加的额外内容,并不是必需的组成部分,读者可以根据自己的需要选择性阅读。

射弹生命周期

“展示受击效果不好搞啊,每次都要操作物体撞上去,位置也很难选,不容易看到清晰的展示...”
“为什么还要我手动扔啊,烦死了!”
“累了,写个脚本自己动吧!”

这一部分中,我们将继续补充之前的脚本,实现射弹的自动发射和生命周期管理,以期获得更好的展示效果。

在开始之前,我们需要准备一个拥有Rigid Body组件的刚体预制件作为我们的发射物,你可以凭自己的喜好在场景中创建一个3D物件,为它添加Rigid Body组件,并拖入Asset 视窗中,制成Prefab备用。

需要注意的是,射弹通常忽略重力,因此在添加RigidBody组件时需要取消勾选Use Gravity。

此外,我们还需要自定义一个名为Bullet的编辑器自定义标签,并将Prefab的标签修改为Bullet,以对射弹进行统一管理。

射弹生成

刚体的创建与Game Object类似,获取预制体后实例化即可。

打开挂载于护盾球上的脚本,我们编写一个创建函数用于实例化预制的子弹刚体,并将预制子弹刚体的变量声明添加到脚本中:

publicRigidbodybulletPrefab;publicfloatbulletCreateSpeed=10;//对外参数,用于控制子弹生成数量
privatefloatcurrentBulletsNum=0;//对内变量,计算当前子弹数量
voidcreateBullets(){Rigidbodybullet=Instantiate<Rigidbody>(bulletPrefab);//定义子弹刚体,然后克隆一个子弹
//此处不用bullet.position,而是bullet.transform.position,两者有区别
Vector3targetPosition=newVector3(0,0,0);targetPosition=this.transform.position+newVector3(Random.Range(-BulletRandomRange,BulletRandomRange),Random.Range(-BulletRandomRange,BulletRandomRange),Random.Range(-BulletRandomRange,BulletRandomRange));//在物体附近随机选择位置
bullet.transform.position=targetPosition;}

我们将在Update()函数中调用这个实例化函数。

子弹密度的控制与受击效果的衰减类似:

voidUpdate(){// 受击效果淡出
if(hitTime>0){hitTime-=Time.deltaTime*fadeSpeed*hitTime*hitTime/1000;if(hitTime<0){hitTime=0;}mat.SetFloat("_HitTime",hitTime);}// 子弹密度控制
currentBulletsNum-=Time.deltaTime*bulletCreateSpeed;if(currentBulletsNum<=0){createBullets();currentBulletsNum=1;}}

细心的读者可能会发现控制变量的表意并不是冷却和密度。这两个变量事实上是一个采用实体数量控制密度的早期方案的残余部分。

密度设置越高,射弹创建冷却衰减速度也就越快,创建函数调用也更频繁,从而生成更密集的射弹。

射弹发射

怎么用石头击中远处的树干?当然是用力扔。

在Unity中,我们可以使用.AddForce()方法对一个具有RigidBody组件的刚体施加一个力,如果这个刚体没有勾选Freeze选项,那么它将根据自身的Mass和力的施加大小、类型产生相应的速度变化,发生运动。

首先,我们在脚本中声明一个参数来对力的大小进行控制:

[Range(1,10)]publicfloatmaxBulletsPower=3;

然后,我们继续向createBullets()方法中添加语句:

bullet.AddForce((this.transform.position-bullet.transform.position).normalized*maxBulletsPower,ForceMode.Impulse);//以脉冲形式施加一个力

施加的力让我们创建的射弹能够向着目标物体运动。换句话说,我们成功向目标物体发射了射弹。

射弹销毁

任何临时创建的物体都应当被完善地管理,确保它从创建、使用到销毁的整个生命周期都是可控的。至少,你得确保它被正确且及时地销毁了,否则等待着你的就是可怕的泄漏事故。

一个临时创建的物体的销毁通常由自己搭载的脚本负责,少数情况下,会将销毁的责任交给其他脚本。这是因为转交的次数越多,潜在的泄漏风险和性能浪费也就越大。但在我们的场景中,由于射弹没有使用重力,且场景中唯一的力就是使其向护盾球发射的力,所有的射弹最终都会击中护盾球,触发受击函数。因此,我们选择直接在护盾球搭载脚本中的受击函数内进行处理。

我们向OnCollisionEnter函数中添加一个判断语句:

if(collision.gameObject.tag=="Bullet"){Destroy(collision.gameObject);}

这里通过判断碰撞物体是否具有Bullet标签来分辨射弹和其他物体,并对击中自身的射弹执行销毁。结合上面我们编写的生成函数,事实上起到了控制同一时间存在在场景内射弹数量的作用。

拓展部分:更好的表现效果

在这个部分,我们将考虑如何改善我们的受击效果表现。

非线性衰减

在前面的脚本中,我们的受击效果是线性衰减的,受击颜色以一个均匀的速度衰减为护盾基色。但真实的波的衰减速度往往和其强度成正相关,强度越高,衰减也随之越快,这事实上是一个非线性过程。

很容易想到对衰减函数进行改造,使之同样变为非线性,以尽可能符合预期:

hitTime-=Time.deltaTime*hitTime*100;

而非线性的公式需要更大的初始值支持,因此我们将basicImpactFactor的范围和默认值增大:

[Range(1,100)]publicfloatbasicImpactFactor=10;

同时,我们也希望受击表现能够更加可控,所以引入了一个额外的参数:

[Range(1,1000)]publicfloatfadeSpeed=1000;

这样,衰减函数则变为:

hitTime-=Time.deltaTime*fadeSpeed*hitTime/10;

为了使波形更加陡峭,我们将衰减函数的分母变为平方:

hitTime-=Time.deltaTime*fadeSpeed*hitTime*hitTime/1000;

完成后,我们发现受击效果的变化曲率更加陡峭,彻底淡出的时间也得到了延长。

轰击强度随机化

雨天的所有雨滴都是完全一样的吗?当然不是。
世界上有完全相同的两片树叶吗?当然没有。
真实的世界里,任何东西都是独一无二的。

在前面的脚本中,我们的轰击强度被basicImpactFactor所控制,所有的射弹轰击的强度和速度都是固定且完全相同的,这让我们的受击效果在连续多次播放时显得毫无生趣。

我们只需要向OnCollisionEnter方法中的hitTime赋值语句内添加一个简单的参数,就能为轰击带来变化:

hitTime=basicImpactFactor*collision.relativeVelocity.magnitude;

collision.relativeVelocity.magnitude的作用是获取撞击物的撞击速度向量并转换为浮点类型的向量长度,所以事实上我们是获取了每一个射弹的终点速度作为随机值,而这就要求我们的射弹的初始速度和加速度至少有一个是随机的。

由于我们的射弹使用了统一的预制件,最简单的随机速度方法就是使我们发射射弹时施加的力随机化:

bullet.AddForce((this.transform.position-bullet.transform.position)*Random.Range(0.1f,maxBulletsPower/3),ForceMode.Impulse);

这样,各个射弹到达护盾时的速度就是基本上随机的了。将射弹密度调低,读者应该能很容易观察到各个射弹轰击时效果强度的随机化。

射弹生成位置优化

在前面的脚本中,我们的射弹生成位置是护盾球物体周围的一个球形空间内的随机位置,射弹将从四面八方射向护盾球。

但事实上,在摄像机拍摄的画面中,我们只能看到其中一部分射弹轰击在护盾球正面的效果,其他地方的射弹轰击几乎是完全不可见的,这使得大量的射弹事实上并没有起到真正有效的表现效果,产生了浪费。

为了改善这一问题,我们对createBullets方法中的语句进行修改:

targetPosition=Camera.main.transform.position+newVector3(Random.Range(-BulletRandomRange,BulletRandomRange),Random.Range(-BulletRandomRange,BulletRandomRange),Random.Range(-BulletRandomRange,BulletRandomRange));//生成中心由物体改为主摄像机

这样可以尽可能地保证射弹轰击的位置是护盾球的正面。

然而,我们希望主摄像机到物体的距离的调整不会对表现产生太大的影响。在当前情况下,如果生成范围大于摄像机到护盾球物体的距离,那么一定会出现射弹与主摄像机视线夹角超过90°的情况;并且,有可能发生射弹凭空出现导致的“穿帮"。

因此,我们再在当前的基础上对生成空间进行位移,确保它位于摄像机正后方:

targetPosition+=(Camera.main.transform.position-this.transform.position).normalized*BulletRandomRange;//基于相对位置方向向量的位移

这样一来,无论我们如何调整范围,射弹都只会在镜头之外生成,并从摄像机后方射向护盾球。同时,轰击的范围也更加集中,受范围缩放的影响程度也降低到了一个可以接受的水平。

https://vdn6.vzuu.com/SD/29dd8dee-321b-11ec-9649-b2a520a92b8f.mp4?pkey=AAUrVng-A6Ffi_DRJNi1JV2_K5Yjn-BKaSMatK8TlP12SU8SjKccIZ-0R0HqlYMnbpPVjxXQjeVVVBEvn_pIOZnP&c=avc.0.0&f=mp4&pu=078babd7&bu=078babd7&expiration=1679476149&v=ks6

改进后的轰击位置分布

这部分笔记到这里就完全结束了。在后面的笔记中,我们会进一步讨论如何实现更好的受击效果。

https://vdn6.vzuu.com/SD/1e525ff8-321c-11ec-bf66-86721c1d7c0e.mp4?pkey=AAVnyfiSSL3i3PpB0qqOCOl5G1htI5EK2gxMX-peS5Zs9b4ag7cxPQJp3VlHqwW45HZgCEBjyei-car14nq6gqQe&c=avc.0.0&f=mp4&pu=078babd7&bu=078babd7&expiration=1679476157&v=ks6

简单力场护盾效果ASE实现笔记相关推荐

  1. 带顶点动画的护盾效果——UnityShader学习笔记

    文章目录 自言自语 一.效果 二.C# 三.Shader 总结 自言自语 最近又是很久没有更新笔记了.原因有二. 一.最近一直再啃一个看起来酷炫的护盾效果 啃了好久啊.直至效果满意 也理解了. 这个是 ...

  2. Unity 实现简单力场效果

    Unity 实现简单力场效果 前言 效果 源码 前言 项目中要用到一个力场的效果,偶然在bilibili中找到了.记录一下. 原视频: https://www.bilibili.com/video/B ...

  3. JAVA程序员笔记(第二阶段:前端)第4篇——定位、太极图、经典轮播图一、简单transfrom变换效果

    定位: 绝对定位Absolution: 元素会脱离文档流,定位是相对于离它最近的且不是static定位的父元素而言,若该元素没有设置宽度,则宽度由元素里面的内容决定,且宽度不会影响父元素,定位为abs ...

  4. 【Unity ASE学习笔记】

    Unity ASE学习笔记 一.工具比较 二.ASE插件工具下载 三.ASE界面 主要工作区详解 四.节点 常用节点概览 4.1.贴图节点 4.2.常数节点 4.3.四则运算(+ - * /) 4.4 ...

  5. 手风琴html例子,jquery实现简单手风琴菜单效果实例

    本文实例讲述了jquery实现简单手风琴菜单效果的方法.分享给大家供大家参考.具体实现方法如下: dd').hide(); $('.accordion > dt > a').click(f ...

  6. html背景只向x轴扩散,有趣的css—简单的下雨效果2.0版

    有趣的css-简单的下雨效果2.0版 推荐 原创 Fatman_2021-05-18 13:37:36©著作权 文章标签 css 阅读数 1119 ©著作权归作者所有:来自51CTO博客作者Fatma ...

  7. html如何添加时钟效果,基于HTML5+CSS3实现简单的时钟效果

    目的: 利用html5,css实现钟摆效果 知识点: 1) 利用position/left/top和calc()实现元素的水平和垂直居中: 2) 利用CSS3的animation/transform/ ...

  8. 如何在css中设置音乐效果,css实现简单音乐符效果

    css实现简单音乐符效果 利用css3中的transform.animation.keyframes实现 1 2 3 4 5 6 7 Document 8 9 .box{ 10 width:60px; ...

  9. 【设计教程】在PS里面制作简单的下雨效果!

     传智播客( http://icd.itcast.cn/)是一家网页平面设计培训学院,专注于网页设计培训,平面设计培训,fash培训,ui设计培训.    在PS里面制作简单的下雨效果   (1)首先 ...

最新文章

  1. oracle汉化包下载地址
  2. pthread_cond_wait()加一个while为什么的解释
  3. 阿里云Redis开发规范
  4. CrateDB——全文搜索使用的是lucene,尚不知其底层实现
  5. 剑网三缘起,葱姜蒜也能卖?欺负新玩家被批评,但说明游戏很自由
  6. matlab中response函数,matlab函数的种类
  7. 需求、需求工程与需求工程师 — 2.需求的来源
  8. Unity的Json解析二–写Json文件
  9. 根据周次显示日期范围_Elasticsearch根据日期价格范围搜索酒店且排序
  10. python爬虫有几种方法_python爬虫-----Python访问http的几种方式
  11. 存款100万能退休了吗?
  12. Docker之nginx集群
  13. 【运维必备-堡垒机】
  14. java jpg转换tif_JAVA 实现jpg/tif/bmp 等图片之间格式得互相转换
  15. C语言 解析lrc歌词文件
  16. html特效代码 枫叶,经典FLASH特效代码
  17. vnr光学识别怎么打开_小区安装家用防盗报警系统方案
  18. 313day(服务器的一些问题)
  19. 东方通TongWeb创建GBase数据库连接池
  20. 微信小程序获取数据接口动态渲染Echarts折线图

热门文章

  1. android graphics2d,Graphics2D的drawString之不带颜色的字体
  2. css clip-path 画五角星
  3. RKRK3399平台开发系列讲解(其他篇)1.29、查看显示时钟
  4. 品葡萄酒的11个常见问题
  5. 2021年深圳盐田区绿色建筑与装配式建筑发展资金申报资助及条件,补贴200万
  6. IEC60870-5-101基本远动任务通信协议测试方法
  7. Android开发自定义相机,自定义拍照界面
  8. ATM维护人员教大家正确使用银行卡和取款机
  9. 连接中控指纹考勤机 zkemkeeper zksoftware ZKTeco
  10. 论文中的图片怎么修改为300dpi?图片dpi怎么调300?