Skybox source, being updated

We’ve been prodding each other in IRC to come up with better skybox functions, so here is an early attempt by me (unsurprisingly).

Full project and source included - but expect it to shift to github and actually be updated very soon.

https://www.dropbox.com/s/2wjtz3mhjjjngbr/Skybox.zip

What you’ll see:

A menu screen that you can ignore completely, just click on a button to start it up.

And then… a skybox. Amazing, I know.

Although the interface will change and some more functionality will be added soon, you can have a quick play with what is there.

The meat is in game.lua in the skybox creation routine (starting at line 20):

[lua]function setUp( group )

    local border = 25

    skybox = skyboxClass.new{

        parent      = group,

        fov         = 90,

        xAngle      = 0,

        yAngle      = 0,

        clip        = true,

        left        = border,

        top         = border,

        width       = display.contentWidth - border * 2,

        height      = display.contentHeight - border * 2,

        subdivide   = 5,

        zCull       = 0.01,

–        zOffset     = 0.5,

        scale       = 400,

        images      = {

            path   = “gfx/sky”,

            suffix = “png”,

            width  = 512,

            height = 512,

        },

    }

end[/lua]

Expect or possibly pray for the following options in the future:

  • Specify the field of view in degrees.
  • Enable / disable individual faces (for example remove top and bottom if you can’t ever look up and down).
  • Rotate and flip individual faces (in case they import in the wrong orientation).
  • Snapshot version (to allow filters)
  • Cloud layers (flat planes with a texture applied that you can scroll and what-not)

Options are:

  • parent - optional. What this group / container gets inserted into.
  • fov - not working - hah!
  • xAngle - optional. The starting x angle. Defaults to 0.
  • yAngle - optional. The starting y angle. Defaults to 0.
  • clip - optional. Whether this uses a container (true) or just a group (false). Defaults to false.
  • left - optional. Where the left edge is. Defaults to 0. *
  • top - optional. Where the top edge is. Defaults to 0. *
  • width - optional. How wide the view is. Defaults to display.contentWidth. *
  • height - optional. How tall the view is. Defaults to display.contentHeight. *
  • subdivide - optional. How many times each face is subdivided to help with culling. Creates subdivide * subdivide cells per face, so there aren’t many reasons to set it higher. Defaults to 4.
  • zCull - optional. At what values a cell gets culled. Any corner nearer than this value won’t be drawn. Defaults to 0.1
  • zOffset - optional. How far back the whole skybox gets pushed from the camera. Can be used for a few odd effects, but likely you aren’t gonna want to touch this. Defaults to 0. Note that the skybox itself is a cube 2 units wide (to give you some idea of values).
  • scale - optional. How much to scale everything drawn on screen. Higher values gives a lower field of view. Eventually this will be replaced by the actual fov value above. Defaults to 500.
  • images - required. A table that contains the following values:
    • path - required. A path from the project root. It also needs to include the ‘stub’ of the imageset filename.
    • suffix - optional. What type of images - png or jpg. Defaults to jpg.
    • width - required. How wide the images are.
    • height - required. How tall the images are.

* Note that these limits are only respected when clip is set to true (IE using a container). If just using a display group, then the skybox can and likely will be drawn outside of these boundaries.

How to set up the images:

The project contains the following 6 files:

  1. gfx/sky-back.png
  2. gfx/sky-down.png
  3. gfx/sky-front.png
  4. gfx/sky-left.png
  5. gfx/sky-right.png
  6. gfx/sky-up.png

These naturally represent the individual faces of the skybox.

The -back, -down, -front etc suffixes are required and must not be changed.

To use these files, in the skybox creation function you would use the following path:

path = “gfx/sky”

and the following suffix:

suffix = “png”

The file names are automatically generated from these by inserting the relevant direction indicator into the filename.

I can’t understand why this didn’t click with me when I was playing with quadrilateral distortion!

I used to be very active in creating 360 degree VR panoramas (http://panoramas.bergmark.com [not mobile friendly]), where you just need a camera, a VR head plus some software to stitch the images together. Later you output to different viewer formats where Quicktime’s QTVR format actually outputs 6 cube faces.

You can also use applications like Bryce to create fractal landscapes and then convert those to 6 cube faces.

This is really cool, but again: why is there always so much fun stuff to look into, but so little time?

Do you also have cylindrical source images? Cylinders are my next trick.

I wasn’t the first to do skyboxes here anyway, Lerg has that honour and in fact it was one of his entries in the compo, but we’ve spent a fair amount of time chatting about it in IRC and it is actually one of the more useful things that the 2.5D can do, so we are just sorta prodding each other to improve it :slight_smile:

Well, I was hoping to make progress but I have apparently run into a bug in the latest daily build from… drawing distorted images in a group… The weird thing is it works in containers, so I am sorta scratching my head here. I’m off to create another thread here to see if anyone else can reproduce it: http://forums.coronalabs.com/topic/41810-skybox-draws-properly-in-container-but-in-display-group-isnt-drawn/

It’s easy to create a cylindrical source from an equirect. The “problem” with cylindrical is that there’s not much of up/down camera movement that can be done since the max verticle fov is not 180.

On Mac there’s a fractal landscape generator called TerraRay. I’m thinking of getting it from the Mac App Store. I think it’s only 10 bucks, but seems to be quite competent.

The cylindrical method more stems from 2 things:

  1. Various games don’t need the up and down functionality and probably would just actually manually create a ‘background’ rather than from a proper VR proggie and

  2. My lack of up-to-date-ness with actual panoramic functionality. A long time ago I wrote a partial cylindrical panoramic bit of code for a client who was tired of the quicktime VR plug-in being the only one with the (non-extensible) features. It was actually my proudest achievement at that point as I did it in lingo, and it had all the stuff you’d expect (zoom in, zoom out, limits on scrolling defined by the image, hotspots) plus more (animations, layering…). Errrr right I digress. The point was that ‘back in the day’ cylindrical panoramas were actually a big deal before sky boxes came onto the scene, and I simply wasn’t sure if they were still in use.

So really, seeing as how you have far more knowledge than me about this now, I was wondering - does anyone actually use cylindrical ones?

I guess Cylindrical has its uses, but everything is going full 360 nowadays, even video.
But as you say, if you don’t care about looking up or down Cylindrical is the way to go.

Update:

Latest update features:

  1. Can now be a group, container or snapshot.
  2. More options for specifying the faces of the skybox (including omitting faces you don’t want).
  3. No longer does a full redraw if the angles don’t change (unless you wish to force it).

Source:  https://www.dropbox.com/s/2wjtz3mhjjjngbr/Skybox.zip

Android build:  https://www.dropbox.com/s/limwh64dfcd75et/Skybox.apk

How to create a skybox:

Step 1: Include the skybox lib:

[lua]local skyboxClass = require( “libs.skybox” )[/lua]

where ‘libs.skybox’ is the path to my library, wherever you installed it.

Step 2: Create a skybox object:

At its most basic you could do the following:

[lua]local skyboxObj = skyboxClass.new{

   images = {

      file = “sky”,

      width = 512,

      height = 512,

   }

}[/lua]

This is the minimum to get up and running and would assume the following 6 images are all located in the root of your project folder and each are 512 x 512 pixels in size:

  1. sky-front.jpg
  2. sky-back.jpg
  3. sky-left.jpg
  4. sky-right.jpg
  5. sky-up.jpg
  6. sky-down.jpg

There are various parameters that you can change or supply, broken down into various related functionality:

General object properties:

  • objType = What type of object is used as the base. This value can be either ‘group’, ‘container’, or ‘snapshot’. Defaults to ‘group’.
  • parent = A group (or similar) that this skybox object will be inserted into automatically upon creation. Defaults to nothing.

View properties:

  • fov = Field of view, measured in degrees along the horizontal axis. Defaults to 90.
  • xAngle = Starting X angle. Defaults to 0.
  • yAngle = Starting Y angle. Defaults to 0.

Window properties*:

  • left = Left edge of the window *
  • top = Top edge of the window *
  • width = Width of the window *
  • height = Height of the window *

* Only containers and snapshots will actually clip to these values. Groups will have some of the skybox poking out, but the values used will be the same as if it were clipped.

Images properties:

The images property is a table that itself can contain various properties, including:

  • path = The optional path to where the images reside. Defaults to “”.
  • file = The optional shared root of the file name for the images. Defaults to “”.
  • extension = The optional file extension of the images. Can be “png” or “jpg”. Defaults to “jpg” if needed.
  • faces = An optional table that can either be a list of faces to include (IE any not mention are not drawn), or a table containing key/value pairs listing both the faces to include, and their file. In either case, the faces are ‘front’, ‘back’, ‘left’, ‘right’, ‘up’ and ‘down’.

Individual file names normally are built up using:

   filename = images.path … images.file … <face_identifier> … “.” … images.extension

where <face_identifier> is ‘-front’, ‘-back’, ‘-left’, ‘-right’, ‘-up’ or ‘-down’.

The exception to this is if the images.faces property is supplied as a set of key/value pairs.

In this case, for each face in this table, the filename is built up using:

    filename = images.path … images.file … images.faces[<face> ]

In this case, images.extension is appended only if set.

This last way of specifying the faces is the most powerful, and in fact can be used as an entire replacement for the general path, file and extension properties, or alternatively can be used to specify the face identifiers, if they are different from the defaults.

Examples to follow.

Miscellaneous properties:

  • subdivide = How many times to subdivide each face along both axes. This means you will end up with subdivide * subdivide cells per faces, so keep this value as low as possible. Defaults to 4.
  • zCull = At what point to cull faces based on any of their corners being closer than this value. The nearer to zero it is, the less likely you are to see holes. Defaults to 0.001.
  • zOffset = How far to push the skybox further away from the camera. Can help to remove ‘holes’, but with the added price of creating more distortion the larger the value. Ideally tweaked only as a last resort. Defaults to 0.

Optional step 3: Update the skybox object

If you wish to change the angles, then you do so using the following code:

[lua]skyboxObj:update( yAngle, xAngle )[/lua]

Where yAngle is the rotation around the Y axis (IE left and right) and xAngle is the rotation around the X axis (IE up and down).

Note that if, for whatever reason, you wish to force a redraw then simply call the :update() function without any parameters like so:

[lua]skyboxObj:update()[/lua]

Note that snapshots automatically get invalidated upon successful redraw.

If you wish to know whether a redraw call was actually processed or not, then capture the result from the :update() function - true means the skybox was actually updated, while false means it wasn’t (this happens if you call the :update() feature with the same angle values as the previous time it was updated).

[lua]local didReallyUpdate = skyboxObj:update()[/lua]

Changing the field of view dynamically:

Simply call :setFieldOfView( angle ) as follows:

[lua]skyboxObj:setFieldOfView( angle )[/lua]

where angle is a value between 1 and 170. Note that increasing the field of view may cause more errors at the edges, so always make sure you set up your skybox to work correctly under the widest field of view you intend to use.

Future features to come:

  1. Major optimisations.
  2. The ability to rotate and flip faces should the images not be correctly created.

Anything else seem needed? I was thinking about having the ability to change the sky box images dynamically, but that is just equivalent to creating a new skybox, so am not sure whether it makes sense, not to mention could get confusing as there are already (too) many image definition options.

It has now been en-github-enated:

https://github.com/Rakoonic/Skybox

I can’t understand why this didn’t click with me when I was playing with quadrilateral distortion!

I used to be very active in creating 360 degree VR panoramas (http://panoramas.bergmark.com [not mobile friendly]), where you just need a camera, a VR head plus some software to stitch the images together. Later you output to different viewer formats where Quicktime’s QTVR format actually outputs 6 cube faces.

You can also use applications like Bryce to create fractal landscapes and then convert those to 6 cube faces.

This is really cool, but again: why is there always so much fun stuff to look into, but so little time?

Do you also have cylindrical source images? Cylinders are my next trick.

I wasn’t the first to do skyboxes here anyway, Lerg has that honour and in fact it was one of his entries in the compo, but we’ve spent a fair amount of time chatting about it in IRC and it is actually one of the more useful things that the 2.5D can do, so we are just sorta prodding each other to improve it :slight_smile:

Well, I was hoping to make progress but I have apparently run into a bug in the latest daily build from… drawing distorted images in a group… The weird thing is it works in containers, so I am sorta scratching my head here. I’m off to create another thread here to see if anyone else can reproduce it: http://forums.coronalabs.com/topic/41810-skybox-draws-properly-in-container-but-in-display-group-isnt-drawn/

It’s easy to create a cylindrical source from an equirect. The “problem” with cylindrical is that there’s not much of up/down camera movement that can be done since the max verticle fov is not 180.

On Mac there’s a fractal landscape generator called TerraRay. I’m thinking of getting it from the Mac App Store. I think it’s only 10 bucks, but seems to be quite competent.

The cylindrical method more stems from 2 things:

  1. Various games don’t need the up and down functionality and probably would just actually manually create a ‘background’ rather than from a proper VR proggie and

  2. My lack of up-to-date-ness with actual panoramic functionality. A long time ago I wrote a partial cylindrical panoramic bit of code for a client who was tired of the quicktime VR plug-in being the only one with the (non-extensible) features. It was actually my proudest achievement at that point as I did it in lingo, and it had all the stuff you’d expect (zoom in, zoom out, limits on scrolling defined by the image, hotspots) plus more (animations, layering…). Errrr right I digress. The point was that ‘back in the day’ cylindrical panoramas were actually a big deal before sky boxes came onto the scene, and I simply wasn’t sure if they were still in use.

So really, seeing as how you have far more knowledge than me about this now, I was wondering - does anyone actually use cylindrical ones?

I guess Cylindrical has its uses, but everything is going full 360 nowadays, even video.
But as you say, if you don’t care about looking up or down Cylindrical is the way to go.

Update:

Latest update features:

  1. Can now be a group, container or snapshot.
  2. More options for specifying the faces of the skybox (including omitting faces you don’t want).
  3. No longer does a full redraw if the angles don’t change (unless you wish to force it).

Source:  https://www.dropbox.com/s/2wjtz3mhjjjngbr/Skybox.zip

Android build:  https://www.dropbox.com/s/limwh64dfcd75et/Skybox.apk

How to create a skybox:

Step 1: Include the skybox lib:

[lua]local skyboxClass = require( “libs.skybox” )[/lua]

where ‘libs.skybox’ is the path to my library, wherever you installed it.

Step 2: Create a skybox object:

At its most basic you could do the following:

[lua]local skyboxObj = skyboxClass.new{

   images = {

      file = “sky”,

      width = 512,

      height = 512,

   }

}[/lua]

This is the minimum to get up and running and would assume the following 6 images are all located in the root of your project folder and each are 512 x 512 pixels in size:

  1. sky-front.jpg
  2. sky-back.jpg
  3. sky-left.jpg
  4. sky-right.jpg
  5. sky-up.jpg
  6. sky-down.jpg

There are various parameters that you can change or supply, broken down into various related functionality:

General object properties:

  • objType = What type of object is used as the base. This value can be either ‘group’, ‘container’, or ‘snapshot’. Defaults to ‘group’.
  • parent = A group (or similar) that this skybox object will be inserted into automatically upon creation. Defaults to nothing.

View properties:

  • fov = Field of view, measured in degrees along the horizontal axis. Defaults to 90.
  • xAngle = Starting X angle. Defaults to 0.
  • yAngle = Starting Y angle. Defaults to 0.

Window properties*:

  • left = Left edge of the window *
  • top = Top edge of the window *
  • width = Width of the window *
  • height = Height of the window *

* Only containers and snapshots will actually clip to these values. Groups will have some of the skybox poking out, but the values used will be the same as if it were clipped.

Images properties:

The images property is a table that itself can contain various properties, including:

  • path = The optional path to where the images reside. Defaults to “”.
  • file = The optional shared root of the file name for the images. Defaults to “”.
  • extension = The optional file extension of the images. Can be “png” or “jpg”. Defaults to “jpg” if needed.
  • faces = An optional table that can either be a list of faces to include (IE any not mention are not drawn), or a table containing key/value pairs listing both the faces to include, and their file. In either case, the faces are ‘front’, ‘back’, ‘left’, ‘right’, ‘up’ and ‘down’.

Individual file names normally are built up using:

   filename = images.path … images.file … <face_identifier> … “.” … images.extension

where <face_identifier> is ‘-front’, ‘-back’, ‘-left’, ‘-right’, ‘-up’ or ‘-down’.

The exception to this is if the images.faces property is supplied as a set of key/value pairs.

In this case, for each face in this table, the filename is built up using:

    filename = images.path … images.file … images.faces[<face> ]

In this case, images.extension is appended only if set.

This last way of specifying the faces is the most powerful, and in fact can be used as an entire replacement for the general path, file and extension properties, or alternatively can be used to specify the face identifiers, if they are different from the defaults.

Examples to follow.

Miscellaneous properties:

  • subdivide = How many times to subdivide each face along both axes. This means you will end up with subdivide * subdivide cells per faces, so keep this value as low as possible. Defaults to 4.
  • zCull = At what point to cull faces based on any of their corners being closer than this value. The nearer to zero it is, the less likely you are to see holes. Defaults to 0.001.
  • zOffset = How far to push the skybox further away from the camera. Can help to remove ‘holes’, but with the added price of creating more distortion the larger the value. Ideally tweaked only as a last resort. Defaults to 0.

Optional step 3: Update the skybox object

If you wish to change the angles, then you do so using the following code:

[lua]skyboxObj:update( yAngle, xAngle )[/lua]

Where yAngle is the rotation around the Y axis (IE left and right) and xAngle is the rotation around the X axis (IE up and down).

Note that if, for whatever reason, you wish to force a redraw then simply call the :update() function without any parameters like so:

[lua]skyboxObj:update()[/lua]

Note that snapshots automatically get invalidated upon successful redraw.

If you wish to know whether a redraw call was actually processed or not, then capture the result from the :update() function - true means the skybox was actually updated, while false means it wasn’t (this happens if you call the :update() feature with the same angle values as the previous time it was updated).

[lua]local didReallyUpdate = skyboxObj:update()[/lua]

Changing the field of view dynamically:

Simply call :setFieldOfView( angle ) as follows:

[lua]skyboxObj:setFieldOfView( angle )[/lua]

where angle is a value between 1 and 170. Note that increasing the field of view may cause more errors at the edges, so always make sure you set up your skybox to work correctly under the widest field of view you intend to use.

Future features to come:

  1. Major optimisations.
  2. The ability to rotate and flip faces should the images not be correctly created.

Anything else seem needed? I was thinking about having the ability to change the sky box images dynamically, but that is just equivalent to creating a new skybox, so am not sure whether it makes sense, not to mention could get confusing as there are already (too) many image definition options.

It has now been en-github-enated:

https://github.com/Rakoonic/Skybox

Doesn’t work for me

skybox.png