Search Unity

Moving Vertices from point to point in a loop

Discussion in 'Shaders' started by m-y, Feb 14, 2020.

  1. m-y

    m-y

    Joined:
    Sep 22, 2013
    Posts:
    472
    Hello , I am still learning writing shaders
    I was able to create a simple shader to assign texture and colors
    what I am trying to do now is to create a shader that allow my cube render to move from
    (x to x +2 ) , it is just a simple thing
    I tried to use lerp but the results was little bit confusing
    that is my code
    Code (CSharp):
    1. Shader "yahia/3012020"
    2. {
    3. Properties
    4. {
    5.     _MainTex("Main Texture",2D)= "White"{}
    6.     _Color ("Color",Color) = (0,0,0,0)
    7.     _Speed ("Speed",Range(0,100))=1
    8. }
    9. SubShader
    10. {
    11. Pass
    12. {
    13.     CGPROGRAM
    14.     #pragma vertex VertFunc
    15.     #pragma fragment FragFunc
    16.  
    17.     sampler2D _MainTex ;
    18.     float4 _Color ;
    19.     fixed4 _Speed ;
    20.     struct Input
    21.     {
    22.     float4 vertex : POSITION ;
    23.     float3 uv : TEXCOORD0 ;
    24.  
    25.     };
    26.  
    27.  
    28.  
    29.     struct output
    30.     {
    31. float4    pos : SV_POSITION ;
    32.     float3 uvmain : TEXCOORD0 ;
    33.  
    34.     };
    35.     output VertFunc (Input IN)
    36.     {
    37.    
    38.         output OUT ;
    39.         OUT.pos = UnityObjectToClipPos (IN.vertex);
    40.     fixed4 testlerp =   lerp(IN.vertex.x,IN.vertex.x +2,_Speed);
    41.     OUT.pos = mul(UNITY_MATRIX_VP,testlerp) ;  
    42.  
    43.         OUT.uvmain = IN.uv ;
    44.         return OUT ;
    45.  
    46.     }
    47.  
    48.     fixed4 FragFunc (output IN) : SV_Target
    49.     {
    50.     fixed4 pixelcolor = tex2D(_MainTex,IN.uvmain);
    51.     return pixelcolor  * _Color  ;
    52.     }
    53.     ENDCG
    54. }
    55. }
    56.  
    57.  
    58.  
    59. }
    60.  



    that is a screen shot of the results
    this image before lerp
    upload_2020-2-14_15-55-33.png



    this one After using lerp

    upload_2020-2-14_15-56-17.png
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    That lerp is interpolating between the floating point value
    x
    and
    x + 2
    , and then assigning that single float to an entire
    fixed4
    value, meaning all values of
    testlerp
    are equal to the lerped
    x
    . You're then passing that
    fixed4
    value that's nothing but the lerped
    x
    to a
    mul
    that's transforming that position from world space to clip space and assigning that as the vertex shader's output position.

    In other words, you're making a giant diagonal line out of your mesh because you're using the x position for everything.

    Lets break it down a bit more.

    First is the biggest issue if you assigning a single value (
    IN.vertex.x
    ) to a vector (
    testlerp
    ) that's supposed to be a position. If it's a position, it needs to have the xyz values be the xyz of the position. The issue will happen even if you don't use the
    lerp
    at all and assigned
    x
    to
    testlerp
    directly.

    So instead of:
    fixed4 testlerp = lerp(IN.vertex.x, IN.vertex.x + 2, _Speed);

    You need to be doing something like this:
    Code (csharp):
    1. float4 vertex = IN.vertex;
    2. vertex.x = lerp(vertex.x, vertex.x + 2.0, _Speed);
    or
    Code (csharp):
    1. float4 vertex = lerp(IN.vertex, IN.vertex + float4(2, 0, 0, 0), _Speed);
    In the first example I'm copying the full
    float4
    value of
    IN.vertex
    to a new variable and then selectively modifying only the
    x
    of it. In the second example I'm lerping between two full
    float4
    values. In this case there's not really any difference to the GPU between the two since you're adding hard coded zeros to the other components of the vector, the compiled shader will skip that.


    Now, you'll also notice I'm using a
    float4
    there, and not a
    fixed4
    . On desktop platforms you won't notice anything different, but on some mobile platforms you absolutely will. The different floating point value types,
    float
    ,
    half
    , and
    fixed
    , tell the GPU the minimum accuracy allowed for that value, going from a "full precision" 32 bit float, a "half precision" 16 bit float, and a value that only needs to be able to store values between -2 and +2 with a worst case accuracy of 1/255. You never, ever want to use a
    fixed
    value for a
    position
    . You almost always want to use a
    float
    , especially since the GPU is going to be converting whatever value you hand to it back into a
    float
    for actual use.

    I mentioned that it doesn't matter for desktop, and that's because those are the minimum precision required. Desktop GPUs just always use a full 32 bit float no matter what you ask for because that's all it supports. Mobile devices more often do support 16 bit floating point math, and much older ones support the
    fixed
    value type and will really limit those values between -2 and +2.


    Next issue is you're using the
    UNITY_MATRIX_VP
    . That in itself is not an issue, but it's the "view projection matrix". The view matrix is the one that transforms a position from world space to view space. The projection matrix is the one that transforms a position from view space into clip space. View space is essentially the position relative to the position and orientation of the camera, it is not the position "on screen". Clip space is sort of the screen position, but not quite. It's a 4 dimensional position the GPU uses to calculate the screen position from. The
    UNITY_MATRIX_VP
    is a combination of the two, meaning it's transforming from world space to clip space. That's all fine ... except
    IN.vertex
    isn't in world space. That's in local space, aka object space. You need to transform that into world space before applying the view projection matrix to it. Also, depending on if you want the "+ 2" to be in local or world space changes when you want to do that transformation.

    Code (csharp):
    1. // transform object space vertex position into world space
    2. float4 worldPos = mul(unity_ObjectToWorld, IN.vertex);
    3.  
    4. // add 2 to the world space position's x based on the _Speed property
    5. worldPos.x = lerp(worldPos.x, worldPos.x + 2, _Speed);
    6.  
    7. // transform from world space into clip space
    8. OUT.pos = mul(UNITY_MATRIX_VP, worldPos);

    One last note. You'll notice I'm using
    unity_ObjectToWorld
    and
    UNITY_MATRIX_VP
    there. Those are both matrices Unity provides to shaders, but you'll notice they're very different in terms of their lettering style. Why? Really just because that's how they most frequently show up in Unity's own shader code. Unity actually has several aliases for most matrices it provides to shaders.
    UNITY_MATRIX_VP
    is also
    unity_MatrixVP
    , and
    unity_ObjectToWorld
    is also
    UNITY_MATRIX_M
    (object to world is also known as the model matrix). So why are they inconsistent in which style they use? Probably because it doesn't break anything. If it bothers you, use the
    unity_*
    versions instead.
     
    neoshaman and m-y like this.
  3. m-y

    m-y

    Joined:
    Sep 22, 2013
    Posts:
    472
    After your Answer I can't say anything
    just thank you so much for full details and I really appreciate your answer
    I need to read it and study from it
    thanks so much
    and I hope in future questions I can ask you
    thanks