#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

#### In this Discussion

edited February 2013 Posts: 2,161

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!

``````displayMode(FULLSCREEN)
function setup()
backingMode(RETAINED)
explosion = mesh()
explosion.texture = "Cargo Bot:Codea Icon"
local vels = explosion:buffer("velocity")
local origin = explosion:buffer("origin")
local angv = explosion:buffer("angvel")
local m,n = 20,20
vels:resize(m*n*6)
origin:resize(m*n*6)
angv:resize(m*n*6)

local w,h = 20,20
local xx,y = (WIDTH - n*w)/2, (HEIGHT - h*m)/2
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
explosion:setRectTex(r,(j-1)/n,(i-1)/m,1/n,1/m)
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
*vec4(math.cos(th),math.sin(th),0,0)
origin[6*r-k+1] = vec2(x,y)
angv[6*r-k+1] = vec2(th,0)
end
x = x + w
end
y = y + h
end
--startRecording()
end

function draw()
if ElapsedTime < 10 then
background(91, 90, 71, 255)
elseif ElapsedTime < 11 then
background(0, 0, 0, 255)
else
end
explosion:draw()
end

function touched(touch)
end

return [[
//
//

//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;
}
]],[[
//
//

//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;
}
]]
end
``````

• Posts: 14

What means this "ODE"?

• edited February 2013 Posts: 489

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

• Posts: 437

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

• edited February 2013 Posts: 4

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

• edited February 2013 Posts: 176

First, I have to apologize for the following.

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

There once was a female mathematician

"It's not what you think"

She said with a wink

"He's no Ordinary Differential Equation!"

• edited February 2013 Posts: 2,161

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

• Posts: 666

• Posts: 2,161
• edited March 2014 Posts: 342

@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 • Posts: 2,161

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
setContext(img)
resetMatrix()
-- draw word on to image
setContext()
self.explosion = Explosion({
image = img,
centre = -- some complicated vector,
trails = true
})
self.explosion:activate(1.5)
``````
• edited March 2014 Posts: 342

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)

• Posts: 2,161

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

• Posts: 342

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)

• Posts: 2,161

• Posts: 1,542

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

• Posts: 1,542
• Posts: 5,396

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

• Posts: 1,542

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

• Posts: 1,542
• Posts: 342

@andrew_stacey I just wanted to set up an explosion in "setup" and then, when a certain variable becomes true, I want to begin and draw the explosion in the draw function (in main).

• Posts: 2,161

@Monkeyman32123 It is so much easier to debug with some actual code. Could you post your attempt somewhere?

• edited March 2014 Posts: 342

In the "drawship" function I did this

``````If youdead and explosion == nil then
local img = image(self.cw,self.lh) -- image the size of the current word
setContext(img)
resetMatrix()
-- draw word on to image
setContext()
self.explosion = Explosion({
image = img,
centre = shiploc,
trails = true
})
self.explosion:activate(1.5)
End
If explosion ~= nil then
explosion:draw()
End
``````
• edited March 2014 Posts: 1,542

@monkeyman32123 try this:

 ```-- 0test   -- Use this function to perform your initial setup function setup() print("Hello World!") img = image(500,500) setContext(img) fill(255, 0, 0, 255) fontSize(50) text("Hello World",250,250) setContext()     end   -- This function gets called once every frame function draw() -- This sets a dark background color background(40, 40, 50)   -- This sets the line thickness strokeWidth(5)   if explosion then explosion:draw() end   -- Do your drawing here   end   function touched(t) if t.state == BEGAN then explosion = Explosion({ image = img, centre = vec2(WIDTH/2,HEIGHT/2), trails = false, rows = 50, cols = 50 }) explosion:activate(1) end end```
• Posts: 1,542

Here is a main tab that lets you play with all the explosion shader settings. This is only the main tab, grab the explosion shader from above.

 ```function setup() explode = nil displayMode(OVERLAY) parameter.number("Friction",0.01,2) parameter.integer("Factor",1,100,10) parameter.integer("Rows",2,100,20) parameter.integer("Cols",2,100,20) parameter.boolean("Trails") parameter.integer("TrailLength",1,100,16) parameter.number("TrailSeparation",0.01,1,0.5) parameter.action("Explode",function() explode = nil print(Trails) local img = readImage("Cargo Bot:Codea Icon") explode = Explosion({image = img, friction = Friction, factor = Factor, rows = Rows, cols = Cols, trails = Trails, trailLength = TrailLength, trailSeparation = TrailSeparation, centre = vec2(0,0) }) explode:activate(1) end)   end   -- This function gets called once every frame function draw() background(0, 0, 0, 255) if explode then translate(WIDTH/2,HEIGHT/2) explode:draw() end     end```
• Posts: 2,161

@Monkeyman32123 You're missing a couple of selfs in that code.

• Posts: 342

I have it so that it sets up the explosion in setup, then activates it when you die, then draws it in the draw step....and it works...BUT it makes the explosion always in the place I set it to be in setup (obviously)...is there a way for me to keep setting up the explosion in setup but change it's location when you die before it draws? If I try to setup the explosion anywhere but in setup it causes massive lag spikes

• Posts: 2,161

Can't you wrap it in a translate?

``````translate(100,200)
explosion:draw()
``````
• Posts: 342

Yeah, I literally just figured that out right before you commented XD
But thank you sir