Planet simulation (video teaser: height and shadows)

Jmv38Jmv38 Mod
edited October 2012 in Examples Posts: 3,295

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!

«1

Comments

  • Posts: 182

    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.

  • SimeonSimeon Admin Mod
    Posts: 5,024

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

  • Posts: 2,161

    The dark rim around each planet would suggest two spheres.

  • Jmv38Jmv38 Mod
    Posts: 3,295

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

  • Posts: 1,255

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

    Very cool stuff, @Jmv38!

  • Jmv38Jmv38 Mod
    Posts: 3,295

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

  • Jmv38Jmv38 Mod
    Posts: 3,295

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

  • Posts: 563

    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.

  • Jmv38Jmv38 Mod
    Posts: 3,295

    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:

    http://db.tt/iNOT5ICT

    And all in one zip file for the others:

    http://db.tt/MctgZxGJ

    And for those who cannot do unzip the txt file:

    http://db.tt/y9gmOOwK

    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!

  • Posts: 76

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

  • Posts: 735

    This is fantastic!

  • Jmv38Jmv38 Mod
    edited October 2012 Posts: 3,295

    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 = 'http://www.evl.uic.edu/pape/data/Earth/2048/PathfinderMap.jpg'
        url2 = "http://web.cortland.edu/flteach/civ/davidweb/images/moonb.jpg"
        url3 = "http://www.sacredart-murals.co.uk/images/mural-rooms/TV-Space-Room/asteroid-crater-moon--sun.jpg"
        if self.ready == false then
            self:clearPrint()
            self:print("")
            self:print("###########  STEP 10  ###########")
            self:print("")
            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
    end
    
  • SimeonSimeon Admin Mod
    Posts: 5,024

    Wow, that background really makes a difference.

  • BortelsBortels Mod
    Posts: 1,557

    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.

  • Jmv38Jmv38 Mod
    edited October 2012 Posts: 3,295

    .@Bortels i am happy you looked at this post! This is your discussion of this spring and the apparent dead end you ran into that triggered me into writing this planet simulation. That would be great if you restarted your project, you had generated so much enthousiasm and hope among this community.

    Concerning opacity it is quite easy to modify. If you dowloaded the code you can replace the sphere init and shadows function by these ones. I have added a shadowDepth parameter, equal to 0.2 (20%) by default.

    Note that when there are several spheres with textures, the fps start to decrease. It should be possible to recover the fps by coloring the vertices from the texture image, instead of stetting it as a texture. The drawback would be a less accurate surface, but i would be ok when one is far from the planet, and one could switch to the texture mode when the spaceship comes close to the planet. Is it a feature you want me to implement?

    function Sphere:init(input)
        -- spatial position of sphere
        self.cx = input.cx or 0
        self.cy = input.cy or 0
        self.cz = input.cz or 0
        -- angular position of sphere, defined by angles around x,y,z axis
        self.ax = 0
        self.ay = 0
        self.az = 0
        -- sphere radius and rotation
        self.radius = input.r
        self.tRot = input.rotTime1
        -- sphere rotation 2
        self.tRot2 = input.rotTime2
        self.cx2 = input.cx2 or 0   -- center of rotation 2
        self.cy2 = input.cy2 or 0
        self.cz2 = input.cz2 or 0
        self.ax2 = input.ax2 or 0   -- axis of rotation 2
        self.ay2 = input.ay2 or 1
        self.az2 = input.az2 or 0
        -- mesh definition
        self.nx = input.nx    -- number of triangles in x
        self.ny = input.ny    -- and in y
        self.c1 = input.c1    -- 2 color() objects, to see the triangles
        self.c2 = input.c2
        self.optimized = input.meshOptimize    -- boolean
        -- sphere decoration
        self.url = input.url    -- texture as a url (text)
        self.hflip = input.hflip    -- to flip image horizontally
        if input.lightDir then
            self.lightDir = input.lightDir:normalize()   -- a vec3 pointing to the sun
        end
        self.shadowRatio = input.shadowRatio or 1.05   -- close to 1.05
        self.shadowDepth = input.shadowDepth or 0.2    -- an number between 0 and 1, close to 0
        
        -- create mesh and colors
        local vertices,colors,tc = {},{},{}
        if self.optimized then
            vertices,colors,tc = self:optimMesh({ nx=self.nx, ny=self.ny, c1=self.c1, c2=self.c2 })
        else
            vertices,colors,tc = self:simpleMesh({ nx=self.nx, ny=self.ny, c1=self.c1, c2=self.c2 })
        end
    
        -- if a radius is given, warp to a sphere
        if self.radius then 
        vertices = self:warpVertices({
                verts=vertices, 
                xangle=180, 
                yangle=180 
            }) end
    
        -- create the mesh itself
        self.ms = mesh()
        self.ms.vertices = vertices
        self.ms.colors = colors
        
        -- add the texture from internet
        if self.url then 
            self:load( self.url ) -- this will not be instantaneous!
        end
        self.ms.texCoords = tc
        
        -- add some shadows
        if self.lightDir then self:shadows() end
    
    end
    
    function Sphere:shadows()
            self.ms2 = mesh()
            local dir = self.lightDir
            local vertices2,colors2 = {},{}
            local d = 0
            local dmax = 255*(1-self.shadowDepth)
            for i,v in ipairs(self.ms.vertices) do
                vertices2[i] = v
                d = v:dot(dir)
                d = 128 - 4*(d-0.1)*128 
                if d<0 then d=0 end
                if d>dmax then d=dmax end
                colors2[i] = color(0,0,0,d)
            end
            self.ms2.vertices = vertices2
            self.ms2.colors = colors2
    end
    
  • BortelsBortels Mod
    Posts: 1,557

    Ah, I wish I had more time (My work tends to be not-so-busy, then very busy - and I'm in a very busy phase) - I'd like to dig into this again, but for now I have to file your neat trick for shading for another day. Bravo, by the way - it seems so simple in hindsight, but I spent many hours trying to work out a cheaper way to light than recoloring everything each frame...

    If we're lucky, changes upcoming to Codea may let us do some "real" lighting; I'm keeping my fingers crossed.

  • Jmv38Jmv38 Mod
    Posts: 3,295

    I hope too that CODEA will include more built-in real-time way to do shadows, because this trick has some drawbacks, that can be managed, but with some efforts though.

    i'll maybe continue to work along the road to starwars, but it will be very slow, unless someone wants to join me pulling the load. My next step should be to integrate Nat controllers to the scene.

  • Jmv38Jmv38 Mod
    Posts: 3,295

    Some news: i've added height map management and night map management.

  • Jmv38Jmv38 Mod
    Posts: 3,295

    Hello everybody. As I went on in my 3d eperiments, if felt the need to gather everything in a signle software package, '3d workbench' where i can try and mix, re-use, things. So i made the following package. It's not really a tutorial, but there are many comments available when you touch 'info', so it is a little bit of a tuto. I have not integrated all my experiments yet (you'll see many items in the menus are disabled), but it is already interesting enough to share (I think). I'll post updates as I integrate things. The most interesting things in this code, from my point of view, are:

    - many menus, all real time.

    - total control of view (3 sets of real time contollers)

    - a 'hand made' multithreading: to be continuously real time from the player's perspective, i have designed a 'jobStack' class which execute CPU intensive tasks by small slices, during each draw().

    - asynchronous loading of internet images is managed

    - the design is expandable (i can add operations without getting lost), and the operations can be combined.

    Here is what it looks like (as usual, the 22fps is due to recording, it is really 50-60fps)

    You can have the code in a txt file (3000 lines) frm my dropbox:
    http://db.tt/YDOAoNJf
    As usual, i don't know how to track the downloads, so if you download the code, please just leave a brief comment (even 1 word, like 'thanks' is enough), so i know how many people are interested.
    For the videos it is easier, because Youtube indicates the number of view.

  • Posts: 563

    Very impressive @jmv38 - I'm not at the 3D stage yet but when I get there I will certainly check out what you have done.

  • Posts: 115

    Very nice. Looking forward to checking it out.

    Thanks for sharing.

  • Posts: 384

    Wow, gotta say this is impressive. What accounts for the slices in the transparent globe bit?

  • Jmv38Jmv38 Mod
    edited October 2012 Posts: 3,295

    Thanks @all. @Fred: the slices is the transparent globle are un unwanted 'bug' in tranparency effect: transparent meshes seem to always have a partially opaque side: 'partially' because it is this side is transparent to other meshes drawn before, but opaque to some parts of the mesh itself. In general, transparent objects are transparent to objects drawn before, but opaque to objects drawn after. This is surprising because the bug is only for transparency, not for occlusion.

    My assuption to explain this: the transparency is managed only once, when the triangle is drawn on the screen buffer. When the pixels of next triangles are drawn, the OS checks if they are visible (with an internal Zmap image i suppose), so he knows if they are visible or not (occlusion). So if the pixel is below the current Zmap level, it is not drawn (opacity), while we would like it to be drawn but mixed with the already present color (transparency). But to work as desired, the Zmap would have to be very complex: it should keep track not only of highest level, but also of the zlevels and colors of all successive drawing at each pixel location! This would be very memory consuming! It is probably why they don't do it.

    So it is (i think) a CODEA or IOS or GraphicProcessor bug. Can we take this as a fact and manage it? It would mean /1/ managing zlevels of objects ourself, by splitting them in sub-meshes of relatively flat regions, and drawing objects in the good order, depending on the viewer position... Too complex i think. For a game it is probably feasible to /2/ limit the object rotation wrt the viewer within limits where the transparency works correctly.

  • Posts: 2,161

    Your assumption is correct and it is OpenGL that is responsible, hence no likelihood of change, sadly.

  • First, this is really cool what you made here :-)

    For the transparency, there is another option to make it look better, but I dont know if this can be used in Codea: When drawing transparency with OpenGL, you normally switch off the DepthBuffer writing (thats what you called zMap). Then all back faces are also drawn. This is not perfect, as the correct drawing order back to front is still needed to make it look correct when the colors are mixed. But at least it then renders all triangles. And it looks correct for transparency higher than about 70% (which is my experience). When drawing mixed transparent and opaque objects you first render the opaques with zBuffer writing enabled and then the transparent with zBuffer writing disabled.

    While writing this I got another idea, which works for convex objects: To render back to front without sorting you would first render the back sides (inner side) of the sphere and then the front sides. In OpenGL this can be set with glCullFace, but I think also this is not available in Codea. You just need to define the triangles correct in counter clockwise vertex order.

    Both options dont need any zsorting so it is still very fast.

    But as Codea will have Shaders soon, this could get possible. I'm a standard OpenGL programmer, so I dont know much about shaders yet, but it should be possible to decide front and back face, maybe also depth writing... or if somebody from Codea reads this, it could maybe be taken into account to add it if it doesnt work with shaders :-)

  • Jmv38Jmv38 Mod
    Posts: 3,295

    Thank for the tips @KilamMalik. Any comment on this problem @Simeon?

  • SimeonSimeon Admin Mod
    Posts: 5,024

    .@Jmv38 that's a really impressive demo you have there.

    Good thoughts, @KilamMalik. I will think about providing interfaces to some of the lower-level OpenGL functions (depth function, enable depth testing, culling, and so on).

    For more information about this issue, here is the OpenGL wiki about transparency sorting: http://www.opengl.org/wiki/Transparency_Sorting

    As you can see from that article, even sorting polygons by Z-value is not enough to get error-free transparency.

  • Jmv38Jmv38 Mod
    Posts: 3,295

    Thank you @simeon.

  • Jmv38Jmv38 Mod
    Posts: 3,295

    Video teaser of my latest extensions: heights and shadows (static)

  • Posts: 25

    Hi @Jmv38, simply Amazing!

  • SimeonSimeon Admin Mod
    Posts: 5,024

    .@Jmv38 the exaggerated height map reminds me of the Spore planets. Looks great!

  • Jmv38Jmv38 Mod
    Posts: 3,295

    Thanks @yelnats & @Simeon

  • Jmv38Jmv38 Mod
    edited October 2012 Posts: 3,295

    Want more?

    I'll be in family next days, so i'll give you a break till monday... ;-)

  • Posts: 688

    I shall be going over your example code with a fine toothcomb, 3D is an area I'd like to get more knowledge on - many many thanks for sharing!

  • Posts: 1,255

    I hadn't looked in on this topic since the early days. Amazing progress, @jmv38! Looking forward to seeing the game that gets wrapped around this.

    Hey, @Bortels, are you still planning your space spectacular? This looks like it would fit wonderfully.

  • Posts: 502

    Nice :)

  • BortelsBortels Mod
    Posts: 1,557

    I still plan my space spectacular.

    Having said that, do keep in mind - I've been planning it for a decade now. I've actually started (and abandoned) it at least 5 different times. It is my key example of the maxim "if you want to succeed - set small, obtainable goals." - in that my vision vastly outpaces my actual ability to produce the game while keeping food on the table for the family. :-)

  • Jmv38Jmv38 Mod
    Posts: 3,295

    Some news: I recently discovered mesh.vertex(i) (.. shame on me that i didnt't notice it before :"> ), and so that i could update the mesh vertex one by one without major time loss. So i decided to recode everything using these functions. It turned out there were a lot of things to correct in my code to make it clean, and i am still in this process of recoding the existing functionnalities. Here is a video of how it looks now.

    Seeing the live updating process is nice because 1/ waiting for the update to complete is less boring 2/ it hepls to find bugs. When i'll be done in recoding, i'll add some save/load 3d objects functionnalites, and some functionnality to assemble several simple objects in complex objects, and save/load them, and then i'll try to make some simple user interface that you can include in your projects to load and use the objects you create with this workbench. Can anyone give me some advice on how to save the 3d objects? I plan to convert everything in a single image so it is easier to manipulate.

  • Jmv38Jmv38 Mod
    Posts: 3,295

    Hi @ubergober thanks for your message. I have solved the feedback problem: now i put all my code there: http://jmv38.comze.com/CODEAbis/server.php . There is a counter that shows the number of downloads for each file, so i know how many people are interested.

  • edited February 2013 Posts: 196

    . @Jmv38 oh this is very nice, can't believe I only see this now.. it seems I missed a lot of cool Codea projects in the few months I left ^^

  • Posts: 1,285

    Hi @ Jmv38,

    Being a LOTR fan and also a 3D World fan I was very interested in this.

    http://www.me-dem.me.uk/

    Have you seen it. I am using your 3D models to set up new fantasy planets and stumbled on the MEDEM package - is this the future for adventure modelling?

    Bri_G

    :-O

  • edited May 2013 Posts: 835

    (Deleted)

  • Jmv38Jmv38 Mod
    Posts: 3,295

    @Bri_G very interesting link. I wish i could run it on the ipad. Do really manage to do sthg with my messy 3d code? That would be great!

  • Posts: 1,285

    Hi @CodeaNoob,

    Just seen your reply, checked the link so I know the site is up. Have the editors deleted your comment or has it been moved into another thread?

    Bri_G

    =;

  • Posts: 1,285

    Hi @Jmv38,

    The video looks awesome, I'll keep playing with your code - built a few new textures but they are a little crude. Could really do with a fractal planet scape mapper, bump mapper and some way of eroding/ageing the initial planet textures.

    The other thing I'm looking into is forming a 2D atlas style map from the texture. Whole idea to build up scenario us for use in games etc.

    Don't hold your breath, this will take me ages. Thanks for your code.

    P.s. also just discovered UDK engine, I seem to have totally lost track of the way things have moved on!!!

    Thanks,

    Bri_G

    =;

Sign In or Register to comment.