- Home /
How to set a texture in an image effect material?
I'm trying to set the texture via code on a material used in a post-process image effect. I'm calling SetTexture() on a reference to the material, but it's not having any effect.
In this example, myMaterial has a shader that has a texture property. Just for this test, the shader simply overwrites the output with whatever color is in the texture.
[ExecuteInEditMode]
public class MyImageEffect : MonoBehaviour
{
public Material myMat;
public Texture myTexture;
void Start()
{
myMat.SetTexture(0, myTexture);
}
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
Graphics.Blit(source, destination, myMat);
}
}
This all works fine if I drag a texture into the material's texture property before running. However, if I try to assign the texture at runtime, it does not work.
For non-image-effect materials, you can change the texture on a material by grabbing the material from an object's renderer:
void Start ()
{
thisRenderer = GetComponent<MeshRenderer>();
thisRenderer.sharedMaterial.SetTexture(0, myTex);
}
In the case of a material used in a image effect, there is no renderer to grab the material off, so I' not sure if I'm accessing it the correct way.
Any help would be appreciated.
Answer by helarts · Dec 09, 2015 at 11:46 PM
However, if I try to assign the texture at runtime, it does not work.
Maybe because you set the texture only once at Start(), try to do it before the Blit like so:
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
myMat.SetTexture(0, myTexture);
Graphics.Blit(source, destination, myMat);
}
Also are you sure your texture ID is 0 ? I would use the property string directly if I have troubles, guessing the sampler2D is called "_MainTex" in the shader:
myMat.SetTexture("_MainTex", myTexture);
If you really want to use an int (which is faster for repetitive calls) check Shader.PropertyToID, it should be much safer than hardcoded ID.
Edit: in Edit mode you might have to manually refresh the game view to see changes, this redraws all views:
UnityEditorInternal.InternalEditorUtility.RepaintAllViews()
Thanks for the suggestions @helarts , that really helped clear things up for me. I mistakenly thought that texture IDs were in order of declaration in the shader starting from zero. I see now that is not the case. So setting the texture by name does work. And retrieving the actual id with Shader.PropertyToID then using that id also does work.
You only need to set the texture once in the Start(), not every frame.
I appreciate you taking the time to reply.
Sure, like you figured out shader property IDs are global, not per shader. You are right, setting the texture once is enough if you don't want to change it at runtime (I though it was something you wanted to do). I am glad you got it working the way you want.
In my case, I am updating the texture every frame, but I have only set it once in the Start(). It is a RenderTexture that a camera draws into, then I use it in an image effect. The image is updating correctly each frame.