Search Unity

Creating a texture in a shader?

Discussion in 'Shaders' started by zoran404, Feb 8, 2016.

  1. zoran404

    zoran404

    Joined:
    Jan 11, 2015
    Posts:
    520
    I want to have 2 Passes.

    The first Pass that will render to a secondary image and another Pass to render the final outcome.

    How would I create this secondary texture for my shader? Do I use a render texture? How?

    And how would I get the fragment shader of the first pass to render to this secondary texture instead of to the frame buffer?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    http://docs.unity3d.com/ScriptReference/Graphics.Blit.html
    Supply a texture, a render texture, and your material.

    The first texture is inconsequential, could be something random from your project, or the default white texture from the game. The main thing to be wary of is this texture will be passed to the material as _MainTex.
    http://docs.unity3d.com/ScriptReference/Texture2D-whiteTexture.html

    The render texture you create to your wanted specifications.
    http://docs.unity3d.com/ScriptReference/RenderTexture-ctor.html

    Call blit every time you want to update the texture. You can use something like OnWillRenderObject to update it every frame the object that uses it is in view.
    http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnWillRenderObject.html
     
  3. zoran404

    zoran404

    Joined:
    Jan 11, 2015
    Posts:
    520
    I've tried this simple code, but regardles of whatever I do with the shader nothing happens..
    [I have a Raw Image using that render texture, along with sprite-default material]

    Code (csharp):
    1.    public RenderTexture renderTexture;
    2.    public Material material;
    3.  
    4.    void OnWillRenderObject()
    5.    {
    6.      Graphics.Blit(Texture2D.whiteTexture, renderTexture, material);
    7.    }
    I've plan to use this shader to get the screen contents (GrabPass) and blur it out before writing it to the render texture which would be of low resolution.

    The blur shader I have now doesn't blur enough, it has 12 calls to tex2D, and repeating the pass multiple times would be terrible for performance (I'm targeting mobile, it's pretty fast on desktops). So I though I'd speed things up by previously shrinking the screen and bluring that lower resolution image instead to get it workin faster and better.

    Any ideas how I would do this?
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Your example code never actually generates a render texture, you're basically passing an null value for the render texture to Blit which is going to either do nothing or try to render to the screen. You need to actually do:
    renderTexture = RenderTexture(512, 512, 0);
    or
    renderTexture = RenderTexture.GetTemporary(512, 512);
    // ... your code
    RenderTexture.ReleaseTemporary(renderTexture);


    However for your specific case Unity has some example code that does almost exactly what you want (and a little more) using command buffers.

    http://blogs.unity3d.com/2015/02/06/extending-unity-5-rendering-pipeline-command-buffers/
     
    Last edited: Feb 9, 2016
  5. ArminJohansson

    ArminJohansson

    Joined:
    Jan 8, 2019
    Posts:
    14
    Why do you have to create a render texture instead of reference a render texture with the public variable?
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    If it’s a render texture that already exists, then sure, just reference it. The context of this question was about rendering to a new render texture, which requires creating one first.
     
  7. ArminJohansson

    ArminJohansson

    Joined:
    Jan 8, 2019
    Posts:
    14
    But OPs example code declares a public variable render texture. I'm guessing a render texture is assigned via the inspector, referencing a file in the project.
    Is that enough for the render texture to be usable in the Blit function, and if not, why?
    Sorry for the noob question, I'm not a coder and graphics code is quite confusing!
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    You’re right. I probably missed that when originally responding to this. So that aspect of my original response isn’t right.

    The real issue was they wanted to use a grab pass to get the contents of the screen and render that into a new render texture. Calling
    Graphics.Blit()
    during
    OnWillRenderObject()
    means it's doing that before anything has even been rendered to the screen, so the grab pass was getting a copy of the currently blank render target and trying to blur that.

    The real issue is you can't change what the available render targets are via a shader, and if you want to get a copy of the screen contents you need to run the shader at the appropriate time, after the things you want to see and make a copy of have already been rendered. Command buffers help solve this by giving more granularity over the control of when things are happening, so you can wait until the scene has finished rendering all opaques, or all transparent surfaces and then make a copy then, and change the render target to another render texture to render the blurred version to. One of the Command Buffer example projects I linked to was of blurring the screen contents and saving it to a new texture for use later. Exactly what the OP was trying to do. So hopefully they found the answer they needed even if the first part of my response wasn't correct.
     
    ArminJohansson likes this.