Last active
November 20, 2019 15:00
-
-
Save KeyMaster-/2bb5e20f824241f3caef to your computer and use it in GitHub Desktop.
Luxe polar warp shader
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
//The source texture that will be transformed | |
uniform sampler2D tex0; | |
//The texture coordinate passed in from the vertex shader (the default luxe vertex shader is suffice) | |
varying vec2 tcoord; | |
//x: width of the texture divided by the radius that represents the top of the image (normally screen width / radius) | |
//y: height of the texture divided by the radius representing the top of the image (normally screen height / radius) | |
uniform vec2 sizeOverRadius; | |
//This is a constant to determine how far left/right on the source image we look for additional samples | |
//to counteract thin lines disappearing towards the center (a somewhat adjusted texel width in uv-coordinates) | |
//This value is 1 / (texture width * 2 PI) | |
uniform float sampleOffset; | |
//Linear blend factor that swaps the direction the y-axis of the source is mapped onto the radius | |
//if the value is 1, y = 0 is at the outer edge of the circle, | |
//if the value is 0, y = 0 is the center of the circle | |
uniform float polarFactor; | |
void main() { | |
//Make relative to center | |
vec2 relPos = tcoord - vec2(0.5,0.5); | |
//Adjust for screen ratio | |
relPos *= sizeOverRadius; | |
//Normalised polar coordinates. | |
//y: radius from center | |
//x: angle | |
vec2 polar; | |
polar.y = sqrt(relPos.x * relPos.x + relPos.y * relPos.y); | |
//Any radius over 1 would go beyond the source texture size, this simply outputs black for those fragments | |
if(polar.y > 1.0){ | |
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); | |
return; | |
} | |
polar.x = atan(relPos.y, relPos.x); | |
//Normally, the angle starts from the axis going right and is counter-clockwise | |
//I want the left edge of the screen image to be the line upwards, | |
//so I rotate the angle half pi clockwise | |
polar.x -= 1.57079632679; | |
//Normalise from angle to 0-1 range | |
polar.x /= 6.28318530718; | |
//Make clockwise | |
polar.x = -polar.x; | |
polar.x = mod(polar.x, 1.0); | |
//The xOffset fixes lines disappearing towards the center of the coordinate system | |
//This happens because there's only a few pixels trying to display the whole width of the source image | |
//so they 'miss' the lines. To fix this, we sample at the transformed position | |
//and a bit to the left and right of it to catch anything we might miss. | |
//Using 1 / radius gives us minimal offset far out from the circle, | |
//and a wide offset for pixels close to the center | |
float xOffset = 0.0; | |
if(polar.y != 0.0){ | |
xOffset = 1.0 / polar.y; | |
} | |
//Adjusts for texture resolution | |
xOffset *= sampleOffset; | |
//This inverts the radius variable depending on the polarFactor | |
polar.y = polar.y * polarFactor + (1.0 - polar.y) * (1.0 - polarFactor); | |
//Sample at positions with a slight offset | |
vec4 one = texture2D(tex0, vec2(polar.x - xOffset, polar.y)); | |
vec4 two = texture2D(tex0, polar); | |
vec4 three = texture2D(tex0, vec2(polar.x + xOffset, polar.y)); | |
//Take the maximum of the three samples. This is not ideal, but the quickest way to choose a coloured sample over the background colour. | |
gl_FragColor = max(max(one, two), three); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment