Licensing
将 Spine 官方运行时整合到自建应用程序中需要持有 Spine 许可证.
渲染
Materials
每个atlas页中的Texture都需要自己的Material, Material会在导入skeleton时自动创建. 当使用除 Normal
外的槽位blend模式时, 运行时也会为每种blend模式额外创建Materials(使用PMA的 Additive
除外, 因为它可以用正常Material渲染). SkeletonRenderer 会逐帧管理MeshRenderer中的Materials数组, 这些Materials取决于当前分配的附件图片和包含这些附件的AtlasAssets, 以及槽位使用了何种blend模式.
请注意: 直接修改Material数组是毫无意义的, 因为后续的
LateUpdate()
会覆盖掉这些更改. 所以应该使用SkeletonRendererCustomMaterials 或 SkeletonGraphicCustomMaterials 组件来替换Material. 也可以在 _Atlas 资产中设置Materials来更改所有实例的Materials. 但修改 _Atlas 资产之后, 需要在SkeletonRenderer
组件的SkeletonData Asset
参数处点击Reload
来重新加载使用了新atlas materials的skeleton.
请注意:
Spine/SkeletonGraphic*
着色器只能在搭配SkeletonGraphic
组件时才能正常渲染materials. 切勿在SkeletonGraphic
组件中使用URP着色器, LWRP着色器或如Spine/Skeleton
这类普通着色器. 缘由详见 SkeletonGraphic - Material重要使用须知 一节.
Material切换和绘制调用
如果附件分布在了多个atlas页上或者有不同的blend模式 (这里不妨以material A
和material B
为例), 运行时会根据绘制顺序访问Materials顺序来设置Materials数组.
若附件访问顺序为:
- 是A中的附件
- 是A中的附件
- 是B中的附件
- 是A中的附件
则Material数组将会是:
- Material A (满足附件1和附件2)
- Material B (满足附件3)
- Material A (满足附件4)
Materials数组中的每个Material都对应着一次 绘制调用. 因此大量的Material切换会削弱性能表现.
Dragon示例展示了这种有大量绘制调用的用例:
因此建议将附件打包到尽可能少的atlas页中, 并根据绘制顺序将附件分组并入atlas页以减少无谓的material切换. 请参阅 Spine Texture Packer: 文件夹结构 一节以了解如何在Spine atlas中编排atlas区域.
更改特定实例的Materials
请注意: 直接修改 SkeletonRenderer 中的material数组没有意义, 因为随后的
LateUpdate()
调用会覆盖掉它们. 如果下文中的方法都不适合你的用例, 可以用SkeletonAnimation.OnMeshAndMaterialsUpdated
回调委托手动地逐帧替换MeshRenderer.Materials
. 在给MeshRenderer.Materials
分配了atlas materials后, 运行时会在LateUpdate()
结束时调用这个回调.
CustomMaterialOverride和CustomSlotMaterials
SkeletonRenderer 可以覆盖(override)某个槽位上的materials, 或者替换掉生成的(resulting) materials.
要在运行中的某个 SkeletonRenderer 实例上, 用新material替换掉原始material, 可以用 SkeletonRenderer.CustomMaterialOverride
属性:
// MeshRenderer.material will not work, MeshRenderer.sharedMaterial might fail in some cases.
if (originalMaterial == null)
originalMaterial = skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial;
skeletonAnimation.CustomMaterialOverride[originalMaterial] = newMaterial; // to enable the replacement.
skeletonAnimation.CustomMaterialOverride.Remove(originalMaterial); // to disable that replacement.
请注意: 请勿使用表达式
originalMaterial = skeletonAnimation.GetComponent<MeshRenderer>().material
, 因为.material
返回的是主Material的一个实例拷贝而非Material本身. 同样也不建议写成originalMaterial = skeletonAnimation.GetComponent<MeshRenderer>().sharedMaterial
, 因为若还未给主Material赋值时 (例如活动帧尚无活动附件, 或者过早调用了这行代码时), 这种写法可能会返回null.
要仅替换某个槽位上的Material, 可以用 SkeletonRenderer.CustomSlotMaterials
:
skeletonAnimation.CustomSlotMaterials.Remove(slot); // to disable that replacement.
保持渲染合批状态下Tint Skeletons
在skeleton实例上使用多种 Materials
或 MaterialPropertyBlocks
会破坏渲染合批(batching). 如果你不修改material的其他属性而只需tint某个skeleton实例, 则应使用 Skeleton.R .G .B .A
颜色属性. 为了使tinting生效, 必须在SkeletonRenderer组件的检查器中启用 Advanced - PMA Vertex Colors
.
...
skeleton = GetComponent<SkeletonRenderer>().Skeleton;
...
skeleton.R = color.r;
skeleton.G = color.g;
skeleton.B = color.b;
skeleton.A = color.a;
这些skeleton颜色属性只设置顶点颜色而不改变其他material属性.
tinting某个附件时也能这么写:
...
slot.R = slotColor.r;
slot.G = slotColor.g;
slot.B = slotColor.b;
slot.A = slotColor.a;
请注意: 如果动画会修改了附件的颜色值, 那么在 SkeletonAnimation.UpdateComplete 这类回调应用了动画之后, 务必记得把每个槽位的颜色值改回来.
MaterialPropertyBlocks
使用 Renderer.SetPropertyBlock 可以设置某个 MeshRenderer
中material的属性值.
mpb.SetColor("_FillColor", Color.red); // "_FillColor" is a named property on the used shader.
mpb.SetFloat("_FillPhase", 1.0f); // "_FillPhase" is another named property on the used shader.
GetComponent<MeshRenderer>().SetPropertyBlock(mpb);
// to deactivate the override again:
MaterialPropertyBlock mpb = this.cachedMaterialPropertyBlock; // assuming you had cached the MaterialPropertyBlock
mpb.Clear();
GetComponent<Renderer>().SetPropertyBlock(mpb);
请注意: 在
MaterialPropertyBlock
中使用的参数名 (如_FillColor
或_FillPhase
), 要匹配着色器中的变量名. 请注意, 着色器变量名不是显示在检查器中的名称 (例如Fill Color
和Fill Phase
). 要查看着色器的参数名称, 需要打开.shader
文件 (点击material旁边的齿轮图标, 选择Edit Shader
) 查看最前面的Properties { .. }
代码段, 其中有全部参数的列表. 在如下这行代码中, 最左边的名字就是参数名_FillColor
:_FillColor ("Fill Color", Color) = (1,1,1,1)
^^^^^^^^^^着色器变量名通常以
_
字符开头, 且从不包含任何空格. 它旁边的字符串"Fill Color"
就是在检查器中显示的名称.
你可以在示例场景 Spine Examples/Other Examples/Per Instance Material Properties
中找到更改特定实例中material属性的演示.
优化提示
- 使用Renderer.SetPropertyBlock设置不同的Material属性值会破坏渲染器合批(batching)操作. 当MaterialPropertyBlock的参数一致时 (例如tint颜色均置为绿色) 渲染器才会合批渲染.
- 每当你改变或添加了MaterialPropertyBlock的属性值时, 都需要调用
SetPropertyBlock
来设置参数. 但你可以把MaterialPropertyBlock保存在类成员中, 如此在改变某个属性值时就无需再实例化出一个新MaterialPropertyBlock了.- 当需要经常更改某个属性时, 你可以使用静态方法
Shader.PropertyToID(string)
来缓存该属性ID(int值), 而无需每次都访问MaterialPropertyBlock中字符串重载过的setter.
透明度与绘制顺序(Draw Order)
所有spine-unity着色器均使用alpha blending来清晰地绘制附件边缘的半透明过渡区域. 若没有使用alpha blending(比如设置成了固定的透明度阈值) 则边缘会产生尖锐的狗牙状轮廓, 类似于锯齿(aliasing artifacts)效果.
然而alpha blending有个老毛病, 就是无法用z-buffer进行自动深度排序. 所以运行时是从后到前渲染三角形, 然后将各部件分层绘制的. 运行时会为每个 SkeletonRenderer 组件生成一个网格, 并按照Spine中设置的 槽位绘制顺序 绘制三角形. 一次绘制调用便可将skeleton中排好序的单网格部件全部绘制出来.
如若网格间有交叠, spine-unity则会利用Unity中的各种渲染顺位机制来判断哪个网格应该在上面. 按照标准的spine-unity设置, 整个skeleton网格的渲染顺序由以下多个因素决定:
- 相机深度(Camera depth). 相机的多机位设置会影响渲染顺序.
- Material.renderQueue. 设置它后将覆盖着色器的
Queue
标签. - 着色器的
Queue
标签. 在Spine
着色器中与其他sprites一样, 默认为"Transparent"
队列. - Sorting Group 组件. 当该组件附加在MeshRenderer的GameObject或其任意父GameObject上时会影响渲染顺序.
- 渲染器的 SortingLayer 和 图层内的SortingOrder.
- 相机透视. 可以把相机配置为 使用平面距离(正交相机)或是透视距离(透视相机).
若场景中的数个渲染器处于相同的sorting layer, 且sorting order和着色器的 Queue
标签也相同, 则可以通过控制与相机的相对距离来控制Spine GameObjects的渲染顺序. Unity的相机类内置了 transparencySortMode 属性可供使用.
Sorting Layer和Order in Layer
SkeletonRenderer 组件 (或子类 SkeletonAnimation) 和 SkeletonMecanim 组件的检查器中有 Sorting Layer
和 Order in Layer
两个属性, 它们本质上修改的是 MeshRenderer
的 sortingLayerID 和 sortingOrder 属性. 这些属性是存在 MeshRenderer
内部而非 SkeletonRenderer
之中.
用代码可以这样访问这些属性:
防止排序错误
在使用正交相机时, 特别容易出现使用多页atlas的skeleton其渲染排序有误的情况. 在skeleton的GameObject上添加一个 Sorting Group 组件就能解决这个问题. 另一种变通之法是轻微旋转一下相机, 比如将摄像机transform旋转中的Y值置为0.001.
在Skeleton部件之间渲染其他对象
有时需要在角色的各部件之间显示其他的GameObjects, 例如角色爬到树上的过程中应该在树干图层之上显示一条腿, 同时在树干之下显示另一条腿.
spine-unity的方案是使用 SkeletonRenderSeparator 组件, 它能将一个skeleton分割为多个部件.
淡入或淡出Skeleton
当降低skeleton的alpha值来实现半透明skeleton时, alpha blending会导致skeleton下层的部件意外露出. 这是一个很常见的问题, 而其成因是运行时绘制每个三角形时都会应用透明度.
解决该问题的一个办法是使用一张临时的 RenderTexture. 先在正常的不透明度下将整个角色渲染到RenderTexture上, 然后再按所需的透明度将RenderTexture绘制到场景中. 建议使用我们提供的 SkeletonRenderTexture 和SkeletonRenderTextureFadeout 组件来实现这一功能. 在示例场景 Spine Examples/Other Examples/RenderTexture FadeOut Transparency
中也能找到对这两个组件使用方法的演示.
诚然这只是实现淡出效果的多种方法之一. 可能还有其他更简单的解决方案, 比如用纯色逐渐地tinting skeleton, 或逐渐减小尺寸等方法来淡出Skeleton. 你也可以从已推出的2D游戏中汲取灵感, 因为RenderTextures是一种过去很少使用且开销很大的方案.
着色器
spine-unity运行时内置多种不同着色器. 新导入的skeleton material默认用的是 Spine/Skeleton
着色器. 你可以通过Material的着色器参数来选用其他着色器. 以下为Spine内置着色器列表.
重要提示:
SkeletonGraphic
组件只支持兼容CanvasRenderer
的特殊着色器. 详情参见 SkeletonGraphic - Material重要使用须知 一节.
重要提示: spine-unity运行时只提供了 内置渲染管线(Built-In Render Pipeline) 着色器, 它们与 Universal Render Pipeline(通用渲染管线) 项目并不兼容. 如果你需要使用通用渲染管线, 请换用 Spine URP着色器扩展UPM包 中的 URP 着色器.
请注意: Spine着色器尚不支持 延迟着色渲染路径.
-
Spine/Skeleton (默认着色器)
无光照(Unlit)透明着色器. 不写入深度缓冲区(z-buffer). -
Spine/Skeleton Graphic (SkeletonGraphic默认着色器)
用于 SkeletonGraphic 组件的无光照透明着色器. 不写入Z-buffer. 当该着色器搭配CanvasGroup
一起使用时, 不支持Additive
blend模式. 若有此需求应使用Spine/Skeleton Graphic Tint Black
着色器. 由于CanvasRenderer的限制, 只能使用单个texture. -
Spine/Skeleton Lit
简单光照(Lit)透明着色器, 不支持法线贴图. 不写入z-buffer. -
Spine/Skeleton Lit ZWrite
简单光照透明着色器, 不支持法线贴图. 写入z-buffer. -
Spine/Skeleton Fill
可自定义颜色叠加(color overlay)的无光照透明着色器. 不写入z-buffer.FillColor
决定叠加何种颜色而FillPhase
设置颜色叠加的强度. -
Spine/Skeleton Tint
可自定义双色tint的无光照透明着色器. 其深色tinting与浅色tinting是分开着色的, 该功能被称为 tint black. 不写入z-buffer.Tint Color
会给texture的浅色着色, 而texture的深色tint使用Black Point
参数. 相较于一般的多色blending, tint会使texture比其原色更亮. 当把Tint Color
和Black Point
置为同一个颜色时, tint结果会是一个纯色叠加(overlay). 当把Tint Color
设置为黑色而Black Point
设置为白色时, 则会将texture反色. -
Spine/Skeleton Tint Black
每个Spine动画槽位均可 tint black 的无光照透明着色器. 不写入z-buffer.
Spine为槽位提供了 Tint Black 功能, 可以在动画中tint black.需要 (对tint color顶点数据) 进行单独设置:
- 应在 SkeletonAnimation 组件检查器的
Advanced
面板中启用Tint Black
:
- 应在 SkeletonAnimation 组件检查器的
-
Spine/Skeleton Tint Black Additive
每个Spine动画槽位均可 tint black 的无光照透明着色器. 使用additive blend模式. 不写入z-buffer. -
Spine/SkeletonGraphic Tint Black
Spine/Skeleton Tint Black
着色器的 SkeletonGraphic 版本. 当搭配CanvasGroup
使用时支持Additive
blend模式.需要 (对tint color顶点数据) 进行单独设置:
- 应在 SkeletonAnimation 组件检查器的
Advanced
面板中启用Tint Black
. - 无论是否使用CanvasGroup, 均应将 SkeletonGraphic 中的material设置为
Spine/Runtime/spine-unity/Materials
对应目录下的SkeletonGraphicTintBlack
material, PMA和Straight alpha两种工作流均能适配这些material.
- 选中父级Canvas并在其
Additional Shader Channels
中启用TexCoord1
和TexCoord2
.
在
CanvasGroup
中使用Additive
blend模式则需要进行以下设置:- a) spine-unity 4.2 及更高版本: 在 SkeletonGraphic 组件检查器的
Advanced
面板中启用CanvasGroup Compatible
.
b) 旧版spine-unity: 在 SkeletonGraphic 组件检查器的Advanced
面板中启用Canvas Group Tint Black
. - 启用着色器的
CanvasGroup Compatible
.
- 应在 SkeletonAnimation 组件检查器的
-
Spine/Sprite
可配置的复杂着色器, 支持比Spine/Skeleton Lit
着色器更高级的光照. 可在示例场景Spine Examples/Other Examples/Sprite Shaders
中找到关于Spine/Sprite/Vertex Lit
着色器的演示.- Spine/Sprite/Unlit
无光照着色器, 支持可配置的blend模式, 支持调整覆盖颜色、色调(hue)、饱和度(saturation)和亮度(brightness). 可配置是否写入z-buffer. 支持雾效(fog). - Spine/Sprite/Vertex Lit
可配置的blend模式的顶点光照复杂着色器.
支持法线贴图(normal map)、次级反照率贴图(secondary albedo map)、金属贴图(metallic map)和自发光贴图(emission map).
可配置的颜色渐变(color ramp)以实现卡通渲染效果(cel-shaded look)和基于法线的边缘光照(rim lighting).
可配置的覆盖颜色、色调(hue)、饱和度(saturation)和亮度(brightness).
可配置是否写入z-buffer. 支持雾效. - Spine/Sprite/Pixel Lit
Spine/Sprite/Vertex Lit
着色器的像素光照(Pixel lit)版本. 它是唯一一个接受逐像素(per-pixel)实时阴影的着色器. 这个着色器总是写入z-buffer (因为它使用ForwardAdd
pass所以启用了ZWrite
).
- Spine/Sprite/Unlit
-
Spine/Special
- Spine/Special/Skeleton Grayscale
灰度强度可调的无光照透明灰度渲染(grayscale rendering)着色器. 不写入z-buffer. - Spine/Special/Skeleton Ghost
SkeletonGhost 组件专用的特殊着色器, 用于渲染踪迹(trail).
- Spine/Special/Skeleton Grayscale
-
Spine/Blend Modes
Intended for slots that have blend modesAdditive
,Multiply
andScreen
assigned in the Spine editor. It is recommended to automatically assign blend mode materials on import via the SkeletonData Blend Mode Materials.- Spine/Blend Modes/Skeleton PMA Additive
无光照透明着色器. 使用additive blend模式. 不写入z-buffer. - Spine/Blend Modes/Skeleton PMA Multiply
无光照透明着色器. 使用multiply blend模式. 不写入z-buffer. - Spine/Blend Modes/Skeleton PMA Screen
无光照透明着色器. 使用screen blend模式. 不写入z-buffer.
- Spine/Blend Modes/Skeleton PMA Additive
-
Spine/Outline
上述所有着色器都提供了Outline
参数, 启用它就能切换到Spine/Outline
版的着色器, 它用于在skeleton的周边绘制一圈彩色轮廓. 你可以在示例场景Spine Examples/Other Examples/Outline Shaders
中找到对Spine/Outline
着色器的演示.- Spine/Outline/OutlineOnly-ZWrite 这是一个只渲染轮廓的单pass特殊着色器. 它会写入z-buffer, 以便在有交叠的(overlapping)附件上正确实现轮廓遮蔽(outline occlusion). 该着色器也可以用于渲染包含多种材质的skeleton, 普通的轮廓着色器在这种情况下会把每个子网格的轮廓都渲染出来而不是将skeleton作为整体渲染. 此时可以用诸如
RenderCombinedMesh
这样的组件重渲染组合后的skeleton网格, 并使用该着色器在skeleton下层加上轮廓.
- Spine/Outline/OutlineOnly-ZWrite 这是一个只渲染轮廓的单pass特殊着色器. 它会写入z-buffer, 以便在有交叠的(overlapping)附件上正确实现轮廓遮蔽(outline occlusion). 该着色器也可以用于渲染包含多种材质的skeleton, 普通的轮廓着色器在这种情况下会把每个子网格的轮廓都渲染出来而不是将skeleton作为整体渲染. 此时可以用诸如
后处理效果
景深(DoF, Depth of Field)等一些后处理效果要求着色器能够写入z-buffer (更准确地说是写入有深度预处理(depth pre-pass)的深度缓冲区). 某些Spine着色器在Material中提供了 Depth Write(深度写入)
(又称ZWrite
) 参数开关, 而另一些着色器则默认写入z-buffer. 欲了解Spine着色器对z-buffer写入功能的支持性, 请见上文中的着色器列表.
根据项目的图形设置 (或渲染管线资产设置), 仅仅让着色器写入z-buffer可能还不足以支持后处理效果, 例如将渲染管线资产设置为 URP-HighFidelity
时就会这样. 这时还需将Material的 Render Queue
参数从 Transparent
改为 AlphaTest
.
若Spine的内置着色器限制了你的创作, 你也可以创建自己的修改版Spine着色器, 并将 (每个Pass块里的) ZWrite Off
改为 ZWrite On
, 同时将标记"Queue"="Transparent"
改为"Queue"="AlphaTest"
. 当然别忘记更改着色器代码第一行的着色器名称, 以避免命名冲突.
URP着色器扩展包
通用渲染管线(URP)着色器通过独立的UPM(Unity Package Manager)包提供. 下载和安装UPM包的指南, 请参见 可选的UPM扩展包 一节; 而更新UPM扩展包的步骤与须知, 则在 更新UPM插件包 一节中详述.
URP着色器UPM包提供了专门为Unity通用渲染管线(URP)构建的着色器, 包括2D渲染器功能.
请注意: 切勿在
SkeletonGraphic
组件上使用URP着色器. 缘由详见 SkeletonGraphic - Material重要使用须知 一节.
请注意: Spine URP着色器尚未支持URP中新添加的 延迟渲染路径 功能.
用于2D渲染器的URP着色器 (请勿用于URP (3D) 前向渲染器)
- Universal Render Pipeline/2D/Spine/Skeleton
URP 2D渲染器版的Spine/Skeleton
着色器. - Universal Render Pipeline/2D/Spine/Skeleton Lit
URP 2D渲染器版的Spine/Skeleton Lit
着色器. - Universal Render Pipeline/2D/Spine/Sprite
URP 2D渲染器版的Spine/Sprite/Vertex Lit
及Pixel Lit
着色器.
用于3D渲染器的URP着色器 (请勿用于 URP 2D 渲染器)
- Universal Render Pipeline/Spine/Skeleton
URP版的Spine/Skeleton
着色器. - Universal Render Pipeline/Spine/Skeleton Lit
URP版的Spine/Skeleton Lit
着色器. 可配置为接受逐像素实时阴影. - Universal Render Pipeline/Spine/Sprite
URP版的Spine/Sprite/Vertex Lit
及Pixel Lit
着色器. 接受逐像素实时阴影. - Universal Render Pipeline/Spine/Outline/Skeleton-OutlineOnly
URP版的Spine/Outline
着色器. 由于URP不允许一个着色器包含多个pass, 因此为了实现outline效果, 需要为该着色器单独创建一个material. 你可以考虑使用RenderExistingMesh
组件, 用法详见着色器UPM包中的示例场景com.esotericsoftware.spine.URP-shaders/Examples/Outline Shaders URP
. 如果你的skeleton需使用多种material, 那么可以用RenderCombinedMesh
来替代RenderExistingMesh
组件.
如普通着色器一样, 也能将这些着色器分配给material, 并同时受 Project Settings - Graphics
中 UniversalRenderPipelineAsset
设置的影响.
可以在UPM包 com.esotericsoftware.spine.URP-shaders/Examples
目录中的示例场景里找到以下三个URP着色器演示场景:
3D/URP 3D Shaders.unity
, 2D/URP 2D Shaders.unity
和 Outline Shaders URP.unity
.
LWRP着色器扩展包
轻量渲染管线(LWRP)着色器通过独立的UPM(Unity Package Manager)包提供. 下载和安装UPM包的指南, 请参见 可选的UPM扩展包 一节; 而更新UPM扩展包的步骤与须知, 则在 更新UPM插件包 一节中详述.
LWRP着色器扩展包内含Unity轻量渲染管线专用的着色器.
请注意: 切勿在
SkeletonGraphic
组件上使用LWRP着色器. 缘由详见 SkeletonGraphic - Material重要使用须知 一节.
- Lightweight Render Pipeline/Spine/Skeleton
LWRP版的Spine/Skeleton
着色器. - Lightweight Render Pipeline/Spine/Skeleton Lit
LWRP版的Spine/Skeleton Lit
着色器. - Lightweight Render Pipeline/Spine/Sprite
LWRP版的Spine/Sprite/Vertex Lit
及Pixel Lit
着色器.
如普通着色器一样, 也能将这些着色器分配给material, 并同时受 Project Settings - Graphics
中 LightweightRenderPipelineAsset
设置的影响.
可以在UPM包 com.esotericsoftware.spine.lwrp-shaders-4.2/Examples/LWRP Shaders.unity
中找到LWRP着色器的演示场景.
Shader Graph
目前尚未推出官方的Shader Graph Spine着色器或着色器节点. 请注意, 当你从Spine导出使用了 Straight alpha 的texture时, 也可以使用任何非Spine的着色器. 如果你想在其中复刻Spine着色器专用功能, 请参见这两篇论坛帖子: [帖子1] 和 [帖子2]. 如果还有任何疑问, 欢迎随时来 Spine论坛的Unity板块 上发帖咨询.
Amplify着色器编辑器
虽然官方没有提供Amplify着色器编辑器的着色器模板, 但用户 Hana
已在论坛上热心分享了 他的模板代码.
编写你自己的着色器
第一步是了解Unity中编写自定义着色器的 通用做法. 特别是 顶点和片元编程教程 是一篇很棒的概述, 理解了其中的概念后便能更容易理解spine-unity着色器的各部分在做什么.
基于已有的spine-unity着色器编写
强烈建议先复制一份已有的spine-unity着色器, 然后逐步修改调整它来实现你期望的效果. 比如在着色器返回最终的颜色值之前添加你的颜色处理代码. 以下代码展示了一个简短的示例, 说明了如何实现一个添加了灰度渲染功能的 SkeletonGraphic
修改版着色器:
{
_GrayIntensity("Intensity", Range(0, 1)) = 1 // this line was added to provide a Material property
[..]
}
float _GrayIntensity; // this parameter was added
..
fixed4 frag (VertexOutput IN) : SV_Target
{
..
color.rgb = lerp(color.rgb, dot(color.rgb, float3(0.3, 0.59, 0.11)), _GrayIntensity); // this line was added
return color;
}
使用非Spine着色器或可视化着色器编辑器时的附加须知
使用这类着色器前, 务必要考虑spine-unity和非Spine着色器间的以下区别:
- 渲染任意Spine skeleton时, 必须用
Cull Off
设置来禁用Backface culling(隐表面剔除). - Spine着色器通常无需法线, 因此在使用光照着色器时可能需要在组件中启用
Advanced - Add Normals
. - Spine着色器通常无需切线, 因此在使用法线贴图时, 可能需要在组件中启用
Advanced - Solve Tangents
. - Spine着色器默认使用Premultiply Alpha textures, 所以要么
a) 将atlas textures导出为 Straight alpha, 要么
b) 将着色器的blend模式改为PMA blend模式Blend One OneMinusSrcAlpha
. - Spine顶点色通常是PMA颜色. 当使用透明槽位或
Additive
槽位时, 你可以
a) 将着色器的blend模式改为PMA blend模式Blend One OneMinusSrcAlpha
并使用PMA atlas textures, 或者 b) 在组件中禁用Advanced - PMA Vertex Colors
(此后将不渲染Additive
槽位).
当然, UI和非UI着色器的通用准则仍是:
- 不要在
SkeletonAnimation
或SkeletonMecanim
上使用UI着色器. - 不要在
SkeletonGraphic
上使用非UI着色器.
Spine/Skeleton
着色器的基本解析
本节将对 Spine/Skeleton
着色器 进行简单解析. 在运行时导入了Spine texture atlas并据此生成了Material后, 默认就会使用该着色器. Spine/Skeleton
着色器相当精简且经典, 它具有以下特点:
- Premultiply Alpha (PMA) blending
- 不写入深度缓冲区
- 无光照
- 无背面剔除(backface culling)
- 无雾效
- 通过顶点色预乘来tint texture
- 可选择使用straight alpha替换PMA textures
- 包含用于投射实时阴影的
"ShadowCaster"
pass - Material属性:
- _MainTex "Main Texture"
- _StraightAlphaInput "Straight Alpha Texture"
- _Cutoff "Shadow alpha cutoff" -进阶参数:
- _StencilRef "Stencil Reference"
- _StencilComp "Stencil Comparison"
- Outline 参数 (_OutlineWidth "Outline Width" 等等)
着色器详解:
-
Premultiply Alpha (PMA) blending
hlslBlend One OneMinusSrcAlphaBlending的本质是这一句
result_rgba = frag_output_rgba * src_factor + framebuffer_rgba * dst_factor
.
非标准的Blend One OneMinusSrcAlpha
PMA blend模式可以在单个渲染pass中既渲染Additive
blend模式的槽位又渲染Normal
blend模式的槽位. 通过将上面这行代码中的SrcFactor
置为One
(而非SrcAlpha
值) 便能实现这一效果. 于是被OneMinusSrcAlpha
加权后的framebuffer_rgba
值将与原始的frag_output_rgba
值相加:
a) 对于Normal
blending, 片元着色器会将RGB
乘以A
, 其中A
保持不变.
b) 对于Additive
blending,RGB
不乘以 alpha, 而是将A
置为0
, 最终result_rgba的计算就变为了result_rgba = frag_output_rgba + (1-0) * framebuffer_rgba
.当在
SkeletonRenderer
或SkeletonGraphic
组件上启用 进阶设置 -PMA Vertex Colors
后, 将把Normal
和Additive
槽位blend模式的输出值作为顶点色隐式传入着色器:hlslstruct VertexInput {
float4 vertexColor : COLOR
}当PMA顶点色乘以采样到的PMA texture颜色时, 会自动应用槽位的
Normal
或Additive
blend模式:hlslreturn (texColor * i.vertexColor);因此在你的着色器中正确支持
Normal
和Additive
PMA blend模式需要:- 将blend函数定义为
Blend One OneMinusSrcAlpha
- 将texture颜色与顶点色相乘
- 在组件中启用 进阶设置 -
PMA Vertex Colors
.
如果你想使用基于标准blend模式
Blend SrcAlpha OneMinusSrcAlpha
的着色器, 且不需要Additive
槽位, 则需要确保从Spine导出的是 Straight alpha atlas textures. - 将blend函数定义为
-
不写入深度缓冲区
hlslZWrite Off典型的alpha-blended 2D sprite着色器均不写入深度缓冲区. 透明物体将根据
Camera.transparencySortMode
的设置从后向前绘制, 而不会用深度缓冲区来深度排序.Spine/Skeleton
与Unity的Sprites/Default
着色器均有这一特性.如果你想使用带有深度写入的着色器, 请确保
SkeletonRenderer
或SkeletonGraphic
组件中的Advanced - Z-Spacing
值置为非0
值, 以防止Z-Fighting现象 (特别是使用了光照之后). 请注意, 使用深度缓冲区可能会在半透明区域的外围渲染出错误效果, 例如边缘锯齿(aliasing effects on edges). -
无光照
场景中的所有灯光均不影响Spine/Skeleton
着色器, 着色器将始终以100%强度(intensity)渲染texColor * i.vertexColor
.如果需要在着色器中使用光照, 建议选择一个现有的光照着色器, 并根据需求对其修改. 不过将
Lighting Off
简单地改为Lighting On
并不能实现效果, 还需要在你的顶点着色器 (用于逐顶点照明(per-vertex lighting)) 或片元着色器函数 (用于逐像素照明(per-pixel lighting)) 中计算光照, 再乘以颜色强度. 要注意的是, URP, URP-2D和标准渲染管线着色器的光照计算方法各异, 所以参考着色器代码时一定要选择对应管线的着色器. -
无背面剔除
hlslCull Off渲染Spine skeleton的唯一硬性要求是必须 禁用backface culling(背面剔除), 对于2D着色器尤其如此.
主流的3D着色器都有背面剔除功能. 但在部件尺寸被缩放为负值或是翻转skeleton朝向的情况下, Spine网格上的背面剔除功能会导致某些三角形消失.
-
无雾效
Spine/Skeleton
着色器不支持雾效.在着色器上支持雾效需要在着色器代码中额外添加一些顶点参数和函数调用. 以下是
UnityCG.cginc
的代码:hlslmulti_compile_fog Will compile fog variants.
UNITY_FOG_COORDS(texcoordindex) Declares the fog data interpolator.
UNITY_TRANSFER_FOG(outputStruct,clipspacePos) Outputs fog data from the vertex shader.
UNITY_APPLY_FOG(fogData,col) Applies fog to color "col". Automatically applies black fog when in forward-additive pass.
Can also use UNITY_APPLY_FOG_COLOR to supply your own fog color.你可以查看
Spine/Sprite/Unlit
着色器来了解如何在你的着色器中支持雾效:hlsl#pragma multi_compile_foghlslUNITY_FOG_COORDS(1) // to declare it at the free attribute TEXCOORD1hlslUNITY_TRANSFER_FOG(output,output.pos); -
通过顶点色预乘来tint texture
详见前文中的 Premultiply Alpha (PMA) blending 一节. -
可选择使用straight alpha替换PMA textures
由于Spine/Skeleton
着色器的blend模式恒定为PMA blending, 所以没有premultiplied alpha颜色的输入texture就得通过采样将texture转换为PMA颜色. 下面这几行代码是该功能的实现:// bool Material parameter, enables the _STRAIGHT_ALPHA_INPUT shader keyword when enabled
[Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0
..
// compiles the shader in two variants so that shader keywords can switch between both variants
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
..
// when enabled, multiply texture rgb values by the texture alpha value.
#if defined(_STRAIGHT_ALPHA_INPUT)
texColor.rgb *= texColor.a;
#endif -
包含用于投射实时阴影的
"ShadowCaster"
pass
在第二个pass中写上Tags { "LightMode"="ShadowCaster" }
就能让这个pass被自动识别为阴影投射器(shadow caster) pass, 因为它带有LightMode
标签.ShadowCaster
pass不会写入RGB颜色, 但会将深度信息写入阴影缓冲区(shadow buffer). 因此它必须置为ZWrite On
. 由于(在渲染半透明物体时)无法在深度缓冲区中写入半透明深度值, 所以只能选择要么将片元写入深度缓冲区, 要么就丢弃片元 (此时将不投射阴影). 这是通过调用阈值(thresholding)函数实现的:hlslclip(texcol.a * i.uvAndAlpha.a - _Cutoff);其中
_Cutoff
Material参数表示alpha阈值, 若 x < 0 则clip(x)
丢弃片元. -
Material属性:
- _MainTex "Main Texture"
主texture. - _StraightAlphaInput "Straight Alpha Texture"
参见上文中的 "可选择使用straight alpha替换PMA textures" 一节. - _Cutoff "Shadow alpha cutoff"
参见上文中的 "包含用于投射实时阴影的"ShadowCaster"
pass" 一节. - 进阶参数:
- _StencilRef "Stencil Reference"
用于遮罩控制(mask interaction). - _StencilComp "Stencil Comparison"
用于遮罩控制, 该参数会根据Mask Interaction
属性值由SkeletonRenderer
或SkeletonGraphic
组件来决定. - Outline parameters (_OutlineWidth "Outline Width", etc.)
在切换到轮廓着色器Spine/Outline/Skeleton
时使用, 普通的非轮廓着色器Spine/Skeleton
不使用该参数.
- _StencilRef "Stencil Reference"
- _MainTex "Main Texture"