Search Unity

Resolved Actual Shader doesn't match Graphics.Blit() - Custom 2D Outline Shader

Discussion in 'Shaders' started by Gmanicus, Jan 5, 2021.

  1. Gmanicus

    Gmanicus

    Joined:
    Dec 14, 2020
    Posts:
    6
    Hey there,

    I'm having some trouble getting a 2D outline shader working. I tried using a prebuilt one, but it only worked with _MainTex. I need my outline shader to take other shader effects into account.

    So, I'm attempting to add an outline to a planet. This planet has a base sprite which is then altered via a shader to add landmass, water, etc. I need the outline to match the new planet shape.

    I have this working, except the texture the outline is getting is not the same as the one actually applied to the sprite. This causes the outline to dramatically stray from the actual edge of the texture.

    Here are the results I'm getting:


    Code (CSharp):
    1. Material shaderMat = GetComponent<SpriteRenderer>().material;
    2. Texture2D tex = GetComponent<SpriteRenderer>().sprite.texture;
    3. RenderTexture output = new RenderTexture(tex.width, tex.height, 16, RenderTextureFormat.ARGB32);
    4. // Renders the result of the shader material to the render texture (output)
    5. // We can then make (output) the starting texture of the outline shader
    6. Graphics.Blit(tex, output, shaderMat);
    7. // (outline) is currently a Material set in the inspector
    8. outline.SetTexture("_TextureToOutline", output);
    Clearly, it's almost working. The only apparent issue is that the UV position of the gradient noise I'm using to generate the landmasses is not matching with the actual result.

    This is it in the planet shader:


    As you can see, I attempted to fix this issue already. I did this by setting UVStartPos to the planet position when generating the texture. However, that didn't fix it. Maybe I misunderstand how the Position node works, but my thought process was that maybe Graphics.Blit() didn't include the object position in the position node, since it wasn't applied "naturally" like a material on a SpriteRenderer, so it was defaulting to something like [0,0] (which, actually, also does not appear to be the case). (P.S: Transition is currently set to [0,0])

    So, any clues on how to fix this UV mismatch between the actual shader result and the Graphics.Blit() result would be greatly appreciated!
     
    Last edited: Jan 5, 2021
  2. AlexTorbin

    AlexTorbin

    Joined:
    Dec 12, 2019
    Posts:
    48
    I guess you misunderstand how Blit() works. What object's position you expect from it to include? After all, we do not pass any object as a parameter. What if specified mat is applied to multiple objects? In fact, as stated in the manual:
    This procedural quad is what your shader is rendering. So you probably have to pass original object position with Material.SetVector() or CommandBuffer.SetGlobalVector() or something else.

    PS: I don't know about Shader Grapth, never used it, but I think that Position node is not an object position, but a vertex position in object space.
     
  3. Gmanicus

    Gmanicus

    Joined:
    Dec 14, 2020
    Posts:
    6
    I did not say I expected that behavior from Blit(). I was stating that maybe the issue was because the position wasn't included in the Blit() process, or maybe it was due to my misunderstanding of how the Position node worked, or maybe I have it all wrong and it is included in the Blit() process because it is using some sort of render position, rather than a world position, for instance. I don't quite know the inner workings of the render process, so I'm stuck to second-guessing sometimes.

    That's what I did with UVStartPos.

    That may be a vital clue. I'll do some research regarding this and see if I find a solution.
     
  4. Gmanicus

    Gmanicus

    Joined:
    Dec 14, 2020
    Posts:
    6
    Aha! I have found something at least. I tested what would happen if I removed the input into the UV parameter of the gradient noise node and BINGO! We have a match. It was the same result as what the Graphics.Blit() produces.

    I just need to know what the Position node outputs by default (I would have expected this to be [0,0], but no, I guess not). Offsetting the UVStartPos by that default value should give me my expected result!

    EDIT: Clearly I have zero idea how the position node works, as I am unable to even get the noise to generate properly by offsetting the UVStartPos without the Position node connected. Being able to see the values of what different nodes output would be helpful in cases like this...
     
    Last edited: Jan 5, 2021
  5. AlexTorbin

    AlexTorbin

    Joined:
    Dec 12, 2019
    Posts:
    48
  6. Gmanicus

    Gmanicus

    Joined:
    Dec 14, 2020
    Posts:
    6
    Yes, but read this:
    Maybe you understand that, but I don't. Are mesh vertexes in world space? What would the values be in Object space? What's a fragment? How do I find these positions outside of shadergraph? How do I recreate these values???

    These are all questions I could not answer. This is just about my third week with any experience in shaders, and all of that has been through Shader Graph only. Just so you are aware, I had attempted to fix this issue for a good part of my day before coming here. This was my last resort after hours of testing, attempting my own fixes, and research.

    Regardless, thanks for the help. Your suggestion regarding the Position node led me to mess with the UV input of the gradient noise. Turns out, I didn't even need the position node. The pos node was the problem, as Blit() couldn't generate the UV through it. I replaced it with a UV node and added my positions on top of the output of that UV node. That got me the results I needed!



    The shader isn't working quite as it should be (Width changes, it gets wavy, and it is alpha'd in some areas), but the outline is in the correct shape now!! Fixing the shader should be a lot more simple.

    EDIT: Just so others can visibily see the change I made in shader graph...
     
    Last edited: Jan 5, 2021