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/