How to manage properties in shader for multiple objects?

I’m a bit confuse on material and shaders for multiple objects using scripts.


Let’s say that I have 2 objects (2D sprites) being the CUBE and the SPHERE. I have to instantiate CUBE and SPHERE to get multiple objects.

All objects and instances use the same shader that have 3 specific properties: _speed, _factor and _delta.

I need that :

  • when I modify _speed, all objects and instances will have this property modified.

  • when I modify _factor, object CUBE and all associated instances will have this property modified.

  • when I modify _delta, only one instance or one object will have this property modified.


So many solutions are possible: Instantiate, prefabs, MaterialPropertyBlock, same material… Difficulty is in the fact that Unity will create an instantiated material when modifying one property.


Could you please propose a possible way ?

So, here’s the scenario: Two objects (could be many more) need to be transformed/colored differently. Here are two ways I know to do this:

Single vertex and fragment shader:
Define a uniform, call it currentObj, in the VS and FS. Both VS and FS have code of the form
if (currentObj = obj1) do obj1 stuff;
if (currentObj = obj2) do obj2 stuff;
The draw routine in the main program looks like
glUniform(make currentObj = obj1);
draw obj1;
glUniform(make currentObj = obj2);
draw obj2;

Separate vertex and fragment shaders:
Make VS1 and FS1 for obj1 and attach them to pipeline1. Make VS2 and FS2 for obj2 and attach them to pipeline2

Thanks for your answer.

My preferred solution is to use the same single shader (VS+FS) for all objects.

 Shader "Unlit/JMNUnlitShader"
            _speed("Speed", Float) = 4
        	_factor("Factor", Float) = 0

Objects can be of 2 kinds, with different computations in the shader as you propose. This is managed using a parameter “_factor” that is passed to each object (and instances) shaders during initialization using :

  public Material the Material;
  void Start()
      CUBE.GetComponent<SpriteRenderer>().material = theMaterial;
      CUBE.GetComponent<SpriteRenderer>().material.SetFloat("_factor", 0.0f);
      for(i=0; i<1000;i++) {
           CUBE_instance *= Instantiate(CUBE, newPosition, Quaternion.identity);*

CUBE_instance*.GetComponent().material.SetFloat("factor", 0.0f);

SPHERE.GetComponent().material = theMaterial;
SPHERE.GetComponent().material.SetFloat(“_factor”, 1.0f);
for(i=0; i<1000;i++) {
SPHERE_instance = Instantiate(CUBE, newPosition, Quaternion.identity);
SPHERE_instance*.GetComponent().material.SetFloat("factor", 1.0f);*
CUBE and SPERE have the same material.
Then, at each frame, a second parameter “_speed” has to be passed to the shader identical for each objects and instances. I would like to use “uniform” to pass it to all objects, but I don’t know how (MaterialPropertyBlock ?). I try to use the initial material but it does not work… I understand this is because Unity creates instantiated materials for each generated objects.
void Update()
theMaterial.SetFloat(“_speed”, xxx);
How to pass the same value to all objects ? Objectif is to avoid to pass this parameter one by one to all objects and instances for performances.
Thanks for your help._