Skip to content

Instantly share code, notes, and snippets.

@tschw
Last active August 31, 2021 17:34
Show Gist options
  • Save tschw/da10c43c467ce8afd0c4 to your computer and use it in GitHub Desktop.
Save tschw/da10c43c467ce8afd0c4 to your computer and use it in GitHub Desktop.
Single image, horizontal cross & compact cubemapping
vec2 cubeToUV( vec3 v, float texelSize ) {
// Horizontal cross layout:
//
// Y Char: Axis
// xzXZ Case: Sign
// y
vec3 absV = abs( v );
// Intersect unit cube
float scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );
v *= scaleToCube;
absV *= scaleToCube;
// Apply scale to cut the seams
// two texels less per square (one texel will do for NEAREST)
vec2 zoom = 1.0 - 2.0 * vec2( 4.0, 3.0 ) * texelSize;
v.xy *= zoom;
// Unwrap
// space: -1 ... 1 range for each square
//
// # dim := ( 4 , 3 )
// #X##
// # center := ( 1 , 1 )
vec2 planar = v.xy;
float almostATexel = 1.5 * texelSizeY;
float almostOne = 1.0 - almostATexel;
if ( absV.z >= almostOne ) {
if ( v.z > 0.0 )
planar.x = 4.0 - v.x;
} else if ( absV.x >= almostOne ) {
float signX = sign( v.x );
planar.x = v.z * signX * zoom.x + 2.0 * signX;
} else if ( absV.y >= almostOne ) {
float signY = sign( v.y );
planar.y = v.z * signY * zoom.y + 2.0 * signY;
}
// Transform to UV space
// scale := 0.5 / dim
// translate := ( center + 0.5 ) / dim
return vec2( 0.125, 0.16666666 ) * planar + vec2( 0.375, 0.5 );
}
vec2 cubeToUVCompact( vec3 v, float texelSizeY ) {
// Compact layout:
//
// xzXZ Char: Axis
// y Y Case: Sign
//
// Horizontal cross layout in this notation:
//
// Y To convert to compact layout,
// xzXZ simply move the top square to
// y the lower right corner.
// Number of texels to avoid at the edge of each square
vec3 absV = abs( v );
// Intersect unit cube
float scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );
absV *= scaleToCube;
// Apply scale to avoid seams
// one texel less per square (half a texel on each side)
v *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );
// Unwrap
// space: -1 ... 1 range for each square
//
// #X## dim := ( 4 , 2 )
// # # center := ( 1 , 1 )
vec2 planar = v.xy;
float almostATexel = 1.5 * texelSizeY;
float almostOne = 1.0 - almostATexel;
if ( absV.z >= almostOne ) {
if ( v.z > 0.0 )
planar.x = 4.0 - v.x;
} else if ( absV.x >= almostOne ) {
float signX = sign( v.x );
planar.x = v.z * signX + 2.0 * signX;
} else if ( absV.y >= almostOne ) {
float signY = sign( v.y );
planar.x = v.x + 2.0 * signY + 2.0;
planar.y = v.z * signY - 2.0;
}
// Transform to UV space
// scale := 0.5 / dim
// translate := ( center + 0.5 ) / dim
return vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );
}
vec2 cubeToUV( vec3 v, float texelSize ); // see cubeToUV.glsl
uniform sampler2D tex;
const float TextureSize = 512.;
// Suitable input:
// http://www.kweepa.com/step/ags/tech/Heartland360.jpg
// http://learnopengl.com/img/advanced/cubemaps_skybox.png
uniform vec4 camAngles;
mat3 rot_zyx( vec3 xyz );
void main() {
vec4 camAnglesRad = radians( camAngles );
// Generate "ray":
vec3 dir = vec3(
gl_TexCoord[0].x - 0.5,
0.5 - gl_TexCoord[0].y, // flip y
-0.5 / tan( camAnglesRad.w * 0.5 ) );
// Transform:
dir *= rot_zyx( camAnglesRad.xyz );
// Sample cube map:
vec2 uv = cubeToUV( dir, 1. / TextureSize );
uv.y = 1.0 - uv.y; // flip y
gl_FragColor = texture2D( tex, uv );
}
mat3 rot_x( float a ) {
float s = sin( a ), c = cos( a );
return mat3(
1.0 , 0.0 , 0.0 ,
0.0 , +c , +s ,
0.0 , -s , +c );
}
mat3 rot_y( float a ) {
float s = sin( a ), c = cos( a );
return mat3(
+c , 0.0 , -s ,
0.0 , 1.0 , 0.0 ,
+s , 0.0 , +c );
}
mat3 rot_z( float a ) {
float s = sin( a ), c = cos( a );
return mat3(
+c , +s , 0.0 ,
-s , +c , 0.0 ,
0.0 , 0.0 , 1.0 );
}
mat3 rot_zyx( vec3 xyz ) {
return rot_z( xyz.z ) * rot_x( xyz.x ) * rot_y( xyz.y );
}
void main() {
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = ftransform();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment