Implementation notes
Nontrivial bits in writing these programs (besides finding time to
work on it, although that was quite a nontrivial feat).
----------------------------------------------------------------------
0. Concept
The novel series is quite entertaining, and I thought... wouldn't it
be great if it gets animated? At that moment the image of Kanata's
"ao no kiseki" came to my mind, and I had to implement it, just like
the most other programs that came about.
"Ao no kiseki" would translate to "trail of blue", or perhaps "azure
orbit". Not seen in official illustrations up to volume 4, so I had
to improvise a bit. Let's hope someone really make an anime out of
these novels ^_^;
----------------------------------------------------------------------
1. Smooth 3D curve
Drawing some never ending curve is fairly intuitive -- have a dot that
moves in some direction, and leave behind vertices at regular
intervals. If the changes to the direction vector were smooth, the
curve will be smooth also. You can then go on to limit the number of
total vertices by keeping them all in a ring buffer, and dropping the
vertices at the tail of the buffer.
This mostly works -- if you can maintain constant frame rate. On my
outdated development machine this is never the case, so instead I use
the clock to interpolate positions along a cubic bezier curve. The
rest follows the intuitive implementation:
- Generate control points for cubic bezier curve such that it's
connected and smooth with respect to previous curve segment.
- Compute position of last vertex to be added by interpolating on
this curve.
+ If the new vertex is too close to the last vertex, replace the
last vertex instead of adding a new one. This limits the maximum
number of vertices that need to be rendered.
- Expire old vertices from ring buffer.
----------------------------------------------------------------------
2. Smooth 3D strip
Simply drawing a curve on screen wouldn't look all that nice,
especially at higher resolutions, where the curve would look really
thin. So the trail is drawn as a strip or ribbon, the surface of
which is generated by sweeping a segment that is perpendicular to the
curve described previously.
This part took a bit more vector math, since there are infinitely many
segments that are perpendicular to a 3D curve, some looking nicer than
others when used to form a surface. The approach I eventually took
was this:
- Compute first derivative of the curve. This gives us a tangent
vector in the direction that the curve is expanding.
- Find a vector that is perpendicular to this tangent. This is done
by taking the cross product of tangent and +Z. Call this the "side
vector".
- Because "side vector" is always on the XY plane (due to +Z being
fixed in the cross product), we rotate it about the direction of
the curve to add more twists to the surface. This rotation angle
is also interpolated along a cubic, so the twisted surface should
be smooth.
In theory the surface should be completely smooth, in practice it's
difficult to generate the control points so that the turns are not too
sharp, especially taking the rotation angle into account. This part
didn't turn out too well, and you get a bit of spiral pattern around
the corners where surface patches overlap.
Instead of trying to fixing the corner artifacts, I eventually got
used to looking at it. Spiral of blue ("ao no rasen") also appears in
volume 2 of the novel, so now it's a feature ^_^;
----------------------------------------------------------------------
3. Colors
Picking some blue color was easy enough, adding some transparency to
it was also fairly easy. The most interesting bit to note here is
that the selected blend function is commutative, so the results will
look the same regardless of the order for which the surface patches
are drawn. This was rather convenient.
Since we are able draw the surface patches in the order stored in the
ring buffer, it was also possible to implement fading at the tail of
the trail efficiently, by stepping up alpha values as we draw from
tail to head. It's efficient in the sense that there are fewer color
change commands, which would not be possible if we had to sort the
surface patches by depth.
Here I decided to fork the code two ways -- by changing the color
theme from blue to pink, we get the color scheme for Konata for free.
Fading and path generation is tweaked a bit here to add more
variation, but the most visible difference (besides color) is the
camera -- for Kanata it's held fixed, for Konata it spins around the
origin at constant rate, just because I had the extra space to do it.
----------------------------------------------------------------------
4. Miscellaneous
After getting something semi-decent looking, I started formatting the
source. Some effort were spent here to make sure that the Kanata and
Konata would look quite different, even when fed through a source
beautifier (but probably not as much as "one having super long
straight hair and the other having shoulder length wavy hair").
kanata.c turned out to be just the right size (that is, the template
had just enough non-whitespace characters to fit the source, after a
few tries). konata.c had a lot more space leftover, so much so that I
decided to make the camera move. This was a one line change to
gluLookAt done in the very last moment, things might have been much
different if I had planned for a moving camera at the beginning, but
this one didn't look all too shabby.
I still have quite a bit of space left at the end due to the
preprocessor lines, just not enough to embed something like a perl
script. But there is the perfect language that can easily live
alongside other languages -- brain****
Since we had Kanata and Konata already, Moeru is embedded in the
remaining scratch space, implemented in BF in two different ways (to
accommodate the different amount of leftover space). I would be
surprised if feeding random source files to a BF interpreter is on
anyone's mind, though.
----------------------------------------------------------------------
5. Finally...
I think the more famous "Kanata" and "Konata" these days come from
Lucky Star, as opposed to Oto Maho. Not that I always side with the
minority, just that these days I prefer to read more text ^_^;
--
omoikane@uguu.org - http://uguu.org/