How to manage properties in shader for multiple objects?
Asked Answered
C

2

0

Hello
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 ?

Curtice answered 30/8, 2023 at 10:45 Comment(0)
R
0

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 https://www.upsers.win/

Retail answered 28/10, 2020 at 13:55 Comment(0)
C
0

Thanks for your answer.

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

 Shader "Unlit/JMNUnlitShader"
 {
     Properties
     {
            _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._

Curtice answered 28/10, 2020 at 21:31 Comment(1)

To declare a shader parameter as GLOBAL, you need to remove it from the properties. Then, delare it in the shader as : uniform float _speed. Then in the script; you can access it using: Shader.SetGlobalFloat("_speed", 1.0f); Done...

Curtice

© 2022 - 2024 — McMap. All rights reserved.