Exploding mesh with shaders

Here’s another bit of fun with shaders. In this one all the interesting stuff happens in the vertex shader. The mesh is divided into squares which “explode”: they zoom off in different directions slowing rotating as they do. The catch is that you have to program in the full path of each square so you can’t do a “step by step” solution of the ODE. This means that it is only practical to use this for ODEs that can be solved with closed form.

It also demonstrates how buffers work.

Second time through in the video then I didn’t call the background function. Rather firework-y in effect!


function setup()
    explosion = mesh()
    local s = shader()
    s.vertexProgram, s.fragmentProgram = expshader()
    explosion.shader = s
    explosion.texture = "Cargo Bot:Codea Icon"
    explosion.shader.friction = .1
    explosion.shader.factor = 10
    local vels = explosion:buffer("velocity")
    local origin = explosion:buffer("origin")
    local angv = explosion:buffer("angvel")
    local m,n = 20,20

    local w,h = 20,20
    local xx,y = (WIDTH - n*w)/2, (HEIGHT - h*m)/2
    explosion.shader.size = vec2(n*w,m*h)
    explosion.shader.lr = vec2(xx - w/2,y - h/2)
    local c = vec2(xx+n*w/2,y+m*h/2)
    local cl = vec2(n*w,m*h):len()/2
    local r,th,sf,x,df
    sf = .3
    df = math.random()
    for i=1,m do
        x = xx
        for j = 1,n do
            r = explosion:addRect(x,y,w,h)
            th = 2*noise(i*sf+df,j*sf+df)*math.pi
            for k=1,6 do
                vels[6*r-k+1] = 20*(2-(c:dist(vec2(x,y))/cl))^2
                origin[6*r-k+1] = vec2(x,y)
                angv[6*r-k+1] = vec2(th,0)
            x = x + w
        y = y + h

function draw()
    if ElapsedTime < 10 then
        background(91, 90, 71, 255)
        explosion.shader.time = math.max(0,ElapsedTime-2)
    elseif ElapsedTime < 11 then
        background(0, 0, 0, 255)
        explosion.shader.time = 0
        explosion.shader.time = math.max(0,ElapsedTime-12)

function touched(touch)

function expshader()
    return [[
// The explosion vertex shader

//This is the current model * view * projection matrix
// Codea sets it automatically
uniform mat4 modelViewProjection;
uniform float time;
uniform vec2 size;
uniform vec2 lr;
uniform float friction;
uniform float factor;
lowp vec4 gravity = vec4(0.,-1.,0.,0.);
//This is the current mesh vertex position, color and tex coord
// Set automatically
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
// These are vertex buffers: initial velocity of the square,
// angular velocity,
// centre of square
attribute vec4 velocity;
attribute vec2 angvel;
attribute vec2 origin;

//This is an output variable that will be passed to the fragment shader
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

// ODE: x'' = -friction x' + gravity
// Solution: A exp(- friction * time) + B + time*gravity/friction
// Initial conditions:
// A = gravity/(friction*friction) - x'(0)/friction
// B = x(0) -A

void main()
    //Pass the mesh color to the fragment shader
    vColor = color;
    vTexCoord = texCoord;
    lowp vec4 pos;
    lowp float angle = time*angvel.x;
    highp vec4 A = gravity/(friction*friction) - velocity/friction;
    highp vec4 B = vec4(origin,0.,0.) - A;
    lowp mat2 rot = mat2(cos(angle), sin(angle), -sin(angle), cos(angle));

    pos = (position - vec4(origin,0.,0.));
    pos.xy = rot * pos.xy;
    pos += exp(-factor*time*friction)*A + B + factor*time * gravity/friction;
    //Multiply the vertex position by our combined transform
    gl_Position = modelViewProjection * pos;
// A basic fragment shader

//This represents the current texture on the mesh
uniform lowp sampler2D texture;

//The interpolated vertex color for this fragment
varying lowp vec4 vColor;

//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;

void main()
    //Sample the texture at the interpolated coordinate
    lowp vec4 col = texture2D( texture, vTexCoord );

    //Set the output color to the texture color
    gl_FragColor = col;

What means this “ODE”?

Hello @Marksolberg. ODE is ordinary differential equation. See this Wikipedia article for more information.

Wow … Would you like to do a script for meta balls in 3D?

Awesome work! had to implement it right away in my WIP “snake on steroids” project:


EDIT: just saw that the video makes it all look awful… ^^

The “sparks” are also made with it.
Thanks for making it easy to put it in the shader lab for easy access. :slight_smile:

Just one thing I haven’t really managed to do is change the “coloring” of the mesh textures (in my case to make it transparent over time).
Does not work the way I usually do it with textured meshes and I am absolutely not sure if has to do with the shader code…

If you would be so kind to help me out, I’d really appreciate it.

First, I have to apologize for the following.

Ode to an ODE. (Well actually a limerick.)

There once was a female mathematician

Who had a sexual aberration

“It’s not what you think”

She said with a wink

“He’s no Ordinary Differential Equation!”

.@VanDread Here’s an example with “trails”:


I’ve now written it as a class to make it easy to use with different projects. It’s part of my library: http://www.math.ntnu.no/~stacey/code/CodeLibrary. It has no dependencies so you can just grab the Explosion.lua file (remove the import.library bit at the start and the last end) and use as-is.

Update your link, I think. it goes to your home page, but not to where your code is stored.



@Andrew_Stacey - Could you please tell me how to make an explosion? I have the class copied into a project, but I don’t understand how to use it [and I can’t see the videos :cry:

Here’s an example that I have:

In setup:

explosion = Explosion({
    image = "Cargo Bot:Codea Icon", -- could be an actual Codea image
    trails = true,
    centre = vec2(WIDTH/2,HEIGHT/2)
explosion:activate(1.5) -- how long in the future to start

Then in draw, I just have explosion:draw(), and that’s it!

How I use it in a more complicated project is as follows:

  1. When I want to have an explosion, I draw whatever it is that should be exploded on to an image (using setContext).
  2. Then I set up a new explosion using syntax like the above.
  3. Lastly, whatever object it was that wants to have the explosion also has to ensure that it calls the draw method during its own draw method.

For example, in my newer version of the Anagrams program, then when the word is guessed, the following code runs:

local img = image(self.cw,self.lh) -- image the size of the current word
-- draw word on to image
self.explosion = Explosion({
    image = img,
    centre = -- some complicated vector,
    trails = true

Thank you as always @Andrew_Stacey \^-^/ it’s a beautiful effect. Is it available to use in any project (or rather, may I have your permission to use it)?
EDIT: I did all of that and it didn’t work (for me at least)

@Monkeyman32123 You’ll need to post some code for me to see. It’s working for me with a simple example program so to figure out what’s not working for you I need something to see.

As for using it, as far as possible I place all my code in the public domain (the only time I can’t is when I’ve used someone else’s code).

I tried to place it in my gyroship project (to explode when “youdead == true”… I can’t really give you just a snippet as the project is large (but it is on github, and there is a “project beta” discussion about it)

Can you upload your attempt with the explosion to github? I downloaded what you have but there’s jo explosion code there.

@Andrew_Stacey that is awesome thank you very much for sharing it. I’m having an issue if my fireworks project. Occasionally the shader shows active = true yet nothing is draw.

Gist - https://gist.github.com/briarfox/8cb3204825694ceeb6ff

@Briarfox - in a situation where a shader works intermittently, it’s most probable that you have a problem with its inputs, because if a shader doesn’t like something, it just doesn’t work (which is your problem).

So I would carefully check all the shader parameters and make sure they are always valid each time they are set. The best may be to output them each time you start a firework, and then look at them carefully for any firework that didn’t explode (and maybe compare with one that did explode).

@Ignatz Thanks, I figured it out. math.random(.1,1) was throwing a 0 out for firction which crashed it.

Fixed firework code here.