Skip to content

3D Skybox

Jonas Mortensen edited this page Feb 7, 2020 · 28 revisions

This demo showcases how Camera Stacking can be used to draw a 3-Dimensional Skybox which is used to improve visual fidelity of the unreachable areas of a scene.

  • Can be found at _CompletedDemos/3DSkybox/3DSkybox.unity
  • Uses Camera Stacking which is part of the URP Package
  • Different cameras for creating the illusion of grand scale

A 3D Skybox is a miniature "subscene" residing outside the bounds of the playable area. It is rendered behind the playable area to create the illusion that the game world is much larger than it actually is. Compared to only having a 2D skybox, the elements in the 3D skybox have the advantage of being rendered in real time and can therefore contain animations, particles etc.

The Setup

Configuring Cameras

The scene has one player camera, and one camera for each 3D skybox. In the common case, a single 3D skybox is enough to achieve the desired effect. In the space scene example however, since distances are so big, an additional camera has been created to render a 3D skybox with objects that are very far away (stars). This gives three cameras. One for rendering the player, one for rendering the planets, and one for rendering both the stars and a 2D skybox:

The camera stack list on the base camera determines the order which the overlay cameras should be rendered in (top to buttom). This intuitively means that the skybox furthest away should be the base camera, and that the planets and player should be drawn on top as overlay cameras. This is however not ideal for performance as any stars blocked by a planet, or planets blocked by the player, will be drawn regardless. Therefore, we would like to be able to draw the closer objects first. This is achieved by having a different render pipeline for each camera. Each render pipeline will override the stencil buffer such that the overlaying camera does not draw on top of what is already there.

Player Camera

The player camera render type is set to Base and is assigned the 3dSkyBox_Ship render pipeline. The background will be drawn by another camera and should be set to Uninitialized. The stack is set up such that planets are drawn after the ship, and the stars are drawn last:

The render pipeline is setup to write "1" into the stencil buffer:

  • Default Layer Mask is set to ignore the Skybox layer as it will be drawn later.
  • Stencil is overridden to contain a value of 1 in pixels where the ship has been drawn. This is used to determine where the planet camera should draw planets.

Planet Camera

The planet camera render type is set to Overlay and is assigned the 3dSkyBox_Planet render pipeline. Which overrides the stencil settings:

  • Tests whether stencil buffer value is equal to zero
    • This will discard pixels already drawn by the player camera.
  • Inverts the stencil value
    • This will mark the newly drawn planets with non-zero stencil values.

Star Camera

The star camera render type is also set to Overlay and is assigned the 3dSkyBox_StarBox render pipeline. The render pipeline overrides the stencil settings and also draws a sky box:

  • Tests whether the stencil buffer value is equal to zero
    • The previous two cameras ensured non-zero values on pixels that should not be overdrawn.
  • The SkyboxRenderFeature simply adds a DrawSkyboxPass to the pipeline at the AfterRenderingOpaques event.

The Skybox Script

When the player flies around in the space ship, the planets and stars will stand still since their cameras aren't rotating with the player. This can be solved using a simple script which will be put on the skybox cameras. The script will have a reference to the player camera and, each frame, make sure that their rotations align: transform.rotation = playerCam.rotation

Since the position of the skybox cameras is not changing, no parallax will be visible in the skybox when the player moves. To solve this we get the start position of the skybox camera in start() and keep it. Using a float variable proportionality we set the position of the camera each frame to be startPos + playerCam.position * proportionality. The lower the proportionality the less that skybox camera moves and the bigger the skybox will seem. In the space example the proportionality is 0 for the star camera and 0.0002 for the planet camera. This means that the stars will seem infinitely far away, and the planets will seem 5000 times larger than they actually are in the scene. If a non-zero proportionality is used, it is important to have boundaries for the playable area. Otherwise the player will be able to move up close to (and through) the sky box, breaking the illusion.

In the picture the closer planet is being clipped by the near clipping plane of the planet skybox camera because the player has been allowed to freely move too close to it.

Clone this wiki locally