mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
use cone shape to mark pixels in stencil buffer for spot lights
- sphere was too inefficient since spot lights usually have quite narrow "beam"
This commit is contained in:
@@ -85,6 +85,7 @@ pub struct DeferredLightRenderer {
|
||||
ambient_light_shader: AmbientLightShader,
|
||||
quad: GeometryBuffer,
|
||||
sphere: GeometryBuffer,
|
||||
cone: GeometryBuffer,
|
||||
skybox: GeometryBuffer,
|
||||
flat_shader: FlatShader,
|
||||
skybox_shader: SkyboxShader,
|
||||
@@ -196,6 +197,16 @@ impl DeferredLightRenderer {
|
||||
GeometryBufferKind::StaticDraw,
|
||||
state,
|
||||
)?,
|
||||
cone: GeometryBuffer::from_surface_data(
|
||||
&SurfaceData::make_cone(
|
||||
16,
|
||||
0.5,
|
||||
1.0,
|
||||
&Matrix4::new_translation(&Vector3::new(0.0, -1.0, 0.0)),
|
||||
),
|
||||
GeometryBufferKind::StaticDraw,
|
||||
state,
|
||||
)?,
|
||||
flat_shader: FlatShader::new(state)?,
|
||||
skybox_shader: SkyboxShader::new(state)?,
|
||||
spot_shadow_map_renderer: SpotShadowMapRenderer::new(
|
||||
@@ -427,43 +438,71 @@ impl DeferredLightRenderer {
|
||||
|
||||
let distance_to_camera = (light.global_position() - camera.global_position()).norm();
|
||||
|
||||
let (raw_radius, shadows_distance, shadows_enabled, shadows_fade_out_range) =
|
||||
if let Some(spot_light) = light.cast::<SpotLight>() {
|
||||
(
|
||||
spot_light.distance(),
|
||||
settings.spot_shadows_distance,
|
||||
spot_light.base_light_ref().is_cast_shadows()
|
||||
&& distance_to_camera <= settings.spot_shadows_distance
|
||||
&& settings.spot_shadows_enabled,
|
||||
settings.spot_shadows_fade_out_range,
|
||||
)
|
||||
} else if let Some(point_light) = light.cast::<PointLight>() {
|
||||
(
|
||||
point_light.radius(),
|
||||
settings.point_shadows_distance,
|
||||
point_light.base_light_ref().is_cast_shadows()
|
||||
&& distance_to_camera <= settings.point_shadows_distance
|
||||
&& settings.point_shadows_enabled,
|
||||
settings.point_shadows_fade_out_range,
|
||||
)
|
||||
} else if let Some(directional) = light.cast::<DirectionalLight>() {
|
||||
(
|
||||
f32::MAX,
|
||||
0.0,
|
||||
directional.base_light_ref().is_cast_shadows()
|
||||
&& settings.csm_settings.enabled,
|
||||
0.0,
|
||||
)
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
let (
|
||||
raw_radius,
|
||||
shadows_distance,
|
||||
shadows_enabled,
|
||||
shadows_fade_out_range,
|
||||
bounding_shape,
|
||||
shape_specific_matrix,
|
||||
) = if let Some(spot_light) = light.cast::<SpotLight>() {
|
||||
let margin = 5.0f32.to_radians();
|
||||
// Angle at the top vertex of the right triangle with vertecal side be 1.0 and horizontal
|
||||
// side be 0.5.
|
||||
let vertex_angle = 26.56f32.to_radians();
|
||||
let k_angle = (spot_light.full_cone_angle() * 0.5 + vertex_angle + margin).tan();
|
||||
(
|
||||
spot_light.distance(),
|
||||
settings.spot_shadows_distance,
|
||||
spot_light.base_light_ref().is_cast_shadows()
|
||||
&& distance_to_camera <= settings.spot_shadows_distance
|
||||
&& settings.spot_shadows_enabled,
|
||||
settings.spot_shadows_fade_out_range,
|
||||
&self.cone,
|
||||
Matrix4::new_nonuniform_scaling(&Vector3::new(
|
||||
spot_light.distance() * k_angle,
|
||||
spot_light.distance() * 1.05,
|
||||
spot_light.distance() * k_angle,
|
||||
)),
|
||||
)
|
||||
} else if let Some(point_light) = light.cast::<PointLight>() {
|
||||
(
|
||||
point_light.radius(),
|
||||
settings.point_shadows_distance,
|
||||
point_light.base_light_ref().is_cast_shadows()
|
||||
&& distance_to_camera <= settings.point_shadows_distance
|
||||
&& settings.point_shadows_enabled,
|
||||
settings.point_shadows_fade_out_range,
|
||||
&self.sphere,
|
||||
Matrix4::new_scaling(point_light.radius() * 1.15),
|
||||
)
|
||||
} else if let Some(directional) = light.cast::<DirectionalLight>() {
|
||||
(
|
||||
f32::MAX,
|
||||
0.0,
|
||||
directional.base_light_ref().is_cast_shadows() && settings.csm_settings.enabled,
|
||||
0.0,
|
||||
// Makes no sense, but whatever.
|
||||
&self.sphere,
|
||||
Matrix4::identity(),
|
||||
)
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let light_position = light.global_position();
|
||||
let scl = light.local_transform().scale();
|
||||
let light_radius_scale = scl.x.max(scl.y).max(scl.z);
|
||||
let light_radius = light_radius_scale * raw_radius;
|
||||
let light_r_inflate = 1.05 * light_radius;
|
||||
let light_radius_vec = Vector3::new(light_r_inflate, light_r_inflate, light_r_inflate);
|
||||
let light_rotation = light
|
||||
.global_transform()
|
||||
.basis()
|
||||
.try_inverse()
|
||||
.unwrap_or_default()
|
||||
.transpose()
|
||||
.to_homogeneous();
|
||||
let bounding_shape_matrix =
|
||||
Matrix4::new_translation(&light_position) * light_rotation * shape_specific_matrix;
|
||||
let emit_direction = light
|
||||
.up_vector()
|
||||
.try_normalize(f32::EPSILON)
|
||||
@@ -494,10 +533,8 @@ impl DeferredLightRenderer {
|
||||
let mut light_view_projection = Matrix4::identity();
|
||||
|
||||
// Mark lighted areas in stencil buffer to do light calculations only on them.
|
||||
let sphere = &self.sphere;
|
||||
|
||||
pass_stats += frame_buffer.draw(
|
||||
sphere,
|
||||
bounding_shape,
|
||||
state,
|
||||
viewport,
|
||||
&self.flat_shader.program,
|
||||
@@ -520,15 +557,13 @@ impl DeferredLightRenderer {
|
||||
|mut program_binding| {
|
||||
program_binding.set_matrix4(
|
||||
&self.flat_shader.wvp_matrix,
|
||||
&(view_projection
|
||||
* Matrix4::new_translation(&light_position)
|
||||
* Matrix4::new_nonuniform_scaling(&light_radius_vec)),
|
||||
&(view_projection * bounding_shape_matrix),
|
||||
);
|
||||
},
|
||||
)?;
|
||||
|
||||
pass_stats += frame_buffer.draw(
|
||||
sphere,
|
||||
bounding_shape,
|
||||
state,
|
||||
viewport,
|
||||
&self.flat_shader.program,
|
||||
@@ -551,9 +586,7 @@ impl DeferredLightRenderer {
|
||||
|mut program_binding| {
|
||||
program_binding.set_matrix4(
|
||||
&self.flat_shader.wvp_matrix,
|
||||
&(view_projection
|
||||
* Matrix4::new_translation(&light_position)
|
||||
* Matrix4::new_nonuniform_scaling(&light_radius_vec)),
|
||||
&(view_projection * bounding_shape_matrix),
|
||||
);
|
||||
},
|
||||
)?;
|
||||
|
||||
Reference in New Issue
Block a user