Search Unity

How to colour individual pixels in fragment shader?

Discussion in 'Shaders' started by AlduousMcBurlington, May 29, 2017.

  1. AlduousMcBurlington

    AlduousMcBurlington

    Joined:
    May 23, 2017
    Posts:
    4
    Hello there, I'm having a bit of an issue with drawing to the screen. So far I'm drawing a procedural mesh with one point in my main thread to activate the shader, grabbing it in the vertex shader and passing it to my fragment shader where I have a loop to do my main work.

    Can anyone explain whether or not you can write to the screen with this method in HLSL, and how I might go about doing it? Right now it doesn't colour any pixels regardless of screen space, and it doesn't appear as though it gets called at all; I've been under the impression that fragment shaders loop through all pixels on the screen, and not just the ones that are coloured, but the examples I find from Unity and elsewhere seem to rely on preexisting points and geometries.

    I would have thought that the following HLSL would colour the entire screen red, considering it's mentioned everywhere that fragment shaders are called once per pixel on the screen, and I'm calling the shader with a single point by drawing a procedural mesh with one point.

    Thanks in advance!

    Code (CSharp):
    1.  
    2.                 struct Vert
    3.                 {
    4.                         float4 pos : SV_POSITION;
    5.                         float4 colour : COLOR;
    6.                 };
    7.  
    8.                 Vert VertFunction()
    9.                 {
    10.                     Vert vert;
    11.  
    12.                     vert.pos = float4(0,0,0,0);
    13.                     vert.colour = float4(0,0,0,0);
    14.  
    15.                     return vert;
    16.                 }
    17.  
    18.                 float4 FragFunction(float4 sp : SV_POSITION) : SV_TARGET
    19.                 {
    20.                         return float4(1,0,0,1); //red colour
    21.                 }
     
    Last edited: May 29, 2017
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    The fragment shader only runs on pixels that each rastorized triangle touches (in 2x2 blocks). If you want it to run on every pixel on the screen, you need a mesh that covers the entire screen. If you don't have a mesh, or the mesh is off screen, or is behind other objects that have already been rendered (and which wrote to the zbuffer) the GPU will completely skip even attempting to run the fragment shader.

    Your example of setting the SV_POSITION to all zeros means the fragment is guaranteed to be culled, and thus never run.
     
    AlduousMcBurlington likes this.
  3. AlduousMcBurlington

    AlduousMcBurlington

    Joined:
    May 23, 2017
    Posts:
    4
    So I'm guessing drawing a fullscreen quad from the geometry shader would do the trick?
    Do you think you could give a simple example of that with screen coords for that for me? I'm kinda new to HLSL and I'm a little confused how it would reference the screen from a 2x2 paradigm.

    Thanks either way!
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    You could use a geometry shader, but why? You're better off just constructing a simple mesh on the CPU side, or using the built in quad mesh, or use the built in blit function which does all of the work for you.

    There's some simple shaders that you can use to ensure full screen rendering with the built in quad mesh, the main magic being:

    o.pos = float4(v.vertex.xy * 2, 0, 1);

    And don't worry about the "2x2" part, that's a low level detail of how GPU hardware works, and not something you need think about right now.
     
    AlduousMcBurlington likes this.
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
  6. AlduousMcBurlington

    AlduousMcBurlington

    Joined:
    May 23, 2017
    Posts:
    4
    Thank you very much bgolus! I see you everywhere and it seems you help a lot.

    I'll keep this post updated when I find a solution in the form of a script!
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    There are a ton of posts on "how to draw a full screen quad in Unity" you should search for if you need help. Many ways to do this depending on what you're going for, and doing this as an image effect might be a valid option.
     
    AlduousMcBurlington likes this.