Plasma tube like effects

Hi all,



I’m thinking of using a plasma tube like effect like:

http://www.strattman.com/products/plasma/images/Plasma-tubes-in-dark.jpg



http://farm1.static.flickr.com/137/335741042_4d5964bfd3.jpg



http://www.resonanceresearch.com/images/crackle_tube_01.jpg

(Hopefully some of those links work!)



My first thought for doing this would be to create a cylinder and wrap a transparent texture around it but I’m not sure what the best way would be to animate that texture (or ideally have one generated on the fly but I expect that would be tricky to code). Is animating the texture as simple as just setting the texture in the material at the appropriate frame times or is there a better way?



For creating a glow around the tube would you attach a light source or use a post processor? Bloom? Would the PP method be supported on platforms like android?



Thanks,

Zarch

Using a noise function in a shader you could generate something like the first picture. The hard part is getting your parameters right. It would be easy to animate using a 4D noise.

1 Like

Thanks Madjack, I did wonder about that but I’ve zero knowledge of writing shaders. Are there any suitable shaders already available that I can adapt?



I’m reading https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:jme3_shaders?s[]=shaders now for some background info.

1 Like

You can use one of the 4D noise here



Some results of using this with suns I make realtime in my game: Here



That’s the shader I use.



The .vert

[java]

/*

  • 4D animated noise texture GLSL vert shader.

    /

    uniform float g_Time;



    uniform mat4 g_WorldViewProjectionMatrix;

    uniform mat4 g_WorldViewMatrix;

    uniform mat4 g_ProjectionMatrix;



    in vec4 inPosition;

    in float m_Radius;



    out vec4 texCoord4D;



    void main( void )

    {

    gl_Position = g_ProjectionMatrix * g_WorldViewMatrix * inPosition;

    texCoord4D = inPosition / (16 + m_Radius);

    }

    [/java]



    The .frag

    [java]

    #import “Shaders/Noise4D.glsllib”



    uniform vec4 m_Color;

    uniform float g_Time;



    in vec4 texCoord4D;



    void main( void ) {

    // Make texel turbulence.

    float n = abs(noise4d(vec4(texCoord4D.xyz, g_Time * 0.15)) - 0.5) +

    abs(noise4d(vec4(texCoord4D.xyz * 2.0, g_Time * 0.15)) - 0.25) +

    abs(noise4d(vec4(texCoord4D.xyz * 4.0, g_Time * 0.15)) - 0.125) +

    abs(noise4d(vec4(texCoord4D.xyz * 8.0, g_Time * 0.15)) - 0.0625) +

    abs(noise4d(vec4(texCoord4D.xyz * 16.0, g_Time * 0.15)) - 0.03125);



    // colorize to sun’s color then return.

    gl_FragColor = vec4(n * m_Color.xyz * vec3(0.50), 1.0);

    }

    [/java]



    Finally the noise function itself.

    [java]

    //

    // Description : Array and textureless GLSL 2D/3D/4D simplex

    // noise functions.

    // Author : Ian McEwan, Ashima Arts.

    // Maintainer : ijm

    // Lastmod : 20110822 (ijm)

    // License : Copyright © 2011 Ashima Arts. All rights reserved.

    // Distributed under the MIT License. See LICENSE file.

    // GitHub - ashima/webgl-noise: Procedural Noise Shader Routines compatible with WebGL

    //



    vec4 mod289(vec4 x) {

    return x - floor(x * (1.0 / 289.0)) * 289.0; }



    float mod289(float x) {

    return x - floor(x * (1.0 / 289.0)) * 289.0; }



    vec4 permute(vec4 x) {

    return mod289(((x
    34.0)+1.0)x);

    }



    float permute(float x) {

    return mod289(((x
    34.0)+1.0)x);

    }



    vec4 taylorInvSqrt(vec4 r)

    {

    return 1.79284291400159 - 0.85373472095314 * r;

    }



    float taylorInvSqrt(float r)

    {

    return 1.79284291400159 - 0.85373472095314 * r;

    }



    vec4 grad4(float j, vec4 ip)

    {

    const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0);

    vec4 p,s;



    p.xyz = floor( fract (vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0;

    p.w = 1.5 - dot(abs(p.xyz), ones.xyz);

    s = vec4(lessThan(p, vec4(0.0)));

    p.xyz = p.xyz + (s.xyz
    2.0 - 1.0) * s.www;



    return p;

    }



    float noise4d(vec4 v)

    {

    const vec4 C = vec4( 0.138196601125011, // (5 - sqrt(5))/20 G4

    0.276393202250021, // 2 * G4

    0.414589803375032, // 3 * G4

    -0.447213595499958); // -1 + 4 * G4



    // (sqrt(5) - 1)/4 = F4, used once below

    #define F4 0.309016994374947451



    // First corner

    vec4 i = floor(v + dot(v, vec4(F4)) );

    vec4 x0 = v - i + dot(i, C.xxxx);



    // Other corners



    // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI)

    vec4 i0;

    vec3 isX = step( x0.yzw, x0.xxx );

    vec3 isYZ = step( x0.zww, x0.yyz );

    // i0.x = dot( isX, vec3( 1.0 ) );

    i0.x = isX.x + isX.y + isX.z;

    i0.yzw = 1.0 - isX;

    // i0.y += dot( isYZ.xy, vec2( 1.0 ) );

    i0.y += isYZ.x + isYZ.y;

    i0.zw += 1.0 - isYZ.xy;

    i0.z += isYZ.z;

    i0.w += 1.0 - isYZ.z;



    // i0 now contains the unique values 0,1,2,3 in each channel

    vec4 i3 = clamp( i0, 0.0, 1.0 );

    vec4 i2 = clamp( i0-1.0, 0.0, 1.0 );

    vec4 i1 = clamp( i0-2.0, 0.0, 1.0 );



    // x0 = x0 - 0.0 + 0.0 * C.xxxx

    // x1 = x0 - i1 + 1.0 * C.xxxx

    // x2 = x0 - i2 + 2.0 * C.xxxx

    // x3 = x0 - i3 + 3.0 * C.xxxx

    // x4 = x0 - 1.0 + 4.0 * C.xxxx

    vec4 x1 = x0 - i1 + C.xxxx;

    vec4 x2 = x0 - i2 + C.yyyy;

    vec4 x3 = x0 - i3 + C.zzzz;

    vec4 x4 = x0 + C.wwww;



    // Permutations

    i = mod289(i);

    float j0 = permute( permute( permute( permute(i.w) + i.z) + i.y) + i.x);

    vec4 j1 = permute( permute( permute( permute (

    i.w + vec4(i1.w, i2.w, i3.w, 1.0 ))
  • i.z + vec4(i1.z, i2.z, i3.z, 1.0 ))
  • i.y + vec4(i1.y, i2.y, i3.y, 1.0 ))
  • i.x + vec4(i1.x, i2.x, i3.x, 1.0 ));



    // Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope

    // 776 = 294, which is close to the ring size 17*17 = 289.

    vec4 ip = vec4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ;



    vec4 p0 = grad4(j0, ip);

    vec4 p1 = grad4(j1.x, ip);

    vec4 p2 = grad4(j1.y, ip);

    vec4 p3 = grad4(j1.z, ip);

    vec4 p4 = grad4(j1.w, ip);



    // Normalise gradients

    vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));

    p0 *= norm.x;

    p1 *= norm.y;

    p2 *= norm.z;

    p3 *= norm.w;

    p4 = taylorInvSqrt(dot(p4,p4));



    // Mix contributions from the five corners

    vec3 m0 = max(0.6 - vec3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.0);

    vec2 m1 = max(0.6 - vec2(dot(x3,x3), dot(x4,x4) ), 0.0);

    m0 = m0 * m0;

    m1 = m1 * m1;

    return 49.0 * ( dot(m0
    m0, vec3( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 )))
  • dot(m1*m1, vec2( dot( p3, x3 ), dot( p4, x4 ) ) ) ) ;



    }

    [/java]



    One of the most important parameter here is in the .vert. It’s:

    [java]

    texCoord4D = inPosition / (16 + m_Radius);

    [/java]



    Radius is the spatial’s radius (a sphere) to which I add 16. If you don’t use a radius, or if they’re all the same, you can remove it and play with 16 until you get a result that fits your need.



    But what’s important for coloring is the Color you’ll pass down to your .frag. Here each sun uses it’s internal spectral class value as a color, but in your case you simply chose the color you want. Since the generated noise texture is grayscale it will colorize the gray to a value of the passed color.



    Hopefully that’ll make sense to you.



    Now, I’ve omitted the .jm3d/.jm3 definition files. I’ll leave that up to you to figure out. :wink:
3 Likes

Almost forgot!



[java]

float n = abs(noise4d(vec4(texCoord4D.xyz, g_Time * 0.15)) - 0.5) +

abs(noise4d(vec4(texCoord4D.xyz * 2.0, g_Time * 0.15)) - 0.25) +

abs(noise4d(vec4(texCoord4D.xyz * 4.0, g_Time * 0.15)) - 0.125) +

abs(noise4d(vec4(texCoord4D.xyz * 8.0, g_Time * 0.15)) - 0.0625) +

abs(noise4d(vec4(texCoord4D.xyz * 16.0, g_Time * 0.15)) - 0.03125);

[/java]



The .frag file will generate a noise with 5 frequencies. Meaning it’ll generate 5 different kind of noise maps. Or if you prefer, level of details, but not in LOD sense. You can play with that too. Note the value ratios. Doubling and / 2…



Oh, and it’s animated to boot.



Have fun.

1 Like

Wow :slight_smile:



I’m going to need a few days to play with these and then I’ll get back to you.



At the moment this is mapping to a sphere, presumably I’d need to change the mappings somewhere to map it to a cylinder?

@zarch said:
At the moment this is mapping to a sphere, presumably I'd need to change the mappings somewhere to map it to a cylinder?

The shape of the object doesn't matter. The shader receives the coordinates of the object and compute the output on this. I haven't tried this on anything else than spheres and cubes, true, but theoretically it should work on anything 3D.
1 Like

Oh and it’s seamless (as with any noise function).

1 Like

So I don’t need to do anything with UV mappings or whatever? I just set up this material and set the colour and off it goes?

Exactly.



The only thing that you have to worry about is the “size” or radius in the case of the .vert above. The noise generated will be dependent on this. So tweak accordingly. If value is wrong you could get a black texture and think it’s not working. Just a FYI. :wink:

1 Like

@madjack



http://imgur.com/RNupX



Took a bit of fiddling around to work out the material parameters but the results are pretty funky :slight_smile:



I see why it’s 4d as well. Rather than generate a 2dimensional texture and wrap it around the three dimensional one you just generate a 3d texture and select the correct location within that 3d space. Time then adds the 4th dimension to get things animated.



Going to need to tweak it a bit of course but it’s given me what I need to build on, thanks a lot.

That’s nice!

1 Like

If you feel the need to, you can use a look up texture (LUT) to paint your torus instead of using a simple color. It can give you more leeway with the way you paint it.

1 Like

Forgot this too…



The “49” you can play a bit with too. (That’s in the 4d noise function)



[java]

return 49.0 * ( dot(m0*m0, vec3( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 )))

  • dot(m1*m1, vec2( dot( p3, x3 ), dot( p4, x4 ) ) ) ) ;

    [/java]
1 Like

@madjack



Well the torus was just a placeholder shape to be a bit different from a cube/sphere. :smiley:



I’m not quite ready to start using it for real yet (development hasn’t reached that point, but I wanted to start thinking in advance about how I was going to do certain things).



Out of interest how did you solve the “washed out bloom” problem from your shader thread? Was it just by tweaking the settings listed in your post or did it involve something more clever?



I got the exact same problem you did - where my torus just becomes a plain colour the colour of the bloom - although with a nice glow halo around it.



http://i.imgur.com/zibaw.jpg

Still got the same problem. I haven’t reworked it yet. You’ll also run into the same problem I did where, when there’s something between the camera and the “glowed” object it will distort the glow, leaving gaps and whatnot.



In the end I’m not sure how I’ll handle it, but I’ll fiddle with it later. Implementing basic space combat for now (at least I will as soon as I fix what @pspeed has broken in my code with the control “fix” ;))

Coolies. Well if I come up with anything I’ll let you know, need to fix/finish a load of other stuff first though :s

@madjack said:
In the end I'm not sure how I'll handle it, but I'll fiddle with it later. Implementing basic space combat for now (at least I will as soon as I fix what @pspeed has broken in my code with the control "fix" ;))


:D

It was already broken. I just made it clearer why it was broken.

I do wonder if you'd extended AbstractControl if we'd have even had this conversation... ;)
@pspeed said:
I do wonder if you'd extended AbstractControl if we'd have even had this conversation... ;)


This isn't art. I use real things, not abstract stuff. ;)

dont set glowcolor, use a glowmap you generate similar texture procedualy via a shader (see wiki for how to use glow in custom materials).