Daniel Lip
Daniel Lip

Reputation: 11317

How can I switch between shaders in real time?

The problem is that I have two shaders. If I change between the shaders while the game is running it will not take effect. Only if I start the game with a current shader it will use the shader but not the one I switch to.

I saw this code but it's switching materials and I want to switch shaders. I mean to switch between shaders on the same GameObject. I'm not sure what array of materials should be in this code ?

var materials : Material[];
var count = 0;

function OnMouseDown() {
    if (count == materials.Length - 1)
        count = 0;
    else
        count++;

    renderer.material = materials[count];
}

Upvotes: 1

Views: 9934

Answers (2)

user585968
user585968

Reputation:

Short Answer

Don't do it. Assigning changing the material's shader property via the gameobject's renderer causes multiple instances of the material to be created which not only is computationally expensive, but expensive-wise in terms of memory on the GPU.

Thomas of Unity Tutorials says it best:

The first thing that will most likely jump into your mind is the following:

GetComponent<Renderer>().material.color = ...

Easy, right? Just grab that color and animate away. The problem with this is that in order to change the color in the shader, Unity needs to tell the GPU that this object is going to be rendered differently, and the only way it can do so is by changing the material instance. Because of this, Unity creates a copy of a material when you access renderer.material for the first time.

This means that there are potentially a lot of material copies out there, all eating memory 1

A scene of 2500 spheres all sharing the same material. The other 39 materials are for other items in the scene. 1

enter image description here 1

After fiddling with GameObject.renderer.material.shader on 2500 objects. Notice how materials has jumped from 40 to 2540 materials!

enter image description here 1

Long Answer

First a refresher. In Unity you create (or buy from the Asset Store) the shader and then create a material. The material then refers to the shader supplying whatever parameters the shader may require such as textures; bumpmaps; and scalars that will differentiate this material from any other material that may be using the same shader. Once complete, you then apply the material to an object.

I mean to switch between shaders on the same GameObject

So it doesn't really make sense to want to switch shaders. Not only is it not correct that an object talks to a shader directly, but it would not have sufficient details for the shader for it to do so.

What you want to do is switch materials on an object instead.

If I change between the shaders while the game is running it will not take effect

Without seeing your code, it's hard to say. Anyway, you its arguably best to define all your assets ahead of time rather than creating dynamically. This way you can bake it for a known fidelity or platform without the code having to make decisions over which shader level it should be using.

Work-around

If you must alter materials at runtime you might want to consider Unity's MaterialPropertyBlock.

MaterialPropertyBlock is used by Graphics.DrawMesh and Renderer.SetPropertyBlock. Use it in situations where you want to draw multiple objects with the same material, but slightly different properties. For example, if you want to slightly change the color of each mesh drawn. Changing the render state is not supported More...

Unfortunately though you will now need to add PerRendererData to your shaders as explained by Thomas in his article below.

It's alot of complexity for such a simple thing. Much better to just have pre-designed materials ahead of time. It's arguably a better practice.

Tell me more

  1. The excellent article THE MAGIC OF MATERIAL PROPERTY BLOCKS

  2. "Change the color of a material for only one object", Answers, Unity

Upvotes: 6

MGDroid
MGDroid

Reputation: 1659

You can set the shader with GameObject.renderer.material.shader. API has example of exactly this thing. Check out documentation.

Upvotes: 1

Related Questions