<p>In case you want to take a look into a ready solution.I have <a href="https://github.com/sasmaster/TrackballControls" rel="nofollow">a port</a> of THREE.JS TrackBall controlls in C++ and C#</p>

CC BY-SA 3.0
2015-09-08T07:59:31.830Z
I tend to think it does.He can learn from the code inside how the trackball works.
Michael IV
CC BY-SA 3.0
2015-11-03T08:45:30.887Z
@MichaelIV Nevertheless, Alan Wolfe has a point. You could greatly improve your answer by including relevant code in the answer itself to make it self-contained and future-proof against the link going dead some day.
Martin Ender
CC BY-SA 3.0
2015-09-03T09:38:08.500Z
2015-09-03T09:38:08.500Z
Michael IV
<p>Assuming you mean a camera that rotates based on mouse movement:</p>

<p>One way to implement it is to keep track of the camera position and its rotation in space. Spherical coordinates happen to be convenient for this, since you can represent the angles directly.</p>

<p><a href="https://i.sstatic.net/9kXOr.png" rel="noreferrer"><img src="https://i.sstatic.net/9kXOr.png" alt="Spherical Coordinates Image"></a></p>

<pre><code>float m_theta;
float m_phi;
float m_radius;

float3 m_target;
</code></pre>

<p>The camera is located at <em>P</em> which is defined by m_theta, m_phi, and m_radius. We can rotate and move freely wherever we want by changing those three values. However, we always look at, and rotate around, m_target. m_target is the local origin of the sphere. However, we are free to move this origin wherever we want in world space. </p>

<p>There are three main camera functions:</p>

<pre><code>void Rotate(float dTheta, float dPhi);
void Zoom(float distance);
void Pan(float dx, float dy);
</code></pre>

<p>In their simplest forms, Rotate() and Zoom() are trivial. The just modify m_theta, m_phi, and m_radius respectively:</p>

<pre><code>void Camera::Rotate(float dTheta, float dPhi) {
    m_theta += dTheta;
    m_phi += dPhi;
}

void Camera::Zoom(float distance) {
    m_radius -= distance;
}
</code></pre>

<p>Panning is a bit more complicated. A camera pan is defined as moving the camera to the left/right and/or up/down respective to the current camera view. The easiest way we can accomplish this is to convert our current camera view from spherical coordinates to cartesian coordinates. This will give us an <em>up</em> and <em>right</em> vectors.</p>

<pre><code>void Camera::Pan(float dx, float dy) {
    float3 look = normalize(ToCartesian());
    float3 worldUp = float3(0.0f, 1.0f, 0.0f, 0.0f);

    float3 right = cross(look, worldUp);
    float3 up = cross(look, right);

    m_target = m_target + (right * dx) + (up * dy);
}

inline float3 ToCartesian() {
    float x = m_radius * sinf(m_phi) * sinf(m_theta);
    float y = m_radius * cosf(m_phi);
    float z = m_radius * sinf(m_phi) * cosf(m_theta);
    float w = 1.0f;

    return float3(x, y, z, w);
}
</code></pre>

<p>So, first, we convert our spherical coordinate system to cartesian to get our <em>look</em> vector. Next, we do the vector cross product with the world <em>up</em> vector, in order to get a <em>right</em> vector. This is a vector that points directly right of the camera view. Lastly, we do another vector cross product to get the camera <em>up</em> vector.</p>

<p>To finish the pan, we move m_target along the <em>up</em> and <em>right</em> vectors.</p>

<p>One question you might be asking is: Why convert between cartesian and spherical all the time (you will also have to convert in order to create the View matrix). </p>

<p>Good question. I too had this question and tried to exclusively use cartesian. You end up with problems with rotations. Since floating point operations are not exactly precise, multiple rotations end up accumulating errors, which corresponded to the camera slowly, and unintentionally rolling. </p>

<p><a href="https://i.sstatic.net/1OFpX.png" rel="noreferrer"><img src="https://i.sstatic.net/1OFpX.png" alt="enter image description here"></a></p>

<p>So, in the end, I stuck with spherical coordinates. In order to counter the extra calculations, I ended up caching the view matrix, and only calculate it when the camera moves.</p>

<p>The last step is to <em>use</em> this Camera class. Just call the appropriate member function inside your app's MouseDown/Up/Scroll functions:</p>

<pre><code>void MouseDown(WPARAM buttonState, int x, int y) {
    m_mouseLastPos.x = x;
    m_mouseLastPos.y = y;

    SetCapture(m_hwnd);
}

void MouseUp(WPARAM buttonState, int x, int y) {
    ReleaseCapture();
}

void MouseMove(WPARAM buttonState, int x, int y) {
    if ((buttonState &amp; MK_LBUTTON) != 0) {
        if (GetKeyState(VK_MENU) &amp; 0x8000) {
            // Calculate the new phi and theta based on mouse position relative to where the user clicked
            float dPhi = ((float)(m_mouseLastPos.y - y) / 300);
            float dTheta = ((float)(m_mouseLastPos.x - x) / 300);

            m_camera.Rotate(-dTheta, dPhi);
        }
    } else if ((buttonState &amp; MK_MBUTTON) != 0) {
        if (GetKeyState(VK_MENU) &amp; 0x8000) {
            float dx = ((float)(m_mouseLastPos.x - x));
            float dy = ((float)(m_mouseLastPos.y - y));

            m_camera.Pan(-dx * m_cameraPanFactor, dy * m_cameraPanFactor);
        }
    }

    m_mouseLastPos.x = x;
    m_mouseLastPos.y = y;
}

void MouseWheel(int zDelta) {
    // Make each wheel dedent correspond to a size based on the scene
    m_camera.Zoom((float)zDelta * m_cameraScrollFactor);
}
</code></pre>

<p>The m_camera*Factor variables are just scale factors that change how quickly your camera rotates/pans/scrolls</p>

<p>The code I have above is a simplified pseudo-code version of the camera system I made for a side project: <a href="https://github.com/RichieSams/thehalflingproject/blob/master/source/scene/camera.h" rel="noreferrer">camera.h</a> and <a href="https://github.com/RichieSams/thehalflingproject/blob/master/source/scene/camera.cpp" rel="noreferrer">camera.cpp</a>. The camera tries to imitate the Maya camera system. The code is free and open source, so feel free to use it in your own project. </p>

CC BY-SA 3.0
2015-08-12T00:43:43.130Z
I guess the division by 300 is just a parameter for the sensitivity of the rotation given the displacement of the mouse?
BRabbit27
CC BY-SA 3.0
2015-08-12T01:02:50.050Z
Correct. It's what happened to work well with my resolution at the time.
RichieSams
CC BY-SA 3.0
2015-08-10T12:07:14.027Z
2016-02-09T06:19:09.250Z
2016-02-09T06:19:09.250Z
RichieSams
<p>After so much reading about transformations it is time to implement a trackball for my app.
I understand I have to create a vector from the origin to where the mouse is clicked and then another from the origin to where the mouse is released.</p>

<p>My question is, do I have to transfor the (x,y) pixel coords to world-coords or should I just do everything in image space (considering image space is the 2D projection of the scene measured in pixels)?</p>

<p><strong>EDIT</strong></p>

<p>Richie Sams' answer is a very good one. However, I think I'm following a slightly different approach, please correct me if I'm wrong or I'm misunderstanding something.</p>

<p>In my application I have a <code>SimplePerspectiveCamera</code> class that receives the <code>position</code> of the camera, the <code>position of the target</code> we are looking at, the <code>up</code> vector, the <code>fovy</code>, <code>aspectRatio</code>, <code>near</code> and <code>far</code> distances.</p>

<p>With those I build my View and Projection matrices. Now, If I want to zoom in/out I update the field of view and update my projection matrix. If I want to pan I move the position of the camera and look at by the delta the mouse produces.</p>

<p>Finally, for rotations I can use either angle-axis transformation or quaternions. For this, I save the pixel-coords where the mouse was pressed and then when the mouse moves I also save the pixel-coords.</p>

<p>For each pair of coords I can compute the Z-value given the formula for a sphere, i.e., sqrt(1-x^2-y^2), then compute to vectors that go from the <code>target</code> to <code>PointMousePressed</code> and from <code>target</code> to <code>PointMouseMoved</code>, do cross product to get the axis of rotation and use any method to compute the new camera position.</p>

<p>However, my biggest doubt is that the (x,y,z) values are given in pixel-coords, and when computing the vectors I'm using <code>target</code> which is a point in world-coords. Isn't this mixing of coordinate system affecting the result of the rotation I'm trying to do?</p>

CC BY-SA 3.0
2015-08-09T23:15:07.823Z
Does "trackball" mean a camera that orbits around an object, like in 3D modeling apps? If so, I think it's usually done by just keeping track of the 2D mouse coordinates and mapping x=yaw, y=pitch for the camera rotation.
Nathan Reed
CC BY-SA 3.0
2015-08-09T23:42:13.803Z
@NathanReed the other option is [axis-angle based](http://codereview.stackexchange.com/q/51205/32061), You project 2 mouse points onto a (virtual) sphere and then find the rotation from one to the other.
ratchet freak
CC BY-SA 3.0
2015-08-10T14:11:54.123Z
@NathanReed yes that is what I meant by trackball, I thought it was a common name in the CG community.
BRabbit27
CC BY-SA 3.0
2015-08-10T14:17:15.137Z
@ratchetfreak yes my approach considers an axis-angle based rotation. My doubt is that if it is needed to map the 2D mouse coords to world-coord or not. I know I can use the (x,y) to compute the `z` value of a sphere of radius `r`, however I'm not sure if that sphere lives in world-space or image-space and what the implications are. Perhaps I'm overthinking the problem.
BRabbit27
CC BY-SA 3.0
2015-08-12T02:19:09.637Z
On your edit: Yes. You would need to transform your (x, y, z) values to world space using the View matrix.
RichieSams
CC BY-SA 3.0
2015-08-12T16:47:01.913Z
Actually, after reading your answer again and thinking about it. If I have the current position of the camera I can transform that into spherical coords and then add to the angles the delta produced by the mouse movement, then go back to cartesian coords and update my view matrix, would that make sense?
BRabbit27
<opengl><trackball>
How to implement a trackball in OpenGL?
BRabbit27
# How to implement a trackball in OpenGL?

(Asked by: username_0 on 2015-08-09)

After so much reading about transformations it is time to implement a trackball for my app.
I understand I have to create a vector from the origin to where the mouse is clicked and then another from the origin to where the mouse is released.

My question is, do I have to transfor the (x,y) pixel coords to world-coords or should I just do everything in image space (considering image space is the 2D projection of the scene measured in pixels)?

**EDIT**

Richie Sams' answer is a very good one. However, I think I'm following a slightly different approach, please correct me if I'm wrong or I'm misunderstanding something.

In my application I have a `SimplePerspectiveCamera` class that receives the `position` of the camera, the `position of the target` we are looking at, the `up` vector, the `fovy`, `aspectRatio`, `near` and `far` distances.

With those I build my View and Projection matrices. Now, If I want to zoom in/out I update the field of view and update my projection matrix. If I want to pan I move the position of the camera and look at by the delta the mouse produces.

Finally, for rotations I can use either angle-axis transformation or quaternions. For this, I save the pixel-coords where the mouse was pressed and then when the mouse moves I also save the pixel-coords.

For each pair of coords I can compute the Z-value given the formula for a sphere, i.e., sqrt(1-x^2-y^2), then compute to vectors that go from the `target` to `PointMousePressed` and from `target` to `PointMouseMoved`, do cross product to get the axis of rotation and use any method to compute the new camera position.

However, my biggest doubt is that the (x,y,z) values are given in pixel-coords, and when computing the vectors I'm using `target` which is a point in world-coords. Isn't this mixing of coordinate system affecting the result of the rotation I'm trying to do?

**Tags:** opengl, trackball

> **Comments:**
> **username_1**: Does "trackball" mean a camera that orbits around an object, like in 3D modeling apps? If so, I think it's usually done by just keeping track of the 2D mouse coordinates and mapping x=yaw, y=pitch for the camera rotation.  
> **username_2**: @username_1 the other option is [axis-angle based](http://codereview.stackexchange.com/q/51205/32061), You project 2 mouse points onto a (virtual) sphere and then find the rotation from one to the other.  
> **username_0**: @username_1 yes that is what I meant by trackball, I thought it was a common name in the CG community.  
> **username_0**: @username_2 yes my approach considers an axis-angle based rotation. My doubt is that if it is needed to map the 2D mouse coords to world-coord or not. I know I can use the (x,y) to compute the `z` value of a sphere of radius `r`, however I'm not sure if that sphere lives in world-space or image-space and what the implications are. Perhaps I'm overthinking the problem.  
> **username_3**: On your edit: Yes. You would need to transform your (x, y, z) values to world space using the View matrix.  
> **username_0**: Actually, after reading your answer again and thinking about it. If I have the current position of the camera I can transform that into spherical coords and then add to the angles the delta produced by the mouse movement, then go back to cartesian coords and update my view matrix, would that make sense?  

---

## 2 answers

### Answer by username_3 on 2015-08-10. Score: 18 | Accepted answer

Assuming you mean a camera that rotates based on mouse movement:

One way to implement it is to keep track of the camera position and its rotation in space. Spherical coordinates happen to be convenient for this, since you can represent the angles directly.

[![Spherical Coordinates Image](https://i.sstatic.net/9kXOr.png)](https://i.sstatic.net/9kXOr.png)

```
float m_theta;
float m_phi;
float m_radius;

float3 m_target;

```

The camera is located at *P* which is defined by m\_theta, m\_phi, and m\_radius. We can rotate and move freely wherever we want by changing those three values. However, we always look at, and rotate around, m\_target. m\_target is the local origin of the sphere. However, we are free to move this origin wherever we want in world space.

There are three main camera functions:

```
void Rotate(float dTheta, float dPhi);
void Zoom(float distance);
void Pan(float dx, float dy);

```

In their simplest forms, Rotate() and Zoom() are trivial. The just modify m\_theta, m\_phi, and m\_radius respectively:

```
void Camera::Rotate(float dTheta, float dPhi) {
    m_theta += dTheta;
    m_phi += dPhi;
}

void Camera::Zoom(float distance) {
    m_radius -= distance;
}

```

Panning is a bit more complicated. A camera pan is defined as moving the camera to the left/right and/or up/down respective to the current camera view. The easiest way we can accomplish this is to convert our current camera view from spherical coordinates to cartesian coordinates. This will give us an *up* and *right* vectors.

```
void Camera::Pan(float dx, float dy) {
    float3 look = normalize(ToCartesian());
    float3 worldUp = float3(0.0f, 1.0f, 0.0f, 0.0f);

    float3 right = cross(look, worldUp);
    float3 up = cross(look, right);

    m_target = m_target + (right * dx) + (up * dy);
}

inline float3 ToCartesian() {
    float x = m_radius * sinf(m_phi) * sinf(m_theta);
    float y = m_radius * cosf(m_phi);
    float z = m_radius * sinf(m_phi) * cosf(m_theta);
    float w = 1.0f;

    return float3(x, y, z, w);
}

```

So, first, we convert our spherical coordinate system to cartesian to get our *look* vector. Next, we do the vector cross product with the world *up* vector, in order to get a *right* vector. This is a vector that points directly right of the camera view. Lastly, we do another vector cross product to get the camera *up* vector.

To finish the pan, we move m\_target along the *up* and *right* vectors.

One question you might be asking is: Why convert between cartesian and spherical all the time (you will also have to convert in order to create the View matrix).

Good question. I too had this question and tried to exclusively use cartesian. You end up with problems with rotations. Since floating point operations are not exactly precise, multiple rotations end up accumulating errors, which corresponded to the camera slowly, and unintentionally rolling.

[![enter image description here](https://i.sstatic.net/1OFpX.png)](https://i.sstatic.net/1OFpX.png)

So, in the end, I stuck with spherical coordinates. In order to counter the extra calculations, I ended up caching the view matrix, and only calculate it when the camera moves.

The last step is to *use* this Camera class. Just call the appropriate member function inside your app's MouseDown/Up/Scroll functions:

```
void MouseDown(WPARAM buttonState, int x, int y) {
    m_mouseLastPos.x = x;
    m_mouseLastPos.y = y;

    SetCapture(m_hwnd);
}

void MouseUp(WPARAM buttonState, int x, int y) {
    ReleaseCapture();
}

void MouseMove(WPARAM buttonState, int x, int y) {
    if ((buttonState & MK_LBUTTON) != 0) {
        if (GetKeyState(VK_MENU) & 0x8000) {
            // Calculate the new phi and theta based on mouse position relative to where the user clicked
            float dPhi = ((float)(m_mouseLastPos.y - y) / 300);
            float dTheta = ((float)(m_mouseLastPos.x - x) / 300);

            m_camera.Rotate(-dTheta, dPhi);
        }
    } else if ((buttonState & MK_MBUTTON) != 0) {
        if (GetKeyState(VK_MENU) & 0x8000) {
            float dx = ((float)(m_mouseLastPos.x - x));
            float dy = ((float)(m_mouseLastPos.y - y));

            m_camera.Pan(-dx * m_cameraPanFactor, dy * m_cameraPanFactor);
        }
    }

    m_mouseLastPos.x = x;
    m_mouseLastPos.y = y;
}

void MouseWheel(int zDelta) {
    // Make each wheel dedent correspond to a size based on the scene
    m_camera.Zoom((float)zDelta * m_cameraScrollFactor);
}

```

The m\_camera\*Factor variables are just scale factors that change how quickly your camera rotates/pans/scrolls

The code I have above is a simplified pseudo-code version of the camera system I made for a side project: [camera.h](https://github.com/username_3/thehalflingproject/blob/master/source/scene/camera.h) and [camera.cpp](https://github.com/username_3/thehalflingproject/blob/master/source/scene/camera.cpp). The camera tries to imitate the Maya camera system. The code is free and open source, so feel free to use it in your own project.

> **Comments:**
> **username_0**: I guess the division by 300 is just a parameter for the sensitivity of the rotation given the displacement of the mouse?  
> **username_3**: Correct. It's what happened to work well with my resolution at the time.  

---

### Answer by username_4 on 2015-09-03. Score: -2

In case you want to take a look into a ready solution.I have [a port](https://github.com/sasmaster/TrackballControls) of THREE.JS TrackBall controlls in C++ and C#

> **Comments:**
> **username_4**: I tend to think it does.He can learn from the code inside how the trackball works.  
> **username_5**: @username_4 Nevertheless, Alan Wolfe has a point. You could greatly improve your answer by including relevant code in the answer itself to make it self-contained and future-proof against the link going dead some day.  

---

