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

Unity中如何将PerRendererData与float数组属性结合使用?

Great question! Combining [PerRendererData] with float arrays in Unity shaders is indeed a bit tricky since you can't directly declare a float array property with that attribute, and the CGPROGRAM block doesn't support [PerRendererData] either. But there are a couple of solid workarounds to achieve this:


1. Simulate an Array with Multiple [PerRendererData] Vector Properties

For small float arrays, you can break the array into individual Vector properties (each marked with [PerRendererData]), then reconstruct the array inside your shader's CGPROGRAM block.

Shader Example:

Shader "Custom/PerRendererArray"
{
    Properties
    {
        // Declare individual vector properties for each array element
        [PerRendererData] _ArrayElem0 ("Array Element 0", Vector) = (0,0,0,0)
        [PerRendererData] _ArrayElem1 ("Array Element 1", Vector) = (0,0,0,0)
        [PerRendererData] _ArrayElem2 ("Array Element 2", Vector) = (0,0,0,0)
        // Add as many as you need (within Unity's property limits)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            // Declare your float array in CGPROGRAM
            float _Array[3];
            float4 _ArrayElem0;
            float4 _ArrayElem1;
            float4 _ArrayElem2;

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                // Reconstruct the array from individual properties
                _Array[0] = _ArrayElem0.x;
                _Array[1] = _ArrayElem1.x;
                _Array[2] = _ArrayElem2.x;

                // Use the array as needed here...
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // Example: Use the first array element to tint the pixel
                return fixed4(_Array[0], _Array[1], _Array[2], 1);
            }
            ENDCG
        }
    }
}

C# Setup Example:

using UnityEngine;

public class PerRendererArraySetup : MonoBehaviour
{
    void Start()
    {
        Renderer renderer = GetComponent<Renderer>();
        MaterialPropertyBlock props = new MaterialPropertyBlock();
        renderer.GetPropertyBlock(props);

        // Set each "array element" property for this specific renderer
        props.SetVector("_ArrayElem0", new Vector4(0.8f, 0, 0, 0));
        props.SetVector("_ArrayElem1", new Vector4(0, 0.8f, 0, 0));
        props.SetVector("_ArrayElem2", new Vector4(0, 0, 0.8f, 0));

        renderer.SetPropertyBlock(props);
    }
}

This works well for small arrays, but gets cumbersome if you need a large number of elements.


For larger float arrays, the cleanest approach is to use a ComputeBuffer to hold your array data, then assign it to each renderer individually via MaterialPropertyBlock. This achieves the same "per-renderer" behavior as [PerRendererData] without relying on the attribute directly.

Shader Example:

Shader "Custom/PerRendererComputeBuffer"
{
    Properties
    {
        // No need for [PerRendererData] here; we'll handle it via code
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            // Declare a structured buffer for your float array
            StructuredBuffer<float> _FloatArray;

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // Access array elements by index
                float r = _FloatArray[0];
                float g = _FloatArray[1];
                float b = _FloatArray[2];
                return fixed4(r, g, b, 1);
            }
            ENDCG
        }
    }
}

C# Setup Example:

using UnityEngine;

public class PerRendererBufferSetup : MonoBehaviour
{
    private ComputeBuffer _buffer;

    void Start()
    {
        // Create and populate your float array
        float[] arrayData = new float[] { 0.2f, 0.6f, 0.9f };
        
        // Create a ComputeBuffer (size = number of elements, stride = size of one float)
        _buffer = new ComputeBuffer(arrayData.Length, sizeof(float));
        _buffer.SetData(arrayData);

        // Assign the buffer to this renderer's property block
        Renderer renderer = GetComponent<Renderer>();
        MaterialPropertyBlock props = new MaterialPropertyBlock();
        renderer.GetPropertyBlock(props);
        props.SetBuffer("_FloatArray", _buffer);
        renderer.SetPropertyBlock(props);
    }

    // Don't forget to release the buffer to avoid memory leaks
    void OnDestroy()
    {
        if (_buffer != null)
        {
            _buffer.Release();
            _buffer = null;
        }
    }
}

This method is far more scalable for large arrays, and each renderer gets its own independent buffer instance—exactly the behavior you'd want from combining [PerRendererData] with a float array.


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:03:29