Text Scrolling with perspective effect - Graphic effect (Typescript)
This page shows the graphic effect of a scrolling text from bottom to top which has a perspective effect to create the illusion that the text also moves 'into" the screen.
Above the implementation of a text-scrolling effect is shown. It is implemented in Typescript using HTML5 canvas.
Feel free to download the source code at the top of the page to check out how it works.
Scrolling text lines is easy. However to create the effect that the text also moves "into the screen" turned out to be more difficult when just using plain HTML5 canvas element without any library like WebGL.
In the end, I had two ideas, both of which I implemented. While the final result is not as good as expected, still the implementation might be interesting.
Variant 1: "Line squeezing"
The idea for this implementation variant is to gradually draw the lines of text narrower from bottom to top and slowly fade out the text.
The main sequence is denoted in below figure:
- Step 1: First the whole text is split into lines, afterwards the lines are just drawn from top to bottom.
By slowly decreasing the start value of the y-coordinate, the text scrolls smoothly from bottom to top. As the canvas takes care about clipping, we do not even must consider which parts are currently visible but just draw the whole text.
- Step 2: In the second step, a smooth fading effect is created. This could have already been done in the first step by modifying the alpha value for each line, but this would create a coarse fading effect.
Instead, the image drawn in step 1 is drawn again, step-wise for each pixel line. So it is redrawn to another canvas object by drawing each pixel line as 1-pixel height rectangle, and for each of this rectangle the used alpha (transparency) value is slightly modified, resulting in a smooth fading effect.
- Step 3: The last step redraws each single pixel line (actually a rectangle with height of 1 pixel) from bottom to top where the width of the target rectangle slowly decreases with each line. The canvas function drawImage() is used for this which allows specifying the height and width of the source rectangle as well as of the target rectangle.
Variant 2: "Pixel rotation"
The idea for this implementation variant is to use a simple 3D engine where the image plane is rotated around the x-axis and all pixels go through a "rendering pipeline" with perspective and screen coordinate transformation.
- Step 1: The same step as in variant 1 - just draw the single lines.
- Step 2: Here comes the interesting part: First we assume a left-hand coordinate system with the viewer positioned at the origin (0, 0, 0) looking down the positive z-axis. The offscreen canvas with the text lines is interpreted as a plane in the x-y plane (parallel to x-axis and y-axis but perpendicular to the z-axis) with some distance to the viewer. So a simple 3D coordinate is implicitely defined.
Now the text plane is rotated. This is done by rotating each each pixel of the text plane by 40 degrees around the z-axis, followed by a camera-to-perspective and subsequent perspective-to-screen transformation.
- Step 3: The previous step has the drawback that it produces gaps inside the letters near to the viewer. This is due to the fact that the rotation and projection steps are not bijective (one-to-one). Several pixels that are rotated away result in the same pixel position while not every target pixel nearer to the viewer has a source pixel.
This is denoted in following figure: The plane with the blue and green pixels is rotated so the pixels which are further away will overlap while there are gaps between the pixels that are nearer towards the viewer.
Therefore a simple post-processing step is implemented: The whole pixel plane is searched for black pixels (background pixels) whose neighboring pixels are not black (letter pixels). Such pixels are probably a hole in a letter, so these pixels get the same color as the neighboring pixels. While this simple step does not find all hole pixels, it still improves the visual quality of the letters.
Variant 3: "Plane rotation and texture mapping"
The idea for this implementation variant is based on variant 2 and also uses a simple 3D engine where the image plane is rotated around the x-axis. However, not all pixels of the canvas are rotated, but only the corner (or "vertices") of the canvas plane. Afterwards the canvas containing the text is "texture-mapped" onto the rotated plane.
- Step 1: The same step as in variant 1 - just draw the single lines.
- Step 2: Using the same 3D coordinate system and same perspective screen transformation as in variant 2, the four vertices of the offscreen canvas are rotated. These four vertices of the offscreen canvas are simply (0, 0) [topleft], (0, height) [bottomleft], (width, 0) [topright] and (width, height) [bottomright].
- Step 3: That's the interesting part of the this variant. Actually the result of the rotated rectangle is a quadrilateral, and the goal is to map the offscreen canvas containing the text onto this quadrilateral - what is in fact actually just a texture mapping to the quadrilateral.
Similar to rasterizing a triangle, the quadrilateral is processed for each scanline from top to bottom. The x-position of the left and right legs of the quadrilateral are calculated by interpolation. Finally, to draw a single horizontal scanline, each single pixel from left to right is processed. For each pixel, the source position inside the texture is calculated and this pixel is then just copied to the final canvas.
History
2021/05/25: Version 2 - added variant 3 using a texture on a rotated quadrilateral.
2021/05/18: Initial release.