fyrox_impl/renderer/observer.rs
1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! An observer holds all the information required to render a scene from a particular point of view.
22//! Contains all information for rendering, effectively decouples rendering entities from scene
23//! entities. See [`Observer`] docs for more info.
24
25use crate::{
26 core::{
27 algebra::{Matrix4, Point3, Vector2, Vector3},
28 math::{frustum::Frustum, Rect},
29 pool::Handle,
30 },
31 graphics::gpu_texture::CubeMapFace,
32 renderer::utils::CubeMapFaceDescriptor,
33 scene::{
34 camera::{Camera, ColorGradingLut, Exposure, PerspectiveProjection, Projection},
35 collider::BitMask,
36 node::Node,
37 probe::ReflectionProbe,
38 EnvironmentLightingSource, Scene,
39 },
40};
41use fyrox_core::color::Color;
42use fyrox_texture::TextureResource;
43
44/// Observer position contains all the data, that describes an observer position in 3D space. It
45/// could be a real camera, light source's "virtual camera" that is used for shadow mapping, etc.
46#[derive(Clone, Default)]
47pub struct ObserverPosition {
48 /// World-space position of the observer.
49 pub translation: Vector3<f32>,
50 /// Position of the near clipping plane.
51 pub z_near: f32,
52 /// Position of the far clipping plane.
53 pub z_far: f32,
54 /// The view matrix of the observer.
55 pub view_matrix: Matrix4<f32>,
56 /// Projection matrix of the observer.
57 pub projection_matrix: Matrix4<f32>,
58 /// Combination of the view and projection matrix.
59 pub view_projection_matrix: Matrix4<f32>,
60}
61
62impl ObserverPosition {
63 /// Creates a new observer position from a scene camera.
64 pub fn from_camera(camera: &Camera) -> Self {
65 Self {
66 translation: camera.global_position(),
67 z_near: camera.projection().z_near(),
68 z_far: camera.projection().z_far(),
69 view_matrix: camera.view_matrix(),
70 projection_matrix: camera.projection_matrix(),
71 view_projection_matrix: camera.view_projection_matrix(),
72 }
73 }
74}
75
76/// Collections of observers in a scene.
77#[derive(Default)]
78pub struct ObserversCollection {
79 /// Camera observers.
80 pub cameras: Vec<Observer>,
81 /// Reflection probes, rendered first.
82 pub reflection_probes: Vec<Observer>,
83}
84
85impl ObserversCollection {
86 /// Creates a new observers collection from a scene. This method collects all observers that
87 /// need to render the scene (which includes camera and reflection probes).
88 pub fn from_scene(scene: &Scene, frame_size: Vector2<f32>) -> Self {
89 let mut observers = Self::default();
90 for node in scene.graph.linear_iter() {
91 if node.is_globally_enabled() {
92 if let Some(camera) = node.cast::<Camera>() {
93 if camera.is_enabled() {
94 observers
95 .cameras
96 .push(Observer::from_camera(camera, frame_size));
97 }
98 } else if let Some(probe) = node.cast::<ReflectionProbe>() {
99 if probe.updated.get() {
100 continue;
101 }
102 probe.updated.set(true);
103
104 let projection = Projection::Perspective(PerspectiveProjection {
105 fov: 90.0f32.to_radians(),
106 z_near: *probe.z_near,
107 z_far: *probe.z_far,
108 });
109 let resolution = probe.resolution() as f32;
110 let cube_size = Vector2::repeat(probe.resolution() as f32);
111 let projection_matrix = projection.matrix(cube_size);
112
113 for cube_face in CubeMapFaceDescriptor::cube_faces() {
114 let translation = probe.global_rendering_position();
115 let view_matrix = Matrix4::look_at_rh(
116 &Point3::from(translation),
117 &Point3::from(translation + cube_face.look),
118 &cube_face.up,
119 );
120 let view_projection_matrix = projection_matrix * view_matrix;
121 observers.reflection_probes.push(Observer {
122 handle: node.handle(),
123 reflection_probe_data: Some(ReflectionProbeData {
124 cube_map_face: cube_face.face,
125 environment_lighting_source: *probe.environment_lighting_source,
126 ambient_lighting_color: *probe.ambient_lighting_color,
127 }),
128 render_target: Some(probe.render_target().clone()),
129 position: ObserverPosition {
130 translation,
131 z_near: *probe.z_near,
132 z_far: *probe.z_far,
133 view_matrix,
134 projection_matrix,
135 view_projection_matrix,
136 },
137 environment_map: None,
138 render_mask: *probe.render_mask,
139 projection: projection.clone(),
140 color_grading_lut: None,
141 color_grading_enabled: false,
142 exposure: Default::default(),
143 viewport: Rect::new(0, 0, resolution as i32, resolution as i32),
144 frustum: Frustum::from_view_projection_matrix(view_projection_matrix)
145 .unwrap_or_default(),
146 })
147 }
148 }
149 }
150 }
151 observers
152 }
153}
154
155/// The data used by the renderer when it's rendering a reflection probe.
156pub struct ReflectionProbeData {
157 /// Cube map face of a cube render target to which to render a scene.
158 pub cube_map_face: CubeMapFace,
159 /// Environment lighting source of the reflection probe. See [`EnvironmentLightingSource`] docs
160 /// for more info.
161 pub environment_lighting_source: EnvironmentLightingSource,
162 /// Ambient lighting color of the reflection probe.
163 pub ambient_lighting_color: Color,
164}
165
166/// An observer holds all the information required to render a scene from a particular point of view.
167/// Contains all information for rendering, effectively decouples rendering entities from scene
168/// entities. Observer can be constructed from an arbitrary set of data or from scene entities,
169/// such as cameras, reflection probes.
170pub struct Observer {
171 /// The handle of a scene node (camera, reflection probe, etc.) that was used to create this
172 /// Observer.
173 pub handle: Handle<Node>,
174 /// Additional data used by reflection probes only.
175 pub reflection_probe_data: Option<ReflectionProbeData>,
176 /// Render target to which to render the scene.
177 pub render_target: Option<TextureResource>,
178 /// Position of the observer. See [`ObserverPosition`] docs for more info.
179 pub position: ObserverPosition,
180 /// Environment map which will be used for IBL and reflections. If not set, then scene's skybox
181 /// will be used as an environment map.
182 pub environment_map: Option<TextureResource>,
183 /// A set of switches that defines which "layers" of the scene will be rendered.
184 pub render_mask: BitMask,
185 /// Projection mode that will be used to project the scene on screen's 2D plane.
186 pub projection: Projection,
187 /// Optional color grading lookup table. See [`ColorGradingLut`] docs for more info.
188 pub color_grading_lut: Option<ColorGradingLut>,
189 /// A flag, that defines whether the color grading enabled or not.
190 pub color_grading_enabled: bool,
191 /// Exposure settings that will be applied to scene's HDR image to convert it to the final
192 /// low dynamic range image that will be shown on a display.
193 pub exposure: Exposure,
194 /// Viewport rectangle in screen space. Defines a porting of the screen that needs to be rendered.
195 pub viewport: Rect<i32>,
196 /// Frustum of the observer, it can be used for frustum culling.
197 pub frustum: Frustum,
198}
199
200impl Observer {
201 /// Creates a new observer from a scene camera.
202 pub fn from_camera(camera: &Camera, mut frame_size: Vector2<f32>) -> Self {
203 if let Some(render_target) = camera.render_target() {
204 if let Some(size) = render_target
205 .data_ref()
206 .as_loaded_ref()
207 .and_then(|rt| rt.kind().rectangle_size().map(|size| size.cast::<f32>()))
208 {
209 frame_size = size;
210 }
211 }
212 Observer {
213 handle: camera.handle(),
214 environment_map: camera.environment_map(),
215 render_mask: *camera.render_mask,
216 projection: camera.projection().clone(),
217 position: ObserverPosition::from_camera(camera),
218 render_target: camera.render_target().cloned(),
219 color_grading_lut: camera.color_grading_lut(),
220 color_grading_enabled: camera.color_grading_enabled(),
221 exposure: camera.exposure(),
222 viewport: camera.viewport_pixels(frame_size),
223 frustum: camera.frustum(),
224 reflection_probe_data: None,
225 }
226 }
227}