This example showcases a 3D first-person camera.
The setup presented here is a very common way of organizing a first-person game where the player can see their own arms. We use two industry terms to differentiate the kinds of models we have:
- The view model is the model that represents the player's body.
- The world model is everything else.
Motivation
The reason for this distinction is that these two models should be rendered with different field of views (FOV). The view model is typically designed and animated with a very specific FOV in mind, so it is generally fixed and cannot be changed by a player. The world model, on the other hand, should be able to change its FOV to accommodate the player's preferences for the following reasons:
- Accessibility: How prone is the player to motion sickness? A wider FOV can help.
- Tactical preference: Does the player want to see more of the battlefield? Or have a more zoomed-in view for precision aiming?
- Physical considerations: How well does the in-game FOV match the player's real-world FOV? Are they sitting in front of a monitor or playing on a TV in the living room? How big is the screen?
Implementation
The Player
is an entity holding two cameras, one for each model. The view model camera has a fixed FOV of 70 degrees, while the world model camera has a variable FOV that can be changed by the player.
We use different RenderLayers
to select what to render.
- The world model camera has no explicit
RenderLayers
component, so it uses the layer 0. All static objects in the scene are also on layer 0 for the same reason. - The view model camera has a
RenderLayers
component with layer 1, so it only renders objects explicitly assigned to layer 1. The arm of the player is one such object. The order of the view model camera is additionally bumped to 1 to ensure it renders on top of the world model. - The light source in the scene must illuminate both the view model and the world model, so it is assigned to both layers 0 and 1.
Controls
Key Binding | Action |
---|---|
mouse | Look around |
arrow up | Decrease FOV |
arrow down | Increase FOV |
use FRAC_PI_2;
use ;
;
;
;
/// Used implicitly by all entities without a `RenderLayers` component.
/// Our world model camera and all objects other than the player are on this layer.
/// The light source belongs to both layers.
const DEFAULT_RENDER_LAYER: usize = 0;
/// Used by the view model camera and the player's arm.
/// The light source belongs to both layers.
const VIEW_MODEL_RENDER_LAYER: usize = 1;