Search Unity

[SOLVED] Rotate normal texture vectors // create blue from red and green

Discussion in 'Shaders' started by Quatum1000, Jan 29, 2021.

  1. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Hi everyone,

    I want to convert a real normal rgb value to vector3 angle.

    I'm sampling the normals as RT in screen-space. The result is similar like this.
    (Or similar the same when Display > shading normals in scene view)

    Is it possible to convert the normal rgb colors into vector3(x,x,x) angle anyhow?
    I got no information about normals from the gbuffers.

    Untitled-1.jpg

    Each color represents an normal vector for sure in local screen space.
    44bbbf8729c99b8cad726989dce8e3dd.png

    Any ideas what math to use to convert the rgb normal color to a local angle vector?

    I thought about to create a LookUpTable as RT, where i store all all possible rgb normals and it's angle.
    But I have no clue to reverse the rgb normal color to an normal vector..
    Thank you..
     
  2. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Normals are usually tangent space and if you're reading from a texture, they're within 0 to 1 usually, so convert by * 2-1 to bring the range into -1 to 1 for each rgb normal.

    Z or depth (blue) can be reconstructed from that if you need it.

    You might want world space normals, those are easy to get to as well (via shader). I guess I don't know what problem you're actually having...
     
    Quatum1000 likes this.
  3. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Thanks for your reply..

    yes good idea

    It's a bit difficultly to explain.. I do research and try to find solutions... In the end want to "rotate" the rgb normal colors in a RT texture by value because every color define a fixed angle. On angles, you can use math to rotate and get new angles. These result angles can be transformed back into colors as well.

    01.jpg
     
    Last edited: Jan 29, 2021
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    You can use math to rotate vectors too. That's a vast majority of what vertex shaders spend their time doing. And this is what you should be doing too.

    Look up how to construct a rotation matrix from an angle axis.
     
  5. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Only for completeness.
    I was able to create the blue channel from .r + .g of a local normal map.
    by
    Code (CSharp):
    1.  c.b  = sqrt(1.0 - ((c.r * c.r) + (c.g * c.g))) / 2.0 + 0.5
    I came to the conclusion to rotate the texture by a shader simply. Without involving any camera or image screen RT..

    Untitled-1.jpg

    For sure it's simple to get the rotation vectors of the x-axis and z-axis. Red and green values.

    But it's ugly to calculate a 3d vector from the single x & z axis with a centered y axis in shaderlap. The result must be rotated around the local axis top view.

    Perhaps it's possible with .transform.rotation in c# (no locked axis). Unfortunately this trigonometric math is out of my acknowledge (I'm from the electronics world)

    Untitled-6.jpg

    Did you have an idea to realize in c#, so I can make sure the result works at first? If its working then I can port it step by step to shaderlap.
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    You can always pass in a rotation matrix calculated in c#.
     
  7. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Any chance you can help me for a short payed session?
    I believe in this case it's useful and build up a tiny free asset for public if it's done.
     
  8. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Got the first solutions:

    The first function
    RotAroundLocalSingleAxis3D()
    is able to rotate texture normals colors by degree. Can be used in a shader (.r,g values -1 to 1).
    Then directly
    Code (CSharp):
    1. c.b  = sqrt(1.0 - ((c.r * c.r) + (c.g * c.g))) / 2.0 + 0.5
    calculates the correct blue channel height map out if red and green.

    The second function
    RotAroundLocalSingleAxis3D
    rotates a 3D point around all axis at the same time. This code can be optimized.

    Code (CSharp):
    1.     /// <summary>
    2.     /// Rotate around one 3D axis at the same time by code. About 10 times faster than Unity GameObject transform using childs or any transform.method
    3.     /// </summary>
    4.     /// <param name="v"></param>
    5.     /// <param name="t"></param>
    6.     /// <returns></returns>
    7.     Vector3 RotAroundLocalSingleAxis3D(Vector3 v, float t)
    8.     {
    9.         Vector3 r = Vector3.zero;
    10.         float cosTheta = Mathf.Cos(t);
    11.         float sinTheta = Mathf.Sin(t);
    12.  
    13.         // Rotate around Y Axis
    14.         r.x = v.x * cosTheta + v.z * sinTheta;
    15.         r.y = v.y;
    16.         r.z = v.z * cosTheta - v.x * sinTheta;
    17.  
    18.         // Rotate around Y Axis
    19.         // X = x;
    20.         // Y = y * cos(theta) - z * sin(theta);
    21.         // Z = y * sin(theta) + z * cos(theta);
    22.  
    23.         // Rotate around Y Axis
    24.         // X = x * cos(theta) - y * sin(theta);
    25.         // Y = x * sin(theta) + y * cos(theta);
    26.         // Z = z;
    27.  
    28.         return r;
    29.     }
    30.  
    31.     /// <summary>
    32.     /// Rotate around any 3D axis at the same time by code.
    33.     /// </summary>
    34.     /// <param name="Ip"></param>
    35.     /// <param name="RV"></param>
    36.     /// <param name="Theta"></param>
    37.     /// <returns></returns>
    38.     Vector3 RotatePointAround3DAxis(Vector3 Ip, Vector3 RV, float Theta)
    39.     {
    40.         float cosTheta, sinTheta;
    41.         Vector3 Q;
    42.    
    43.         cosTheta = Mathf.Cos(Theta);
    44.         sinTheta = Mathf.Sin(Theta);
    45.  
    46.         Q.x = (cosTheta + (1 - cosTheta) * RV.x * RV.x) * Ip.x;
    47.         Q.x += ((1 - cosTheta) * RV.x * RV.y - RV.z * sinTheta) * Ip.y;
    48.         Q.x += ((1 - cosTheta) * RV.x * RV.z + RV.y * sinTheta) * Ip.z;
    49.  
    50.         Q.y = ((1 - cosTheta) * RV.x * RV.y + RV.z * sinTheta) * Ip.x;
    51.         Q.y += (cosTheta + (1 - cosTheta) * RV.y * RV.y) * Ip.y;
    52.         Q.y += ((1 - cosTheta) * RV.y * RV.z - RV.x * sinTheta) * Ip.z;
    53.  
    54.         Q.z = ((1 - cosTheta) * RV.x * RV.z - RV.y * sinTheta) * Ip.x;
    55.         Q.z += ((1 - cosTheta) * RV.y * RV.z + RV.x * sinTheta) * Ip.y;
    56.         Q.z += (cosTheta + (1 - cosTheta) * RV.z * RV.z) * Ip.z;
    57.         return Q;
    58.     }
    59.  
     
    Last edited: Feb 4, 2021
    Furgl likes this.
  9. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Some perfect results:
    c.b  = sqrt(1.0 - ((c.r * c.r) + (c.g * c.g))) / 2.0 + 0.5

    Calculates the blue channel out of the red and green.

    Untitled-1.jpg

    Then rotated the normal (rgb) Vectors around any degree. In this case 33° ccw.
    Code (CSharp):
    1.         float t = 33.0 * UNITY_PI / 180.0;
    2.         float3 r;  // ... Rotated normals
    3.         float3 n = [ normal texture values rgb (-1.0 - 1.0) ]
    4.         float cosTheta = cos(t);
    5.         float sinTheta = sin(t);
    6.         r.r = n.x * cosTheta + n.z * sinTheta;
    7.         r.g = n.z * cosTheta - n.x * sinTheta;
    8.         r.b = n.y;
    9.         o.Normal = r;
    10.  
    Untitled-2.jpg

    float t = 219.0 * UNITY_PI / 180.0;

    Untitled-1.jpg
     
    Last edited: Feb 4, 2021
    Spike likes this.