Search Unity

Spherical UV Projection

Discussion in 'Scripting' started by RoughSpaghetti3211, May 23, 2020.

  1. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,708
    Ive got a tile im procedurally generating UVs using a simple spherical projection.

    Code (CSharp):
    1.  
    2. var uv = new float2(math.atan2(normal.y, normal.z) / (-2f * math.PI), math.asin(normal.x) / math.PI + 0.5f);
    3.  
    Problem is the further I move away from origin the larger the texture projection is as show with the two tiles in the image. I know the radius from each tile to origin 0.0.0 so I feel there some fancy way to fix this. Please any help.

    Screen Shot 2020-05-22 at 6.47.47 PM.png
     
  2. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    Last edited: May 23, 2020
  3. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,708
    Yea they are normalized. I can’t see where this is going wrong elsewhere, very lost
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    Is that top pentagon the same size in worldspace as the yellow cutout on the one at the bottom? I infer that but I just wanted to ask to be sure, because from that perspective it obviously looks bigger. :)

    I assume these are also using the same instance of the material, ie., same UV multipliers?

    Edit: just noticed the bottom ones are hexagons... but are they the same diameter/radius (within reason).
     
  5. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,708
    yea same radius ... what is going on here :(
     
  6. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,708
    Yea same material too , so the only real difference between the two tiles is where they are samples . Bottom tile is at y 0 and top at y 25. If I sample bottom tile at y 25 the texture tiling is the same.
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    It just feels like one of the shader ops is doing something more with local space. It can't be those trig functions so perhaps however you end up with the normal implies that it be also offset/scaled by local position???

    EDIT: the above is NOT correct... look below
     
    Last edited: May 23, 2020
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    Oh wait, I think I see it: if you are normalizing the vert positions, then the size of the x and the y will be consequentially smaller as the z (vertical) axis grows larger, which changes your mapping inputs.

    Think about 2 points separated by 1 horizontal unit. Raise that 1 vertical and normalize you have 1 and 1, so 0.7071 for horizontal, or sqrt(2). something like (0.7, 0.7, 0.7)

    Now lift up by 10 vertical unit and you have norm of (1, 1, 10): this normalizes out to something with much smaller x and y axes (something like (0.1, 0.1, 0.9));

    FIX: I think maybe don't normalize the vertex positions before you put into your atan/asin funcs?
     
  9. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    Ahaha, just re-read the top posts... I think @eisenpony got it right first. I think normalize has to go.
     
  10. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,708
    Man something funky going on here, if I dont use normalized it doesnt even render
     
  11. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    Arr... you're right. Asin() won't take anything above 1 or below -1... maybe use the normalized member for that input to asin() ?

    Reason: Atan2 is computing its own ratio (as per opposite / adjacent)

    Asin is implying a hypotenuse of 1.0 and accepts only the opposite side length.
     
  12. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,708
    do you have a different spherical type projection method I could try.
     
  13. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    If you can give us a little more of your code, someone might notice a scaling factor. The one line of code from yesterday doesn't seem like it should depend on radius.

    Best we can do is hazard guesses what is wrong with your normal vector.

    Sorry, I've never attempted a spherical projection, so I don't have any examples I prefer.
     
  14. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,708
    Nothing fancy, what i did find is if I offset the the normal of y in the fist tile by the radius of the second the textures match

    Code (CSharp):
    1.  
    2.  
    3. private static float3 GetGraphVertexPosition([ReadOnly] ref BlobAssetReference<PlanetGraphData> graph, int index)
    4. {
    5.     return new float3(
    6.         graph.Value.Vertices[index].PositionX,
    7.         graph.Value.Vertices[index].PositionY,
    8.         graph.Value.Vertices[index].PositionZ);
    9. }
    10.  
    11. private static float3 GetGraphVertexNormal([ReadOnly] float3 vertex)
    12. {
    13.     return math.normalize(vertex);
    14. }
    15.  
    16. private static float4 GetGraphVertexTangent([ReadOnly] float3 normal)
    17. {
    18.     return new float4(-normal.z, 0, normal.x, -1);
    19. }
    20.  
    21. private static float2 GetGraphVertexUv00([ReadOnly] float3 normal, bool axesVertical)
    22. {
    23.    
    24.     // TODO : https://gamedev.stackexchange.com/questions/136314/sphere-uv-mapping-texture-streched
    25.    
    26.     if (axesVertical == true)
    27.     {
    28.         var uv = new float2(math.atan2(normal.x, normal.z) / (-2f * math.PI), math.asin(normal.y) / math.PI + 0.5f);
    29.         if (uv.x < 0f) uv.x += 1f;
    30.         return uv;
    31.     }
    32.     else
    33.     {
    34.         var uv = new float2(math.atan2(normal.y, normal.z)/ (-2f * math.PI), math.asin(normal.x) / math.PI + 0.5f);
    35.         if (uv.x < 0f) uv.x += 1f; // TODO maybe should be y
    36.         return uv;
    37.     }
    38. }
    39.  
    40. //...
    41.  
    42. var posB = GetGraphVertexPosition(ref GraphInput, tri[1]);
    43. var norB = GetGraphVertexNormal( posB);
    44. var tanB = GetGraphVertexTangent( norB);
    45. var uv0B = GetGraphVertexUv00(norB, true);
    46. var vertexDataB = new PlanetVertexData
    47. {
    48.     Position = posB,
    49.     Normal = norB,
    50.     Tangent = tanB,
    51.     UVs = uv0B,
    52.     UvBarycentric = new float2(0f, 1f),
    53.     Color = new float4(InputColor[tri[0]].AlbedoIndex, InputColor[tri[1]].AlbedoIndex, InputColor[tri[2]].AlbedoIndex, 0)
    54. };
    55.  
    56.  
    57. //...
    58.  
     
  15. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    This is what I was suggesting in my Reply #11 above. Note the addition of the actual vector argument, which is un-normalized.

    You would intuit this would not make a difference because the use is in a ratio, but I think it makes a difference on two subsequent calls to this UV-maker with linearly-spaced points being pulled further up the axis.

    Try it. You just have to modify your call site to also supply the actual vert in addition to the normal.

    Code (csharp):
    1. private static float2 GetGraphVertexUv00_MOAR([ReadOnly] float3 actual, [ReadOnly] float3 normal, bool axesVertical)
    2. {
    3.  
    4.     // TODO : https://gamedev.stackexchange.com/questions/136314/sphere-uv-mapping-texture-streched
    5.  
    6.     if (axesVertical == true)
    7.     {
    8.         var uv = new float2(math.atan2(actual.x, actual.z) / (-2f * math.PI), math.asin(normal.y) / math.PI + 0.5f);
    9.         if (uv.x < 0f) uv.x += 1f;
    10.         return uv;
    11.     }
    12.     else
    13.     {
    14.         var uv = new float2(math.atan2(actual.y, actual.z)/ (-2f * math.PI), math.asin(normal.x) / math.PI + 0.5f);
    15.         if (uv.x < 0f) uv.x += 1f; // TODO maybe should be y
    16.         return uv;
    17.     }
    18. }
     
  16. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,708
    OK that worked thanks so much appreciate the help
     
    Kurt-Dekker likes this.