Planet simulation (video teaser: height and shadows)

Hi everybody. I’ve made this little planet simulation. It has about 60000 triangles but still runs 55 fps on ipad1!
I never though i could ever do such a 3D animation. Thank you Simeon for making Codea so simple and intuitive to program!

Wow that looks amazing, are you the posting source code? (sorry I’m a source code junkie)

Looks very good. How did you do the shading? Did you use two textures, one for the structure and one for the shadow and overlay two spheres? Because calculating the lighting color for each vertex in real time for 60k triangles would not work with 55 fps.

Looks fantastic @Jmv38. I’m pretty amazed by the 3D stuff you and others have been coming up with lately.

The dark rim around each planet would suggest two spheres.

.@dalorbi i think i’ll post the source when it is cleaned up.

@kilamMalik Andrew Stacey is ‘‘eye of the tiger’’! I’ll try to remove the dark rim by some trick. The problem is that if i put the shadow sphere very close to the inner sphere, then i get blinking pixels when the shperes are too far - too small (rounding errors in the system i assume). I then adjust the shadow sphere radius in real time so it is ‘‘not too close’’, but i get the dark rim

thats called z-fighting: each pixel has a z depth on the screen (not the z coordinate in your world, but z in the screen coordinates) to find out if it is before or behind other pixels, it compares the pixel that gets drawn with the depth in the z-buffer. but the z-buffer only has a limited resolution. so when the two spheres are too close, you get this problem. There are two options you can try:

  1. Whats the near and far values of your camera? thats where the z-buffer lies. that means, the closer near and far are, the closer can your spheres be. near and far should be as closely as possible describe your maximum extents. e.g., when your whole scene has a size of 1000, but your far value is 10000, then you loose a lot of resolution. so this could minimize the black rim.

  2. in standard opengl there is something called polygonoffset. you can tell an object to always add something to the z value before comparing it to the zbuffer. e.g. you first draw the base sphere, then set the polygon offset and draw the shadow sphere with exactly the same size. now the shadow sphere has no more z fighting. i have seen, that there is a function called zlevel in codea. i havent tried it yet, but maybe it does the same?

sorry if this is confusing… maybe you lookup z fighting on wikipedia additionally :slight_smile:

You know, if space was… black, perhaps, I think you’d not see the shadow edges.

Very cool stuff, @Jmv38!

.@KilamMalik thanks for the hints. 1/ i will try to do this. I didn’t know far and near were the key, but that makes sense. 2/ i’ve tried to do this ‘‘by hand’’, just by shifting the shadow sphere towards camera origin, but because of perspective effects, the shadows also shifts in the visual plane and the 2 spheres are no exactly superimposed. So it would be great if zlevel would work. I’ll check.
@Mark right, i came to the same conclusion. I’ll try that too. Thanks.

if zlevel works and you can draw two spheres of same size you could also think of a third sphere which is a bit larger to show the atmosphere. make the texture transparent at most places, but with a light reflection at one point. then you rotate the light reflection where you would see it.

.@KilamMalik just tried zLevel: actually it seems designed for 2D: it simply moves the object along the z axis by the specified amount. So it doesn’t hepl here, because we are in 3D.

looks brilliant @Jmv38

So maybe it helps to work with the near / far. also, i would not shift the sphere towards the camera like you wrote, but give it a larger radius. because when you only move it, the artefacts will be stronger at the edge of the sphere, as the triangles are then closer there.

I wrote this tutorial on planet simulations.

The fps is always above 50 fps (slow down is due to recording)

The code is there in a zip file. Feel free to use and improve it!

This is the codea directory for those who have the jailbreak:

And all in one zip file for the others:

And for those who cannot do unzip the txt file:

Let me know your feedback.

Fantastic job. I am new to Codea this week, bu a long time programmer. I just downloaded the “tutorial.” Wow!

Thank you for your tutorial. I thought you were a 3D expert.

This is fantastic!

Those who have downloaded the code can replace step10 function by this one: it adds a nice background to universe. Now it looks really cool.

function Tutorial:step10()
    url1 = ''
    url2 = ""
    url3 = ""
    if self.ready == false then
        self:print("###########  STEP 10  ###########")
        self:print("Finally we can add some other spheres:")
        self:print("a small one, the moon to turn around our earth (too fast and too close...)")
        self:print("and a very big one, to make the universe background")
        self:print("(sorry for the asteroid, i couldn't find a better image on the web")
        self:print("and i wanted it to be available for everyone without downloads, so i used what i found)")
        local sunDir = vec3(-1,0.3,0)
        local color1 = color(255, 255, 255, 255)
        planet1 = Sphere({  
            nx = 80, ny = 40 ,            -- mesh definition
            meshOptimize = true,           -- optimize mesh for sphere
            c1 = color1 , c2 = color1 ,    -- mesh colors
            cx=0, cy=-50, cz=0  ,         -- sphere center    
            r = 100      ,         -- radius of the sphere
            rotTime1 = 30 ,   -- rotation time in s
            url = url1,        -- texture image url
            hflip = true,    -- to flip image horozontally
            lightDir = sunDir,   -- a vec3 pointing to the sun
            shadowRatio = 1.02,    -- the ratio of radius of shadow sphere to sphere
        local color2 = color(223, 211, 138, 255)
        moon1 = Sphere({  
            nx = 60, ny = 30 ,            -- mesh definition
            meshOptimize = true,           -- optimize mesh for sphere
            c1 = color2 , c2 = color2 ,    -- mesh colors
            cx=150, cy=0, cz=0  ,         -- sphere center    
            r = 20      ,         -- radius of the sphere
            rotTime1 = 30 ,   -- rotation time in s
            url = url2,
            lightDir = sunDir,   -- a vec3 pointing to the sun
            shadowRatio = 1.02,    -- the ratio of radius of shadow sphere to sphere
            rotTime2 = 30,
            cx2=0, cy2=0, cz2=0,    -- center of rotation 2
            ax2=0, ay2=1, az2=0,    -- rotation axis
        local color2 = color(255, 255, 255, 255)
        background1 = Sphere({  
            nx = 40, ny = 20 ,            -- mesh definition
            meshOptimize = true,           -- optimize mesh for sphere
            c1 = color2 , c2 = color2 ,    -- mesh colors
            cx=0, cy=0, cz=0  ,         -- sphere center    
            r = 2000      ,         -- radius of the sphere

            url = url3,
        self.ready = true
        --     change camera position
        cam.camX, cam.camY, cam.camZ = 200, 100, 300
    else background1:draw() planet1:draw() moon1:draw() end

Wow, that background really makes a difference.

I love using the 2nd sphere as a shadow - that’s a problem I tried (unsuccessfully) for a long time to solve with my procedurally generated planets. I may need to revisit that now.

Consider making the maximum opacity less than 100% - so the night side still shows up dimly, to reflect earth and star shine.