11,576,963 members (52,357 online)

# Implementing a Basic Camera Model (Pinhole)

, 9 Apr 2013 GPL3 29K 657 50
 Rate this:
Implementing a basic camera model to extend the raytracing algorithms

## Introduction

Extending our ray tracing algorithms now we will implement a camera class.

The objective is to render the images setting the viewer at any position without restrictions since in our previous models, the viewer must be located at positive z axis, (0,0,z) z>0.

## Background

Although not implementing raytracing in this article, it is required to have an advanced level in mathematics and also read the previous articles on Raytracing on CodeProject.

Link to previous articles

The objective is to render the images setting the viewer at any position without restrictions as our previous model where the viewer must be located at positive z axis, (0,0,z) z > 0.

What is a pinhole camera?

"...A pinhole camera is a very simple camera with no lens and a single very small aperture. Simply explained, it is a light-proof box with a small hole on one side. Light from a scene passes through this single point and projects an inverted image on the opposite side of the box. Cameras using small apertures and the human eye in bright light both act like a pinhole camera.

The smaller the hole, the sharper the image, but the dimmer the projected image. Optimally, the size of the aperture should be 1/100 or less of the distance between it and the screen..."

A pinhole camera

## Step 1 - Defining Parameters

In order to perform all calculations, we do need some predefined parameters:

• Camera position Cp(x,y,z)
• Viewing direction vector V (x,y,z) normalized... means its module = 1 |V| = 1
• Focal length F (the distance between Camera position Cp and the camera projection plane S)

From the above parameters, we can retrieve other parameters which will be useful further:

• P, a point located at the plane

P = Cp-V*F(x,y,z)

• The S plane equation

From math books plane equation is in the form Ax+By+Cz+D=0

and also if we have a normal vector it is quite simple, and luckily we do have it and it is V.

From the same book...

A = Vx
B = Vy
C = VZ

we need to get D, but it simple now because we do have a point at the plane

so D = -(A*Px+B*PY+C*PZ)

```A = normalVector.x;
B = normalVector.y;
C = normalVector.z;
D = -(normalVector.x * point.x + normalVector.y * point.y + normalVector.z * point.z);```

## The Camera Coordinates System

Now let's call pinhole model as camera coordinates system.

So to represent a model, now we do have a Cartesian reference system x,y,z and also a camera coordinates system.

The plan is to translate and rotate our camera coordinates system to fit the reference Cartesian coordinates system, for this we need some equations on spherical coordinates to retrieve the theta and phi angles.

"...In mathematics, a spherical coordinate system is a coordinate system for three-dimensional space where the position of a point is specified by three numbers: the radial distance of that point from a fixed origin, its elevation angle measured from a fixed plane, and the azimuth angle of its orthogonal projection on that plane, measured from a fixed reference direction on the same. The elevation angle is often replaced by the inclination angle measured from a zenith direction perpendicular to the reference plane. ..."

Spherical coordinates

From my math book, we get how to represent a given R3 point into spherical coordinates and also conversions... (it will be used further).

Converting Cartesian coordinates to spherical

x = R sin (phi) cos (theta)
y = R sin (phi) sin (theta)
z = R cos (phi)

Converting spherical coordinates to Cartesian

R = sqrt(x2+y2+z2)
S = sqrt(x2+y2)
phi = acos(z/R)
theta = x>=0 asin(y/S)
x<0 PI - asin(y/S)

Follows how to calculate phi and theta angles, this will help us to rotate our coordinate system to fit the reference system

```Point oNormalizedDirection = Algebra.Normalize(m_oDirection.x,
m_oDirection.y, m_oDirection.z);
// calculate frontpoint
m_oFrontPoint = new Point(m_oOrigin.x + oNormalizedDirection.x,
m_oOrigin.y + oNormalizedDirection.y,
m_oOrigin.z + oNormalizedDirection.z);
// 1 translate to origin
Point oTranslatedFrontPoint = new Point(m_oFrontPoint.x - m_oOrigin.x,
m_oFrontPoint.y - m_oOrigin.y,
m_oFrontPoint.z - m_oOrigin.z);
// calc phi & theta
double x2 = oTranslatedFrontPoint.x * oTranslatedFrontPoint.x;
double y2 = oTranslatedFrontPoint.y * oTranslatedFrontPoint.y;
double radius = Math.Sqrt(x2 + y2 + oTranslatedFrontPoint.z * oTranslatedFrontPoint.z);
double s = Math.Sqrt(x2 + y2);
m_dPhi = Math.Acos(oTranslatedFrontPoint.z / radius);
m_dTheta = 0;
if (Math.Abs(s) > 1.0E-5)
{
if (oTranslatedFrontPoint.x >= 0)

{
m_dTheta = Math.Asin(oTranslatedFrontPoint.y / s);
}
else
{
m_dTheta = Math.PI - Math.Asin(oTranslatedFrontPoint.y / s);
}
}```

## Calculating Projections

Projection

Our first objective is to calculate the projected point `a `at the plane `S`.

## How To Get This?

From my old math book again...

We can easily calculate the intersection between a line and a plane if we have both equations, and luckily again we do!

Our line equation in parametric form is r = p + t*v.

• p is any point at the line t is an scalar
• v is the line vector
• our p is the point a
• our v can be calculated from the Camera position to a as Cp-a

Using this parametric equation against the plane equation, we find the parameter t and so we do find the intersection point using

• t value at p + tv

#### Code

```public Point GetIntersection(Point p, Point Origin)
{
Vector v = new Vector(p, Origin);
double E = (v.x * A + v.y * B + v.z * C);
if (Math.Abs(E)<1.0E-5)
{
return null;
}
v = Algebra.Normalize(v.x, v.y, v.z);
double t = -(A * p.x + B * p.y + C * p.z + D) / (E);
return new Point(p.x + t * v.x, p.y + t * v.y, p.z + t * v.z);
}```

Our last objective is to map this intersection point into our screen.

For this, we need to fit the point into our reference coordinate system using the calculated phi and theta...

#### Code

```public Point LocalToCartesian(Point point)
{
point.x -= m_oOrigin.x;
point.y -= m_oOrigin.y;
point.z -= m_oOrigin.z;

rtPoint.RotZ(-m_dTheta, ref point.x, ref point.y);
rtPoint.RotY(m_dPhi, ref point.x, ref point.z);

return new Point(point.x, point.y, point.z);
}```

## Using the Code

All required code is in a project in the zip file at the top of the article, just download and compile.

## Points of Interest

It is very challenging to keep improving the algorithms on my own and using only math instead of using libraries. Many people ask me why to create something which is already in many libraries. The response is that I like the challenge, the discovery, and it is very satisfactory to see the results by my own hands and effort.

## History

Creating a camera class is a next step in the raytracing articles series, it will bring us to the next level and allow to start creating animations.

## About the Author

 Engineer IBM Brazil
Senior Analyst

Founder of TIHunter Vagas de TI

## Comments and Discussions

 First Prev Next
 My vote of 5 manoj kumar choubey26-Feb-12 21:46 manoj kumar choubey 26-Feb-12 21:46
 Broken link John Whitmire3-Feb-10 5:41 John Whitmire 3-Feb-10 5:41
 Re: Broken link andalmeida3-Feb-10 6:30 andalmeida 3-Feb-10 6:30
 Re: Broken link andalmeida1-Mar-10 14:15 andalmeida 1-Mar-10 14:15
 Are spherical coordinates necessary? supercat91-Feb-10 13:36 supercat9 1-Feb-10 13:36
 Re: Are spherical coordinates necessary? andalmeida2-Feb-10 0:14 andalmeida 2-Feb-10 0:14
 You are right, the simplest is using the position at z axis as in the previous models. To simulate rotating and moving objects it is fine, but to simulate moving cameras it is not enough, the model needed to be extended to make me able to move the camera anywhere in R3 and point it to any target. Anderson J. Almeida Systems Analyst TIHunter http://www.tihunter.com
 Nice... Alexander Müller30-Jan-10 23:01 Alexander Müller 30-Jan-10 23:01
 Last Visit: 31-Dec-99 18:00     Last Update: 4-Jul-15 0:14 Refresh 1

General    News    Suggestion    Question    Bug    Answer    Joke    Rant    Admin

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.