Shaders not working in Graphics.Blit when using my own RenderTexture

Hey Guys,

I am currently working on a system that allows users to edit and paint on to multiple custom built texture layers that will then be blended together to a render texture and applied to a material. The current issue that I am having is a problem with the Graphics.Blit() function.

When I pass in my source texture and my own RenderTexture and include a material containing a shader (any shader, even “Diffuse”) my output is black as if nothing was copied to the RenderTexture.

Graphics.Blit(src, dest, ms_TextureBlendMaterial); //<-- output is black.

If I use the same parameters but set the destination RenderTexture to null, then everything works and the output is displayed to the screen RECT.

Graphics.Blit(src, null, ms_TextureBlendMaterial); //<-- correct output but is of course rendered to the screen Rect.

If I use my own RenderTexture but remove the material parameter so that I am simply copying my source texture to the RenderTexture that also works.

Graphics.Blit(src, dest); //<-- works

I looked at compositor effects as a reference as they basically achieve what I am trying to do. I have seen that many examples first link the RenderTexture to a camera and then call Blit() within the OnRenderImage() call. Must the RenderTexture be linked to a camera when attemping to pass a shader through the blit function? I’m sure I am making some stupid little mistake or missing some concept here but any information would be appreciated.

This is a snippet of my TextureModification class:

public class TextureManipulation
{
    static bool ms_bLoaded = false;
    static Material ms_TextureBlendMaterial;

    static void Init()
    {
        if (ms_bLoaded)
            return;

        ms_TextureBlendMaterial = new Material(Shader.Find("LayerBlend"));
        ms_bLoaded = true;
    }

    //This gets called every frame 
    public static void BlendTextures(Texture src, Texture blendTex, ref RenderTexture dest)
    {
        Init();
        ms_TextureBlendMaterial.SetTexture("_BlendTex", blendTex);
        Graphics.Blit(src, dest, ms_TextureBlendMaterial);
        RenderTexture.active = null;
    }

    ...
}

Cheers.

I’m fighting the same problem, seems to have been around for some time (http://answers.unity3d.com/questions/35482/graphicsblit-using-a-material-does-not-work.html).

I’m trying to understand why it seems to work in several ImageEffects (like Grayscaleeffect). One difference is probably that most image effects render directly to screen or render to a GL generated quad, but still it would be nice to understand why Graphics.blit do not work when the target is a RenderTexture.

Update (solved): Now looking at the shader used in Grayscaleeffect I can see that it is a fragment shader, not a surface shader. I have tried not to get into CG-programming in my current project, but it seems that all the shaders now use CGPROGRAM, and the Grayscaleeffect is only a few lines of code. I managed to edit the shader to perform exactly what I was trying to do.
Now using a material with my newly created /modified fragment shader, the Graphics.Blit(src,dst,mm) works perfectly !

So there seems to be a requirement that the shader used in Graphics.Blit() has to be a fragment shader. (need to read more about this now that it seems to work), would have been nice to have a comment on that on the documentation pages :wink:

Thank you. That was the exact same issue that was happening to me. I was using a CGPROGRAM but it was using a surface shader. Once I modified it to use a fragment shader instead, the output to my custom RenderTexture was valid.

I was very much hoping that my issue was some silly little thing like this rather than having to re-think my entire approach. I do agree, having this minor detail included in the documentation for Graphics.Blit() would have been be nice.

Cheers

Thanks very much, guys. The hint with the Greyscale Effect helped me fix my problem, which was very similar to 0xDEADCODE’s. My blit with my custom material/shader returned black. My shader was already a fragment shader, but I forgot one more thing:

ZTest Always Cull Off ZWrite Off
Fog { Mode off }

Adding these lines (within Pass{}) made mine work (mostly because of the ZTest Always; I guess the ZTest just failed for every pixel earlier). Hope I can help some other people with the same issue.

2 Likes

Thank you! Thank you! Thank you! Now, my homework for tonight is figure out what these lines of code mean… and why this would have fixed anything.
I was having a problem where my shader (already a fragment shader) worked in the first scene but would not work in a subsequent scene that used the same shader. My shader didn’t even return black it just returned something like a blur even though it was a pixelate shader.

this issue is mainly caused by dds format textures, make sure to find and replace them with jpeg or any other supported formats on IOS.