TLDR.: I’m trying to find the tangent vector of a cubesphere using only world space coordinates.
Background:
A cubesphere is basically just an inflated cube. It is commonly used to project 2D textures onto a sphere due to its comparatively even pixel density. Cubesphere tangent space coordinates (also known as UVs) are generated using the following HLSL code:
// Default Cubemap using if from IG https://www.shadertoy.com/view/ltl3D8
vec2 Cubemap(vec3 uvw)
{
// intersect cube
vec3 n = abs(uvw);
vec3 v = (n.x>n.y && n.x>n.z) ? uvw.xyz:
(n.y>n.z) ? uvw.yzx:
uvw.zxy;
// project into face
vec2 uv = v.yz/v.x;
// Cass Everitt's piecewise quadratic warp to even out pixel density
// https://github.com/casseveritt/projection/blob/master/envmap.h (Ctrl+F pinch)
vec2 distort = (1.45109572583 - 0.451095725826*abs(uv));
uv *= distort;
// rescale to 0-1 range
return 0.5+0.5*uv;
}
The tangent vector is used together with the normal and bitangent vectors to translate vectors vetween world space and the tangent space of the mapping.
The normal vector just points straight up from the sphere surface and for a cubesphere and spheres in general is just normalize(uvw). The bitangent is perpendicular to the tangent and normal, so it is calculated as cross(Normal, Tangent).
The tangent is a vector that points in the direction of the tangent coordinates’ positive x-axis direction in world space. The bitangent does the same for the y-axis. So if we use a quiver plot to show the vector (1,0) in tangent space, we can see what vector we have to match in world space. Tangent Space Vector (1,0) as blue quiver plot, with white outlines of the cube edges.
There are a few naive solutions:
Use the same function that you used to translate the coordinates into tangent space for the vector. This does not work as the function only takes only the XY axis of the vector for the positive z side, for example, and vectors like (0,0,1) would be 0 for the entire side which is not correct.
Normally one would just generate a mesh of a cubesphere and read out the vertex tangent coordinates (Catlike Coding). While that works well enough, I can’t use this method for my application and need to calculate it from scratch using world coordinates. But we can use it to check what our solution should look like. Tangent space (1,0) vector in blue quiver plot, XY component of world space Tangent vector in green quiver plot. While the arrow positions do not align due to different projections, their direction does.
Using a perpendicular vector and normals to generate the tangent like For example for the positive z side of the cubesphere this would be Normalize(cross(Normal, (0,1,0))). Tangent space (1,0) vector in blue quiver plot, XY component of world space Tangent vector in red quiver plot. Notice how the vectors do not point in the same direction.
I also tried approximating the tangent vector ,see code below. This is certainly technically wrong but is quite close. Tangent space (1,0) vector in blue quiver plot, XY component of world space Tangent vector in red quiver plot. Notice how the vectors mostly point in the same direction.
vec3 normal = normalize(UVW);
vec3 tangent = normalize(vec3(abs(0.5(normal.x)-1),
normal.x*normal.y*normal.z,
normal.x));
Final Notes:
I only need the tangent vector for a single side of the cubemap as rotating and flipping it for the other 6 sides is trivial. I’ve searched for information on this topic but haven’t been able to find anything that specifically addresses my problem. Can anyone help me with this tricky geometry problem?
I found two solutions. You can either solve it with finite difference or derivatives. I have both implemented.
See here my shadertoy implementation.
And here the python script on how I got to the solutions.