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

Unity开发:如何为可复用Shader设置默认纹理?

解决Unity中Sprite使用自定义Shader闪白时显示全白的问题

问题原因分析

Sprite显示全白,大概率是以下两个原因:

  1. 自定义Shader未正确处理纹理采样(比如缺少UV变换、未声明必要的纹理属性)
  2. 代码创建Material时,只设置了纹理,未同步原材质的UV平铺/偏移、颜色等关键属性

修复步骤

1. 确保自定义Shader正确处理纹理

检查你的Shader代码,必须包含完整的纹理属性声明和UV处理逻辑,示例如下:

Properties {
    _MainTex ("Sprite Texture", 2D) = "white" {}
    _FlashAmount ("Flash Intensity", Range(0, 1)) = 0.0
}

SubShader {
    Tags { 
        "RenderType"="Transparent" 
        "Queue"="Transparent" 
        "IgnoreProjector"="True"
        "RenderPipeline"="UniversalPipeline" // 若使用URP,添加此标签
    }
    Blend SrcAlpha OneMinusSrcAlpha
    Cull Off ZWrite Off

    Pass {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #include "UnityCG.cginc"

        struct appdata {
            float4 vertex : POSITION;
            float2 uv : TEXCOORD0;
            float4 color : COLOR;
        };

        struct v2f {
            float2 uv : TEXCOORD0;
            float4 vertex : SV_POSITION;
            float4 color : COLOR;
        };

        sampler2D _MainTex;
        float4 _MainTex_ST; // 必须声明,用于UV平铺/偏移变换
        float _FlashAmount;

        v2f vert (appdata v) {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            o.uv = TRANSFORM_TEX(v.uv, _MainTex); // 处理UV的平铺和偏移
            o.color = v.color;
            return o;
        }

        fixed4 frag (v2f i) : SV_Target {
            fixed4 baseColor = tex2D(_MainTex, i.uv) * i.color;
            // 闪白混合逻辑:原颜色与白色按_FlashAmount插值
            baseColor.rgb = lerp(baseColor.rgb, fixed3(1,1,1), _FlashAmount);
            return baseColor;
        }
        ENDCG
    }
}

2. 修改C#代码,正确创建Material

不要直接用Shader创建空Material,而是基于原SpriteRenderer的材质实例化,自动继承所有纹理和UV属性:

public class Health : MonoBehaviour {
    [SerializeField] private int _maxHealth;
    [SerializeField] private Shader _flashShader;
    [SerializeField] private SpriteRenderer _spriteRenderer;

    private int _health;
    private Material _flashMaterial;

    private void Awake() {
        _health = _maxHealth;
        // 基于原材质创建实例,再替换为闪白Shader
        _flashMaterial = new Material(_spriteRenderer.material);
        _flashMaterial.shader = _flashShader;
        _spriteRenderer.material = _flashMaterial;
    }

    public void OnDamage(int damage) {
        FlashDamage();
        _health -= damage;
        if(_health <= 0) {
            Destroy(gameObject);
        }
    }

    public void OnHeal(int heal) {
        _health = Mathf.Min(_health + heal, _maxHealth);
    }

    private void FlashDamage() {
        StopAllCoroutines();
        StartCoroutine(FlashDamageRoutine());
    }

    private IEnumerator FlashDamageRoutine() {
        _flashMaterial.SetFloat("_FlashAmount", 1f);
        yield return new WaitForSeconds(0.15f);
        _flashMaterial.SetFloat("_FlashAmount", 0f);
    }
}

3. 额外检查点

  • 确认Sprite的纹理导入设置正确(比如Sprite模式、Alpha通道开启)
  • 如果使用URP/HDRP,Shader要对应适配渲染管线的标签

内容的提问来源于stack exchange,提问作者Nombre de Usuario Genérico

火山引擎 最新活动