Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  2. Ever participated in one our Game Jams? Want pointers on your project? Our Evangelists will be available on Friday to give feedback. Come share your games with us!
    Dismiss Notice

Resolved Color gradient on outline : lerp between two methods

Discussion in 'Shaders' started by Quasar47, Jun 30, 2020 at 12:37 PM.

  1. Quasar47

    Quasar47

    Joined:
    Mar 24, 2017
    Posts:
    90
    Hello everyone,

    I'm making a toon shader that blends between two colors to create a gradient for an outline. So far so good, it works as intended. i've also made an option to switch to a step function to only allow two colors with a hard cut between the two :

    smooth.png

    step.png

    To do so, I get the y component of the vertex coordinate of the object, and remap it from between 0.5 and 1 to 0 and 1 for the lerp. For the step, I then just check if the y > 0.5 to get the hard cut, then I use that value to lerp between the two colors.

    In the vertex function I have simply this :

    o.gradientCoord = i.vertex;


    and in the frag function, where I calculate the color :

    Code (CSharp):
    1.  
    2.                 float xOrY = lerp(i.gradientCoord.x, i.gradientCoord.y, _VerticalGradient) * lerp(1, -1, _InvertGradient);
    3.  
    4.  
    5.                 xOrY += 1;
    6.                 xOrY = Remap(xOrY, 0.5, 1.5, 0, 1);
    7.  
    8.  
    9.                 float lerpT = xOrY;
    10.                 float stepT = 1 - step(xOrY, 0.5);
    11.                 float t = lerp(stepT, lerpT, _UseSmoothOutlineGradient);

    Now, what I want to do is replace that lerp/step part with another snippet of code that allow me to "bend" a curve according to a certain factor to get a curve closer and closer and to a step function, like this:


    4 functions.png

    Is it even possible, and if so, how can I achieve it ?
    Also, since I'm using the vertex position, can you explan why the gradient on the default character is offset to his feet ? Does it depend on the pivot point's position ?

    Thank you for your answers !
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    8,798
    Yes. The object space vertex position is explicitly defined as "a position relative to the object's pivot". If you want the change to be at the visual mid point you'll need to manually set that on the material for each object, since the GPU doesn't know where that is, only the CPU does.
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    8,798
    The easiest solution I can think of is to have a start end and use a smoothstep function.

    Something like this:
    Code (csharp):
    1. float xOrY = lerp(i.gradientCoord.x, i.gradientCoord.y, _VerticalGradient);
    2. float t = smoothstep(_GradientStart, _GradientEnd, xOrY);
    Get rid of the rest of the code you have above. The
    _GradientStart
    and
    _GradientEnd
    will be object space positions. If you want a stepped edge, just use two values that are almost the same, like 0.0 and 0.000001. Generally a smoothstep will look better than a straight lerp for color blends, so there's no reason to have to pick between them. And you can easily invert the gradient by making the start a larger value than the end.
     
  4. Quasar47

    Quasar47

    Joined:
    Mar 24, 2017
    Posts:
    90

    Thank you for your answer, it works perfectly ! It surprises me a bit, since I've done something similar a few days ago, but apparently I did it wrong. It kinda sucks I have to set up the pivot point manually for this to work correctly, but I guess you can't always have everything. Thanks again !
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    8,798
    Yep. The GPU only knows the pivot position and the relative vertex positions. The shader only knows the information about a single vertex, or a single pixel, and never the entire mesh. Only the CPU knows about the whole mesh in a way that's useful to you. And when it comes to skinned meshes, technically neither the CPU nor the GPU actually know where the mesh's "center" is, since the bounds on the CPU are approximate (just needs to make sure it encompasses the entire mesh, but isn't going trying to be especially tight) and the GPU never bothers to calculate that so you may need to manually update it every frame depending on your use case. In the past I've attached a script that tracks a bone to pass that position / orientation to the shader.
     
  6. Quasar47

    Quasar47

    Joined:
    Mar 24, 2017
    Posts:
    90
    You learn every day I see. I'm still a beginner in shaders but I'm gathering infos left and right for months now to make my own shader. Thanks for the info.
     
unityunity