Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Creating oscillating laser effect
Started by rune7 Feb 13 2019 11:38 PM

11 replies to this topic
[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

rune7

[GLOBAL: userInfoPane.html]
rune7
  • Contributor

  • 353 posts
  • Corona SDK

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.



[TOPIC: post.html]
#2

davebollinger

[GLOBAL: userInfoPane.html]
davebollinger
  • Corona Geek

  • 1,296 posts
  • Enterprise

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.


  • roaminggamer likes this

[TOPIC: post.html]
#3

rune7

[GLOBAL: userInfoPane.html]
rune7
  • Contributor

  • 353 posts
  • Corona SDK

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. 



[TOPIC: post.html]
#4

davebollinger

[GLOBAL: userInfoPane.html]
davebollinger
  • Corona Geek

  • 1,296 posts
  • Enterprise

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


  • XeduR @Spyric likes this

[TOPIC: post.html]
#5

rune7

[GLOBAL: userInfoPane.html]
rune7
  • Contributor

  • 353 posts
  • Corona SDK

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.



[TOPIC: post.html]
#6

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 786 posts
  • Corona SDK

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.  :)


  • XeduR @Spyric likes this

[TOPIC: post.html]
#7

rune7

[GLOBAL: userInfoPane.html]
rune7
  • Contributor

  • 353 posts
  • Corona SDK

Hi StarCrunch,

 

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



[TOPIC: post.html]
#8

rune7

[GLOBAL: userInfoPane.html]
rune7
  • Contributor

  • 353 posts
  • Corona SDK

@StarCrunch, 

 

Can shaders achieve something like this:

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



[TOPIC: post.html]
#9

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 786 posts
  • Corona SDK

@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.



[TOPIC: post.html]
#10

Appletreeman

[GLOBAL: userInfoPane.html]
Appletreeman
  • Contributor

  • 422 posts
  • Corona SDK

@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.



[TOPIC: post.html]
#11

rune7

[GLOBAL: userInfoPane.html]
rune7
  • Contributor

  • 353 posts
  • Corona SDK

@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.

 

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.



[TOPIC: post.html]
#12

rune7

[GLOBAL: userInfoPane.html]
rune7
  • Contributor

  • 353 posts
  • Corona SDK

@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 Appletreeman, I was not aware of this contribution. I'll check their code.




[topic_controls]
[/topic_controls]