Processing

Hi guys an’ gals,

Since Codea is built like Processing I started to look not it. I found a nice little sphere program in Processing and tried to fit it into Codea, but ran into problems . He is the
Processing code:

import processing.opengl.*;


 float Xpos=0;
 float Ypos=0;
 float Zpos=0;

 float z= 0;
 float StepsV =50;
 float StepsH=StepsV;


void setup(){
 size(600, 600,OPENGL);

 background(0);
 lights();
 stroke(255);
 smooth();
}



void draw(){

 translate(width/2, height/2,0);
 background(0);
 
 //////////////////////////////////////////////////////////////////
 camera(mouseX, mouseY, 220.0, // eyeX, eyeY, eyeZ
 0.0, 0.0, 0.0, // centerX, centerY, centerZ
 mouseX, 1.0, 0.0); // upX, upY, up
 /////////////////////////////////////////////////////////////////
 stroke(255);
 strokeWeight(0.5);

 pushMatrix();

 for (int i = 1; i<=StepsV;i++){

   rotateY(radians(360/StepsV));
   for (float a = 90; a < 270; a+=360/StepsV) {

     pushMatrix();
     float lineLength= width/3;
     float Xpos1=Xpos + ( cos(radians(a)) * lineLength );
     float Ypos1=Ypos + ( sin(radians(a)) * lineLength );
     float Zpos1=Zpos + ( sin(radians(z-HALF_PI) * lineLength) );

     stroke(0,255,0);


     point(Xpos1,Ypos1,Zpos1);

     //ellipse(Xpos1,Ypos1,2,5,2,5);
     popMatrix();
   }
 }

 popMatrix();
 //endShape();
}

Here is my Codea take on it, I missed out the mouse response links - just aimed for the basic sphere. Bit it don’t work!!!

function setup()
    --
    displayMode(FULLSCREEN)
 --   backingMode(RETAINED)
    Xpos = 0
    Ypos = 0
    Zpos = 0
    z = 0
    StepsV = 36
    StepsH = StepsV
    degs = 360/StepsV
    midX = WIDTH/2
    midY = HEIGHT/2
    Polar:init(20)
end

-- This function gets called once every frame
function draw()
    translate(midX, midY)
    -- This sets a dark background color 
    background(0, 0, 0, 255)
    stroke(23, 255, 0, 255)
    smooth()
    -- This sets the line thickness 
    strokeWidth(5)
    -- Do your drawing here
    pushMatrix()
    for i = 1, StepsV, 1 do
        rotate(degs,0,1,0)
        for a = 90, 270, degs do
            pushMatrix()        
            lineLength = WIDTH/3
            Xpos1 = Xpos+(math.cos(math.rad(a))*lineLength)
            Ypos1 = Ypos+(math.sin(math.rad(a))*lineLength)
            Zpos1 = Zpos+(math.sin(math.rad(z-90)*lineLength))
            stroke(0, 251, 0, 255)
--            ellipse(Xpos1, Ypos1,5,5)
            point(Xpos1, Ypos1, 
            popMatrix()  
        end
    end
    popMatrix()
end

Any ideas?

Bri_G

:slight_smile:

I see no problems with the code but it will not run :-?

For a = 90,270, degs do

I’m not sure you can use increments in lua.

Yes you can.

What I see in the code (don’t have my ipad here, have to rely on reading :wink: ) is:

  • Polar:init() does not ring a bell
  • Zpos is computed with a z that never changes (and is never used)
  • point(Xpos1, Ypos1, should have a closing brace instead of the comma

maybe one of these? The last one is a definite showstopper.

Hi All,

Oops, couple of mistooks!!

Ignore the Polar:init() that’s a call to an alternative output system.

The other line should read point(Xpos1, Ypos1, Zpos1).

The actual output I get is a peripheral circle of dots.

The Processing output is a 3D sphere which moves/rotates in response to mouse movement.

I’m beginning to think this is a feature of the processing.openGL library opened in the first line of the processing code.

Thanks for trying.

Bri_G

:slight_smile:

When I close the ) at the point(Xpos1… And delete the polar:init() line, I get a circle of dots

Well, I couldn’t help but playing a bit, here’s the 3d sphere, with star wars motion blur effect :slight_smile:

If you have an ipad3, turn landscape

function setup()
    --
 --   displayMode(FULLSCREEN)
    backingMode(RETAINED)
    Xpos = 0
    Ypos = 0
    Zpos = 0
    z = 0
    StepsV = 36
    StepsH = StepsV
    degs = 360/StepsV
    midX = WIDTH/2
    midY = HEIGHT/2
    mouseX = 0
    mouseY = 0
    perspective(90)
 --   Polar:init(20)
t = 0
    noSmooth()
end

-- This function gets called once every frame
function draw()
   -- perspective(none)
--ortho()
    perspective(90)
  
--zLevel(-20)
 --background(0, 0, 0, 16)   
   -- translate(midX, midY)
    translate(0,0,-220)
    
   

   fill(0, 0, 0, 56)
--zLevel(20)
pushMatrix()
zLevel(-1)
translate(0,0,-1220)
  rect(-WIDTH*10,-HEIGHT*10,WIDTH*45,HEIGHT*45)    
fill(0, 255, 30, 255)
popMatrix()
 
    camera(mouseX, mouseY, 220.400, -- eyeX, eyeY, eyeZ
 0.0, 0.0, 0.0, -- centerX, centerY, centerZ
 0.0, 1.0, 0.0); -- upX, upY, up 
    
    -- This sets a dark background color 
--    background(0, 0, 0, 255)
    stroke(23, 255, 0, 255)

    -- This sets the line thickness 
 --   strokeWidth(5)
    -- Do your drawing here
               rotate(t/3,0,1,1)
    pushMatrix()
    for i = 1, StepsV, 1 do
        rotate(degs,0,1,0)
        for a = 90, 270, degs do
            pushMatrix()        
            lineLength = WIDTH/3
            Xpos1 = Xpos+(math.cos(math.rad(a))*lineLength)
            Ypos1 = Ypos+(math.sin(math.rad(a))*lineLength)
            Zpos1 = Zpos+(math.sin(math.rad(z-90)*lineLength))
       --     stroke(0, 251, 0, 255)
            --rotate(t)
           -- pushMatrix()
           -- resetMatrix()
            pushMatrix()
            translate(Xpos1, Ypos1)
            rotate(math.random(0,360),1,1,1)
           ellipse(0, 0,5,5)
            popMatrix()
    --    popMatrix()
        --    point(Xpos1, Ypos1) 
            popMatrix()  
        end
    end
    popMatrix()
    t = t + 1
end

function touched()
    mouseX = mouseX + CurrentTouch.deltaX
    mouseY = mouseY + CurrentTouch.deltaY
    end

Hi Inviso,

Fantastic, thanks for the time you spent in getting this workable. I must admit I’m more confused now. I can’t understand what the rect() function is doing - is it clipping?

The other thing is some of the figures seem to orders of magnitude removed from the screen range e.g. WIDTH x 10 ??? What’ that about.

Finally, what’s the motio blur effect - is that the point trail on rotation - kind Doppler effect?

Oh, one other thing - do you know why the original code didn’t draw each iteration of the inner loop, resulting in only the outer circle? Is it a feature of openGL?

Thanks again.

Bri_G

:slight_smile:

To achieve the “motion blurry thingy” I used some kind of trick. Usually, the screen is redrawn every frame and everything from the last screen is deleted.

When you use e.g. background(), the screen is filled in a specific color…
What I did, I set the backing mode to retained, that means, the last frame is not deleted, it stays…

Your original code did just draw the circle, because the standard mode in codea has no perspective… Imagine it as a flat piece of paper on which you draw… If your program draws something above or behind the paper, you cannot see it. So I used perspective and could see more…

That is also th explanation about the width * 10 things…
If I wouldn’t draw that rect, everything that is rendered would stay forever… So every time a point is drawn, it stays…
What I do to achieve this effect, I draw a rectangle above the last image, that is black but transparent… So the last image gets simply darker… In the next frame the frames before the last frames are darker and get even more darker, until it’s pure black… That gives the desired effect.

The width and height is just like this, because I need a plane in the 3d space behind the sphere… Because I am lazy and don’t want to calculate it accurately, I just made a gigantic rect in the background just far enough away… That’s it…

And it has to be so far away, because if I draw it like just in front of the camera, the renderer knows that something is drawn in that front and everything behind it wouldnt be drawn (the renderer does not know that my rect is transparent)

Your original code did just draw the circle, because the standard mode in codea has no perspective… Imagine it as a flat piece of paper on which you draw… If your program draws something above or behind the paper, you cannot see it.

That’s not quite right. The standard mode has no perspective, but that means just that it projects everything orthogonally onto the “flat piece of paper”. So it is okay to draw above and below the plane. There is a cut-off, though, and if you draw above or below that then you don’t get anything.

However that doesn’t seem to be what’s going on here. If I hard code your rotation then I get something sensible. So it seems to be something to do with the interaction between rotate and the drawing commands. Specifically, if I take out the rotate(degs,0,1,0) line and replace the coordinate calculations by:

Xpos1 = Xpos + math.cos(math.rad(a)) * math.cos(math.rad(i)) * lineLength
Ypos1 = Ypos + math.sin(math.rad(a)) * math.cos(math.rad(i)) * lineLength
Zpos1 = Zpos + math.sin(math.rad(i)) * lineLength

and I also have to make the outer loop:

for i = degs,360,degs do

Then I get something that looks about right.


While I’m at it:

Usually, the screen is redrawn every frame and everything from the last screen is deleted.

No. The screen isn’t deleted. However, it is very uncommon to not blank it at the beginning of the draw function because there are actually three “canvases” that are used in succession so what is drawn in one iteration will turn up as the background on the third successive frame, unless it is blanked first. This is almost never useful!

(Plus, this every-third bit is a bit unstable for the first dozen or so frames.)

What I did, I set the backing mode to retained, that means, the last frame is not deleted, it stays…

Setting the backing mode to RETAINED gets around the every-third-frame issue by copying the previous canvas to the current one at the start of the draw cycle. So the effect is as if the last frame was retained.

cool thx, that makes some things clearer :smiley:
but in general i was quite right :wink:

Hi Guys,

Thanks for the feedback, both plugged holes in my understanding of 3D on computers.

My understanding is there are many ways to achieve this, including zplanes and trig.

  1. First principles uses the mathematics based around polar coordinates of a sphere and projection of the points onto a 2D page. Loadsa maths!!!

  2. Uses a virtual reality, containing objects (including self/camera) and a host of library calls (which effectively do the maths in 1) making it easier to achieve 3D. But it is the same i.e. a 3D projection onto a 2D screen.

That’s the overview - my difficulty has always been understanding the nuts and bolts needed to put this mechano set together.

Firstly are there any good articles/books on this ?

Secondly, I deleted references in the processing code to openGL and it resulted in nil output. I can only assume, from this, that the openGL library provides the relevant 3D routines to perform the sphere image.

I am still puzzled why my initial conversion didn’t work, it seems logical enough an I didn’t use layers/clipping or other options that could overwrite the graphics produced.

I’m determined to understand the first principles before using the new 3D routines built into Codea.

Thanks again,

Bri_G

:slight_smile:

I am still puzzled why my initial conversion didn’t work

Found it. Turns out that whilst I was technically correct, Inviso was practically correct (so my apologies to @Inviso). It is true that the screen is not a flat piece of paper, but if you think of it as a thick piece of paper then the analogy - whilst a bit stretched - is okay: if you draw too high or too low then it doesn’t get rendered. The thickness of this piece of paper is … not very thick, particularly when compared to the size of the screen: it is +/-10. My guess would be that the choice of default there dates to the times when Codea was very much a 2D system so the z-level was merely a way of stacking 2D pictures on top of each other to get them to show in the right order (much as scenery in the early days of animation). Now that we have true 3D handling of coordinates, this default is a bit meagre.

Increasing it with your code produced points on the sphere. To increase it, put the following line at the start of the draw() function (before the translate):

ortho(0,WIDTH,0,HEIGHT,-WIDTH,WIDTH)

Actually, what I did was to shift the lineLength calculation to the start of the draw() function and do ortho(0,WIDTH,0,HEIGHT,-lineLength,lineLength) but the above does it with minimum changes to your code.

Then it works.


Some comments on your code. There’s a lot of redundancy there. I know you were mainly just copying from Processing, but it’s always worth looking to see how to modify things a little so that copying isn’t a “cut-and-paste” but is “cut-and-paste-and-understand”. There are many statements that don’t actually do anything: all the pushMatrix() and popMatrix() commands can go, the stroke command that is actually used (the second) should be at the start of the draw() function (and the first removed). I don’t know if smooth() has an effect on points (try it), ditto strokeWidth() (actually, I don’t know what colour is used by point - experiment - so stroke()s might be not used at all here). The computation of lineLength should be shifted to the setup() function.

as far as i know, point is an ellipse with a defined size…
so the stroke etc. do something, while i was playing with the code at some point i had gray dots with green stroke around…

Hi Guys,

Thanks for the help - this has really been useful. I learnt a lot from this.

The reasons behind this were primarily to learn about 3D a la ‘Old School’ approach so that I could understand what was involved. I found a neat precedent which I thought I would try to translate - HTML5 canvas to Lua:

http://www.bitstorm.it/blog/en/2011/05/3d-sphere-html5-canvas/

So I started to play around and looked for alternatives to building up spheres, one of which I posted earlier.

I have now virtually finished, not quite still a few bugs in there but I decided to slow down on this and pursue other projects.

Latest code here:

-- A translation of the javascript from Guido D'Albore by Bri_G
-- reference http://www.bitstorm.it/blog/en/2011/05/3d-sphere-html5-canvas/
-- with help from Inviso and Andrew Stacey on the mechanics
-- set up for Love2D too - remove the comment marks
--[[ if require ~= nil then
     require("loveCodea")
     require("Polar")    
 end --]]

function setup()
    -- tested in the portrait screen mode
    displayMode(FULLSCREEN)
    watch("drwTime")
    pts = { x = {}, y = {}, z = {}}
    rotation = 0
    distance = 0
    Speed = 1
    z = 0
    t = 0
    fps = 0
    StepsV = 36
    degs = 360/StepsV
    midX = WIDTH/2
    midY = HEIGHT/2
    font("Georgia")
    fontSize(20)
	-- call to routine to draw the spheres
    Polar:init(16)
	-- index the array - initialise
    index = 1
	-- outer circle then front and back loops in 10 deg increments
    for i = 0, 360, degs do
        for direction = 1, -1, -2 do
			for a = 10, 180, degs do       
				pts.x[index] = math.cos(math.rad(a)) * math.cos(math.rad(i)) 
				pts.y[index] = math.sin(math.rad(a)) * math.cos(math.rad(i))  
				pts.z[index] = math.sin(math.rad(i)) * direction
				index = index + 1
			end
        end
    end
end

-- This function gets called once every frame
function draw()
    translate(midX, midY)
    -- This sets a dark background color 
    background(0, 0, 0, 250)
    for display = 1,2 do
	-- loop twice to get front and nack hemispheres
        for i = 1, index - 1 do
        
            rotateX(i, rotation)
            rotateY(i, rotation)
            rotateZ(i, rotation)
            -- modified call to adjust rotational movements
            x = projection(pts.x[i], pts.z[i], 100, distance)
            y = projection(pts.y[i], pts.z[i], 100, distance)
            -- first pass on loop draws the back hemisphere, second the front
            if pts.z[i] <= 0 and display == 1 then
                Polar:draw(x, y, pts.z[i])
            elseif pts.z[i] > 0 and display == 2 then
                Polar:draw(x, y, pts.z[i])
            end
        end
    end
	-- dictates the intial forward movement and all rotational movements
    rotation = rotation + math.pi/360
    if distance < 24000 then distance = distance + 400 end
    fill(81, 232, 27, 255)
    text("Thanks to Guido D'Albore for the precedent",100,-350)
    text("plus Inviso and Andrew Stacey for their help", 100, -400)
end

function rotateX(pt, rads)
    y = pts.y[pt]
    pts.y[pt] = (y*math.cos(rads))-(pts.z[pt]*math.sin(rads))
    pts.z[pt] = (y*math.sin(rads))+(pts.z[pt]*math.cos(rads))
end

function rotateY(pt, rads)
    x = pts.x[pt]
    pts.x[pt] = (x*math.cos(rads))-(pts.z[pt]*math.sin(rads))
    pts.z[pt] = (x*math.sin(rads))+(pts.z[pt]*math.cos(rads))   
end


function rotateZ(pt, rads)
    x = pts.x[pt]
    pts.x[pt] = (x*math.cos(rads))-(pts.y[pt]*math.sin(rads))
    pts.y[pt] = (x*math.sin(rads))+(pts.y[pt]*math.cos(rads))   
end

function projection(xy, z, zOffset, distance)
    return((distance*xy)/(z-zOffset))
end

for the main routines with the Polar.lua class below:

-- Lua routing for drawing reflective spheres
-- by Bri_G

Polar = class()

function Polar:init(w)
    -- you can accept and set parameters here
    self.bigrad = w or 20
    self.smallrad = self.bigrad * 0.4 or 8
    self.colour = color(0, 255, 55, 255)
    self.shine = color(247, 247, 247, 228)
    self.shaded = color(69, 100, 66, 255)
end

function Polar:draw(x,y,z)
    -- Codea does not automatically call this method
    local offset = self.bigrad/6
    pushMatrix()
    pushStyle()
    noStroke()
    if z < 0 then
        fill(self.shaded)
        ellipse(x, y, self.smallrad, self.smallrad)
    else
        fill(self.colour)
        ellipse(x, y, self.bigrad, self.bigrad)
        fill(self.shine)
        ellipse(x - offset , y + offset, self.smallrad, self.smallrad)
    end 
    popStyle()
    popMatrix()
end

function Polar:touched(touch)
    -- Codea does not automatically call this method
end

I’ve also put the code in a gist on Github:

https://gist.github.com/2890949

I didn’t appreciate the links between distance and sphere width. The sphere I was constructing was a unit cell and as a result was lost over the horizon. When I corrected the sphere was there. Left it as a unit cell (didn’t multiply by radius/diameter) as I wished to use the point locations (pts.z[i]) as an index for front and back of the y plane through the sphere to enable easy depth. Wow, when the penny dropped on that I had to have a quick Guiness!!!

Thanks again for your help.

Bri_G

p.s if anyone can suggest how to get round the bugs please post them up.

:slight_smile:

Hi All,

Here’s a video:

http://www.youtube.com/watch?v=TxcDH-cyk5w

Bri_G

:slight_smile:

Hehe, cool… I’m mentioned in the credits :smiley:

Credit where credit’ due Inviso. Thanks for your help.

Bri_G

:slight_smile:

Is the point() function an undocumented feature of Codea? It does not come up on autocomplete or lookup.

@mpilgrem it is undocumented. I’ll document it and add it properly in a future release. It was initially supposed to be cut, but it does seem useful.