Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Render to texture without a camera?

Discussion in 'Shaders' started by Deleted User, Mar 19, 2014.

  1. Deleted User

    Deleted User

    Guest

    Is there a method to use a shader to render into a rendertexture without using a camera?

    An example being I'm using a webcamtexture bringing in the feed from my webcam (not displaying it on screen yet). I want to pass the current frame from the webcam and the previous frame through a shader that would combine them in an interesting way into a new texture that I could then use.

    I might be looking at it wrong, but that doesn't seem to be what the Camera.renderWithShader feature is for.
     
  2. WhiskyJoe

    WhiskyJoe

    Joined:
    Aug 21, 2012
    Posts:
    143
    I'm not sure if there is a limitation to this when not using pro, but you probably want to take a look at Graphics.Blit().
     
  3. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    A camera is necessary to render anything. A camera contains things like the projection matrix, interaction with the modelview matrix, which includes translation of coordinate systems from the game world into the window space. It also deals with some other stuff. Unity has basically tied a camera to the backbuffer in the sense that you have to have at least one camera in the scene to render anything. So even if you are doing stuff in the background that's not visible, if you want it to go to a rendertexture you either have to upload to the texture with the cpu over the graphics bus ie SetPixels(), or you need to use a camera to `view` the texture so that its fragments can be processed and thus render something. Even graphics.blit will need a camera to be able to know where to blit to. I would think?
     
  4. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    I think you can do this using Graphics.SetRenderTarget() followed by Graphics.DrawTexture() or Graphics.Blit(). Blit() is probably simplest.
     
    Carterryan1990 likes this.
  5. WhiskyJoe

    WhiskyJoe

    Joined:
    Aug 21, 2012
    Posts:
    143
    @imaginaryhuman, he mentioned he is getting the texture feed from his webcam :) Also, according to the Unity script reference, you can use Graphics.Blit() without the use of a camera. Personally only used it for the sake of image effects, so he should probably just have to try it out to see if it works.
     
  6. Deleted User

    Deleted User

    Guest

    Thanks guys. I'll have to check that out and see how it works!
     
  7. Deleted User

    Deleted User

    Guest

    Looks like Graphics.Blit was the answer, thanks all! I was able to bring in a frame from the webcam and do some processing on it and output that to a rendertexture.

    I'd +1 you all if there was such an option :p
     
  8. DaveHoskins

    DaveHoskins

    Joined:
    Sep 9, 2013
    Posts:
    190
    Is it possible to create a camera that only sees the Blit? So it's in the scene but it doesn't show the scene, as I want to completely wipe over what it's looking at with the Blit.
    Thanks,
    Dave.
     
  9. WhiskyJoe

    WhiskyJoe

    Joined:
    Aug 21, 2012
    Posts:
    143
    DaveHoskins, I think what you want is to only render some specific stuff to a texture and use that for something in regards to the actual scene? If that is the case, you should assign Layers to the objects you (don't) want to show and create another camera that does so by setting the Culling Mask option. Look it up or play around to see how it works.
     
  10. SantosR

    SantosR

    Joined:
    Dec 18, 2013
    Posts:
    27
    If anyone else is having trouble using Graphics.Blit(), it must be called from within OnPostRender() !
     
  11. DaveHoskins

    DaveHoskins

    Joined:
    Sep 9, 2013
    Posts:
    190
    Thanks Rld_, and thanks SantosR!
    Only from a OnPostRender? It only works with a camera as has been said, I guess.
    It's not as flexible as I'd hoped, all I wanted was to render a shader to a texture.
     
  12. WhiskyJoe

    WhiskyJoe

    Joined:
    Aug 21, 2012
    Posts:
    143
    I can't test this at the moment, but what you are saying SantosR is not true. Next to the fact that Unity states differently in their own examples, I use it for Image Effects in OnRenderImage().

    Just try it out DaveHoskins.
     
  13. DaveHoskins

    DaveHoskins

    Joined:
    Sep 9, 2013
    Posts:
    190
    Yes I have it working in 'OnRenderImage(RenderTexture src, RenderTexture dest),' which only gets called if I attach a camera to the object.
    I set Clear Flags to 'Don't Clear' and the Culling Mask to 'Nothing' so I'm not wasting time rendering the scene.
    Can I safely ignore the 'src' and 'dest' and update my own RenderTexures? I've already seen that 'src' can be null, which is great news.
     
  14. SantosR

    SantosR

    Joined:
    Dec 18, 2013
    Posts:
    27
    I'm new to shaders and rendering pipeline, so I might have done something wrong. However in my case having the Blit() called on a OnClick() or Update() didn't work at all. (no visible changes)

    Maybe it is shader dependent?
     
  15. WhiskyJoe

    WhiskyJoe

    Joined:
    Aug 21, 2012
    Posts:
    143
    I just had time to try it out.

    It seems that although you aren't prohibited to use it where you want, you will only be able to use it to blit between textures if you aren't using a shader/material. So yeah, in that case you will need to use it with a camera.

    @DaveHoskins, the src and dest parameters passed are holding/will hold the information you need for image effects. If you don't want to use them, you don't have to, but the Blit() functions expects certain values which you likely can't deny.

    What is it exactly you are trying to achieve?
     
  16. DaveHoskins

    DaveHoskins

    Joined:
    Sep 9, 2013
    Posts:
    190
    Hi Rld_, I'm using the GPU for procedural data acquisition. Basically making landscape height maps on the GPU and sending that data to the CPU.
    The first frame has to make the entire local area so it would be nice to repeatedly call Blit/Read on all the landscape patches before starting. What I currently have working is a Queue of patches that need updating, and they are taken one at a time off the Queue in OnRenderImage, render them with a Blit, then grab them at the next patch rendering time. That bit works fine, so far.
     
  17. WhiskyJoe

    WhiskyJoe

    Joined:
    Aug 21, 2012
    Posts:
    143
  18. DaveHoskins

    DaveHoskins

    Joined:
    Sep 9, 2013
    Posts:
    190
    I don't quite understand, that thread you linked seems to be about sending data to another shader, not the CPU.
    Anyway I have it all working now, and I can do multiple Blits in the code and grab the whole landscape in one go at the beginning.

    I did find what appears to be a Unity bug though, the first time Camera.targetTexture gets set was in OnRenderImage, and it got completely ignored for that particular call. Which may be a problem in the future if I want to set different targets at different times. Can I not set this in OnRenderImage?
    Thanks,
    Dave.
     
  19. drudiverse

    drudiverse

    Joined:
    May 16, 2013
    Posts:
    218
    In the unity DX11 examples, there is a code example that passes data from the GPU to the CPU in a direct compute code.
     
  20. DaveHoskins

    DaveHoskins

    Joined:
    Sep 9, 2013
    Posts:
    190
    Thanks, I wanted Mac OSX OpenGL and AMD support as well, so it has to be some form of ReadPixels.
     
  21. WhiskyJoe

    WhiskyJoe

    Joined:
    Aug 21, 2012
    Posts:
    143
    The link I provided uses a renderTexture to store results so it could be used again in another shader, so in that case, you would have a texture that you can use. I always thought you can't use it that way, but apparently you can.

    As for the problem you are having, I am not 100% sure as I don't know what's going on under the hood, but it could be that the current rendertarget is being written to or read from and you can't do both at the same time in most cases.
     
  22. Carterryan1990

    Carterryan1990

    Joined:
    Dec 29, 2016
    Posts:
    79
    Hi David, this method does seem to work but once a camera is added to the scene it no longer works unless the script is on the camera object. But if its on the camera object and the camera moves from its position of 0.5,0.5,-0.5, the output gets distorted and shows weird angles and cropped sections.
     
  23. Przemyslaw_Zaworski

    Przemyslaw_Zaworski

    Joined:
    Jun 9, 2017
    Posts:
    314
    Code (CSharp):
    1.     void Blit(RenderTexture destination, Material mat)
    2.     {
    3.         RenderTexture.active = destination;
    4.         GL.PushMatrix();
    5.         GL.LoadOrtho();
    6.         GL.invertCulling = true;
    7.         mat.SetPass(0);
    8.         GL.Begin(GL.QUADS);
    9.         GL.MultiTexCoord2(0, 0.0f, 0.0f);
    10.         GL.Vertex3(0.0f, 0.0f, 0.0f);
    11.         GL.MultiTexCoord2(0, 1.0f, 0.0f);
    12.         GL.Vertex3(1.0f, 0.0f, 0.0f);
    13.         GL.MultiTexCoord2(0, 1.0f, 1.0f);
    14.         GL.Vertex3(1.0f, 1.0f, 0.0f);
    15.         GL.MultiTexCoord2(0, 0.0f, 1.0f);
    16.         GL.Vertex3(0.0f, 1.0f, 0.0f);
    17.         GL.End();
    18.         GL.invertCulling = false;
    19.         GL.PopMatrix();  
    20.     }
     
  24. Carterryan1990

    Carterryan1990

    Joined:
    Dec 29, 2016
    Posts:
    79
    Just tried this while using unity 2019.1 with the hd srp and it doesnt seem to be working.
     
  25. Przemyslaw_Zaworski

    Przemyslaw_Zaworski

    Joined:
    Jun 9, 2017
    Posts:
    314
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class render : MonoBehaviour
    6. {
    7.     public Material material;
    8.     public RenderTexture rt;
    9.     public int Pass = 0;
    10.    
    11.     void Blit(RenderTexture destination, Material mat, int pass)
    12.     {
    13.         RenderTexture.active = destination;
    14.         GL.PushMatrix();
    15.         GL.LoadOrtho();
    16.         GL.invertCulling = true;
    17.         mat.SetPass(pass);
    18.         GL.Begin(GL.QUADS);
    19.         GL.MultiTexCoord2(0, 0.0f, 0.0f);
    20.         GL.Vertex3(0.0f, 0.0f, 0.0f);
    21.         GL.MultiTexCoord2(0, 1.0f, 0.0f);
    22.         GL.Vertex3(1.0f, 0.0f, 0.0f);
    23.         GL.MultiTexCoord2(0, 1.0f, 1.0f);
    24.         GL.Vertex3(1.0f, 1.0f, 0.0f);
    25.         GL.MultiTexCoord2(0, 0.0f, 1.0f);
    26.         GL.Vertex3(0.0f, 1.0f, 0.0f);
    27.         GL.End();
    28.         GL.invertCulling = false;
    29.         GL.PopMatrix();  
    30.     }
    31.    
    32.     void Start()
    33.     {
    34.         Pass = material.passCount - 1;
    35.     }
    36.  
    37.     void Update()
    38.     {
    39.         Blit(rt, material,Pass);
    40.     }
    41. }
    42.  
    Tested with HDRP and LWRP in Unity 2018.3.11. Works with custom shaders and built-in unlit. Not work with HDRenderPipeline/Lit etc.
     
  26. Carterryan1990

    Carterryan1990

    Joined:
    Dec 29, 2016
    Posts:
    79
    Ok well Im using shader graphs unlit material node. Maybe this is not compatible with shader graph.
     
  27. BionicWombatGames

    BionicWombatGames

    Joined:
    Oct 5, 2020
    Posts:
    33