You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何为每个GameObject独立调整同一Shader的Outline width参数?

解决Unity中Outline Shader参数同步问题

问题原因

你遇到的核心问题是多个GameObject共享了同一个材质球实例。在Unity中,材质球是共享资源——当多个物体使用同一个材质球时,修改材质球的任何参数都会同步到所有引用它的物体上,这就是为什么改Cube的Outline Width会影响Sphere和Cylinder。

解决方案

下面提供两种不同场景下的解决方案,你可以根据自己的需求选择:


方案1:为每个物体创建独立材质球(简单直接)

这是最容易实现的方法,适合物体数量不多的场景:

  • 选中Cube,找到Inspector面板中Renderer组件的材质球,点击材质球右侧的小箭头,选择Duplicate。这会生成一个原材质球的副本,仅属于当前Cube。
  • 对Sphere和Cylinder重复上述操作,让每个物体拥有自己独立的材质球副本。
  • 现在修改每个物体材质球的_Outline参数,只会影响对应的物体,不会再同步到其他物体。

方案2:使用MaterialPropertyBlock实现单材质多实例独立参数(性能友好)

如果你的场景中有大量需要独立Outline参数的物体,创建多个材质球会增加Draw Call,影响性能。这种情况下,推荐使用MaterialPropertyBlock来实现单材质球下每个物体拥有独立参数

步骤1:修改Shader(可选但推荐)

在原Shader的Properties部分,给_Outline参数加上[PerRendererData]标记,告诉Unity这个参数可以被每个Renderer独立覆盖:

Properties { 
    _Color ("Main Color", Color) = (.5,.5,.5,1) 
    _OutlineColor ("Outline Color", Color) = (0,0,0,1) 
    [PerRendererData] _Outline ("Outline width", Range (0.0, 0.1)) = .005 
    _MainTex ("Base (RGB)", 2D) = "white" { } 
}
步骤2:编写C#控制脚本

创建一个名为PerObjectOutline.cs的脚本,挂载到每个需要独立Outline的物体上:

using UnityEngine;

[RequireComponent(typeof(Renderer))]
public class PerObjectOutline : MonoBehaviour
{
    [Range(0.0f, 0.1f)]
    public float outlineWidth = 0.005f;

    private Renderer _renderer;
    private MaterialPropertyBlock _propertyBlock;

    void Awake()
    {
        _renderer = GetComponent<Renderer>();
        _propertyBlock = new MaterialPropertyBlock();
        // 初始化时就设置一次参数
        UpdateOutlineWidth();
    }

    // 当Inspector参数修改时自动更新
    void OnValidate()
    {
        if (_renderer != null)
            UpdateOutlineWidth();
    }

    void UpdateOutlineWidth()
    {
        _renderer.GetPropertyBlock(_propertyBlock);
        _propertyBlock.SetFloat("_Outline", outlineWidth);
        _renderer.SetPropertyBlock(_propertyBlock);
    }
}
使用方法
  • 将脚本分别挂载到Cube、Sphere、Cylinder上。
  • 现在你可以在每个物体的Inspector面板中直接修改Outline Width参数,只会影响当前物体,同时所有物体仍然共享同一个材质球,不会增加额外的Draw Call。

额外提示

原Shader的Outline Pass中使用了顶点颜色来计算偏移(v.vertex.xyz += v.color * _Outline),如果你的物体顶点颜色不是纯白色,可能会导致Outline偏移方向异常。如果需要基于法线的标准Outline,可以把vert函数修改为:

v2f vert(appdata v) {
    v2f o;
    // 基于法线方向偏移顶点,实现标准轮廓线
    float3 norm = normalize(mul((float3x3)UNITY_MATRIX_IT_MV, v.normal));
    float2 offset = TransformViewToProjection(norm.xy);
    o.pos = UnityObjectToClipPos(v.vertex);
    o.pos.xy += offset * o.pos.z * _Outline;
    o.color = _OutlineColor;
    return o;
}

内容的提问来源于stack exchange,提问作者Daniel Lip

火山引擎 最新活动