Tech Report: A Technique for Rendering Cheap Laser Bolts That Look Good From All Angles

[Note: An explanatory video of the 3D laser bolt effect is now available on YouTube.]

In this post, I will present a technique for rendering laser bolts that look good from any viewing angle (including head-on), without the use of expensive computations such as blurring. To understand this technique, we will assume the effect has already been achieved, and work backwards to discover the correct approach.

Our completed effect is depicted below:

laser-single-no-markup

Advanced rendering techniques might accomplish this effect with post-processing: the laser would be rendered as solid geometry, and blur passes would generate the glow. Let’s assume that the costly blur operation has already been accomplished for us, i.e., that we’ve gotten it for free.

To do this, we’ll pretend that the blur itself is a simple texture (in the shape of a laser bolt) that has been overlayed on the screen such that it covers both end points of the laser:

laser-single-by-texture

No single texture will do the job, however, because the texture would have to be different for differently shaped lasers, and its appearance would depend greatly on the user’s viewing angle.

Consider a single texture like the one below:

laser-front

Interestingly, this is exactly what we would expect a laser bolt to look like if we viewed it dead-on. If we viewed the laser bolt from its side, we would expect to see something like the following:

laser-side-no-markup

We can easily see that the second texture can be generated from the first texture. We simply divide the first texture into three sections: left, middle, and right segments. The right and left segments always remain unchanged, but we can stretch the middle one to generate the second texture:

laser-front-with-markup.png          laser-side-with-markup.png

Since we can stretch the middle portion to any length, and scale or rotate the resulting image arbitrarily, we can easily see that it is possible to essentially “pre-compute” the blur effect that would be necessary for a convincing laser bolt effect. All that is necessary is to overlay the pre-computed blur onto the screen coordinates of the laser bolt itself, using an orthographic projection.

The screen coordinates of the laser bolt are easily calculated by projecting the 3D end-points of the laser into screen space. Once we have those two points, we easily compute the 8 vertex positions (necessary for the left, middle, and right segments of our blur texture) within orthographic space. We can also scale these vertex positions based on their distance from the camera to generate the illusion of a perspective view even though we’re using an orthographic projection.

laser-single-with-markup

Note that the laser bolt also looks exactly like we would expect, when viewed directly from the front:

laser-demo-screenshot-front

There is one more hurdle to overcome. Because we have rendered the laser bolt using an orthographic projection, our fragment depth values do not exist in the same coordinate system as the rest of our (3D) scene. In other words, our lasers will not occlude (or be occluded by) other geometry. To correct this, we will use the z-coordinates that were computed during our projection step above to obtain depth values for the laser end points. In our vertex shader, we can then assign appropriate depth values to each of the 8 vertices used to render our laser. This will allow us to depth-test the lasers against the rest of the scene.

By using batch rendering techniques, we can render a large number of laser bolts efficiently:

laser-demo-screenshot

An example implementation and complete source code for the above screenshot is available here.

GN

Picking a Project

Allow me to introduce Gateway.

Set in a future where the destruction of Earth and the colonization of space are fading images of the past, humanity has spread throughout a galaxy for which they are not prepared. Although their scientific understanding of the universe is not what it once was, humanity has constructed a massive gate network that allows fighters and cruisers to be deployed anywhere in the regions they control. An ongoing civil war only adds to humanity’s stress and amidst the turmoil, nearby regions of space begin showing signs of activity.

Don’t let the story bore you — here are a few screenshots coming from Gateway’s nearly-complete game engine:

Two massive cruisers face off.

Four massive cruisers face off.

An enemy fighter takes laser fire damage.

An enemy fighter takes laser fire damage.

A massive space battle takes place in high orbit over New Röntgen.

A massive space battle takes place in high orbit over New Röntgen.

Friendly reinforcements arrive through the gate system.

Friendly reinforcements arrive through the gate system.

An alien cruiser returns deadly fire.

An alien cruiser returns deadly fire.

This is not a technical blog. Yes, I might mention things such as depth sorting, matrix multiplication, and stack-based menu systems, but I reserve that right at all times. What we will be talking about here is the nature of game dev for the lone developer, with some personal project management tips and the occasional technical detail thrown in for additional flavour. In my opinion, finishing a game is a lot harder than any of its technical implementations.

Ideally, I’d have started this blog at the beginning of Gateway, not somewhere between the middle and the end. I’ve never been this close to finishing such a large project before, but even a few thoughts at this point in my game’s development might be valuable to someone (maybe even myself).

If you know a fair bit of C++ and have a good OpenGL background, it’s tempting to think: “I know how to implement every single one of my game’s subsystems. I can easily write this game.” Perhaps this kind of optimism is the reason why we can be so motivated — if we really knew how much effort or work something meaningful was going to be, we might find it hard to even get started.

Unfortunately, writing a game (yes, even a small one) is much harder than implementing just the sum of its parts. Significant overhead and time must be committed to putting all of these parts together, and it’s laughably easy to underestimate this effort.

This is not meant to discourage anyone, but to provide a note of caution: you don’t have to write the game of a lifetime. Your project doesn’t need to be the single, greatest goal you’ve ever had in mind. Some of the best, most fun projects (not all of them games, either) I’ve ever worked on in my free time have been ones much smaller than I was capable of producing. Don’t worry: the big, unstoppable projects will come, and you’ll be ready for them.

How do you pick a project to work on? Maybe you can make a pros-and-cons list, or write down what you think it would be like to work on it. My own approach, especially when I’m trying to decide between multiple ideas, is to not work on anything. Eventually, perhaps after about a week or two, one of those ideas surfaces higher in my brain than the others, and begins to keep me up at night and distract me while I’m driving. At that point, I know I’ve made up my mind and am ready to begin.

GN