Super cool missile trails

Hey,

I’m trying to create something very similar to the missiles from Space Deadbeef, specifically the ‘trails’.

https://www.youtube.com/watch?v=M6k84M_PeM4

I got really close with particle systems (using small rectangles - see attached), but they’re too resource intensive.

I’d like to achieve the same ‘clean’ vector-style trails using some kind of draw function… Has anyone cracked this already? - The line would have to partially fade out after a pre-determined time event.

Any help would be appreciated

All the best

Hi.

First of all, those beams / halo look gorgeous.

I have some experience doing dynamic curved geometry, outside Corona. I’ve held back back on porting that, with the new shader availability, until the uniform userdata interface is revealed (since I want to do fairly parameter-heavy stuff), but if your effect is simple enough maybe you could get by with vertex userdata.

This all entails shaders, as I said. I’m assuming this is just graphical fluff, so you don’t need physics and stuff on them. The idea, roughly, goes as follows.

Basically, you want “tessellated” (left-to-right, at least) rects, so just rect-shaped polygons with lots of vertices, each of which gets evaluated in a vertex kernel. These will be wider than your old rects, since the tessellation lets you sculpt a curve.

In the vertex kernel, you read out  CoronaTexCoord.** x**(when it’s a uv, it’s also common to use .s), which should be 0 for the leftmost coordinates and 1 for the rightmost. This can be used to calculate the alpha, though that’s better done in the fragment kernel. Here, you can use it to fit your points to a curve. I’ve found Catmull-Rom well-suited to this, but it’s your call.

You’ve only got four vertex userdata to work with, and a cubic curve takes four vectors, so you’ll have to encode them. For values between 0 and 1 (in this case, normalized screen coordinates), I’ve used the following scheme. For decoding them in the shader:

P\_POSITION vec2 UnitPair (P\_UV float xy) { P\_UV float axy = abs(xy); P\_UV float frac = fract(axy); return vec2((axy - frac) / 1023., sign(xy) \* frac + .5); }

and for encoding them in the first place, in Lua:

function Encode (x, y) y = y - .5 return (y \< 0 and -1 or 1) \* (math.floor(1023 \* x) + math.abs(y)) end

(The “1023” (2^10 - 1) values are made to comport with GLSL’s  mediump precision and low-end fragment shaders. If this stuff will only be done on vertex kernels or higher-end devices, those could be “65535” (2^16 - 1) instead, I believe.)

So, you pass in four pieces of data (in the Catmull-Rom case, points along the curve, including the two endpoints of the “rect”), then in each vertex, evaluate the curve at t = CoronaTexCoord.x. From the derivative of the curve equation you can get the tangent, and from that the normal (-y, x) so you can position vertices “up” and “down” from the curve using CoronaTexCoord.y.

You’ll need to un-normalize these values, from [0, 1]. Unfortunately, the best idea I have here is to bake the content dimensions into the shader (since the kernel code is a string, this is easy enough to do at startup).

(The polygon display object’s coordinates don’t come into play, in my scheme. If you could come up with a way to use them instead, that might buy you back some userdata.)

Anyhow, that’s a very high-level overview, but maybe it gives you something to work with?

Hi StarCrunch, thanks for your kind words. I was an Art Director before I turned Indie, so it’s ‘automatic’ that I always put a priority on aesthetics… With this particular game I’m trying to create a level-of-polish that Phone/Tablet Users might expect to see on a handheld console. In a nutshell, thanks for the compliment it means a lot that you noticed.

Vertex user data is something I’ve only really ‘touched on’ before. I’m also looking at Bezier Curves, but again the math is tough (for a non-mathematician like me)… I’ll do some reading and let you know how I get on.

M

You can also try (makes pretty good trails; I’ve done them myself before) just drawing a line from previous point to current point each frame or so and fading it out slowly. That’s not as memory and speed intensive as rectangles (don’t ask me why; I guess it’s because all the rotation math and drawing calculation is done natively? And maybe because you need fewer?). Doing it this way lets you apply other effects to the line as well. Once quite a while ago I made the beginnings of a Fruit Ninja clone and drawing the line behind the touch + alpha fade + width fade looked almost identical to the real thing.

  • Caleb

Hi.

First of all, those beams / halo look gorgeous.

I have some experience doing dynamic curved geometry, outside Corona. I’ve held back back on porting that, with the new shader availability, until the uniform userdata interface is revealed (since I want to do fairly parameter-heavy stuff), but if your effect is simple enough maybe you could get by with vertex userdata.

This all entails shaders, as I said. I’m assuming this is just graphical fluff, so you don’t need physics and stuff on them. The idea, roughly, goes as follows.

Basically, you want “tessellated” (left-to-right, at least) rects, so just rect-shaped polygons with lots of vertices, each of which gets evaluated in a vertex kernel. These will be wider than your old rects, since the tessellation lets you sculpt a curve.

In the vertex kernel, you read out  CoronaTexCoord.** x**(when it’s a uv, it’s also common to use .s), which should be 0 for the leftmost coordinates and 1 for the rightmost. This can be used to calculate the alpha, though that’s better done in the fragment kernel. Here, you can use it to fit your points to a curve. I’ve found Catmull-Rom well-suited to this, but it’s your call.

You’ve only got four vertex userdata to work with, and a cubic curve takes four vectors, so you’ll have to encode them. For values between 0 and 1 (in this case, normalized screen coordinates), I’ve used the following scheme. For decoding them in the shader:

P\_POSITION vec2 UnitPair (P\_UV float xy) { P\_UV float axy = abs(xy); P\_UV float frac = fract(axy); return vec2((axy - frac) / 1023., sign(xy) \* frac + .5); }

and for encoding them in the first place, in Lua:

function Encode (x, y) y = y - .5 return (y \< 0 and -1 or 1) \* (math.floor(1023 \* x) + math.abs(y)) end

(The “1023” (2^10 - 1) values are made to comport with GLSL’s  mediump precision and low-end fragment shaders. If this stuff will only be done on vertex kernels or higher-end devices, those could be “65535” (2^16 - 1) instead, I believe.)

So, you pass in four pieces of data (in the Catmull-Rom case, points along the curve, including the two endpoints of the “rect”), then in each vertex, evaluate the curve at t = CoronaTexCoord.x. From the derivative of the curve equation you can get the tangent, and from that the normal (-y, x) so you can position vertices “up” and “down” from the curve using CoronaTexCoord.y.

You’ll need to un-normalize these values, from [0, 1]. Unfortunately, the best idea I have here is to bake the content dimensions into the shader (since the kernel code is a string, this is easy enough to do at startup).

(The polygon display object’s coordinates don’t come into play, in my scheme. If you could come up with a way to use them instead, that might buy you back some userdata.)

Anyhow, that’s a very high-level overview, but maybe it gives you something to work with?

Hi StarCrunch, thanks for your kind words. I was an Art Director before I turned Indie, so it’s ‘automatic’ that I always put a priority on aesthetics… With this particular game I’m trying to create a level-of-polish that Phone/Tablet Users might expect to see on a handheld console. In a nutshell, thanks for the compliment it means a lot that you noticed.

Vertex user data is something I’ve only really ‘touched on’ before. I’m also looking at Bezier Curves, but again the math is tough (for a non-mathematician like me)… I’ll do some reading and let you know how I get on.

M

You can also try (makes pretty good trails; I’ve done them myself before) just drawing a line from previous point to current point each frame or so and fading it out slowly. That’s not as memory and speed intensive as rectangles (don’t ask me why; I guess it’s because all the rotation math and drawing calculation is done natively? And maybe because you need fewer?). Doing it this way lets you apply other effects to the line as well. Once quite a while ago I made the beginnings of a Fruit Ninja clone and drawing the line behind the touch + alpha fade + width fade looked almost identical to the real thing.

  • Caleb