Created
December 3, 2023 12:27
-
-
Save BeRo1985/01580ec71c093d503217bf6aea221cc3 to your computer and use it in GitHub Desktop.
GLSL Octahedral Texture Mapping with Edge Mirroring and Catmull-Rom Interpolation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// GLSL Octahedral Texture Mapping with Edge Mirroring and Catmull-Rom Interpolation (by Benjamin 'BeRo' Rosseaux) | |
ivec2 wrapOctahedralTexelCoordinates(const in ivec2 texel, const in ivec2 texSize) { | |
ivec2 wrapped = ((texel % texSize) + texSize) % texSize; | |
return ((((abs(texel.x / texSize.x) + int(texel.x < 0)) ^ (abs(texel.y / texSize.y) + int(texel.y < 0))) & 1) != 0) ? (texSize - (wrapped + ivec2(1))) : wrapped; | |
} | |
vec4 textureCatmullRomCoefficents(const in float v){ | |
float t = v, tt = t * t, ttt = tt * t; | |
return vec4((tt - (ttt * 0.5)) - (0.5 * t), ((ttt * 1.5) - (tt * 2.5)) + 1.0, ((tt * 2.0) - (ttt * 1.5)) + (t * 0.5), (ttt * 0.5) - (tt * 0.5)); | |
} | |
// Catmull-Rom in 9 samples - I've also tried just-four-taps variants, but they din't matched to my 16-tap reference implementation exactly. | |
vec4 textureCatmullRom(const in sampler2D tex, const in vec2 uv, const in int lod){ | |
vec2 texSize = textureSize(tex, lod); | |
vec2 samplePos = uv * texSize; | |
vec2 p11 = floor(samplePos - vec2(0.5)) + vec2(0.5); | |
vec2 t = samplePos - p11, tt = t * t, ttt = tt * t; | |
vec2 w0 = (tt - (ttt * 0.5)) - (0.5 * t); | |
vec2 w1 = ((ttt * 1.5) - (tt * 2.5)) + vec2(1.0); | |
vec2 w2 = ((tt * 2.0) - (ttt * 1.5)) + (t * 0.5); | |
vec2 w3 = (ttt * 0.5) - (tt * 0.5); | |
vec2 w4 = w1 + w2; | |
vec2 p00 = (p11 - vec2(1.0)) / texSize; | |
vec2 p33 = (p11 + vec2(2.0)) / texSize; | |
vec2 p12 = (p11 + (w2 / w4)) / texSize; | |
return (((textureLod(tex, vec2(p00.x, p00.y), float(lod)) * w0.x) + | |
(textureLod(tex, vec2(p12.x, p00.y), float(lod)) * w4.x) + | |
(textureLod(tex, vec2(p33.x, p00.y), float(lod)) * w3.x)) * w0.y) + | |
(((textureLod(tex, vec2(p00.x, p12.y), float(lod)) * w0.x) + | |
(textureLod(tex, vec2(p12.x, p12.y), float(lod)) * w4.x) + | |
(textureLod(tex, vec2(p33.x, p12.y), float(lod)) * w3.x)) * w4.y) + | |
(((textureLod(tex, vec2(p00.x, p33.y), float(lod)) * w0.x) + | |
(textureLod(tex, vec2(p12.x, p33.y), float(lod)) * w4.x) + | |
(textureLod(tex, vec2(p33.x, p33.y), float(lod)) * w3.x)) * w3.y); | |
} | |
vec4 textureCatmullRomOctahedralMap(const in sampler2D tex, vec3 direction) { | |
direction = normalize(direction); // just for to make sure that it is normalized | |
vec2 uv = direction.xy / (abs(direction.x) + abs(direction.y) + abs(direction.z)); | |
uv = fma((direction.z < 0.0) ? ((1.0 - abs(uv.yx)) * vec2((uv.x >= 0.0) ? 1.0 : -1.0, (uv.y >= 0.0) ? 1.0 : -1.0)) : uv, vec2(0.5), vec2(0.5)); | |
ivec2 texSize = textureSize(tex, 0).xy; | |
vec2 invTexSize = vec2(1.0) / vec2(texSize); | |
if(any(lessThanEqual(uv, invTexSize * 2.0)) || any(greaterThanEqual(uv, vec2(1.0) - (invTexSize * 2.0)))){ | |
// Handle edges with manual catmull rom interpolation using texelFetch for correct octahedral texel edge mirroring | |
uv = fma(uv, texSize, vec2(-0.5)); | |
ivec2 baseCoord = ivec2(floor(uv)); | |
vec2 fractionalPart = uv - vec2(baseCoord); | |
vec4 xCoefficients = textureCatmullRomCoefficents(fractionalPart.x); | |
vec4 yCoefficients = textureCatmullRomCoefficents(fractionalPart.y); | |
return (((texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2(-1, -1), texSize), 0) * xCoefficients.x) + | |
(texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2( 0, -1), texSize), 0) * xCoefficients.y) + | |
(texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2( 1, -1), texSize), 0) * xCoefficients.z) + | |
(texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2( 2, -1), texSize), 0) * xCoefficients.w)) * yCoefficients.x) + | |
(((texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2(-1, 0), texSize), 0) * xCoefficients.x) + | |
(texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2( 0, 0), texSize), 0) * xCoefficients.y) + | |
(texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2( 1, 0), texSize), 0) * xCoefficients.z) + | |
(texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2( 2, 0), texSize), 0) * xCoefficients.w)) * yCoefficients.y) + | |
(((texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2(-1, 1), texSize), 0) * xCoefficients.x) + | |
(texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2( 0, 1), texSize), 0) * xCoefficients.y) + | |
(texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2( 1, 1), texSize), 0) * xCoefficients.z) + | |
(texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2( 2, 1), texSize), 0) * xCoefficients.w)) * yCoefficients.z) + | |
(((texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2(-1, 2), texSize), 0) * xCoefficients.x) + | |
(texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2( 0, 2), texSize), 0) * xCoefficients.y) + | |
(texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2( 1, 2), texSize), 0) * xCoefficients.z) + | |
(texelFetch(tex, wrapOctahedralTexelCoordinates(baseCoord + ivec2( 2, 2), texSize), 0) * xCoefficients.w)) * yCoefficients.w); | |
}else{ | |
// Non-edge texels can be sampled directly with an optimized catmull rom interpolation using just nine bilinear textureLod calls | |
return textureCatmullRom(tex, uv, 0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment