You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity URP中如何为自定义Shader添加纹理实例化属性?

纹理实例化属性实现方案

1. Shader内的声明与采样实现

首先在Shader的Properties块中声明纹理占位(即使是实例化属性,也需要这个关联后续的采样器),然后在实例化缓冲区中添加纹理和对应的缩放偏移属性:

Properties
{
    // 保留你原有的属性...
    [HideInInspector]_CustomPatternTex("Custom Pattern", 2D) = "white" {}
}

CGPROGRAM
// 确保开启实例化编译指令
#pragma multi_compile_instancing
// 其他URP相关编译指令...

struct appdata
{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    UNITY_VERTEX_INPUT_INSTANCE_ID // 必须添加以支持实例化属性访问
};

struct v2f
{
    float2 uv : TEXCOORD0;
    float4 pos : SV_POSITION;
    UNITY_VERTEX_OUTPUT_STEREO
};

// 实例化缓冲区
UNITY_INSTANCING_BUFFER_START(Props)
    UNITY_DEFINE_INSTANCED_PROP(half, _Injury)
    UNITY_DEFINE_INSTANCED_PROP(half4, _Custom1)
    UNITY_DEFINE_INSTANCED_PROP(half4, _Custom2)
    // 声明实例化纹理采样器
    UNITY_DEFINE_INSTANCED_PROP(sampler2D, _CustomPatternTex)
    // 对应纹理的缩放偏移属性,必须一起声明
    UNITY_DEFINE_INSTANCED_PROP(float4, _CustomPatternTex_ST)
UNITY_INSTANCING_BUFFER_END(Props)

v2f vert(appdata v)
{
    v2f o;
    UNITY_SETUP_INSTANCE_ID(v); // 初始化实例ID
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    
    o.pos = TransformObjectToHClip(v.vertex);
    o.uv = v.uv;
    return o;
}

half4 frag(v2f i) : SV_Target
{
    UNITY_SETUP_INSTANCE_ID(i); // 片元函数中初始化实例ID
    
    // 获取当前实例的纹理和ST参数
    sampler2D patternTex = UNITY_ACCESS_INSTANCED_PROP(Props, _CustomPatternTex);
    float4 patternST = UNITY_ACCESS_INSTANCED_PROP(Props, _CustomPatternTex_ST);
    float2 adjustedUV = TRANSFORM_TEX(i.uv, _CustomPatternTex);
    
    // 采样纹理
    half4 patternColor = tex2D(patternTex, adjustedUV);
    
    // 结合原有逻辑(示例:混合自定义颜色与受伤等级)
    half4 baseColor = UNITY_ACCESS_INSTANCED_PROP(Props, _Custom1);
    half injury = UNITY_ACCESS_INSTANCED_PROP(Props, _Injury);
    baseColor = lerp(baseColor, half4(1,0,0,1), injury);
    
    // 混合图案颜色
    half4 finalColor = baseColor * patternColor;
    return finalColor;
}
ENDCG

2. C#脚本设置实例化纹理

通过MaterialPropertyBlock给单个对象设置实例化纹理,不会影响其他使用同一材质的对象:

using UnityEngine;

public class AssignInstanceTexture : MonoBehaviour
{
    [SerializeField] private Texture2D customPattern;
    [SerializeField] private Vector2 textureScale = Vector2.one;
    [SerializeField] private Vector2 textureOffset = Vector2.zero;

    private void Awake()
    {
        var renderer = GetComponent<Renderer>();
        var propertyBlock = new MaterialPropertyBlock();
        
        // 先读取当前对象已有的属性,避免覆盖其他实例化参数
        renderer.GetPropertyBlock(propertyBlock);
        
        // 设置实例化纹理
        propertyBlock.SetTexture("_CustomPatternTex", customPattern);
        // 可选:单独设置纹理的缩放和偏移
        propertyBlock.SetVector("_CustomPatternTex_ST", new Vector4(textureScale.x, textureScale.y, textureOffset.x, textureOffset.y));
        
        // 应用属性块
        renderer.SetPropertyBlock(propertyBlock);
    }
}

关键注意事项

  • 必须在Shader的Pass中添加#pragma multi_compile_instancing指令,同时在顶点/片元函数中添加UNITY_SETUP_INSTANCE_ID初始化实例ID,否则无法正确访问实例化属性。
  • 实例化纹理的采样器必须和对应的_ST偏移缩放属性一起声明,TRANSFORM_TEX宏依赖这个参数计算正确的UV。
  • 确保Renderer组件开启了GPU Instancing(URP下默认启用,可在Inspector面板确认)。
  • 不同平台对实例化缓冲区的大小有限制,建议控制实例化纹理的数量(一般不超过4个)。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 05:35:16