在 Unity 的日常开发中,我们经常会遇到需要显示或隐藏一个物体的场景。默认情况下,使用 SetActive()
或 enabled
方法虽然能立即控制物体是否可见,但切换时过于突兀。如果能通过渐变透明度的方式来控制物体的显隐,将极大提升视觉体验。
本文将详细讲解如何在 Unity 的 URP(通用渲染管线)中,使用脚本动态控制材质透明度,实现渐变的显隐效果。
一、为什么不能用 SetActive()
实现渐隐/渐显?
在 Unity 中,SetActive(false)
会直接将 GameObject 从场景中禁用,包括它的渲染、脚本执行、碰撞体等所有行为,这种方式适用于逻辑性强、对性能要求高的场景。但它带来的问题也很明显:
- 画面会瞬间消失,没有过渡效果;
- 无法插入动画或渐变;
- 禁用状态下无法再通过材质控制其透明度;
因此,如果我们希望让物体 逐渐显现或消失,最佳做法是通过材质透明度来控制物体可见性。
二、URP 中透明材质的设置方式
在标准渲染管线(Built-in)中,我们可以使用 Standard Shader
设置 Rendering Mode
为 Transparent
。但在 URP 中,Shader 和材质系统进行了重构,我们必须使用 Universal Render Pipeline/Lit 这类新 Shader,并手动设置材质透明属性。
2.1 手动设置 URP 材质为透明
- 选中你的 Material;
- Shader 选择:
Universal Render Pipeline/Lit
; - 找到 Surface Type,选择
Transparent
; - 调整 Base Map 或 Base Color 的 Alpha 值,即可控制透明度。
这样设置后,材质就能响应我们通过代码设置的透明值,产生渐变效果。
三、通过代码修改透明度的核心逻辑
为了实现渐变效果,我们需要在脚本中动态修改材质的透明度,并确保材质处于透明状态。
下面是完整的实现流程:
3.1 获取材质并设置为透明模式
private void SetMaterialTransparent(Material material)
{
material.SetFloat("_Surface", 1); // 1 = Transparent
material.SetFloat("_Blend", 0); // Alpha blending
material.SetFloat("_ZWrite", 0); // 不写入深度缓冲
material.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
}
这个方法确保材质从 Opaque 转为 Transparent,并设置适当的混合模式和渲染顺序。
3.2 修改材质颜色的 Alpha 值
URP 中的 Lit Shader 使用 _BaseColor
属性表示主颜色,因此我们要修改这个值的 Alpha 分量:
private void SetAlpha(Material material, float alpha)
{
if (material.HasProperty("_BaseColor"))
{
Color color = material.GetColor("_BaseColor");
color.a = Mathf.Clamp01(alpha);
material.SetColor("_BaseColor", color);
}
}
四、渐隐 / 渐显效果实现:完整组件
我们可以将上面的逻辑封装成一个脚本组件,挂载到任意带有 MeshRenderer 的 GameObject 上。
4.1 完整脚本:URPTransparencyController.cs
using UnityEngine;
using System.Collections;
public class URPTransparencyController : MonoBehaviour
{
public float fadeDuration = 1.0f;
private Material material;
private void Start()
{
material = GetComponent<Renderer>().material;
SetMaterialTransparent(material);
SetAlpha(material, 0f); // 初始为透明
}
public void FadeTo(float targetAlpha)
{
StartCoroutine(FadeCoroutine(targetAlpha));
}
private IEnumerator FadeCoroutine(float targetAlpha)
{
float startAlpha = material.GetColor("_BaseColor").a;
float time = 0f;
while (time < fadeDuration)
{
float alpha = Mathf.Lerp(startAlpha, targetAlpha, time / fadeDuration);
SetAlpha(material, alpha);
time += Time.deltaTime;
yield return null;
}
SetAlpha(material, targetAlpha);
}
private void SetMaterialTransparent(Material mat)
{
mat.SetFloat("_Surface", 1); // Transparent
mat.SetFloat("_Blend", 0); // Alpha blending
mat.SetFloat("_ZWrite", 0);
mat.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
}
private void SetAlpha(Material mat, float alpha)
{
Color color = mat.GetColor("_BaseColor");
color.a = Mathf.Clamp01(alpha);
mat.SetColor("_BaseColor", color);
}
}
五、调用方式示例
// 渐显
GetComponent<URPTransparencyController>().FadeTo(1f);
// 渐隐
GetComponent<URPTransparencyController>().FadeTo(0f);
你还可以通过按钮点击、UI 滑块、触发器等方式调用这些方法,实现交互式控制。
六、进阶拓展:渐变后自动隐藏对象
有时候你希望在透明度降为 0 后,将对象禁用以节省性能,可以在 FadeCoroutine
中加一个回调:
if (targetAlpha == 0f)
{
gameObject.SetActive(false);
}
当然,你也可以用 UnityEvent 触发其他逻辑,例如:
public UnityEvent onFadeOutComplete;
七、常见问题排查
问题 | 原因 |
---|---|
改变透明度没效果 | 材质未设置为 Transparent 模式 |
所有物体都变透明 | 多个对象共用同一个材质,未使用 .material |
材质突然变黑/失真 | 渲染模式设置不当,可能没有启用混合模式 |
渐变期间无法交互 | 使用透明材质时 ZWrite 为 0,可能遮挡关系异常 |
八、小结
本文完整介绍了如何在 Unity 的 URP 环境中,通过代码控制材质透明度,平滑实现 GameObject 的显隐过渡。相比直接使用 SetActive()
,这种方式更加自然、精细,适用于游戏中的过场动画、淡入淡出特效、UI 元素动态出现等各种场景。