=================
Creating a Skybox
=================

This walkthrough shows how to create a skybox in Visualize. A skybox is a collection of 2D textures applied to the six faces of a cube that serve as the background of a scene, creating the illusion of 3D immersion.

The skybox is built by applying textures to a cubemap. Ideally, these textures will be created from spherical panoramas (using, for example, iOS or Android camera apps that produce these images). To convert your spherical image to six different textures, use an online application such as this one: `<https://jaxry.github.io/panorama-to-cubemap/>`_. 

If you would like to see a working sample, feel free to copy and paste the full source code (provided below) into the User Code slots in either the MFC Sandbox or the WPF Sandbox, assigning ``myCanvas`` to the respective built-in ``GetCanvas()`` functions in the sandbox.

In addition, a video demonstration for the provided code is `available on YouTube <https://youtu.be/RGIrCWKw5KE>`_ (this demo was created using the MFC Sandbox).

For your convenience, here is a link to a downloadable zip file containing PNG images you can use to define your cubemap:

`Download cubemap zip file <https://downloads.techsoft3d.com/resources/cubemap_images.zip>`_

.. _0701:

7.1 Image Mapping Overview
==========================

The following images show how a spherical panoramic photograph is mapped to each face in the cubemap:

.. image:: images/07/skybox_cube_faces.jpg

.. image:: images/07/skybox_example_faces.jpg

*Textures on faces of cubemap*

Each face of the cube represents a plane at the extent of each of the three axes: positive x, negative x, positive y, negative y, positive z, and negative z. A texture is applied to each of these faces.


.. _0702:

7.2 Importing Images
====================

To assign our textures to the faces of the cubemap, we'll need to import the six images into Visualize using an ``HPS::Image::ImportOptionsKit``.

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_skybox.cpp
		   :start-after: //! [00700_skybox_import_images]
		   :end-before: //! [00700_skybox_import_images]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_skybox.cs
		   :start-after: //! [00700_skybox_import_images]
		   :end-before: //! [00700_skybox_import_images]
		   

.. _0703:
		   
7.3 Define the Cubemap in a Portfolio
=====================================

Once the images have been imported, we'll add them to a ``HPS::Portfolio`` object and call ``HPS::PortfolioKey::DefineCubeMap()``, passing the six images as parameters:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_skybox.cpp
		   :start-after: //! [00700_skybox_portfolio]
		   :end-before: //! [00700_skybox_portfolio]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_skybox.cs
		   :start-after: //! [00700_skybox_portfolio]
		   :end-before: //! [00700_skybox_portfolio]

Once all the importing is finished, a call to ``HPS::SubwindowControl::SetBackground()`` will set the cubemap as the background on our subwindow.

At this point, your skybox is set up. Geometry and lighting can now be added to the scene and they will be contained inside of the skybox. 

In the next section, simply as a demonstration, we'll add some animation to our scene -- these steps are entirely optional.


.. _0704:

7.4 Animation: Inserting a Cube
===============================

To give a frame of reference in our animation, let's insert a cube. As our camera position changes, this cube will appear in the center of the screen and will seem to rotate as the camera moves:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_skybox.cpp
		   :start-after: //! [00700_skybox_cube_program]
		   :end-before: //! [00700_skybox_cube_program]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_skybox.cs
		   :start-after: //! [00700_skybox_cube_program]
		   :end-before: //! [00700_skybox_cube_program]
		   
This function defines a basic cube and returns a ``HPS::ShellKey``. We'll call this function in our main application code later.


.. _0705:

7.5 Animation: Creating a SmoothTransition EventHandler
=======================================================

Next we'll set up a custom event class to manage the transition between keyframes; this class can be defined outside of our main application code. Our class will have one variable that is updated once any ``HPS::View::SmoothTransition()`` function has completed. 

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_skybox.cpp
		   :start-after: //! [00700_skybox_smooth_transition_handler]
		   :end-before: //! [00700_skybox_smooth_transition_handler]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_skybox.cs
		   :start-after: //! [00700_skybox_smooth_transition_handler]
		   :end-before: //! [00700_skybox_smooth_transition_handler]
		   

.. _0706:

7.6 Animation: Adjusting the Camera
===================================

Returning back to our main application code, we'll now insert a cube in the center of the screen and implement our animation by calling ``HPS::View::SmoothTransition()`` twice, rotating the camera 180 degrees with each call:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_skybox.cpp
		   :start-after: //! [00700_skybox_animation]
		   :end-before: //! [00700_skybox_animation]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_skybox.cs
		   :start-after: //! [00700_skybox_animation]
		   :end-before: //! [00700_skybox_animation]
		   
The first line of code enables the built-in navigation cube, which will appear at the corner of the scene - this is helpful for manually rotating 
your camera. 

In addition, we've inserted a cube into the center of the scene using the ``InsertCube()`` function we defined in 
section 7.4.

We then update the scene with an ``HPS::UpdateNotifier``. Calling ``HPS::UpdateNotifier::Wait`` ensures that the scene is up to date before any other changes take place. After the update has been completed, we define an ``HPS::EventDispatcher``, which will let us know when camera rotations have been completed.

The ``while`` loop continuously checks to see if the ``HPS::View::SmoothTransition()`` is complete, after which the camera is orbited another 180 degrees, concluding our simple animation.


.. _0707:

7.7 Usage Notes
===============

If the camera’s field of view (FOV) is too small the image quality of the skybox will be noticeably poor. Adjusting the values of the field of view in your View's ``HPS::CameraKit`` with the function ``HPS::CameraKit::SetField()`` will help fix this problem.


.. _0708:

Appendix -- Full Source Code
============================

**Main application code.** If you're using one of the sandboxes, this code should be added to one of the ``OnUserCode`` slots (MFC Sandbox) or one of the ``DemoUserCommand.Execute()`` slots (WPF Sandbox). 

You will likely need to initialize ``myCanvas`` to the value returned by the sandbox's built-in ``GetCanvas()`` function.

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_skybox.cpp
		   :start-after: //! [00700_skybox]
		   :end-before: //! [00700_skybox]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_skybox.cs
		   :start-after: //! [00700_skybox]
		   :end-before: //! [00700_skybox]
		   

**Event Handler.** This is a simple event handler to manage the animation sequence; this code should live outside your main application function:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_skybox.cpp
		   :start-after: //! [00700_skybox_smooth_transition_handler]
		   :end-before: //! [00700_skybox_smooth_transition_handler]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_skybox.cs
		   :start-after: //! [00700_skybox_smooth_transition_handler]
		   :end-before: //! [00700_skybox_smooth_transition_handler]
		   
Here's the program to insert a cube into the scene:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_skybox.cpp
		   :start-after: //! [00700_skybox_cube_program]
		   :end-before: //! [00700_skybox_cube_program]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_skybox.cs
		   :start-after: //! [00700_skybox_cube_program]
		   :end-before: //! [00700_skybox_cube_program]
		   
