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 ?
2 Answers
2
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/
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._
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...
– sudoku1v2