Reader small image

You're reading from  Game Physics Cookbook

Product typeBook
Published inMar 2017
Reading LevelIntermediate
PublisherPackt
ISBN-139781787123663
Edition1st Edition
Languages
Tools
Concepts
Right arrow
Author (1)
Gabor Szauer
Gabor Szauer
author image
Gabor Szauer

Gabor Szauer has been making games since 2010. He graduated from Full Sail University in 2010 with a bachelor's degree in game development. Gabor maintains an active Twitter presence, and maintains a programming-oriented game development blog. Gabor's previously published books are Game Physics Programming Cookbook and Lua Quick Start Guide, both published by Packt.
Read more about Gabor Szauer

Right arrow

Chapter 13. Camera and Frustum

In this chapter, we will explore some rendering related functionality. We are going to explore creating a camera and controlling that camera to help us visualize the physics demos that we will create in the next chapter. This chapter will cover the following topics:

  • Camera object

  • Camera controls

  • Frustum object

  • Frustum from matrix

  • Sphere in frustum

  • Bounding Box in frustum

  • Octree culling

  • Picking

Introduction


In this chapter, we are going to build a camera. This camera should let us view the 3D scene we created in the last chapter. A camera might not seem relevant to physics, but we need a way to visualize everything which we are doing. As we build up the camera, you will find that most of the work revolves around matrix math covered in Chapter 2, Matrices and Chapter 3, Matrix Transformations.

A camera consists of two matrices. The view matrix is the inverse of the camera's world matrix. View matrix is used to transform the world in a way that the camera is at its center looking down the Z axis. The projection matrix transforms vertex data from eye coordinates to NDC coordinates.

Later we will use these matrices to construct a new Frustum primitive. We will finish up the chapter by learning how to un-project a point from pixel coordinates into world space. We will then use this un-projection to create a ray that allows us to pick objects in a 3D scene using the mouse.

Camera object


In order to build engaging physics demos, we need to be able to view a 3D scene in some way. This is where a camera becomes useful. A 3D camera is made up of two matrices, the view matrix and the projection matrix. The view matrix is the inverse of the camera's world transform. The projection matrix transforms vertex data from eye space to NDC space:

The view matrix of a camera should be orthogonal. An orthogonal camera is one whose rotation basis vectors are at right angles from each other. Two vectors that are at a right angle are orthogonal. Orthogonal vectors are perpendicular to each other. The result of the dot product between two perpendicular vectors is zero.

In general, cameras should not have any scale. Because scale is stored within the same components of a 4D matrix as rotation, it is a bad idea to add scale to a camera. Each of the rotation basis vectors we store within our camera will be of unit length. When the rotation basis vectors of an orthogonal matrix are...

Camera controls


In this section, we are going to make the camera more useful. We will extend the camera class to create an Orbital Camera. Many 3D content creation tools such as 3DS Max or Unity3D use Orbital Cameras to navigate a 3D scene.

Getting ready

We are going to implement an Orbital Camera that will help us visualize what is happening within our physics simulations. This camera has three public functions that need to be called when input is received. The camera also has an update function that should be called at the end of every frame. The three functions that need to be called on input are Rotate, Zoom, and Pan. The Update function should always be the last camera function to be called during a frame.

How to do it…

Follow these steps to create a new Orbital Camera. Orbit cameras are used by most 3D Content Creation applications to view a 3D scene. Sometimes, these are referred to as free cameras:

  1. Start declaring the OrbitCamera class in Camera.h by declaring the protected variables...

Frustum object


A camera's viewing volume can be represented by a frustum. A frustum is made up of six planes, visually it looks like a pyramid with its peek truncated:

The frustum is composed of the top, bottom, left, right, near, and far planes. The normal of each plane points inward, towards the center of the frustum:

Having a view Frustum is very useful in graphics. We can use the frustum to render only what is visible to the camera. We don't need a Frustum primitive for our engine to work, but it is a very useful primitive to have in our toolbox.

Getting ready

We are going to create a new Frustum object that will contain six planes. We are also implementing an Intersection helper function, which will return the point at which three planes intersect. This helper function will be used to find the corner points of the frustum. We will also create a GetCorners function to make finding the corners of the frustum less verbose.

Our Frustum definition will contain variables named near and far. If...

Frustum from matrix


In the last section, we created a Frustum primitive. We know that a frustum is made up of six planes: near, far, top, bottom, left, and right. In this section, we will explore how to extract those six planes from a view-projection matrix.

Getting ready

We are going to add a new method to the Camera class. This new method will create a frustum from the camera. In order for the Camera class to know what a Frustum is, we need to include Geometry3D.h in Camera.h.

How to do it…

Follow these steps to build a frustum out of the camera's view and projection matrices:

  1. Add the public GetFrustum function to the Camera class in Camera.h:

    class Camera {
       // Existing class implementation not listed
       // The GetFrusutm function is new
       Frustum GetFrustum();
    };
  2. Begin implementing the new GetFrustum function in Camera.cpp by creating a view-projection matrix; store each column of this matrix as a vector:

    Frustum Camera::GetFrustum() {
       Frustum result;
  3. Build out the view projection matrix...

Sphere in frustum


Now that we can get the view frustum of a camera, we will explore how to check primitives for intersection against the frustum. We will start by checking if a point or sphere intersects the frustum. This intersection test will also handle containment:

Getting ready

In this section, we are going to implement two intersection functions. The first function will test if a point is inside of a frustum. The second function will check if a sphere intersects a frustum. Both functions handle containment as well as intersection.

How to do it…

Follow these steps to implement intersection tests for a point and a sphere against a Frustum:

  1. Declare the functions to test a point and a sphere against a frustum in Geometry3D.h:

    bool Intersects(const Frustum& f, const Point& p);
    bool Intersects(const Frustum& f, const Sphere& s);
  2. Implement the point Intersects function in Geometry3D.cpp:

    bool Intersects(const Frustum& f, const Point& p) {
       for (int i = 0; i < 6; ++i)...

Bounding Box in frustum


To test if an Oriented Bounding Box (OBB) or an Axis Aligned Bounding Box (AABB) intersects a frustum, follow the same steps. First we have to be able to classify the box against a plane. A box and a plane can have one of three intersection states:

  • The box is in front of the plane

  • The box is behind the plane

  • The box intersects the plane

Once we are able to classify a box to a plane, we need to loop through every plane of the frustum and classify the box against each plane. If the box is fully behind any of the six planes, there is no intersection. If the box is in front of every plane, it is contained within the frustum. Otherwise, the box intersects the frustum:

Getting ready

In this section, we are going to implement two Classify functions. One to classify an OBB against a plane, and one to classify an AABB against a plane. The Classify functions will have the following return values:

  • If the box is behind the plane, the negative distance is returned

  • If the box is in front...

Octree culling


Now that we have a frustum and we can check said frustum for intersection against primitives, we can finally implement scene level culling. We will provide the Scene class with a Frustum object, the Scene class will return a list of Model objects. The OBB of each model within this list intersects the frustum. This way, we only need to consider objects for rendering, which the camera might see.

If a scene is spatially divided with an Octree, this method of culling should increase render time by eliminating non visible objects from being rendered. However, if a scene is not accelerated, and we just linearly test every object against the frustum we might actually make performance worse.

Getting Ready

We are going to add a new method named Cull to the existing Scene class. This new method will take a Frustum as an argument and will return a list of Model objects that intersect the frustum.

How to do it…

Follow these steps to cull the Octree of a Scene using a Frustum:

  1. In Scene.h, add...

Picking


Picking objects in 3D space is a common problem. If you want your 3D simulation to interact with a mouse, we need to solve this problem. To implement picking, we need to find the pixel that the user has clicked relative to both the near and far planes of the camera. We can construct a ray from the point on the near plane to the point on the far plane. Finally, we can query the world using this ray.

The job of a graphics pipeline is to take a 3D point in world space and project it onto the screen. This transformation from world space to screen space is called Projection. To find the 3D world space position of a point based on the 2D pixel position of that same point we need to do the opposite of what the graphics pipeline does. Putting a pixel through the inverse of the graphics pipeline is called Unprojection.

When we unproject a pixel, it has no Z coordinate. We will provide a Z component that is a linear depth value. That is, a Z value of 0 will result in the pixel on the near plane...

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Game Physics Cookbook
Published in: Mar 2017Publisher: PacktISBN-13: 9781787123663
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Gabor Szauer

Gabor Szauer has been making games since 2010. He graduated from Full Sail University in 2010 with a bachelor's degree in game development. Gabor maintains an active Twitter presence, and maintains a programming-oriented game development blog. Gabor's previously published books are Game Physics Programming Cookbook and Lua Quick Start Guide, both published by Packt.
Read more about Gabor Szauer