######
Camera
######

In computer graphics, a "camera" is technically nothing more than a set of viewing transformations that transforms the world space coordinates of a model into screen coordinates. In |HCNOW| a camera is defined by its position, the viewing target as well as the dimensions of the screen and the projection mode (more on that later in this chapter)

There can only be one camera at a time for a View in the HOOPS WebViewer but each Overlay can have a camera. This is further discussed in the :doc:`Overlays Programming Guide </prog_guide/viewing/scene_attributes/overlays>`.


Setting a camera
================

To set a new camera on the view you can call the :ref:`setCamera() <api_ref/viewing/classes/Communicator.View:setcamera>` function which takes a camera object and an optional transition time to the new camera in milliseconds. As an example the code below transitions the current camera to the camera defined in newcamera in 2 seconds:

.. literalinclude:: /../../applications/client/docs/PG_Viewing_camera.ts
   :start-after: //! [webviewer_setcamera]
   :end-before: //! [webviewer_setcamera]
	
To reset the camera to the initial view of the model when it was first loaded you can use the :ref:`resetCamera() <api_ref/viewing/classes/Communicator.View:resetcamera>` function.


Getting a camera
================

To retrieve the current camera you can call the :ref:`getCamera() <api_ref/viewing/classes/Communicator.View:getcamera>` function which returns the parameters for the currently active camera.

.. literalinclude:: /../../applications/client/docs/PG_Viewing_camera.ts
   :start-after: //! [webviewer_getcamera]
   :end-before: //! [webviewer_getcamera]

This is not the actual camera object of the HOOPS Web Viewer but just a copy of the parameters defining the camera so any changes to this copy only get applied when the camera is set with the :ref:`setCamera() <api_ref/viewing/classes/Communicator.View:setcamera>` function above.


Storing and retrieving a camera
===============================

You can store a camera object returned from the :ref:`getCamera() <api_ref/viewing/classes/Communicator.View:getcamera>` function directly. You can also conveniently serialize it without its internal structures using the :ref:`Camera::toJson() <api_ref/viewing/classes/Communicator.Camera:tojson>` function that turns all relevant parameters of a camera into JSON text that is ready for serialization.

.. literalinclude:: /../../applications/client/docs/PG_Viewing_camera.ts
   :start-after: //! [webviewer_cameratojson]
   :end-before: //! [webviewer_cameratojson]
	
Content of jsoncamera:
	
.. code-block:: 

	{
	"position":{
		"x": 773.7705950899608, 
		"y": 408.3032520621853, 
		"z": 33.276514806174674 
	}, 

	"target": { 
		"x": 782.6946956181886, 
		"y": 412.0387572028094, 
		"z": 32.7747394131153 
	}, 
	
	"up": { 
		"x": 0.04777981198034891, 
		"y": 0.01999996892752277, 
		"z": 0.9986576444457934 
	}, 

	"width": 8.715595404843834, 
	"height": 8.715595404843834, 
	"projection": 1,\ 
	"nearLimit": 0.001, 
	"className": "Communicator.Camera" 
	} 
	
	
To pass this JSON definition of the camera back into the HOOPS Web Viewer you can use the :ref:`fromJson() <api_ref/viewing/classes/Communicator.Camera:fromjson>` function.

.. literalinclude:: /../../applications/client/docs/PG_Viewing_camera.ts
   :start-after: //! [webviewer_camerafromjson]
   :end-before: //! [webviewer_camerafromjson]
	

Camera components
=================

Below is a list of the main components that make up a camera in the HOOPS Web Viewer, a short description and the corresponding functions to get and set those components on the camera object.

Position: A point that represents the location of the camera in World Space. See :ref:`setPosition() <api_ref/viewing/classes/Communicator.Camera:setposition>`, :ref:`getPosition() <api_ref/viewing/classes/Communicator.Camera:getposition>`.

Target: A point, specified in world coordinates, at which the camera is looking. The camera target must not be at the same position as the camera. The vector between the camera position and the camera target is called the "line of sight". For camera related operators the camera target can often be the point that the camera will rotate around. See :ref:`setTarget() <api_ref/viewing/classes/Communicator.Camera:settarget>`, :ref:`getTarget() <api_ref/viewing/classes/Communicator.Camera:gettarget>`.

Up-vector: The up vector defines the orientation of the camera along the view vector. It essentially determines which way is "up" when you are viewing the model. The up vector must not be all zeros, and cannot be parallel to the line of sight. When setting the up vector yourself you should ensure that it is perpendicular to the line of sight. See :ref:`setUp() <api_ref/viewing/classes/Communicator.Camera:setup>`, :ref:`getUp() <api_ref/viewing/classes/Communicator.Camera:getup>`.

Width, height: The width and height define the field of view of the camera which is the minimum area around the target that will be visible in the output window. The camera field, along with the distance between the camera position and the camera target, determine - in photographic terms - what kind of lens the camera is using. If the field is larger than the distance from the camera position to the target, then we have the equivalent of a wide-angle lens. If the distance between the camera position and target is much larger than the camera field, then we have the equivalent of a telephoto lens. Changing the size of the field (if the camera position and target remain fixed) is the same as zooming the lens. The ratio of the width to the height of the field is called the aspect ratio. See :doc:`Communicator.Camera </api_ref/viewing/classes/Communicator.Camera>` for more details.

Projection: The projection determines how the HOOPS Web Viewer converts the 3D coordinates representing a scene to the 2D coordinates of the screen. A perspective projection scales the **x** and **y** coordinates depending on the **z** coordinate (depth), such that objects that are farther away appear smaller on the screen. In an orthographic projection, the direction of projection is perpendicular to the camera target plane (so, the x and y coordinates aren't scaled). See :doc:`Communicator.Camera </api_ref/viewing/classes/Communicator.Camera>` for more details on the related functions.

.. image:: images/camera_perspective_orthographic.png

*A model rendered in Perspective Projection (left) and Orthographic Projection (right)*

.. image:: images/camera_field_of_view.png

The same model and viewpoint but in the left image, the camera target is 500 units away from the camera position, while in the right image the target is 2000 units away, resulting in a wider field of view. The same effect can be achieved by increasing the width of the camera proportionately.

The distance from the camera position to the camera target should ideally be 2.5 times the field width. This 2.5:1 camera ratio maximizes the z-buffer resolution around the camera target, thus reducing the occurrence of edge stitching or shinethrough. It also provides a commonly accepted level of foreshortening for perspective projections.

.. image:: images/camera_near_limit.png

The left image shows the model rendered with the default ``nearLimit``. The image in the middle with a ``nearLimit`` set to "1" using otherwise the same camera. This results in geometry close to the camera getting clipped by the near clipping plane. The image on the right is rendered with a very small near limit resulting in rendering artifacts and z-fighting for objects further away from the camera.


Retrieving the camera matrices
==============================

Sometimes it can be useful to retrieve the internal matrix representing the camera's orientation. This can be done with the :ref:`getViewMatrix() <api_ref/viewing/classes/Communicator.Camera:getviewmatrix>` function. An example of what this matrix can be used for is aligning text to the current camera or orienting geometry within an overlay to the current camera. If you need a matrix that fully projects a point from its 3D position into 2D space you can use the :ref:`getFullMatrix() <api_ref/viewing/classes/Communicator.Camera:getfullmatrix>` function.


Camera callback
===============

To find out if the active camera has changed either due to a camera related operator or for other reasons you can set the camera callback:

.. literalinclude:: /../../applications/client/docs/PG_Viewing_camera.ts
   :start-after: //! [webviewer_cameracallback]
   :end-before: //! [webviewer_cameracallback]
	

Conversion functions
====================

Several functions help with moving from the various coordinate spaces defined by the current camera.


Point to window position
========================

The function :ref:`view.pointToWindowPosition() <api_ref/viewing/classes/Communicator.View:pointtowindowposition>` takes a point defined in pixel space and converts it to a normalized window space (defined in the range from (-1,1).

.. literalinclude:: /../../applications/client/docs/PG_Viewing_camera.ts
   :start-after: //! [webviewer_pointtowindow]
   :end-before: //! [webviewer_pointtowindow]
   
Result:

``{x: -0.05535055350553508, y: 0.34560327198364005}``


Project point
=============

The function :ref:`view.projectPoint() <api_ref/viewing/classes/Communicator.View:projectpoint>` projects a 3D world space point into 2D screen space. We use it in our markup code to calculate the 2D positions for our SVG markup elements that are anchored to points in 3D space.
