1#![allow(missing_docs)] use crate::{
26 asset::untyped::ResourceKind,
27 core::{
28 algebra::{Matrix4, Vector3, Vector4},
29 arrayvec::ArrayVec,
30 color,
31 color::Color,
32 log::Log,
33 math::{frustum::Frustum, Rect},
34 pool::Handle,
35 sstorage::ImmutableString,
36 },
37 graph::BaseSceneGraph,
38 material::{
39 self, shader::ShaderDefinition, MaterialProperty, MaterialPropertyGroup, MaterialResource,
40 },
41 renderer::{
42 cache::{
43 geometry::GeometryCache,
44 shader::ShaderCache,
45 texture::TextureCache,
46 uniform::{UniformBlockLocation, UniformMemoryAllocator},
47 TimeToLive,
48 },
49 framework::{
50 error::FrameworkError,
51 framebuffer::{BufferLocation, FrameBuffer, ResourceBindGroup, ResourceBinding},
52 gpu_program::{ShaderProperty, ShaderPropertyKind, ShaderResourceKind},
53 gpu_texture::GpuTexture,
54 server::GraphicsServer,
55 uniform::StaticUniformBuffer,
56 uniform::{ByteStorage, UniformBuffer},
57 ElementRange,
58 },
59 FallbackResources, LightData, RenderPassStatistics,
60 },
61 resource::texture::TextureResource,
62 scene::{
63 graph::Graph,
64 light::{
65 directional::{CsmOptions, DirectionalLight},
66 point::PointLight,
67 spot::SpotLight,
68 BaseLight,
69 },
70 mesh::{
71 buffer::{
72 BytesStorage, TriangleBuffer, TriangleBufferRefMut, VertexAttributeDescriptor,
73 VertexBuffer, VertexBufferRefMut,
74 },
75 surface::{SurfaceData, SurfaceResource},
76 RenderPath,
77 },
78 node::{Node, RdcControlFlow},
79 },
80};
81use fxhash::{FxBuildHasher, FxHashMap, FxHasher};
82use fyrox_core::math::Matrix4Ext;
83use fyrox_graph::{SceneGraph, SceneGraphNode};
84use std::{
85 cell::RefCell,
86 fmt::{Debug, Formatter},
87 hash::{Hash, Hasher},
88 rc::Rc,
89};
90
91#[derive(Clone, Default)]
94pub struct ObserverInfo {
95 pub observer_position: Vector3<f32>,
97 pub z_near: f32,
99 pub z_far: f32,
101 pub view_matrix: Matrix4<f32>,
103 pub projection_matrix: Matrix4<f32>,
105}
106
107pub struct RenderContext<'a> {
110 pub elapsed_time: f32,
114 pub observer_info: &'a ObserverInfo,
115 pub frustum: Option<&'a Frustum>,
118 pub storage: &'a mut dyn RenderDataBundleStorageTrait,
121 pub graph: &'a Graph,
124 pub render_pass_name: &'a ImmutableString,
126}
127
128impl RenderContext<'_> {
129 pub fn calculate_sorting_index(&self, global_position: Vector3<f32>) -> u64 {
133 let granularity = 1000.0;
134 u64::MAX
135 - (self
136 .observer_info
137 .view_matrix
138 .transform_point(&(global_position.into()))
139 .z
140 * granularity) as u64
141 }
142}
143
144#[allow(missing_docs)] pub struct BundleRenderContext<'a> {
146 pub texture_cache: &'a mut TextureCache,
147 pub render_pass_name: &'a ImmutableString,
148 pub frame_buffer: &'a mut dyn FrameBuffer,
149 pub viewport: Rect<i32>,
150 pub uniform_memory_allocator: &'a mut UniformMemoryAllocator,
151
152 pub use_pom: bool,
154 pub light_position: &'a Vector3<f32>,
155 pub ambient_light: Color,
156 pub scene_depth: Option<&'a Rc<RefCell<dyn GpuTexture>>>,
159 pub fallback_resources: &'a FallbackResources,
160}
161
162pub struct SurfaceInstanceData {
164 pub world_transform: Matrix4<f32>,
166 pub bone_matrices: Vec<Matrix4<f32>>,
168 pub blend_shapes_weights: Vec<f32>,
170 pub element_range: ElementRange,
173 pub node_handle: Handle<Node>,
175}
176
177pub struct RenderDataBundle {
179 pub data: SurfaceResource,
181 pub time_to_live: TimeToLive,
184 pub instances: Vec<SurfaceInstanceData>,
186 pub material: MaterialResource,
188 pub render_path: RenderPath,
190 sort_index: u64,
191}
192
193impl Debug for RenderDataBundle {
194 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
195 write!(
196 f,
197 "Bundle {}: {} instances",
198 self.data.key(),
199 self.instances.len()
200 )
201 }
202}
203
204pub struct InstanceUniformData {
207 pub instance_block: UniformBlockLocation,
209 pub bone_matrices_block: Option<UniformBlockLocation>,
211}
212
213pub struct BundleUniformData {
216 pub material_property_group_blocks: Vec<(usize, UniformBlockLocation)>,
218 pub light_data_block: UniformBlockLocation,
220 pub instance_blocks: Vec<InstanceUniformData>,
222}
223
224pub struct GlobalUniformData {
225 pub camera_block: UniformBlockLocation,
227 pub lights_block: UniformBlockLocation,
229 pub graphics_settings_block: UniformBlockLocation,
231}
232
233fn write_with_material<T: ByteStorage>(
234 shader_property_group: &[ShaderProperty],
235 material_property_group: &MaterialPropertyGroup,
236 buf: &mut UniformBuffer<T>,
237) {
238 for shader_property in shader_property_group {
241 let material_property = material_property_group.property_ref(shader_property.name.clone());
242
243 macro_rules! push_value {
244 ($variant:ident, $shader_value:ident) => {
245 if let Some(property) = material_property {
246 if let MaterialProperty::$variant(material_value) = property {
247 buf.push(material_value);
248 } else {
249 buf.push($shader_value);
250 Log::err(format!(
251 "Unable to use material property {} because of mismatching types.\
252 Expected {:?} got {:?}. Fallback to shader default value.",
253 shader_property.name, shader_property, property
254 ));
255 }
256 } else {
257 buf.push($shader_value);
258 }
259 };
260 }
261
262 macro_rules! push_slice {
263 ($variant:ident, $shader_value:ident, $max_size:ident) => {
264 if let Some(property) = material_property {
265 if let MaterialProperty::$variant(material_value) = property {
266 buf.push_slice_with_max_size(material_value, *$max_size);
267 } else {
268 buf.push_slice_with_max_size($shader_value, *$max_size);
269 Log::err(format!(
270 "Unable to use material property {} because of mismatching types.\
271 Expected {:?} got {:?}. Fallback to shader default value.",
272 shader_property.name, shader_property, property
273 ))
274 }
275 } else {
276 buf.push_slice_with_max_size($shader_value, *$max_size);
277 }
278 };
279 }
280
281 use ShaderPropertyKind::*;
282 match &shader_property.kind {
283 Float(value) => push_value!(Float, value),
284 FloatArray { value, max_len } => push_slice!(FloatArray, value, max_len),
285 Int(value) => push_value!(Int, value),
286 IntArray { value, max_len } => push_slice!(IntArray, value, max_len),
287 UInt(value) => push_value!(UInt, value),
288 UIntArray { value, max_len } => push_slice!(UIntArray, value, max_len),
289 Vector2(value) => push_value!(Vector2, value),
290 Vector2Array { value, max_len } => push_slice!(Vector2Array, value, max_len),
291 Vector3(value) => push_value!(Vector3, value),
292 Vector3Array { value, max_len } => push_slice!(Vector3Array, value, max_len),
293 Vector4(value) => push_value!(Vector4, value),
294 Vector4Array { value, max_len } => push_slice!(Vector4Array, value, max_len),
295 Matrix2(value) => push_value!(Matrix2, value),
296 Matrix2Array { value, max_len } => push_slice!(Matrix2Array, value, max_len),
297 Matrix3(value) => push_value!(Matrix3, value),
298 Matrix3Array { value, max_len } => push_slice!(Matrix3Array, value, max_len),
299 Matrix4(value) => push_value!(Matrix4, value),
300 Matrix4Array { value, max_len } => push_slice!(Matrix4Array, value, max_len),
301 Bool(value) => push_value!(Bool, value),
302 Color { r, g, b, a } => {
303 let value = &color::Color::from_rgba(*r, *g, *b, *a);
304 push_value!(Color, value)
305 }
306 };
307 }
308}
309
310fn write_shader_values<T: ByteStorage>(
311 shader_property_group: &[ShaderProperty],
312 buf: &mut UniformBuffer<T>,
313) {
314 for property in shader_property_group {
315 use ShaderPropertyKind::*;
316 match &property.kind {
317 Float(value) => buf.push(value),
318 FloatArray { value, max_len } => buf.push_slice_with_max_size(value, *max_len),
319 Int(value) => buf.push(value),
320 IntArray { value, max_len } => buf.push_slice_with_max_size(value, *max_len),
321 UInt(value) => buf.push(value),
322 UIntArray { value, max_len } => buf.push_slice_with_max_size(value, *max_len),
323 Vector2(value) => buf.push(value),
324 Vector2Array { value, max_len } => buf.push_slice_with_max_size(value, *max_len),
325 Vector3(value) => buf.push(value),
326 Vector3Array { value, max_len } => buf.push_slice_with_max_size(value, *max_len),
327 Vector4(value) => buf.push(value),
328 Vector4Array { value, max_len } => buf.push_slice_with_max_size(value, *max_len),
329 Matrix2(value) => buf.push(value),
330 Matrix2Array { value, max_len } => buf.push_slice_with_max_size(value, *max_len),
331 Matrix3(value) => buf.push(value),
332 Matrix3Array { value, max_len } => buf.push_slice_with_max_size(value, *max_len),
333 Matrix4(value) => buf.push(value),
334 Matrix4Array { value, max_len } => buf.push_slice_with_max_size(value, *max_len),
335 Bool(value) => buf.push(value),
336 Color { r, g, b, a } => buf.push(&color::Color::from_rgba(*r, *g, *b, *a)),
337 };
338 }
339}
340
341impl RenderDataBundle {
342 pub fn write_uniforms(
344 &self,
345 view_projection_matrix: &Matrix4<f32>,
346 render_context: &mut BundleRenderContext,
347 ) -> Option<BundleUniformData> {
348 let mut material_state = self.material.state();
349
350 let material = material_state.data()?;
351
352 let mut material_property_group_blocks = Vec::new();
354 let shader = material.shader().data_ref();
355 for resource_definition in shader.definition.resources.iter() {
356 if resource_definition.is_built_in() {
358 continue;
359 }
360
361 let ShaderResourceKind::PropertyGroup(ref shader_property_group) =
362 resource_definition.kind
363 else {
364 continue;
365 };
366
367 let mut buf = StaticUniformBuffer::<16384>::new();
368
369 if let Some(material_property_group) =
370 material.property_group_ref(resource_definition.name.clone())
371 {
372 write_with_material(shader_property_group, material_property_group, &mut buf);
373 } else {
374 write_shader_values(shader_property_group, &mut buf)
378 }
379
380 material_property_group_blocks.push((
381 resource_definition.binding,
382 render_context.uniform_memory_allocator.allocate(buf),
383 ))
384 }
385
386 let light_data = StaticUniformBuffer::<256>::new()
387 .with(render_context.light_position)
388 .with(&render_context.ambient_light.as_frgba());
389 let light_data_block = render_context.uniform_memory_allocator.allocate(light_data);
390
391 let mut instance_blocks = Vec::with_capacity(self.instances.len());
393 for instance in self.instances.iter() {
394 let mut packed_blend_shape_weights =
395 [Vector4::<f32>::default(); ShaderDefinition::MAX_BLEND_SHAPE_WEIGHT_GROUPS];
396
397 for (i, blend_shape_weight) in instance.blend_shapes_weights.iter().enumerate() {
398 let n = i / 4;
399 let c = i % 4;
400 packed_blend_shape_weights[n][c] = *blend_shape_weight;
401 }
402
403 let instance_buffer = StaticUniformBuffer::<1024>::new()
404 .with(&instance.world_transform)
405 .with(&(view_projection_matrix * instance.world_transform))
406 .with(&(instance.blend_shapes_weights.len() as i32))
407 .with(&(!instance.bone_matrices.is_empty()))
408 .with_slice_with_max_size(
409 &packed_blend_shape_weights,
410 ShaderDefinition::MAX_BLEND_SHAPE_WEIGHT_GROUPS,
411 );
412
413 let mut instance_uniform_data = InstanceUniformData {
414 instance_block: render_context
415 .uniform_memory_allocator
416 .allocate(instance_buffer),
417 bone_matrices_block: None,
418 };
419
420 if !instance.bone_matrices.is_empty() {
421 const INIT: Matrix4<f32> = Matrix4::new(
422 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
423 );
424 let mut matrices = [INIT; ShaderDefinition::MAX_BONE_MATRICES];
425 const SIZE: usize = ShaderDefinition::MAX_BONE_MATRICES * size_of::<Matrix4<f32>>();
426 matrices[0..instance.bone_matrices.len()].copy_from_slice(&instance.bone_matrices);
427
428 let bone_matrices_block = render_context
429 .uniform_memory_allocator
430 .allocate(StaticUniformBuffer::<SIZE>::new().with_slice(&matrices));
431 instance_uniform_data.bone_matrices_block = Some(bone_matrices_block);
432 }
433
434 instance_blocks.push(instance_uniform_data);
435 }
436
437 Some(BundleUniformData {
438 material_property_group_blocks,
439 light_data_block,
440 instance_blocks,
441 })
442 }
443
444 pub fn render_to_frame_buffer<F>(
446 &self,
447 server: &dyn GraphicsServer,
448 geometry_cache: &mut GeometryCache,
449 shader_cache: &mut ShaderCache,
450 instance_filter: &mut F,
451 render_context: &mut BundleRenderContext,
452 bundle_uniform_data: BundleUniformData,
453 global_uniform_data: &GlobalUniformData,
454 ) -> Result<RenderPassStatistics, FrameworkError>
455 where
456 F: FnMut(&SurfaceInstanceData) -> bool,
457 {
458 let mut stats = RenderPassStatistics::default();
459
460 let mut material_state = self.material.state();
461
462 let Some(material) = material_state.data() else {
463 return Ok(stats);
464 };
465
466 let Some(geometry) = geometry_cache.get(server, &self.data, self.time_to_live) else {
467 return Ok(stats);
468 };
469
470 let Some(render_pass) =
471 shader_cache
472 .get(server, material.shader())
473 .and_then(|shader_set| {
474 shader_set
475 .render_passes
476 .get(render_context.render_pass_name)
477 })
478 else {
479 return Ok(stats);
480 };
481
482 let mut material_bindings = ArrayVec::<ResourceBinding, 32>::new();
483 let shader = material.shader().data_ref();
484 for resource_definition in shader.definition.resources.iter() {
485 let name = resource_definition.name.as_str();
486
487 match name {
488 "fyrox_sceneDepth" => {
489 material_bindings.push(ResourceBinding::texture_with_binding(
490 if let Some(scene_depth) = render_context.scene_depth.as_ref() {
491 scene_depth
492 } else {
493 &render_context.fallback_resources.black_dummy
494 },
495 resource_definition.binding,
496 ));
497 }
498 "fyrox_cameraData" => {
499 material_bindings.push(
500 render_context.uniform_memory_allocator.block_to_binding(
501 global_uniform_data.camera_block,
502 resource_definition.binding,
503 ),
504 );
505 }
506 "fyrox_lightData" => {
507 material_bindings.push(
508 render_context.uniform_memory_allocator.block_to_binding(
509 bundle_uniform_data.light_data_block,
510 resource_definition.binding,
511 ),
512 );
513 }
514 "fyrox_graphicsSettings" => {
515 material_bindings.push(
516 render_context.uniform_memory_allocator.block_to_binding(
517 global_uniform_data.graphics_settings_block,
518 resource_definition.binding,
519 ),
520 );
521 }
522 "fyrox_lightsBlock" => {
523 material_bindings.push(
524 render_context.uniform_memory_allocator.block_to_binding(
525 global_uniform_data.lights_block,
526 resource_definition.binding,
527 ),
528 );
529 }
530 _ => match resource_definition.kind {
531 ShaderResourceKind::Texture { fallback, .. } => {
532 let fallback = render_context.fallback_resources.sampler_fallback(fallback);
533
534 let texture = if let Some(binding) =
535 material.binding_ref(resource_definition.name.clone())
536 {
537 if let material::MaterialResourceBinding::Texture(binding) = binding {
538 binding
539 .value
540 .as_ref()
541 .and_then(|t| render_context.texture_cache.get(server, t))
542 .unwrap_or(fallback)
543 } else {
544 Log::err(format!(
545 "Unable to use texture binding {}, types mismatch! Expected \
546 {:?} got {:?}",
547 resource_definition.name, resource_definition.kind, binding
548 ));
549
550 fallback
551 }
552 } else {
553 fallback
554 };
555
556 material_bindings.push(ResourceBinding::texture_with_binding(
557 texture,
558 resource_definition.binding,
559 ));
560 }
561 ShaderResourceKind::PropertyGroup(_) => {
562 if let Some((_, block_location)) = bundle_uniform_data
564 .material_property_group_blocks
565 .iter()
566 .find(|(binding, _)| *binding == resource_definition.binding)
567 {
568 material_bindings.push(
569 render_context
570 .uniform_memory_allocator
571 .block_to_binding(*block_location, resource_definition.binding),
572 );
573 }
574 }
575 },
576 }
577 }
578
579 for (instance, uniform_data) in self
580 .instances
581 .iter()
582 .zip(bundle_uniform_data.instance_blocks)
583 {
584 if !instance_filter(instance) {
585 continue;
586 }
587 let mut instance_bindings = ArrayVec::<ResourceBinding, 32>::new();
588
589 for resource_definition in shader.definition.resources.iter() {
590 let name = resource_definition.name.as_str();
591 match name {
592 "fyrox_instanceData" => {
593 instance_bindings.push(
594 render_context.uniform_memory_allocator.block_to_binding(
595 uniform_data.instance_block,
596 resource_definition.binding,
597 ),
598 );
599 }
600 "fyrox_boneMatrices" => {
601 match uniform_data.bone_matrices_block {
602 Some(block) => {
603 instance_bindings.push(
604 render_context
605 .uniform_memory_allocator
606 .block_to_binding(block, resource_definition.binding),
607 );
608 }
609 None => {
610 instance_bindings.push(ResourceBinding::Buffer {
613 buffer: &*render_context
614 .fallback_resources
615 .bone_matrices_stub_uniform_buffer,
616 binding: BufferLocation::Explicit {
617 binding: resource_definition.binding,
618 },
619 data_usage: Default::default(),
620 });
621 }
622 }
623 }
624 _ => (),
625 };
626 }
627
628 stats += render_context.frame_buffer.draw(
629 geometry,
630 render_context.viewport,
631 &*render_pass.program,
632 &render_pass.draw_params,
633 &[
634 ResourceBindGroup {
635 bindings: &material_bindings,
636 },
637 ResourceBindGroup {
638 bindings: &instance_bindings,
639 },
640 ],
641 instance.element_range,
642 )?;
643 }
644
645 Ok(stats)
646 }
647}
648
649pub trait RenderDataBundleStorageTrait {
651 fn push_triangles(
672 &mut self,
673 layout: &[VertexAttributeDescriptor],
674 material: &MaterialResource,
675 render_path: RenderPath,
676 sort_index: u64,
677 node_handle: Handle<Node>,
678 func: &mut dyn FnMut(VertexBufferRefMut, TriangleBufferRefMut),
679 );
680
681 fn push(
686 &mut self,
687 data: &SurfaceResource,
688 material: &MaterialResource,
689 render_path: RenderPath,
690 sort_index: u64,
691 instance_data: SurfaceInstanceData,
692 );
693}
694
695pub enum LightSourceKind {
696 Spot {
697 full_cone_angle: f32,
698 hotspot_cone_angle: f32,
699 distance: f32,
700 shadow_bias: f32,
701 cookie_texture: Option<TextureResource>,
702 },
703 Point {
704 radius: f32,
705 shadow_bias: f32,
706 },
707 Directional {
708 csm_options: CsmOptions,
709 },
710 Unknown,
711}
712
713pub struct LightSource {
714 pub handle: Handle<Node>,
715 pub global_transform: Matrix4<f32>,
716 pub kind: LightSourceKind,
717 pub position: Vector3<f32>,
718 pub up_vector: Vector3<f32>,
719 pub side_vector: Vector3<f32>,
720 pub look_vector: Vector3<f32>,
721 pub cast_shadows: bool,
722 pub local_scale: Vector3<f32>,
723 pub color: Color,
724 pub intensity: f32,
725 pub scatter_enabled: bool,
726 pub scatter: Vector3<f32>,
727}
728
729pub struct RenderDataBundleStorage {
732 bundle_map: FxHashMap<u64, usize>,
733 pub observer_info: ObserverInfo,
734 pub bundles: Vec<RenderDataBundle>,
736 pub light_sources: Vec<LightSource>,
737}
738
739pub struct RenderDataBundleStorageOptions {
740 pub collect_lights: bool,
741}
742
743impl Default for RenderDataBundleStorageOptions {
744 fn default() -> Self {
745 Self {
746 collect_lights: true,
747 }
748 }
749}
750
751impl RenderDataBundleStorage {
752 pub fn new_empty(observer_info: ObserverInfo) -> Self {
753 Self {
754 bundle_map: Default::default(),
755 observer_info,
756 bundles: Default::default(),
757 light_sources: Default::default(),
758 }
759 }
760
761 pub fn from_graph(
765 graph: &Graph,
766 elapsed_time: f32,
767 observer_info: ObserverInfo,
768 render_pass_name: ImmutableString,
769 options: RenderDataBundleStorageOptions,
770 ) -> Self {
771 let capacity = graph.node_count() as usize;
773 let mut storage = Self {
774 bundle_map: FxHashMap::with_capacity_and_hasher(capacity, FxBuildHasher::default()),
775 observer_info: observer_info.clone(),
776 bundles: Vec::with_capacity(capacity),
777 light_sources: Default::default(),
778 };
779
780 let frustum = Frustum::from_view_projection_matrix(
781 observer_info.projection_matrix * observer_info.view_matrix,
782 )
783 .unwrap_or_default();
784
785 let mut lod_filter = vec![true; graph.capacity() as usize];
786 for (node_handle, node) in graph.pair_iter() {
787 if let Some(lod_group) = node.lod_group() {
788 for level in lod_group.levels.iter() {
789 for &object in level.objects.iter() {
790 if let Some(object_ref) = graph.try_get(object) {
791 let distance = observer_info
792 .observer_position
793 .metric_distance(&object_ref.global_position());
794 let z_range = observer_info.z_far - observer_info.z_near;
795 let normalized_distance = (distance - observer_info.z_near) / z_range;
796 let visible = normalized_distance >= level.begin()
797 && normalized_distance <= level.end();
798 lod_filter[object.index() as usize] = visible;
799 }
800 }
801 }
802 }
803
804 if options.collect_lights {
805 if let Some(base_light) = node.component_ref::<BaseLight>() {
806 if frustum.is_intersects_aabb(&node.world_bounding_box())
807 && base_light.global_visibility()
808 && base_light.is_globally_enabled()
809 {
810 let kind = if let Some(spot_light) = node.cast::<SpotLight>() {
811 LightSourceKind::Spot {
812 full_cone_angle: spot_light.full_cone_angle(),
813 hotspot_cone_angle: spot_light.hotspot_cone_angle(),
814 distance: spot_light.distance(),
815 shadow_bias: spot_light.shadow_bias(),
816 cookie_texture: spot_light.cookie_texture(),
817 }
818 } else if let Some(point_light) = node.cast::<PointLight>() {
819 LightSourceKind::Point {
820 radius: point_light.radius(),
821 shadow_bias: point_light.shadow_bias(),
822 }
823 } else if let Some(directional_light) = node.cast::<DirectionalLight>() {
824 LightSourceKind::Directional {
825 csm_options: (*directional_light.csm_options).clone(),
826 }
827 } else {
828 LightSourceKind::Unknown
829 };
830
831 let source = LightSource {
832 handle: node_handle,
833 global_transform: base_light.global_transform(),
834 kind,
835 position: base_light.global_position(),
836 up_vector: base_light.up_vector(),
837 side_vector: base_light.side_vector(),
838 look_vector: base_light.look_vector(),
839 cast_shadows: base_light.cast_shadows(),
840 local_scale: **base_light.local_transform().scale(),
841 color: base_light.color(),
842 intensity: base_light.intensity(),
843 scatter_enabled: base_light.is_scatter_enabled(),
844 scatter: base_light.scatter(),
845 };
846
847 storage.light_sources.push(source);
848 }
849 }
850 }
851 }
852
853 let mut ctx = RenderContext {
854 elapsed_time,
855 observer_info: &observer_info,
856 frustum: Some(&frustum),
857 storage: &mut storage,
858 graph,
859 render_pass_name: &render_pass_name,
860 };
861
862 #[inline(always)]
863 fn iterate_recursive(
864 node_handle: Handle<Node>,
865 graph: &Graph,
866 lod_filter: &[bool],
867 ctx: &mut RenderContext,
868 ) {
869 if lod_filter[node_handle.index() as usize] {
870 let node = graph.node(node_handle);
871 if let RdcControlFlow::Continue = node.collect_render_data(ctx) {
872 for child in node.children() {
873 iterate_recursive(*child, graph, lod_filter, ctx);
874 }
875 }
876 }
877 }
878
879 iterate_recursive(graph.root(), graph, &lod_filter, &mut ctx);
880
881 storage.sort();
882
883 storage
884 }
885
886 pub fn sort(&mut self) {
888 self.bundles.sort_unstable_by_key(|b| b.sort_index);
889 }
890
891 pub fn write_global_uniform_blocks(
892 &self,
893 render_context: &mut BundleRenderContext,
894 ) -> GlobalUniformData {
895 let mut light_data = LightData::<{ ShaderDefinition::MAX_LIGHTS }>::default();
896
897 for (i, light) in self
898 .light_sources
899 .iter()
900 .enumerate()
901 .take(ShaderDefinition::MAX_LIGHTS)
902 {
903 let color = light.color.as_frgb();
904
905 light_data.color_radius[i] = Vector4::new(color.x, color.y, color.z, 0.0);
906 light_data.position[i] = light.position;
907 light_data.direction[i] = light.up_vector;
908
909 match light.kind {
910 LightSourceKind::Spot {
911 full_cone_angle,
912 hotspot_cone_angle,
913 distance,
914 ..
915 } => {
916 light_data.color_radius[i].w = distance;
917 light_data.parameters[i].x = (hotspot_cone_angle * 0.5).cos();
918 light_data.parameters[i].y = (full_cone_angle * 0.5).cos();
919 }
920 LightSourceKind::Point { radius, .. } => {
921 light_data.color_radius[i].w = radius;
922 light_data.parameters[i].x = std::f32::consts::PI.cos();
923 light_data.parameters[i].y = std::f32::consts::PI.cos();
924 }
925 LightSourceKind::Directional { .. } => {
926 light_data.color_radius[i].w = f32::INFINITY;
927 light_data.parameters[i].x = std::f32::consts::PI.cos();
928 light_data.parameters[i].y = std::f32::consts::PI.cos();
929 }
930 LightSourceKind::Unknown => {}
931 }
932
933 light_data.count += 1;
934 }
935
936 let lights_data = StaticUniformBuffer::<2048>::new()
937 .with(&(light_data.count as i32))
938 .with_slice(&light_data.color_radius)
939 .with_slice(&light_data.parameters)
940 .with_slice(&light_data.position)
941 .with_slice(&light_data.direction);
942 let lights_block = render_context
943 .uniform_memory_allocator
944 .allocate(lights_data);
945
946 let inv_view = self
948 .observer_info
949 .view_matrix
950 .try_inverse()
951 .unwrap_or_default();
952 let view_projection = self.observer_info.projection_matrix * self.observer_info.view_matrix;
953 let camera_up = inv_view.up();
954 let camera_side = inv_view.side();
955 let camera_uniforms = StaticUniformBuffer::<512>::new()
956 .with(&view_projection)
957 .with(&self.observer_info.observer_position)
958 .with(&camera_up)
959 .with(&camera_side)
960 .with(&self.observer_info.z_near)
961 .with(&self.observer_info.z_far)
962 .with(&(self.observer_info.z_far - self.observer_info.z_near));
963 let camera_block = render_context
964 .uniform_memory_allocator
965 .allocate(camera_uniforms);
966
967 let graphics_settings = StaticUniformBuffer::<256>::new().with(&render_context.use_pom);
968 let graphics_settings_block = render_context
969 .uniform_memory_allocator
970 .allocate(graphics_settings);
971
972 GlobalUniformData {
973 camera_block,
974 lights_block,
975 graphics_settings_block,
976 }
977 }
978
979 pub fn render_to_frame_buffer<BundleFilter, InstanceFilter>(
981 &self,
982 server: &dyn GraphicsServer,
983 geometry_cache: &mut GeometryCache,
984 shader_cache: &mut ShaderCache,
985 mut bundle_filter: BundleFilter,
986 mut instance_filter: InstanceFilter,
987 mut render_context: BundleRenderContext,
988 ) -> Result<RenderPassStatistics, FrameworkError>
989 where
990 BundleFilter: FnMut(&RenderDataBundle) -> bool,
991 InstanceFilter: FnMut(&SurfaceInstanceData) -> bool,
992 {
993 let global_uniforms = self.write_global_uniform_blocks(&mut render_context);
994
995 let view_projection = self.observer_info.projection_matrix * self.observer_info.view_matrix;
996 let mut bundle_uniform_data_set = Vec::with_capacity(self.bundles.len());
997 for bundle in self.bundles.iter() {
998 if !bundle_filter(bundle) {
999 continue;
1000 }
1001 bundle_uniform_data_set
1002 .push(bundle.write_uniforms(&view_projection, &mut render_context));
1003 }
1004 render_context.uniform_memory_allocator.upload(server)?;
1005
1006 let mut stats = RenderPassStatistics::default();
1007 for (bundle, bundle_uniform_data) in self
1008 .bundles
1009 .iter()
1010 .filter(|bundle| bundle_filter(bundle))
1011 .zip(bundle_uniform_data_set)
1012 {
1013 if let Some(bundle_uniform_data) = bundle_uniform_data {
1014 stats += bundle.render_to_frame_buffer(
1015 server,
1016 geometry_cache,
1017 shader_cache,
1018 &mut instance_filter,
1019 &mut render_context,
1020 bundle_uniform_data,
1021 &global_uniforms,
1022 )?
1023 }
1024 }
1025 Ok(stats)
1026 }
1027}
1028
1029impl RenderDataBundleStorageTrait for RenderDataBundleStorage {
1030 fn push_triangles(
1051 &mut self,
1052 layout: &[VertexAttributeDescriptor],
1053 material: &MaterialResource,
1054 render_path: RenderPath,
1055 sort_index: u64,
1056 node_handle: Handle<Node>,
1057 func: &mut dyn FnMut(VertexBufferRefMut, TriangleBufferRefMut),
1058 ) {
1059 let mut hasher = FxHasher::default();
1060 hasher.write_u64(material.key());
1061 layout.hash(&mut hasher);
1062 hasher.write_u32(render_path as u32);
1063 let key = hasher.finish();
1064
1065 let bundle = if let Some(&bundle_index) = self.bundle_map.get(&key) {
1066 self.bundles.get_mut(bundle_index).unwrap()
1067 } else {
1068 let default_capacity = 4096;
1069
1070 let vertex_buffer = VertexBuffer::new_with_layout(
1072 layout,
1073 0,
1074 BytesStorage::with_capacity(default_capacity),
1075 )
1076 .unwrap();
1077
1078 let triangle_buffer = TriangleBuffer::new(Vec::with_capacity(default_capacity * 3));
1080
1081 let data = SurfaceResource::new_ok(
1083 ResourceKind::Embedded,
1084 SurfaceData::new(vertex_buffer, triangle_buffer),
1085 );
1086
1087 self.bundle_map.insert(key, self.bundles.len());
1088 self.bundles.push(RenderDataBundle {
1089 data,
1090 sort_index,
1091 instances: vec![
1092 SurfaceInstanceData {
1094 world_transform: Matrix4::identity(),
1095 bone_matrices: Default::default(),
1096 blend_shapes_weights: Default::default(),
1097 element_range: Default::default(),
1098 node_handle,
1099 },
1100 ],
1101 material: material.clone(),
1102 render_path,
1103 time_to_live: TimeToLive(0.0),
1105 });
1106 self.bundles.last_mut().unwrap()
1107 };
1108
1109 let mut data = bundle.data.data_ref();
1110 let data = &mut *data;
1111
1112 let vertex_buffer = data.vertex_buffer.modify();
1113 let triangle_buffer = data.geometry_buffer.modify();
1114
1115 func(vertex_buffer, triangle_buffer);
1116 }
1117
1118 fn push(
1122 &mut self,
1123 data: &SurfaceResource,
1124 material: &MaterialResource,
1125 render_path: RenderPath,
1126 sort_index: u64,
1127 instance_data: SurfaceInstanceData,
1128 ) {
1129 let mut hasher = FxHasher::default();
1130 hasher.write_u64(material.key());
1131 hasher.write_u64(data.key());
1132 hasher.write_u32(render_path as u32);
1133 let key = hasher.finish();
1134
1135 let bundle = if let Some(&bundle_index) = self.bundle_map.get(&key) {
1136 self.bundles.get_mut(bundle_index).unwrap()
1137 } else {
1138 self.bundle_map.insert(key, self.bundles.len());
1139 self.bundles.push(RenderDataBundle {
1140 data: data.clone(),
1141 sort_index,
1142 instances: Default::default(),
1143 material: material.clone(),
1144 render_path,
1145 time_to_live: Default::default(),
1146 });
1147 self.bundles.last_mut().unwrap()
1148 };
1149
1150 bundle.instances.push(instance_data)
1151 }
1152}