use super::MeshAdvRenderFeature;
use super::MeshAdvRenderOptions;
use crate::components::{
DirectionalLightComponent, PointLightComponent, SpotLightComponent, TransformComponent,
};
use crate::features::mesh_adv::internal::{ShadowMapAtlas, ShadowMapAtlasElement};
use crate::features::mesh_adv::ShadowMapAtlasElementInfo;
use crate::phases::ShadowMapRenderPhase;
use fnv::{FnvHashMap, FnvHashSet, FnvHasher};
use legion::*;
use rafx::framework::render_features::RenderFeatureFlagMask;
use rafx::rafx_visibility::{
DepthRange, OrthographicParameters, PerspectiveParameters, Projection,
};
use rafx::render_features::{
ExtractResources, RenderFeatureMask, RenderFeatureMaskBuilder, RenderPhaseMaskBuilder,
RenderView, RenderViewDepthRange, RenderViewIndex, RenderViewSet,
};
use rafx::visibility::{ObjectId, ViewFrustumArc};
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum MeshAdvLightId {
PointLight(ObjectId),
SpotLight(ObjectId),
DirectionalLight(ObjectId),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum MeshAdvShadowViewId {
SpotLight(ObjectId),
DirectionalLight(ObjectId),
PointLight(ObjectId, u8),
}
impl MeshAdvShadowViewId {
fn light_type_to_int_and_object_id(&self) -> (u8, ObjectId) {
match self {
MeshAdvShadowViewId::SpotLight(object_id) => (1, *object_id),
MeshAdvShadowViewId::DirectionalLight(object_id) => (0, *object_id),
MeshAdvShadowViewId::PointLight(object_id, cube_map_index) => {
(2 + cube_map_index, *object_id)
}
}
}
}
impl PartialOrd for MeshAdvShadowViewId {
fn partial_cmp(
&self,
other: &Self,
) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for MeshAdvShadowViewId {
fn cmp(
&self,
other: &Self,
) -> Ordering {
let (lhs_type, lhs_object_id) = self.light_type_to_int_and_object_id();
let (rhs_type, rhs_object_id) = other.light_type_to_int_and_object_id();
lhs_object_id
.cmp(&rhs_object_id)
.then_with(|| lhs_type.cmp(&rhs_type))
}
}
#[derive(Clone)]
pub enum MeshAdvShadowMapRenderViewIndices {
Single(ShadowViewIndex),
Cube([Option<ShadowViewIndex>; 6]),
}
impl MeshAdvShadowMapRenderViewIndices {
pub fn unwrap_single(&self) -> ShadowViewIndex {
match self {
MeshAdvShadowMapRenderViewIndices::Single(value) => *value,
MeshAdvShadowMapRenderViewIndices::Cube(_) => {
panic!("Called unwrap_single() on MeshAdvShadowMapRenderViewIndices::Cube")
}
}
}
pub fn unwrap_cube_any(&self) -> ShadowViewIndex {
match self {
MeshAdvShadowMapRenderViewIndices::Single(_) => {
panic!("Called unwrap_cube_any() on MeshAdvShadowMapRenderViewIndices::Single")
}
MeshAdvShadowMapRenderViewIndices::Cube(views) => {
for view in views {
if view.is_some() {
return view.unwrap();
}
}
panic!("Called unwrap_cube_any() on MeshAdvShadowMapRenderViewIndices::Cube but all views are unassigned")
}
}
}
}
#[derive(PartialEq)]
struct PotentialShadowView {
score: f32,
shadow_view_id: MeshAdvShadowViewId,
light_state_hash: u64,
}
impl Eq for PotentialShadowView {}
impl PartialOrd for PotentialShadowView {
fn partial_cmp(
&self,
other: &Self,
) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for PotentialShadowView {
fn cmp(
&self,
other: &Self,
) -> Ordering {
self.score
.partial_cmp(&other.score)
.unwrap()
.then_with(|| self.shadow_view_id.cmp(&other.shadow_view_id))
}
}
#[derive(Clone)]
pub struct MeshAdvShadowMapRenderViewMeta {
pub view_dir: glam::Vec3,
pub view_proj: glam::Mat4,
pub depth_range: RenderViewDepthRange,
}
impl MeshAdvShadowMapRenderViewMeta {
fn new(
view: &glam::Mat4,
proj: &glam::Mat4,
depth_range: RenderViewDepthRange,
) -> MeshAdvShadowMapRenderViewMeta {
MeshAdvShadowMapRenderViewMeta {
view_dir: RenderView::view_mat4_to_view_dir(&view),
view_proj: (*proj) * (*view),
depth_range,
}
}
}
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct ShadowViewIndex(usize);
#[derive(Default)]
pub struct MeshAdvShadowMapResource {
pub(super) shadow_map_lookup_by_shadow_view_id:
FnvHashMap<MeshAdvShadowViewId, ShadowViewIndex>,
pub(super) shadow_map_atlas_element_assignments: Vec<Option<ShadowMapAtlasElement>>,
pub(super) previous_light_state_hashes: Vec<u64>,
pub(super) shadow_maps_needing_redraw: FnvHashSet<ShadowViewIndex>,
pub(super) shadow_map_render_views_meta: Vec<MeshAdvShadowMapRenderViewMeta>,
pub(super) shadow_map_render_views: Vec<Option<RenderView>>,
pub(super) shadow_map_lookup_by_render_view_index: FnvHashMap<RenderViewIndex, ShadowViewIndex>,
pub(super) shadow_map_lookup_by_light_id:
FnvHashMap<MeshAdvLightId, MeshAdvShadowMapRenderViewIndices>,
}
impl MeshAdvShadowMapResource {
pub fn shadow_map_render_views(&self) -> &[Option<RenderView>] {
&self.shadow_map_render_views
}
pub fn shadow_maps_needing_redraw(&self) -> &FnvHashSet<ShadowViewIndex> {
&self.shadow_maps_needing_redraw
}
pub fn clear(&mut self) {
self.shadow_maps_needing_redraw.clear();
self.shadow_map_atlas_element_assignments.clear();
self.shadow_map_lookup_by_shadow_view_id.clear();
self.shadow_map_lookup_by_render_view_index.clear();
self.shadow_map_render_views.clear();
self.shadow_map_render_views_meta.clear();
self.shadow_map_lookup_by_light_id.clear();
}
pub(super) fn shadow_map_atlas_element_assignment(
&self,
shadow_view_index: ShadowViewIndex,
) -> &ShadowMapAtlasElement {
self.shadow_map_atlas_element_assignments[shadow_view_index.0]
.as_ref()
.unwrap()
}
pub(super) fn shadow_map_render_views_meta(
&self,
shadow_view_index: ShadowViewIndex,
) -> &MeshAdvShadowMapRenderViewMeta {
&self.shadow_map_render_views_meta[shadow_view_index.0]
}
pub fn shadow_map_atlas_element_info_for_shadow_view_index(
&self,
shadow_view_index: ShadowViewIndex,
) -> ShadowMapAtlasElementInfo {
self.shadow_map_atlas_element_assignments[shadow_view_index.0]
.as_ref()
.unwrap()
.info()
}
pub fn shadow_map_atlas_element_info_for_view(
&self,
view_index: RenderViewIndex,
) -> Option<ShadowMapAtlasElementInfo> {
self.shadow_map_lookup_by_render_view_index
.get(&view_index)
.map(|&index| {
self.shadow_map_atlas_element_assignments[index.0]
.as_ref()
.unwrap()
.info()
})
}
pub fn append_render_views(
&self,
render_views: &mut Vec<RenderView>,
) {
for shadow_map_view in &self.shadow_map_render_views {
if let Some(shadow_map_view) = shadow_map_view {
render_views.push(shadow_map_view.clone());
}
}
}
pub fn recalculate_shadow_map_views(
&mut self,
render_view_set: &RenderViewSet,
extract_resources: &ExtractResources,
shadow_map_atlas: &mut ShadowMapAtlas,
main_view_eye_position: glam::Vec3,
) {
Self::reassign_shadow_atlas_elements(
&mut self.shadow_map_lookup_by_shadow_view_id,
&mut self.shadow_map_atlas_element_assignments,
&mut self.previous_light_state_hashes,
&mut self.shadow_maps_needing_redraw,
extract_resources,
main_view_eye_position,
shadow_map_atlas,
);
Self::calculate_shadow_map_views(
render_view_set,
extract_resources,
&self.shadow_map_lookup_by_shadow_view_id,
&self.shadow_map_atlas_element_assignments,
&self.shadow_maps_needing_redraw,
&mut self.shadow_map_render_views_meta,
&mut self.shadow_map_render_views,
&mut self.shadow_map_lookup_by_render_view_index,
&mut self.shadow_map_lookup_by_light_id,
);
}
fn hash_f32<HasherT: Hasher>(
value: f32,
hasher: &mut HasherT,
) {
rafx::base::DecimalF32(value).hash(hasher);
}
fn hash_option_f32<HasherT: Hasher>(
value: Option<f32>,
hasher: &mut HasherT,
) {
value.map(|x| Self::hash_f32(x, hasher));
}
fn hash_vec3<HasherT: Hasher>(
value: glam::Vec3,
hasher: &mut HasherT,
) {
Self::hash_f32(value.x, hasher);
Self::hash_f32(value.y, hasher);
Self::hash_f32(value.z, hasher);
}
fn hash_quat<HasherT: Hasher>(
value: glam::Quat,
hasher: &mut HasherT,
) {
Self::hash_f32(value.x, hasher);
Self::hash_f32(value.y, hasher);
Self::hash_f32(value.z, hasher);
Self::hash_f32(value.w, hasher);
}
fn hash_transform<HasherT: Hasher>(
value: &TransformComponent,
hasher: &mut HasherT,
) {
Self::hash_vec3(value.translation, hasher);
Self::hash_quat(value.rotation, hasher);
Self::hash_vec3(value.scale, hasher);
}
fn find_potential_shadow_views(
extract_resources: &ExtractResources,
main_view_eye_position: glam::Vec3,
) -> Vec<PotentialShadowView> {
let world_fetch = extract_resources.fetch::<World>();
let world = &*world_fetch;
fn calculate_score(
eye_position: glam::Vec3,
light_position: glam::Vec3,
) -> f32 {
eye_position.distance_squared(light_position)
}
let mut heap = std::collections::binary_heap::BinaryHeap::<PotentialShadowView>::new();
let mut query = <(Entity, Read<SpotLightComponent>, Read<TransformComponent>)>::query();
for (entity, light, transform) in query.iter(world) {
if light.shadow_view_frustum.is_none() {
continue;
}
let shadow_view_id = MeshAdvShadowViewId::SpotLight(ObjectId::from(*entity));
let score = calculate_score(main_view_eye_position, transform.translation);
let mut h = FnvHasher::default();
Self::hash_transform(&transform, &mut h);
Self::hash_vec3(light.direction, &mut h);
Self::hash_f32(light.spotlight_half_angle, &mut h);
Self::hash_option_f32(light.range, &mut h);
heap.push(PotentialShadowView {
shadow_view_id,
score,
light_state_hash: h.finish(),
});
}
let mut query = <(Entity, Read<DirectionalLightComponent>)>::query();
for (entity, light) in query.iter(world) {
if light.shadow_view_frustum.is_none() {
continue;
}
let shadow_view_id = MeshAdvShadowViewId::DirectionalLight(ObjectId::from(*entity));
let score = 0.0;
let mut h = FnvHasher::default();
Self::hash_vec3(light.direction, &mut h);
heap.push(PotentialShadowView {
shadow_view_id,
score,
light_state_hash: h.finish(),
});
}
let mut query = <(Entity, Read<PointLightComponent>, Read<TransformComponent>)>::query();
for (entity, light, transform) in query.iter(world) {
if light.shadow_view_frustums.is_none() {
continue;
}
for i in 0..6 {
let shadow_view_id = MeshAdvShadowViewId::PointLight(ObjectId::from(*entity), i);
let score = calculate_score(main_view_eye_position, transform.translation);
let mut h = FnvHasher::default();
Self::hash_transform(&transform, &mut h);
Self::hash_option_f32(light.range, &mut h);
heap.push(PotentialShadowView {
shadow_view_id,
score,
light_state_hash: h.finish(),
});
}
}
heap.into_sorted_vec()
}
fn reassign_shadow_atlas_elements(
shadow_map_lookup_by_shadow_view_id: &mut FnvHashMap<MeshAdvShadowViewId, ShadowViewIndex>,
shadow_map_atlas_element_assignments: &mut Vec<Option<ShadowMapAtlasElement>>,
previous_light_state_hashes: &mut Vec<u64>,
shadow_maps_needing_redraw: &mut FnvHashSet<ShadowViewIndex>,
extract_resources: &ExtractResources,
main_view_eye_position: glam::Vec3,
shadow_map_atlas: &mut ShadowMapAtlas,
) {
shadow_maps_needing_redraw.clear();
let mut potential_views =
Self::find_potential_shadow_views(extract_resources, main_view_eye_position);
let mut new_assignments = Vec::with_capacity(potential_views.len());
let mut new_light_state_hashes = Vec::with_capacity(potential_views.len());
for potential_view in &potential_views {
if let Some(&old_shadow_view_index) =
shadow_map_lookup_by_shadow_view_id.get(&potential_view.shadow_view_id)
{
let assignment = shadow_map_atlas_element_assignments[old_shadow_view_index.0]
.take()
.unwrap();
let new_shadow_view_index = ShadowViewIndex(new_assignments.len());
new_assignments.push(Some(assignment));
new_light_state_hashes.push(potential_view.light_state_hash);
if potential_view.light_state_hash
!= previous_light_state_hashes[old_shadow_view_index.0]
{
shadow_maps_needing_redraw.insert(new_shadow_view_index);
}
} else {
new_assignments.push(None);
new_light_state_hashes.push(potential_view.light_state_hash);
}
}
shadow_map_atlas_element_assignments.clear();
let quality_level_count = shadow_map_atlas.quality_level_count();
let mut in_use_assignments_by_quality = vec![Vec::default(); quality_level_count];
for (shadow_view_index, assignment) in new_assignments.iter_mut().enumerate() {
if let Some(assignment) = assignment {
in_use_assignments_by_quality[assignment.quality() as usize]
.push(shadow_view_index);
}
}
for shadow_view_index in 0..new_assignments.len() {
'find_shadow_map: for desired_quality in 0..quality_level_count {
if let Some(assignment) = &new_assignments[shadow_view_index] {
if assignment.quality() <= desired_quality as u8 {
break 'find_shadow_map;
}
}
if let Some(element) = shadow_map_atlas.allocate(desired_quality as u8) {
shadow_maps_needing_redraw.insert(ShadowViewIndex(shadow_view_index));
new_assignments[shadow_view_index] = Some(element);
break 'find_shadow_map;
}
while let Some(other_shadow_view_index) =
in_use_assignments_by_quality[desired_quality].pop()
{
if other_shadow_view_index > shadow_view_index {
shadow_maps_needing_redraw.insert(ShadowViewIndex(shadow_view_index));
new_assignments[shadow_view_index] =
new_assignments[other_shadow_view_index].take();
break 'find_shadow_map;
}
}
}
}
let shadow_view_count = new_assignments
.iter()
.position(|x| x.is_none())
.unwrap_or(new_assignments.len());
new_assignments.resize_with(shadow_view_count, || unreachable!());
potential_views.resize_with(shadow_view_count, || unreachable!());
let mut new_lookup = FnvHashMap::default();
new_lookup.reserve(shadow_view_count);
for (i, potential_view) in potential_views.iter().enumerate() {
new_lookup.insert(potential_view.shadow_view_id, ShadowViewIndex(i));
}
*shadow_map_lookup_by_shadow_view_id = new_lookup;
*shadow_map_atlas_element_assignments = new_assignments;
*previous_light_state_hashes = new_light_state_hashes;
}
#[profiling::function]
fn calculate_shadow_map_views(
render_view_set: &RenderViewSet,
extract_resources: &ExtractResources,
shadow_map_lookup_by_shadow_view_id: &FnvHashMap<MeshAdvShadowViewId, ShadowViewIndex>,
shadow_map_atlas_element_assignments: &Vec<Option<ShadowMapAtlasElement>>,
shadow_maps_needing_redraw: &FnvHashSet<ShadowViewIndex>,
out_shadow_map_render_views_meta: &mut Vec<MeshAdvShadowMapRenderViewMeta>,
out_shadow_map_render_views: &mut Vec<Option<RenderView>>,
out_shadow_map_lookup_by_view_index: &mut FnvHashMap<RenderViewIndex, ShadowViewIndex>,
out_shadow_map_lookup_by_light_id: &mut FnvHashMap<
MeshAdvLightId,
MeshAdvShadowMapRenderViewIndices,
>,
) {
let world_fetch = extract_resources.fetch::<World>();
let world = &*world_fetch;
out_shadow_map_render_views_meta.clear();
out_shadow_map_render_views.clear();
out_shadow_map_lookup_by_view_index.clear();
out_shadow_map_lookup_by_light_id.clear();
let mut shadow_map_render_views_meta =
vec![None; shadow_map_atlas_element_assignments.len()];
let mut shadow_map_render_views = vec![None; shadow_map_atlas_element_assignments.len()];
let shadow_map_phase_mask = RenderPhaseMaskBuilder::default()
.add_render_phase::<ShadowMapRenderPhase>()
.build();
let render_options = extract_resources.fetch::<MeshAdvRenderOptions>();
let shadow_map_feature_mask = if render_options.show_surfaces
&& render_options.show_shadows
&& render_options.enable_lighting
{
RenderFeatureMaskBuilder::default()
.add_render_feature::<MeshAdvRenderFeature>()
.build()
} else {
RenderFeatureMask::empty()
};
let mut query = <(Entity, Read<SpotLightComponent>, Read<TransformComponent>)>::query();
for (entity, light, transform) in query.iter(world) {
let shadow_view_id = MeshAdvShadowViewId::SpotLight(ObjectId::from(*entity));
let shadow_view_index = shadow_map_lookup_by_shadow_view_id.get(&shadow_view_id);
if let Some(&shadow_view_index) = shadow_view_index {
let eye_position = transform.translation;
let light_to = transform.translation + light.direction;
let view =
glam::Mat4::look_at_rh(eye_position, light_to, glam::Vec3::new(0.0, 0.0, 1.0));
let near_plane = 0.25;
let far_plane = light.range();
const MAX_HALF_ANGLE_DEG: f32 = 89.0;
const MAX_HALF_HANGLE_RAD: f32 =
MAX_HALF_ANGLE_DEG * (std::f32::consts::PI / 180.0);
let spotlight_half_angle = if light.spotlight_half_angle > MAX_HALF_HANGLE_RAD {
log::warn!(
"Spotlight has > {} degree FOV, clamping the value",
2.0 * MAX_HALF_ANGLE_DEG
);
MAX_HALF_HANGLE_RAD
} else {
light.spotlight_half_angle
};
let fov_y_radians = spotlight_half_angle * 2.0;
let projection = Projection::Perspective(PerspectiveParameters::new(
fov_y_radians,
1.0,
near_plane,
far_plane,
DepthRange::Reverse,
));
let proj = projection.as_rh_mat4();
let depth_range = RenderViewDepthRange::from_projection(&projection);
shadow_map_render_views_meta[shadow_view_index.0] = Some(
MeshAdvShadowMapRenderViewMeta::new(&view, &proj, depth_range.clone()),
);
if shadow_maps_needing_redraw.contains(&shadow_view_index) {
let view_frustum: ViewFrustumArc =
light.shadow_view_frustum.as_ref().unwrap().clone();
view_frustum.set_projection(&projection).set_transform(
eye_position,
light_to,
glam::Vec3::new(0.0, 0.0, 1.0),
);
let shadow_map_assignment = shadow_map_atlas_element_assignments
[shadow_view_index.0]
.as_ref()
.unwrap();
let resolution = shadow_map_assignment.texture_size_pixels() as u32;
let view = render_view_set.create_view(
view_frustum.clone(),
eye_position,
view,
proj,
(resolution, resolution),
depth_range,
shadow_map_phase_mask,
shadow_map_feature_mask,
RenderFeatureFlagMask::empty(),
"shadow_map_spotlight".to_string(),
);
out_shadow_map_lookup_by_view_index
.insert(view.view_index(), shadow_view_index);
shadow_map_render_views[shadow_view_index.0] = Some(view);
}
let light_id = MeshAdvLightId::SpotLight(ObjectId::from(*entity));
out_shadow_map_lookup_by_light_id.insert(
light_id,
MeshAdvShadowMapRenderViewIndices::Single(shadow_view_index),
);
}
}
let mut query = <(Entity, Read<DirectionalLightComponent>)>::query();
for (entity, light) in query.iter(world) {
let shadow_view_id = MeshAdvShadowViewId::DirectionalLight(ObjectId::from(*entity));
let shadow_view_index = shadow_map_lookup_by_shadow_view_id.get(&shadow_view_id);
if let Some(&shadow_view_index) = shadow_view_index {
let eye_position = light.direction * -40.0;
let view = glam::Mat4::look_at_rh(
eye_position,
glam::Vec3::ZERO,
glam::Vec3::new(0.0, 0.0, 1.0),
);
let near_plane = 0.25;
let far_plane = 1000.0;
let ortho_projection_size = 10.0;
let view_frustum: ViewFrustumArc =
light.shadow_view_frustum.as_ref().unwrap().clone();
let projection = Projection::Orthographic(OrthographicParameters::new(
-ortho_projection_size,
ortho_projection_size,
-ortho_projection_size,
ortho_projection_size,
near_plane,
far_plane,
DepthRange::Reverse,
));
let proj = projection.as_rh_mat4();
let depth_range = RenderViewDepthRange::from_projection(&projection);
shadow_map_render_views_meta[shadow_view_index.0] = Some(
MeshAdvShadowMapRenderViewMeta::new(&view, &proj, depth_range.clone()),
);
if shadow_maps_needing_redraw.contains(&shadow_view_index) {
view_frustum.set_projection(&projection).set_transform(
eye_position,
glam::Vec3::ZERO,
glam::Vec3::new(0.0, 0.0, 1.0),
);
let shadow_map_assignment = shadow_map_atlas_element_assignments
[shadow_view_index.0]
.as_ref()
.unwrap();
let resolution = shadow_map_assignment.texture_size_pixels() as u32;
let view = render_view_set.create_view(
view_frustum,
eye_position,
view,
proj,
(resolution, resolution),
depth_range,
shadow_map_phase_mask,
shadow_map_feature_mask,
RenderFeatureFlagMask::empty(),
"shadow_map_directional".to_string(),
);
out_shadow_map_lookup_by_view_index
.insert(view.view_index(), shadow_view_index);
shadow_map_render_views[shadow_view_index.0] = Some(view);
}
let light_id = MeshAdvLightId::DirectionalLight(ObjectId::from(*entity));
out_shadow_map_lookup_by_light_id.insert(
light_id,
MeshAdvShadowMapRenderViewIndices::Single(shadow_view_index),
);
}
}
#[rustfmt::skip]
let cube_map_view_directions = [
(glam::Vec3::X, glam::Vec3::Y),
(glam::Vec3::X * -1.0, glam::Vec3::Y),
(glam::Vec3::Y, glam::Vec3::Z * -1.0),
(glam::Vec3::Y * -1.0, glam::Vec3::Z),
(glam::Vec3::Z, glam::Vec3::Y),
(glam::Vec3::Z * -1.0, glam::Vec3::Y),
];
let mut query = <(Entity, Read<PointLightComponent>, Read<TransformComponent>)>::query();
for (entity, light, transform) in query.iter(world) {
let mut any_face_has_shadow_map = false;
let mut shadow_view_indices = [None; 6];
for face_index in 0..6 {
let shadow_view_id =
MeshAdvShadowViewId::PointLight(ObjectId::from(*entity), face_index as u8);
let shadow_view_index = shadow_map_lookup_by_shadow_view_id.get(&shadow_view_id);
if let Some(&shadow_view_index) = shadow_view_index {
let cube_map_view_directions = cube_map_view_directions[face_index];
let eye_position = transform.translation;
let near = 0.25;
let far = light.range();
let view_frustum: ViewFrustumArc =
light.shadow_view_frustums.as_ref().unwrap()[face_index].clone();
let fov_y_radians = std::f32::consts::FRAC_PI_2;
let projection = Projection::Perspective(PerspectiveParameters::new(
fov_y_radians,
1.0,
near,
far,
DepthRange::Reverse,
));
let proj = projection.as_lh_mat4();
let view = glam::Mat4::look_at_lh(
eye_position,
eye_position + cube_map_view_directions.0,
cube_map_view_directions.1,
);
let depth_range = RenderViewDepthRange::from_projection(&projection);
shadow_map_render_views_meta[shadow_view_index.0] = Some(
MeshAdvShadowMapRenderViewMeta::new(&view, &proj, depth_range.clone()),
);
shadow_view_indices[face_index] = Some(shadow_view_index);
any_face_has_shadow_map = true;
if shadow_maps_needing_redraw.contains(&shadow_view_index) {
view_frustum.set_projection(&projection).set_transform(
eye_position,
eye_position + cube_map_view_directions.0,
cube_map_view_directions.1,
);
let shadow_map_assignment = shadow_map_atlas_element_assignments
[shadow_view_index.0]
.as_ref()
.unwrap();
let resolution = shadow_map_assignment.texture_size_pixels() as u32;
let view = render_view_set.create_view(
view_frustum,
eye_position,
view,
proj,
(resolution, resolution),
RenderViewDepthRange::from_projection(&projection),
shadow_map_phase_mask,
shadow_map_feature_mask,
RenderFeatureFlagMask::empty(),
format!("shadow_map_point_light_face_{}", face_index),
);
out_shadow_map_lookup_by_view_index
.insert(view.view_index(), shadow_view_index);
shadow_map_render_views[shadow_view_index.0] = Some(view);
}
}
}
if any_face_has_shadow_map {
MeshAdvShadowMapRenderViewIndices::Cube(shadow_view_indices).unwrap_cube_any();
let light_id = MeshAdvLightId::PointLight(ObjectId::from(*entity));
out_shadow_map_lookup_by_light_id.insert(
light_id,
MeshAdvShadowMapRenderViewIndices::Cube(shadow_view_indices),
);
}
}
*out_shadow_map_render_views = shadow_map_render_views;
*out_shadow_map_render_views_meta = shadow_map_render_views_meta
.into_iter()
.map(|x| x.unwrap())
.collect();
}
}