Blitz3D Intermediates: Mesh Trails (think Home World)
by Jonathan Nguyen (world_creator)

If any of you have played Homeworld, I'm sure one of the first things you take note of are the trails coming from the ships. It's a great effect and pretty simple to do. Conceptually, it's simple but implementing it in code is somewhat tricky.

How It Works

Think about it, where is the trail? The ship's engine, right? Yes, where are the other parts of the trail? Where the ship used to be. Following on this, how the trail works is that you create a mesh with a number of segments. During each refresh, you put the first segment right where the engine is, that'll connect the trail to the ship in a sense. What you do with the other trail segments is that you give it the previous segment's position. Do this continually and you have your trail.

Implementation

If you've never played with dynamic mesh creation, I suggest you just read up on the commands to check out how it works. The first thing we do is initialize a memory position for the mesh, the surface, each of the vertices, and each of the triangles. This gets just a little tricky. First off, there are 4 vertices per segment. However, the last 2 vertices of a segment are shared as the first 2 vertices of the next segment. Also, there are 4 triangles per segment. Two triangles make a quad, one quad on top, one quad on the bottom. Check out the diagram, that'll help explain it a bit.



Now think about it, if you have 20 segments, how many vertices do you have? There is one pair of vertices for each segment, but if you do that, you'll leave a segment at the end without any ending vertices. So the number of vertex pairs you have is one more than the number of segments you have. Each pair of vertices has two vertices therefore if you have 20 segments, you have 42 vertices. So let's start seeing some code. Here is the creation of the mesh, the surface, and the array containing the vertices. You also need to create an array holding the vertices' positions. Remember that an array starts at zero, so if you want to make an array hold 2, the value you put in for the dimension is 1, one less than the actual number.


Now for the triangles, like I said, there are 4 triangles per segment. Two quads a segment, two triangles per quad, one quad for top and on for bottom. Let's initialize the array holding the triangles.


With the memory allocated, you have to create the vertices and meshes now. It's easier to pre-create the vertices and update their positions than clearing the mesh and recreating everything. Now takes a little graphical thinking, we have to organize the verticies and triangles in the right positions. The diagram shows how I organize my stuff.



Okay, simple enough, right? Nope! You gotta specify the UV coordinates! Unless you want a trail that's a solid color with no fading. Okay, I've provided the trail texture:



Now how do you create the UV coordinates for that? Well, first off you gotta know what UV coordinates are. UV coordinates help specify the location of a vertice on a texture. How UV coordinates work is that at UV coordinates (0,0), the position is at the top-left corner of the image. At (1,1), the position is at the bottom-right corner. basically a percentage value across the width and height of the texture. Looking at the image, we know that the top vertice will already have a V (vertical, height) coordinate of 0 and the bottom vertice with a V coordinate of 1. Now, if a U coordinate of 1 is considered at the very and of the image and that's where our trail ends, how would we go about specifying the coordinates for the U component? Well, if there are a maximum of 20 segments, 21 verticies, the U coordinate is simply the segment vertice number divided by the maximum number of segments verticies. This works because UV coordinates work as a percentage. Check out the diagram if you're having trouble recognizing this.



So with that in mind, here's the code. Remember that we don't need to care about the position of the vertex during its creation because we'll be changing it later anyway.


Okay, now our vertices are in place. Next is yet another tricky part, the triangles. Going back to the diagram with the vertices' labels, follow that in order to figure out which vertices each triangle uses. So basically, here's how the creation of the triangles goes.


...and tada! We have our mesh trail finished. Now we have to update it.

Update Routine

Remember how the trail works, each time it's updated, the first segment is positioned to where the engine is. Then for every other segment, it recieves the positions of the segment ahead of it, therefore the segment ahead of it passes its position over to the next segment. First let's whip up the code for the positioning of the first segment to the engine, the first segment is also position 0 in the array. For now, I'm going to be using x# and z# for the position of the engine assuming that this is only in a 2d plane overhead, the y value stays at a contant zero. If you want to make it into 3d, you just need to add another dimension to the vertice positions. Also, I'm going to specify a width# variable that determines how wide the trail is. Accompanying that is an ang# variable that represents the angle of direction of the ship on the y axis. Check out the diagram.



Here's the code for position the first segment towards the engine.


Okay, now we need to assign the rest of the vertices their new positions which are the old positions of the vertices ahead of them. We need to take note here though that we're not incrementing in the for loop but decrementing. This is because we're going from the end of the trail to the beginning. Now think about it, if we ran it forward, every vertex position will eventually be the same. Another thing I'm going to take into consideration is the update time. The update time is basically the delay between each trail update. If you have an update time of 0 or 1, it'll update every frame. An update time of 2 would update the mesh every other frame, and etc. The longer the update time, the longer the trail but it tends to look rough with a long update time. However, I don't make the first segment dependent to the update time because if I do, it'll look like the trail detaches itself from the engine. For now, I'll use an every other update method. So here it goes.


We put that for loop before the engine attachment part so that we can retrieve the old engine position before it gets updated. Okay, now that the vertex positions are updated, we need to update the actual vertices. We simply run through a loop for each vertex and position it where it belongs. Then of course, we need to update the mesh and then update it's normals.


And there you have it! Here's a sample program if you want to see it in action, make sure you run it with the texture in the same directory. In the sample program, I added a little wavy feature where it adds a small random number to the vertex positions to give it a wavy appearance. I'm hoping you understood the code before you implemented it, but either way it's fine as long as you got it working. If you have any comments or questions, just run 'em over to world_creator@hotmail.com.

Sample Program



For a printable copy of this article, please click HERE.


This site is Copyright© 2000-2004, BlitzCoder. All rights reserved.