Creating oscillating laser effect

Hi,

I’m trying to make sort of laser effect where there are several threads of thin lines oscillating around a central beam. I’ve tried using the built-in particle system, but it does not allow to provide a movement function which can create this kind of behavior. I’ve also tried to create the sine lines dynamically and move them along the beam but it seems too much work is done during enterFrame to allow smooth movement. Instead I get some kind of stutter whenever a new section is added to the snapshot parent. 

My preference would be to use some kind of particle system to achieve this as opposed to pre-creating several lines and switching them. however, I could not find a system that will allow me to do so.

this totally depends on what your definition of a “laser effect” is.  fe, most “lasers” in bullet-hell -type shmups are just many discrete “bullets” that happen to overlap and appear continuous.  you could easily animate through a sprite sequence to add detail in that case.  or spawn additional “laser bullets” beside it and update their positions to “orbit” it as they progress, giving the “sine waves”.  (and all of this is pretty easy, speaking from experience)  but if you’re doing it with full-length actual line geometry then you’ll face different challenges - maybe just animating the x scale from -1…1 of a wavy line would achieve something acceptable?  my first impression would be that a particle system is the wrong tool for this job - but only you know what it’s supposed to look like, so maybe it’d work, but i couldn’t tell you how.

Hi davebollinger,

Thanks for replying. This is somewhat similar to the effect I’m trying to achieve:

https://play.google.com/store/apps/details?id=com.tapanywhere.laseroverload&hl=en

I believe they are using a native particle system to achieve their effect.

I tried creating sine lines from basic circles or image dots and then scaling them as you suggested, its not the same but somewhat close. However, I need a lot of them running at the same time which cause the system to drop to a crawl very quickly - 3-4FPS. I tried pre-creating these are in memory textures and applying them on snapshot to reduce impact. It helps but they are still costly to draw when in large numbers. Perhaps there are optimizations I’m not aware of to reduce this impact but to my understanding, redrawing each frame a large number of images, even if mostly transparent is going to cost dearly no matter what. It seems using a native particle system has much better performance even with order of magnitude more elements and it also provides much better looking effect. However, the current system does not allow me to attribute something like custom movements function to the emitter (at least I’m not aware of such option). This is why I asked for advice in this forum. 

that doesn’t look like a particle system to me, it looks like a shader.  for example:  https://www.shadertoy.com/view/XtBXW3

Hi davebollinger,

Thanks for the tip! didn’t know shaders can do that! I’ll look into it, this is close to what I want.

Hi.

I’m not terribly happy with it, but this is something I use when a UFO character fires a laser:

local kernel = { category = "generator", group = "enemy\_attack", name = "beam" } kernel.vertexData = { { name = "width", default = .07, min = 0, max = 1, index = 0 }, { name = "taper", default = .34, min = 0, max = 1, index = 1 }, { name = "frequency", default = .017, min = 0, max = 1, index = 2 }, { name = "falloff", default = 3.7, min = 0, max = 5, index = 3 } } kernel.isTimeDependent = true kernel.fragment = [[// Created by inigo quilez - iq/2013 // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. P\_DEFAULT float hash1 (P\_DEFAULT float n) { #if !defined(GL\_ES) || defined(GL\_FRAGMENT\_PRECISION\_HIGH) return fract(sin(n) \* 43758.5453); #else return fract(sin(n) \* 43.7585453); #endif } // Created by inigo quilez - iq/2013 // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. P\_DEFAULT float IQ (P\_DEFAULT vec2 x) { P\_DEFAULT vec2 p = floor(x); P\_DEFAULT vec2 f = fract(x); f = f \* f \* (3.0 - 2.0 \* f); P\_DEFAULT float n = p.x + p.y \* 57.0; return mix(mix(hash1(n + 0.0), hash1(n + 1.0), f.x), mix(hash1(n + 57.0), hash1(n + 58.0), f.x), f.y); } P\_POSITION float Height (P\_POSITION vec2 to\_uv) { P\_POSITION float t = 256. - abs(256. - mod(CoronaTotalTime, 512.)); P\_POSITION float taper\_base = max(0., CoronaVertexUserData.y); P\_POSITION float x = smoothstep(taper\_base, .5, abs(to\_uv.x)); P\_POSITION float y = CoronaVertexUserData.x \* (1. - x \* x); return y \* (.875 + IQ(-to\_uv.xx \* (1024. \* CoronaVertexUserData.z) + vec2(8.9, sign(to\_uv.y) \* 1.7) \* t) \* .125); } P\_COLOR vec4 FragmentKernel (P\_UV vec2 uv) { P\_COLOR vec4 color = CoronaColorScale(vec4(1.)); P\_POSITION vec2 to\_uv = uv - .5; P\_POSITION float h = Height(to\_uv); P\_POSITION float ratio = abs(to\_uv.y) / max(h, .0001); h \*= .17 \* (1. + IQ(vec2(uv.x, h))); P\_COLOR float white = 1. + pow(max(1. - ratio, 0.), .47); P\_COLOR vec3 mixed = mix(vec3(white), color.rgb, 1. - exp(-CoronaVertexUserData.w \* ratio) \* (1. - h)); return vec4(min(mixed, 1.), color.a) \* smoothstep(-.2671, 0., 1. - ratio); }]] graphics.defineEffect(kernel) local r = display.newRect(display.contentCenterX, display.contentCenterY, 500, 300) r:setFillColor(1, 0, 0) r.fill.effect = "generator.enemy\_attack.beam" -- none: r.fill.effect.taper = .5 -- less decay: r.fill.effect.width = .3

uv.x runs along the length of the beam and uv.y from side-to-side. I’d have to refresh myself on the rest.  :slight_smile:

Hi StarCrunch,

Thanks for sharing your code. I’ll be sure to give it a go. Shaders are unexplored territory for us :slight_smile:

@StarCrunch

Can shaders achieve something like this:

https://wiki.unrealengine.com/Beam_Particle_(Tutorial)

@ rune7 The “material” you see in that link, with the nodes all hooked together, is basically a high-level view of a shader. You can probably make a decent guess about the code it generates just from the names and what plugs into what. A tool like that is on my to-do list.

You can achieve the look of that example at the very least. The parts with “white” in my own shader are basically saturating the brightness in spots, sort of what an emissive color does. I assume the little bumps in one texture are meant to be driven forward along uv.x. ( uv.x = 0 is the left side of the texture, uv.x  the right; similarly for bottom and too. You can add a delta such as time to them, scale them, and so on.) This can be done either with time or a parameter you supply. If you’re okay with a straight line then it should be fairly straightforward. Give it a try and report back if you get stuck.

The lightning-ish geometry is a different animal entirely.  :) If you do go with the effect, there’s now the effort of keeping it continuous, definitely more challenging. I’ve actually been working with the Corona source and might have some relevant contributions here, in one case with meshes and down the road trying to expose more shader memory for stuff like this (cf. my rambling notes). I don’t know when they’ll be ready, though.

@rune7

There’s a great little library created by @ponywolf that includes something just like that.

https://github.com/ponywolf/ponyblitz

At its most basic it only requires 2 lines of code to create a single lightning bolt.

giphy.gif

The bit you want is a function in the ponyFX module called newBolt.

Hope it helps.

Thanks StarCrunch. Using as strait line seems doable, but I don’t see how I can “connect” the end of one section to the beginning of the next if I add randomness to the line. I also considered tiling the shader in a snapshot but the problem remains.

Thanks Appletreeman, I was not aware of this contribution. I’ll check their code.

I use that effect in Knights of the Card Table to destroy cards… Forgot I included it in Ponyblitz :slight_smile:

this totally depends on what your definition of a “laser effect” is.  fe, most “lasers” in bullet-hell -type shmups are just many discrete “bullets” that happen to overlap and appear continuous.  you could easily animate through a sprite sequence to add detail in that case.  or spawn additional “laser bullets” beside it and update their positions to “orbit” it as they progress, giving the “sine waves”.  (and all of this is pretty easy, speaking from experience)  but if you’re doing it with full-length actual line geometry then you’ll face different challenges - maybe just animating the x scale from -1…1 of a wavy line would achieve something acceptable?  my first impression would be that a particle system is the wrong tool for this job - but only you know what it’s supposed to look like, so maybe it’d work, but i couldn’t tell you how.

Hi davebollinger,

Thanks for replying. This is somewhat similar to the effect I’m trying to achieve:

https://play.google.com/store/apps/details?id=com.tapanywhere.laseroverload&hl=en

I believe they are using a native particle system to achieve their effect.

I tried creating sine lines from basic circles or image dots and then scaling them as you suggested, its not the same but somewhat close. However, I need a lot of them running at the same time which cause the system to drop to a crawl very quickly - 3-4FPS. I tried pre-creating these are in memory textures and applying them on snapshot to reduce impact. It helps but they are still costly to draw when in large numbers. Perhaps there are optimizations I’m not aware of to reduce this impact but to my understanding, redrawing each frame a large number of images, even if mostly transparent is going to cost dearly no matter what. It seems using a native particle system has much better performance even with order of magnitude more elements and it also provides much better looking effect. However, the current system does not allow me to attribute something like custom movements function to the emitter (at least I’m not aware of such option). This is why I asked for advice in this forum. 

that doesn’t look like a particle system to me, it looks like a shader.  for example:  https://www.shadertoy.com/view/XtBXW3

Hi davebollinger,

Thanks for the tip! didn’t know shaders can do that! I’ll look into it, this is close to what I want.

Hi.

I’m not terribly happy with it, but this is something I use when a UFO character fires a laser:

local kernel = { category = "generator", group = "enemy\_attack", name = "beam" } kernel.vertexData = { { name = "width", default = .07, min = 0, max = 1, index = 0 }, { name = "taper", default = .34, min = 0, max = 1, index = 1 }, { name = "frequency", default = .017, min = 0, max = 1, index = 2 }, { name = "falloff", default = 3.7, min = 0, max = 5, index = 3 } } kernel.isTimeDependent = true kernel.fragment = [[// Created by inigo quilez - iq/2013 // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. P\_DEFAULT float hash1 (P\_DEFAULT float n) { #if !defined(GL\_ES) || defined(GL\_FRAGMENT\_PRECISION\_HIGH) return fract(sin(n) \* 43758.5453); #else return fract(sin(n) \* 43.7585453); #endif } // Created by inigo quilez - iq/2013 // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. P\_DEFAULT float IQ (P\_DEFAULT vec2 x) { P\_DEFAULT vec2 p = floor(x); P\_DEFAULT vec2 f = fract(x); f = f \* f \* (3.0 - 2.0 \* f); P\_DEFAULT float n = p.x + p.y \* 57.0; return mix(mix(hash1(n + 0.0), hash1(n + 1.0), f.x), mix(hash1(n + 57.0), hash1(n + 58.0), f.x), f.y); } P\_POSITION float Height (P\_POSITION vec2 to\_uv) { P\_POSITION float t = 256. - abs(256. - mod(CoronaTotalTime, 512.)); P\_POSITION float taper\_base = max(0., CoronaVertexUserData.y); P\_POSITION float x = smoothstep(taper\_base, .5, abs(to\_uv.x)); P\_POSITION float y = CoronaVertexUserData.x \* (1. - x \* x); return y \* (.875 + IQ(-to\_uv.xx \* (1024. \* CoronaVertexUserData.z) + vec2(8.9, sign(to\_uv.y) \* 1.7) \* t) \* .125); } P\_COLOR vec4 FragmentKernel (P\_UV vec2 uv) { P\_COLOR vec4 color = CoronaColorScale(vec4(1.)); P\_POSITION vec2 to\_uv = uv - .5; P\_POSITION float h = Height(to\_uv); P\_POSITION float ratio = abs(to\_uv.y) / max(h, .0001); h \*= .17 \* (1. + IQ(vec2(uv.x, h))); P\_COLOR float white = 1. + pow(max(1. - ratio, 0.), .47); P\_COLOR vec3 mixed = mix(vec3(white), color.rgb, 1. - exp(-CoronaVertexUserData.w \* ratio) \* (1. - h)); return vec4(min(mixed, 1.), color.a) \* smoothstep(-.2671, 0., 1. - ratio); }]] graphics.defineEffect(kernel) local r = display.newRect(display.contentCenterX, display.contentCenterY, 500, 300) r:setFillColor(1, 0, 0) r.fill.effect = "generator.enemy\_attack.beam" -- none: r.fill.effect.taper = .5 -- less decay: r.fill.effect.width = .3

uv.x runs along the length of the beam and uv.y from side-to-side. I’d have to refresh myself on the rest.  :slight_smile:

Hi StarCrunch,

Thanks for sharing your code. I’ll be sure to give it a go. Shaders are unexplored territory for us :slight_smile:

@StarCrunch

Can shaders achieve something like this:

https://wiki.unrealengine.com/Beam_Particle_(Tutorial)