Multiple cameras

By default you have exactly one camera object in your game. But there are particular situations in which more camera objects are required. For example you may want to make a split screen multiplayer game. Or you may want to add security cameras to your game which take pictures that can be displayed on monitors. Also, you may want to add real reflections to your water planes or to other objects. For all these things you need additional camera objects.

In Ultimate 3D you can use up to 32 camera objects at the same time. Using them is quite simple. In principle all camera objects work in the same way as the first one. The only difference is that you have to define the destination the other camera objects should render to. There are two different kinds of destinations. You can either render to a user defined part of the screen as usual or you can render to a special texture. These special textures can be applied to objects, just like standard textures. They can also be drawn to the screen using DrawTex(...) or DrawTexEx(...).


Adding a new camera to the scene

Every camera object has the same variables as the first camera object, which are the following: x, y, z, height, rotx, roty, rotz, view, min_range, max_range, falling, falling_speed, follow, perspective, and distance. To get information about these variables, have a look at the tutorial Getting started. There's also a couple of new variables you need to know about. The first camera object has them as well, but if you do not set them up manually they get set to default values. So here are the new variables:

number
The index of this camera object. The first camera object has the index 0 (there always has to be a camera with number=0). The highest valid value for this variable is 31. You should never have two camera objects with the same index at the same time.

v_left, v_top, v_width, v_height
The position and the dimensions of the viewport you want to use for the camera. This is the area this camera will render to. Note that these values have to be given relative to the left top of the first Game Maker view.

actual_aspect
If you do not need this variable, you can simply ignore it. By default, Ultimate 3D will calculate the aspect of the viewport by dividing v_width/v_height. But since render target textures must have dimensions made up of powers of two, it may happen that this quotient is not the aspect you actually want. In this case you can use this variable to set up another one.

render_target
If you do not want to render to a texture you can simply ignore this variable. Otherwise, you have to set it to the index of the render target texture you want. Render target textures can be created using the function CreateTextureRenderTarget(...) (see below).


Every camera object has to call MoveCamera() in its step event and Destroy() in its destroy event. MoveCamera() will transmit any change of the variables to Ultimate 3D. If the camera has a texture render target set up you have to call RenderToTexture() to make it render. Of course there's no need to call this in every single step. If the objects that use the texture aren't visible it would be a giant waste of computing time to call it. Also, things like a security camera do not need to update their picture in every step. Ten times a second should be enough. This way you can make your program much more efficient.


Clipping planes and orthogonal cameras

Sometimes particular cameras do not need to render everything. There are two possibilities to code this. The easiest one is the use of the advanced culling functions. With these functions you can define which cameras render which objects. But sometimes this is not precise enough. For example, when programming effects for water reflections, you need one camera that renders only the world above the water surface. To do this you can use something called clipping planes. You simply define an arbitrary plane. Everything above the plane will be rendered, and the rest will be invisible. Here's the function to set up clipping planes for the camera it's called by:

SetClippingPlane(
ClippingPlaneIndex,
PlaneOriginX, PlaneOriginY, PlaneOriginZ,
PlaneOrientationLongitude, PlaneOrientationLatitude
)

ClippingPlaneIndex
There can be up to six clipping planes per camera, depending on the graphics device. GetClippingPlaneSupport() returns the number of supported clipping planes. Through this parameter you define which clipping plane you want to set. It can be a value in the range from 0 to 5.

PlaneOriginX/Y/Z
This is an arbitrary point that lies in the plane you want to set up as clipping plane.

PlaneOrientationLongitude, PlaneOrientationLatitude
These two variables define the orientation of the plane (the direction the plane is facing).


Another small but useful feature of Ultimate 3D is that it allows the use of cameras with an orthogonal projection. These are mainly used for utilities like level editors or modeling programs. In an orthographic view objects that are farther away do not seem to be smaller (nor do they seem bigger). There's no vanishing point. You do not have an angle giving the field of view, because the boundaries of the visible area are always parallel. Instead you give a rectangular area, which should be visible by giving a height and a width. Orthogonal cameras are something that can not exist in reality, but for different kinds of editors they are very useful, because they reduce the seen image to two axes.

This function enables an orthogonal projection for the camera it's called by.

SetOrtho(
UseOrthogonalProjection,
SeenAreaWidth, SeenAreaHeight
)

UseOrthogonalProjection
If you pass true for this parameter, Ultimate 3D will enable an orthogonal projection for this camera, otherwise it will get disabled.

SeenAreaWidth, SeenAreaHeight
The width and height of the area that should be visible. These are used instead of the value of the variable view.


Note that orthogonal cameras will not be able to see anything that lies behind them, just like usual cameras. For this reason you have to move them away from the scene far enough.


Creating render target textures and rendering to cube maps

Rendering to textures is a very widely usable technique. You can render an image to a texture and use it like any other texture. Also, render to texture functions are required to make post screen shaders, which can be used for effects such as HDR, motion-blurring or effects that make your game look like a really old movie. Using a post screen shader means that you render your scene to a texture instead of rendering it directly to the screen. Then you render the texture which contains a picture of the scene to the screen, applying some shader effect to it. A later version of Ultimate 3D will make the use of post screen shaders a bit easier.

Since you already know how to set up a texture as a render target for a camera, the only thing you've got to learn about now is how to create a render target texture. To do this you need only one simple function:

This function creates a render target texture with the given dimensions and associates it with the given index.

CreateTextureRenderTarget(
TextureIndex,
RequestedWidth, RequestedHeight
)

TextureIndex
The index the texture is to be associated with. This can be an arbitrary integer value in the range of 0 to 998.

RequestedWidth, RequestedHeight
The requested dimensions for the render target texture. Like any other type of texture, most graphics devices do not support render target textures that are not made up of powers of two. Some really old graphics devices support only quadratic textures.


It's also possible to render to cube textures. This way you can make absolutely realistic reflections. You render a picture of the environment to a cube texture and then you use cubic environment mapping to map this picture of the environment onto an object. This is the perfect technique for making reflections, but it's not difficult to use. The first step is the creation of a cube texture that can be used as render target. To do this you have to call only one function:

This function creates a cube texture with the given dimensions that can be used as a render target and associates it with the given index.

CreateCubeTextureRenderTarget(
TextureIndex,
RequestedEdgeLength
)

TextureIndex
The index the texture is to be associated with. This can be an arbitrary integer value from 0 to 998.

RequestedEdgeLength
The side length of the cube texture you want to create. The cube texture will be made up of six 2D textures with a size of RequestedEdgeLength * RequestedEdgeLength. You should enter a power of two for this parameter since most graphics devices do not support other texture sizes.


Rendering to cube textures is not done using a camera object. It's much easier. Since all directions are represented by a cube texture, there's no need to give a view direction or an angle of view. The only information that matters is the position, and possibly a color with an alpha value. When the whole scene has been rendered to the cube texture, vertex quads with this color and transparency value will be drawn over the finished texture. You should always enter an alpha value lower than 255, or else the whole rendering process would make no sense since the results would not be visible. You should usually put something like r=g=b=0 and a=128. Here's the function:

This function renders the scene as it's seen from the given position to the cube texture render target.

RenderToCubeTexture(
CubeTextureIndex,
PositionX, PositionY, PositionZ,
ColorR, ColorG, ColorB, ColorA
RoomIndex1, RoomIndex2, ..., RoomIndex8
)

CubeTextureIndex
The index of the cube texture render target you want to render to. This has to be the index of a cube texture render target that has been created using
CreateCubeTextureRenderTarget(...), otherwise this function will fail.

PositionX, PositionY, PositionZ
The position from where the scene should be rendered.

ColorR, ColorG, ColorB, ColorA
The color of the vertex quads that are to be rendered to the cube texture after rendering the scene. The values for these parameters should be in the range from 0 to 255. If you do not want these vertex quads to be drawn, just put 0 for ColorA. Passing 255 for ColorA makes no sense, because then you would not see the scene.

RoomIndex1, RoomIndex2, ..., RoomIndex8
The indices of the rooms that are to be rendered. For more information about room indices have a look at the advanced culling functions. Room 0 will always be rendered, regardless of the values you pass for this parameter.


Drawing 2D graphics to textures

I would have called this subchapter "Drawing textures and text to textures" if that did not sound too weird. But that's just what you will be able to do once you've read and understood it. Imagine you have a control panel in your game on which miscellaneous settings get displayed. So you have to draw 2D graphics to a texture that can be used as a texture for the monitor. That's just what this feature is meant to be used for. You already know the functions that can be used for drawing textures and text to textures: DrawTexEx(...) and DrawText(...). There's only one additional parameter I did not tell you about in the novice section to avoid confusing you. So here's the full syntax of these two functions.

DrawTexEx(
TextureIndex, Left,Top, Width,Height, X,Y, ScalingX,ScalingY, Rotation, R,G,B,A,
CameraIndex
)

CameraIndex
The index of the camera to whose render target you want to draw the texture.

DrawText(
FontIndex, X, Y, Text,
CameraIndex
)

CameraIndex
See above.


Note that the texture will not be drawn to the render target texture before the corresponding camera object calls RenderToTexture().



© Christoph Peters. Some rights reserved.

Creative Commons License XHTML 1.0 Transitional