Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Need Simple Example how to Use MaterialPropertyBlock.SetFloatArray in ECS

Discussion in 'Entity Component System' started by RoughSpaghetti3211, Mar 28, 2020.

  1. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,695
    OK Been trying to get this working for hours and hours. Please if any one can post a simple example how to use MaterialPropertyBlock.SetFloatArray in a system I would be grateful.
     
  2. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Two quirks that usually get people with this.

    1. For arrays you need to append _Array to the name
    2. The first time you set the array that's the size it has, it won't grow. When you create the property block call SetFloatArray with an empty array of the max size you will need.
     
  3. bhavyanshmishra

    bhavyanshmishra

    Joined:
    Dec 12, 2019
    Posts:
    7
    I am facing the same problem. I have literally tried every single permutation and combination I could think of with SetFloatArray. I really need a good basic example on how to get simply a float array to a shader from C#. This is urgent. I have attached both my C# script and the HLSL shader to this post.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. using map_sense = RosSharp.RosBridgeClient.MessageTypes.MapSense;
    6. using sensor = RosSharp.RosBridgeClient.MessageTypes.Sensor;
    7. using RosSharp.RosBridgeClient;
    8.  
    9. [RequireComponent(typeof(RosConnector))]
    10. public class PlanarRegionSubscriber : MonoBehaviour
    11. {
    12.     private RosConnector rosConnector;
    13.     private Texture2D dtex;
    14.     //private GameObject pointMap;
    15.     public MeshRenderer renderer;
    16.  
    17.     private float[] paramData;
    18.     public ComputeBuffer cb_params;
    19.     private MaterialPropertyBlock matBlock;
    20.  
    21.  
    22.     void Start()
    23.     {
    24.         rosConnector = GetComponent<RosConnector>();
    25.         string subscription_id = rosConnector.RosSocket.Subscribe<map_sense.PlanarRegions>("/map/regions", RegionMsgHandler);
    26.         matBlock = new MaterialPropertyBlock();
    27.         paramData = new float[192];
    28.         renderer = GameObject.FindWithTag("QuadMap").GetComponent<MeshRenderer>();
    29.  
    30.     }
    31.  
    32.     private void RegionMsgHandler(map_sense.PlanarRegions message)
    33.     {
    34.         Debug.Log(message.data.Length);
    35.         for(int i = 0; i<192; i++){
    36.             paramData[i] = (float)i;
    37.         }
    38.  
    39.         renderer.material.SetFloatArray("_Params", paramData);
    40.  
    41.  
    42.     }
    43.  
    44. }
    45.  
    Code (CSharp):
    1. //Enable option "Keep quads" in model import settings.
    2. //source: https://forum.unity3d.com/threads/my-own-terrane-shader-is-not-working.283406/
    3. Shader "Custom/QuadTessellationHLSL"
    4. {
    5.     SubShader
    6.     {
    7.         Pass
    8.         {
    9.             Cull Off
    10.             CGPROGRAM
    11.             #pragma vertex TessellationVertexProgram
    12.             #pragma hull HullProgram
    13.             #pragma domain DomainProgram
    14.             #pragma fragment FragmentProgram
    15.             #pragma target 4.6
    16. // ----------------------------------------------------------------
    17.  
    18.             struct appdata {
    19.                 float4 vertex : POSITION;
    20.                 float2 uv : TEXCOORD0;
    21.             };
    22.             struct ControlPoint
    23.             {
    24.                 float4 vertex : INTERNALTESSPOS;
    25.                 float2 uv : TEXCOORD0;
    26.             };
    27.             struct hsConstOut
    28.             {
    29.                 float Edges[4] : SV_TessFactor;
    30.                 float Inside[2] : SV_InsideTessFactor;
    31.             };
    32.             struct v2f
    33.             {
    34.                 float4 vertex : SV_POSITION;
    35.                 float2 uv : TEXCOORD0;
    36.             };
    37.  
    38.             uniform float _ArrayParams[192];
    39. // ---------------------------------------------------------------
    40.  
    41.  
    42.             v2f VertexProgram(appdata v) // Not the primary vertex program.
    43.             {
    44.                 v2f o;
    45.                 o.vertex = UnityObjectToClipPos(v.vertex);
    46.                 o.uv = v.uv;
    47.                 return o;
    48.             }
    49.  
    50.             ControlPoint TessellationVertexProgram(appdata v){
    51.                 ControlPoint p;
    52.                 p.vertex = v.vertex;
    53.                 p.uv = v.uv;
    54.                 return p;          
    55.             };
    56.            
    57.             hsConstOut hull_constant_function(InputPatch<ControlPoint, 4> patch)
    58.             {
    59.                 hsConstOut output;
    60.                 output.Edges[0] = output.Edges[1] = output.Edges[2] = output.Edges[3] = output.Inside[0] = output.Inside[1] = 16;
    61.                 return output;
    62.             }
    63.                 [domain("quad")]
    64.                 [partitioning("integer")]
    65.                 [outputtopology("triangle_cw")]
    66.                 [outputcontrolpoints(4)]
    67.                 [patchconstantfunc("hull_constant_function")]          
    68.             ControlPoint HullProgram(InputPatch<ControlPoint, 4>patch, uint id: SV_OutputControlPointID)
    69.             {
    70.                 return patch[id];
    71.             }
    72.                 [domain("quad")]
    73.             v2f DomainProgram(hsConstOut factors,
    74.                                 const OutputPatch<ControlPoint, 4>patch,
    75.                                 float2 UV:SV_DomainLocation)
    76.             {
    77.                 float4 a = patch[0].vertex;
    78.                 float4 b = patch[1].vertex;
    79.                 float4 c = patch[2].vertex;
    80.                 float4 d = patch[3].vertex;
    81.  
    82.                 float4 v0 = lerp(a,b,UV.x);
    83.                 float4 v1 = lerp(d,c,UV.x);
    84.                 float4 vFinal = lerp(v0,v1,UV.y);
    85.  
    86.                 float2 uv0 = lerp(a,b,UV.x);
    87.                 float2 uv1 = lerp(d,c,UV.x);
    88.                 float2 uvFinal = lerp(uv0,uv1,UV.y);
    89.  
    90.                 float3 n0 = cross(a.xyz-b.xyz,a.xyz-d.xyz);
    91.                 float4 normal = float4(normalize(n0),1);
    92.  
    93.                 float scale = 0.00001;
    94.  
    95.                 float x = UV.x*10 - 5;
    96.                 float y = UV.y*10 - 5;
    97.  
    98.                 //float height = scale * (pow(x,3) + pow(y,3));
    99.  
    100.                 int i = int(a.x);
    101.                 int j = int(a.y);
    102.  
    103.  
    104.  
    105.                 //float height = scale * (2*pow(x,2) + 0.5*pow(y,2)) + (a.x + a.y);
    106.  
    107.  
    108.  
    109.  
    110.  
    111.  
    112.                 float height = _ArrayParams[3];
    113.  
    114.                 appdata data;
    115.                    data.vertex = vFinal + height * normal;
    116.                    data.uv = uvFinal;
    117.  
    118.                 return VertexProgram(data);
    119.             }
    120.  
    121.  
    122.             fixed4 FragmentProgram(v2f i) : SV_TARGET
    123.             {
    124.                 //float4 col = tex2D(_MainTex, i.uv);
    125.                 fixed4 col = fixed4(0.5,0.8,0.4,1.0);
    126.                 return col;
    127.             }
    128.             ENDCG
    129.         }
    130.     }
    131. }
     
  4. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,695
    Should
    renderer = GameObject.FindWithTag("QuadMap").GetComponent<MeshRenderer>();

    Be ?
    renderer = GameObject.FindWithTag("QuadMap").GetComponent<Renderer>();
     
  5. bhavyanshmishra

    bhavyanshmishra

    Joined:
    Dec 12, 2019
    Posts:
    7
    Just tried replacing the MeshRenderer with Renderer everywhere. It did not work either and based on the rest of the syntax, it looked like MeshRenderer is the more appropriate object to use here. I am missing something I know for sure. I'd really appreciate a basic example here. :(
     
  6. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Maybe you misread my post. You need to append _Array to the name you use in SetFloatArray. So if your shader variable is Params, you call SetFloatArray with Params_Array.
     
  7. SenseEater

    SenseEater

    Joined:
    Nov 28, 2014
    Posts:
    84
    Following should work for above posted code.

    Code (CSharp):
    1.     private void RegionMsgHandler(map_sense.PlanarRegions message)
    2.     {
    3.         Debug.Log(message.data.Length);
    4.         for(int i = 0; i<192; i++){
    5.             paramData[i] = (float)i;
    6.         }
    7.         matBlock.SetFloatArray("_ArrayParams",paramData);
    8.         renderer.SetMaterialPropertyBlock(matBlock);
    9.     }
    10.  
    Also you have declared float array with name _ArrayParams in your shader but passing the array in your C# script to _Params property.
     
    Last edited: Apr 16, 2020
  8. SenseEater

    SenseEater

    Joined:
    Nov 28, 2014
    Posts:
    84
    I am unware of any such requirement. https://docs.unity3d.com/ScriptReference/MaterialPropertyBlock.SetFloatArray.html

    Passing to same property name in Material block as declared in shader works just fine for me.

    This is true for the MaterialPropertyBlock buffer but also mind that the max array length would be only as defined in shader code itself. Setting MaterialPropertyBlock array size to a larger length wont expand the shader array.
     
    Last edited: Apr 16, 2020
  9. LaireonGames

    LaireonGames

    Joined:
    Nov 16, 2013
    Posts:
    696
    Pretty shocking that the documentation still doesn't show samples of how to use this. For anyone else that stumbles across this thread this is how to get arrays working with MPB:

    In c# you don't need to append _Array to the name, perhaps something they improved. So it looks something like:

    Code (CSharp):
    1. float[] currentValues = new float[]{1,2,3,4,5,6,7,8,9,0}
    2. materialProperties.SetFloatArray("Values", currentValues);
    3. meshRenderer.SetPropertyBlock(materialProperties);
    Then shader side. Variable declaration:

    Code (CSharp):
    1.              
    2. UNITY_INSTANCING_BUFFER_START(Props)
    3. UNITY_DEFINE_INSTANCED_PROP(float, Values[10])
    4. UNITY_INSTANCING_BUFFER_END(Props)
    Data access:
    Code (CSharp):
    1. UNITY_ACCESS_INSTANCED_PROP(Props, Values[0])
    As a note I was just looking for this info in general, nothing to do with ECS and with Unity version 2021.1.2
     
    georgerh likes this.
  10. KibsUnityStudios

    KibsUnityStudios

    Joined:
    Jun 27, 2023
    Posts:
    2