@@ -622,6 +622,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
622622
623623 RD::ComputeListID compute_list = RD::get_singleton ()->compute_list_begin ();
624624 bool any_uses_time = false ;
625+ Vector3 cam_position = p_cam_transform.get_origin ();
625626
626627 for (int i = 0 ; i < (int )p_fog_volumes.size (); i++) {
627628 FogVolumeInstance *fog_volume_instance = fog_volume_instance_owner.get_or_null (p_fog_volumes[i]);
@@ -652,41 +653,68 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
652653
653654 any_uses_time |= shader_data->uses_time ;
654655
655- Vector3i min ;
656- Vector3i max ;
656+ Vector3i froxel_min ;
657+ Vector3i froxel_max ;
657658 Vector3i kernel_size;
658659
659- Vector3 position = fog_volume_instance->transform .get_origin ();
660+ Vector3 fog_position = fog_volume_instance->transform .get_origin ();
660661 RS::FogVolumeShape volume_type = RendererRD::Fog::get_singleton ()->fog_volume_get_shape (fog_volume);
661662 Vector3 extents = RendererRD::Fog::get_singleton ()->fog_volume_get_size (fog_volume) / 2 ;
662663
663664 if (volume_type != RS::FOG_VOLUME_SHAPE_WORLD) {
664665 // Local fog volume.
665- Vector3i points[8 ];
666666 Vector3 fog_size = Vector3 (fog->width , fog->height , fog->depth );
667667 float volumetric_fog_detail_spread = RendererSceneRenderRD::get_singleton ()->environment_get_volumetric_fog_detail_spread (p_settings.env );
668- points[0 ] = _point_get_position_in_froxel_volume (fog_volume_instance->transform .xform (Vector3 (extents.x , extents.y , extents.z )), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
669- points[1 ] = _point_get_position_in_froxel_volume (fog_volume_instance->transform .xform (Vector3 (-extents.x , extents.y , extents.z )), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
670- points[2 ] = _point_get_position_in_froxel_volume (fog_volume_instance->transform .xform (Vector3 (extents.x , -extents.y , extents.z )), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
671- points[3 ] = _point_get_position_in_froxel_volume (fog_volume_instance->transform .xform (Vector3 (-extents.x , -extents.y , extents.z )), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
672- points[4 ] = _point_get_position_in_froxel_volume (fog_volume_instance->transform .xform (Vector3 (extents.x , extents.y , -extents.z )), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
673- points[5 ] = _point_get_position_in_froxel_volume (fog_volume_instance->transform .xform (Vector3 (-extents.x , extents.y , -extents.z )), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
674- points[6 ] = _point_get_position_in_froxel_volume (fog_volume_instance->transform .xform (Vector3 (extents.x , -extents.y , -extents.z )), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
675- points[7 ] = _point_get_position_in_froxel_volume (fog_volume_instance->transform .xform (Vector3 (-extents.x , -extents.y , -extents.z )), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
676-
677- min = Vector3i (int32_t (fog->width ) - 1 , int32_t (fog->height ) - 1 , int32_t (fog->depth ) - 1 );
678- max = Vector3i (1 , 1 , 1 );
679-
668+ Vector3 corners[8 ]{
669+ fog_volume_instance->transform .xform (Vector3 (extents.x , extents.y , extents.z )),
670+ fog_volume_instance->transform .xform (Vector3 (-extents.x , extents.y , extents.z )),
671+ fog_volume_instance->transform .xform (Vector3 (extents.x , -extents.y , extents.z )),
672+ fog_volume_instance->transform .xform (Vector3 (-extents.x , -extents.y , extents.z )),
673+ fog_volume_instance->transform .xform (Vector3 (extents.x , extents.y , -extents.z )),
674+ fog_volume_instance->transform .xform (Vector3 (-extents.x , extents.y , -extents.z )),
675+ fog_volume_instance->transform .xform (Vector3 (extents.x , -extents.y , -extents.z )),
676+ fog_volume_instance->transform .xform (Vector3 (-extents.x , -extents.y , -extents.z ))
677+ };
678+ Vector3i froxels[8 ];
679+ Vector3 corner_min = corners[0 ];
680+ Vector3 corner_max = corners[0 ];
680681 for (int j = 0 ; j < 8 ; j++) {
681- min = min.min (points[j]);
682- max = max.max (points[j]);
682+ froxels[j] = _point_get_position_in_froxel_volume (corners[j], fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
683+ corner_min = corner_min.min (corners[j]);
684+ corner_max = corner_max.max (corners[j]);
685+ }
686+
687+ froxel_min = Vector3i (int32_t (fog->width ) - 1 , int32_t (fog->height ) - 1 , int32_t (fog->depth ) - 1 );
688+ froxel_max = Vector3i (1 , 1 , 1 );
689+
690+ // Tracking just the corners of the fog volume can result in missing some fog:
691+ // when the camera's near plane is inside the fog, we must always consider the entire screen
692+ Vector3 near_plane_corner (frustum_near_size.x , frustum_near_size.y , z_near);
693+ float expand = near_plane_corner.length ();
694+ if (cam_position.x > (corner_min.x - expand) && cam_position.x < (corner_max.x + expand) &&
695+ cam_position.y > (corner_min.y - expand) && cam_position.y < (corner_max.y + expand) &&
696+ cam_position.z > (corner_min.z - expand) && cam_position.z < (corner_max.z + expand)) {
697+ froxel_min.x = 0 ;
698+ froxel_min.y = 0 ;
699+ froxel_min.z = 0 ;
700+ froxel_max.x = int32_t (fog->width );
701+ froxel_max.y = int32_t (fog->height );
702+ for (int j = 0 ; j < 8 ; j++) {
703+ froxel_max.z = MAX (froxel_max.z , froxels[j].z );
704+ }
705+ } else {
706+ // Camera is guaranteed to be outside the fog volume
707+ for (int j = 0 ; j < 8 ; j++) {
708+ froxel_min = froxel_min.min (froxels[j]);
709+ froxel_max = froxel_max.max (froxels[j]);
710+ }
683711 }
684712
685- kernel_size = max - min ;
713+ kernel_size = froxel_max - froxel_min ;
686714 } else {
687715 // Volume type global runs on all cells
688716 extents = Vector3 (fog->width , fog->height , fog->depth );
689- min = Vector3i (0 , 0 , 0 );
717+ froxel_min = Vector3i (0 , 0 , 0 );
690718 kernel_size = Vector3i (int32_t (fog->width ), int32_t (fog->height ), int32_t (fog->depth ));
691719 }
692720
@@ -695,15 +723,15 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
695723 }
696724
697725 VolumetricFogShader::FogPushConstant push_constant;
698- push_constant.position [0 ] = position .x ;
699- push_constant.position [1 ] = position .y ;
700- push_constant.position [2 ] = position .z ;
726+ push_constant.position [0 ] = fog_position .x ;
727+ push_constant.position [1 ] = fog_position .y ;
728+ push_constant.position [2 ] = fog_position .z ;
701729 push_constant.size [0 ] = extents.x * 2 ;
702730 push_constant.size [1 ] = extents.y * 2 ;
703731 push_constant.size [2 ] = extents.z * 2 ;
704- push_constant.corner [0 ] = min .x ;
705- push_constant.corner [1 ] = min .y ;
706- push_constant.corner [2 ] = min .z ;
732+ push_constant.corner [0 ] = froxel_min .x ;
733+ push_constant.corner [1 ] = froxel_min .y ;
734+ push_constant.corner [2 ] = froxel_min .z ;
707735 push_constant.shape = uint32_t (RendererRD::Fog::get_singleton ()->fog_volume_get_shape (fog_volume));
708736 RendererRD::MaterialStorage::store_transform (fog_volume_instance->transform .affine_inverse (), push_constant.transform );
709737
0 commit comments