Kaleidoscope effects are created by repeatedly duplicating and mirroring an image.
In a shader, we can manipulate uv coordinates to duplicate and mirror regions of an image.
A uv
coordinate is a 2D tuple (x,y). The coordinate (0,0) will map to the bottom, left corner
of the image. The coordinate (1,1) will map to the top,right corner of the image. Because we
are using a shader, the image we are using is passed to the shader as a texture. The technique
we are using to create the kaleidoscope is based on [texture mapping](https://en.wikipedia.org/wiki/Texture_mapping).
These following shader can be run in [vscode](https://code.visualstudio.com/) using the [shadertoy plugin](https://marketplace.visualstudio.com/items?itemName=stevensona.shader-toy).
Our shader computes a color for each pixel on the screen. The coordinate of the pixel is stored
in the variable fragCoord
. The resolution of the screen is stored in the variable iResolution.
To start, let’s map the bottom, left corner of the screen to uv-coordinate (0,0). Let’s map the
top, right of the screen to uv-coordinate (1,1). This will show the entire image.
We will map the fragCoord
of the current pixel to a uv coordinate, such that
the bottom, left pixel with screen coordinate (0,0) maps to uv (0,0) and the top,
right pixel at (screenWidth, screenHeight) maps to uv (1,1).
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 resolution = iResolution.xy;
vec2 uv = fragCoord.xy/resolution;
fragColor = texture(iChannel0, uv);
}
void main()
{
vec4 fragColor;
mainImage(fragColor, gl_FragCoord.xy);
gl_FragColor = fragColor;
}
|Step 1 | Step 2 | Step 3 | Step 4 | <img src="/media/kaleidoscope-rousseau1.png" height="175px"/> |<img src="/media/kaleidoscope-rousseau2.png" height="175px"/> | <img src="/media/kaleidoscope-rousseau3.png" height="175px"/> | <img src="/media/kaleidoscope-rousseau4.png" height="175px"/> |
Step 1: Map screen coordinates to range [0,0] → [1,1]. This image is rendered using the above code.
Step 2: Map screen coordinates to range [-1,-1] → [1,1]. The top right block corresponds to uv coordinates in range [0,1]. Other quadrants get their colors from the closest pixel.
Step 3: Map screen coordinates to range [-1,-1] → [1,1]. Use absolute value for uv coordinate.
Step 4: Map screen coordinates to range [-1,-1] → [1,1]. Again use the absolute value but also reflect the coordinate around line x = y
Add more repetitions
We can use mod to clamp and repeat pixels within a quadrant.
<img src="/media/kaleidoscope-rousseau5a.png" width="175px"/> | <img src="/media/kaleidoscope-rousseau5b.png" width="175px"/> | mod(uv, 0.55) | mod(uv, 0.3) |
Rotate and offset
We can also rotate and offset the uv coordinates to generate more variations based on a single image.
|<img src="/media/kaleidoscope-rousseau6a.png" width="256px"/> | <img src="/media/kaleidoscope-rousseau6b.png" width="256px"/> | <img src="/media/kaleidoscope-rousseau6c.png" width="256px"/> | <img src="/media/kaleidoscope-rousseau6e.png" width="256px"/> |
<!-- == Demo
<video muted autoplay controls> <source src="https://alinenormoyle.com/Kaleidoscope.mp4" type="video/mp4" width="600px"> </video> -→