Search Unity

How to "loop through" a texture in my Shader like an array to retrieve data precisely? Something see

Discussion in 'Shaders' started by TheProfessor, Sep 2, 2015.

  1. TheProfessor

    TheProfessor

    Joined:
    Nov 2, 2014
    Posts:
    74
    Edit: Didn't notice thread cut off my title, meant to say "Something seems very wrong."

    So I'm using shader forge and having difficulties getting my hexagon blending algorithm to work correctly; I probably need to set up a debugging environment with Visual Studio if this doesn't have a straight forward solution but hopefully some genius out there can help me out. :(

    As it stands now outputting colour isn't helping me as predominantly the problem I'm having is being unable to tell if negative values are being suitably used.

    Context: I am trying to set up a hexagon grid of 3D tiles; I want the tiles to "transition" and blend from one tile to the next based on the texture of the surrounding tiles. Rather than create possibly thousands of materials and whatever performance costs that may bring, I decided to try to make a single shader/material where I pass to it the whole "grid" data as a texture.

    Code with hopefully helpful comments:

    Code (csharp):
    1.  
    2. // E: AB - R
    3. // F: ED - L
    4. // A: EF - BL
    5. // B: BC - TR
    6. // C: CD - TL
    7. // D: AF - BR
    8.  
    9. float3 hexDeltas[6];
    10.  
    11. // deltas in order of Top Right to Top Left going clockwise
    12. hexDeltas[0] = int3(1,0,-1); // TR
    13. hexDeltas[1] = int3(1,-1,0); // R
    14. hexDeltas[2] = int3(0,-1,1); // BR
    15. hexDeltas[3] = int3(-1,0,1); // BL
    16. hexDeltas[4] = int3(-1,1,0); // L
    17. hexDeltas[5] = int3(0,1,-1); // TL
    18.  
    19. // Firstly, convert given x,y,z coordinates in worldspace to axial/cube coordinates.
    20. // Size equals 1 because by hand that's correct, but if fed to the shader and I do the calculations
    21. // within the shader I get the completely wrong result.
    22. float mSize = 1;
    23.  
    24. float q;
    25. float r;
    26.  
    27. // World Space to Hex conversion:
    28. //[url]http://www.redblobgames.com/grids/hexagons/#pixel-to-hex[/url]
    29. float2x2 matA = { sqrt(3)/3, -1/3,
    30.                      0, 2/3 };
    31.  
    32. float1x2 matB = { HexOrigin.x,
    33.          HexOrigin.z };
    34.  
    35. float1x2 matQR = mul(mul(matA,matB), 1/(-mSize));
    36.  
    37. q = matQR[0][0];
    38. r = matQR[0][1];
    39.  
    40. // z because worldspace from the camera angle is X,Z instead of X,Y.
    41. // Although strangely I need to flip x and y here and multiply by
    42. // -size to get correct values.
    43.  
    44. float3 HexOriginCubeCoords = float3(-q-r,q,r);
    45.  
    46. // now we round..
    47. // I'm not sure if these work.
    48. // If I skip this step I find less tiles.
    49. int rx = round(HexOriginCubeCoords.x);
    50. int ry = round(HexOriginCubeCoords.y);
    51. int rz = round(HexOriginCubeCoords.z);
    52.  
    53. float x_diff = abs(rx - HexOriginCubeCoords.x);
    54. float y_diff = abs(ry - HexOriginCubeCoords.y);
    55. float z_diff = abs(rz - HexOriginCubeCoords.z);
    56.  
    57. if (x_diff > y_diff && x_diff > z_diff)
    58. {
    59.     rx=-ry-rz;
    60. }
    61. else if (y_diff > z_diff)
    62. {
    63.     ry = -rx-rz;
    64. }
    65. else
    66. {
    67.     rz = -rx-ry;
    68. }
    69.  
    70. int3 myHex = int3((rx),(ry),(rz));
    71.  
    72. // We now know for sure "where" our tile is in cube coordinates.
    73. // Now we need to find out which textures are being used in neigbhouring hexes.
    74.  
    75. // Textures for current hex is mTexases[0]
    76. // All surrounding hexes are from 1 to 6 clockwise TR to TL.
    77. int mTexases[7];
    78.  
    79. float3 test = float3(0,0,0);
    80. // ID:0 is reserved as "our" texture of the current hex.
    81. // 1 to 6 go from top right clockwise to top left.
    82. // Every hex has it's own texture, find out current hex and track it's texture.
    83. // Loop for each pixel and check it's r,g,b aak it's xyz and compare with myHex.xyz
    84. // If they match check the alpha channel where we store it's texture ID.
    85.  
    86. for (int m=0; m<Radius; m++)
    87. {
    88.     for (int k=0; k<Radius;k++)
    89.     {
    90.       float ecks = (k/Radius);
    91.       float why = (m/Radius);
    92.       if (round(tex2D(TexMap, float2(ecks,why)).x) == myHex.x
    93.          && round(tex2D(TexMap, float2(ecks,why)).y) == myHex.y
    94.          && round(tex2D(TexMap, float2(ecks,why)).z) == myHex.z)
    95.       {
    96.         mTexases[0] = tex2D(TexMap, float2(ecks,why)).a;
    97.         test = float3(0,1,0);
    98.         break;
    99.       }
    100.     }
    101. }
    102.  
    103. // We do the same here but now we're also checking the surrounding hexes.
    104. bool isFound = false;
    105. for (int c=1; c < 7; c++)
    106. {
    107.   isFound = false;
    108.   for (int m=0; m<Radius; m++)
    109.   {
    110.     for (int k=0; k<Radius;k++)
    111.     {
    112.       float ecks = k/Radius;
    113.       float why = m/Radius;
    114.       int3 temp = int3(hexDeltas[c-1].x + myHex.x, hexDeltas[c-1].y +
    115.       myHex.y, hexDeltas[c-1].z + myHex.z);
    116.       if ((round(tex2D(TexMap, float2(ecks,why)).x) == temp.x)
    117.           && (round(tex2D(TexMap, float2(ecks,why)).y) == temp.y)
    118.           && (round(tex2D(TexMap, float2(ecks,why)).z) == temp.z))
    119.       {
    120.         mTexases[c] = tex2D(TexMap, float2(ecks,why)).a;
    121.         test += float3(0,0,1);
    122.         isFound = true;
    123.       }
    124.     }
    125.   }
    126.   if (!isFound)
    127.   {
    128.     mTexases[c] = 4;
    129.   }
    130. }
    131. // The above strangely only works for the surrounding tiles of the only tile we find.
    132. // This implies to me that the sampling code doesn't work as intended.
    133. // Okay in theory we now have all of our surrounding textures.
    134.  
    135. // Blending code
    136. float i,j;
    137. float a[6];
    138. int b[6];
    139. float3 lookup[7];
    140.  
    141. float3 tempColor;
    142. float iMin;
    143. float iMax;
    144. float temp = 0;
    145. int intTemp = 0;
    146. float interp;
    147.  
    148. // E: AB - R
    149. // F: ED - L
    150. // A: EF - BL
    151. // B: BC - TR
    152. // C: CD - TL
    153. // D: AF - BR
    154.  
    155. a[0] = B; //
    156. a[1] = E; //
    157. a[2] = D; //
    158. a[3] = A; //
    159. a[4] = F; //
    160. a[5] = C; //
    161.  
    162. b[0] = 0;
    163. b[1] = 1;
    164. b[2] = 2;
    165. b[3] = 3;
    166. b[4] = 4;
    167. b[5] = 5;
    168.  
    169. // These are now the six textures the game currently
    170. // allows, will switch to texture atlas asap.
    171. lookup[0] = tex2D(mHex, _UVs).rgb;
    172. lookup[1] = tex2D(TR, _UVs).rgb;
    173. lookup[2] = tex2D(R, _UVs).rgb;
    174. lookup[3] = tex2D(BR, _UVs).rgb;
    175. lookup[4] = tex2D(BL, _UVs).rgb;
    176. lookup[5] = tex2D(L, _UVs).rgb;
    177. lookup[6] = tex2D(TL, _UVs).rgb;
    178.  
    179. for (j=0;j<6;j++)
    180. {
    181. iMin = j;
    182. for (i = j+1; i<6;i++)
    183. {
    184.   if (a[i] < a[iMin]
    185. )
    186.   {
    187.     iMin = i;
    188.   }
    189. }
    190.  
    191. if (iMin != j)
    192. {
    193.   temp =
    194. a[j];
    195.   a[j] = a[iMin];
    196.   a[iMin] = temp;
    197.  
    198.   intTemp =
    199. b[j];
    200.   b[j] = b[iMin];
    201.   b[iMin] = intTemp;
    202.  
    203.   intTemp = mTexases[j+1];
    204.   mTexases[j+1] = mTexases[iMin+1];
    205.   mTexases[iMin+1] = intTemp;
    206. }
    207. }
    208.  
    209. iMax = a[1];
    210.  
    211. float exp = 5.0;
    212.  
    213. float interp1 = pow(abs(a[0]-1),exp);
    214. float interp2 = pow(abs(a[1]-1),exp);
    215. float interp3 = pow(abs(a[2]-1),exp);
    216.  
    217. /*
    218. tempColor = (interp1*lookup[b[0]+1] +
    219.     interp2*lookup[b[1]+1] +
    220.     interp3*lookup[b[2]+1]) / (interp1 + interp2 + interp3);
    221. */
    222. tempColor = (interp1*lookup[mTexases[1]] +
    223.     interp2*lookup[mTexases[2]] +
    224.     interp3*lookup[mTexases[3]]) / (interp1 + interp2 + interp3);
    225.  
    226. float interp0 = pow(abs(a[0] - 1), 2.2);
    227.  
    228. //return lerp(lookup[mTexases[0]], tempColor, interp0);
    229. return test;
    230. //return float3(2/Radius,0,0);
    231. //mSize /= 10;
    232. //return float3(mSize / 2,0,0);
    233. //return tex2D(TexMap, float2(0.6,0.1)).rgb;
    234. //int3 temp2 = int3(hexDeltas[0].x + myHex.x, hexDeltas[0].y +
    235. //myHex.y, hexDeltas[0].z + myHex.z);
    236. //return HexOrigin;
    237. //return myHex;
    238. //return float3(rx,ry,rz);
    239. //return HexOriginCubeCoords;
    240.  
    241.  
    242.  

    Right now "return test" is just to see if I FIND any of the tiles.



    Which weirdly I apparently only find 0,0,0 and... It's adjacent tiles Yes and No (It would be yellow if it found it properly, but it doesnt!?)?

    The end result of my coordinate conversion scheming seems to work now:



    Albeit for some weird interpolation that shouldn't exist.

    The problem is despite seemingly getting accurate values for MyHex (aka the current Hex) when I try to do a comparison between any current hex and a given pixel it finds nothing.

    I strongly suspect that tex2D( sampler2D, float2); isn't working or is interpolating my values somehow when I want to sample a specific pixel; that or I'm not actually at the correct pixel. I found that integers of x,y didn't seem to work and I think the coordinates are from 0 to 1.

    Any suggestions?

    e: My texture maping:



    I get this bizarre result if in the first for loop I have if X and Y equal 0 but z matches.



    This doesn't make any sense at all.

    The most frustrating thing has gotta be that I have no idea if anything is correct, for some reason Size = (Height / (3/4)) / 2 doesn't give me 1 in the shader with 1.5 passed in as Height. But does in Wolfram/by hand. I divide by 10 and is still bright red when outputted. I get different results when I have it as (Height * 1/(3/4)) / 2 which is really really frustrating and I can't determine if there's a bug.