Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 88 additions & 32 deletions servers/visual/visual_server_scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2458,7 +2458,7 @@ void VisualServerScene::_update_instance_lightmap_captures(Instance *p_instance)
p_instance->lightmap_capture_data.write[0].a = interior ? 0.0f : 1.0f;
}

bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario, uint32_t p_visible_layers) {
bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, uint32_t p_visible_layers) {
InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);

Transform light_transform = p_instance->transform;
Expand Down Expand Up @@ -2559,8 +2559,6 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons

bool overlap = VSG::storage->light_directional_get_blend_splits(p_instance->base);

float first_radius = 0.0;

for (int i = 0; i < splits; i++) {
// setup a camera matrix for that range!
CameraMatrix camera_matrix;
Expand All @@ -2572,8 +2570,8 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons

camera_matrix.set_orthogonal(vp_he.y * 2.0, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
} else {
float fov = p_cam_projection.get_fov();
camera_matrix.set_perspective(fov, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
float fov = p_cam_projection.get_fov(); //this is actually yfov, because set aspect tries to keep it
camera_matrix.set_perspective(fov, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true);
}

//obtain the frustum endpoints
Expand Down Expand Up @@ -2602,8 +2600,6 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons
float z_min_cam = 0.f;
//float z_max_cam = 0.f;

float bias_scale = 1.0;

//used for culling

for (int j = 0; j < 8; j++) {
Expand Down Expand Up @@ -2632,21 +2628,19 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons
z_max = d_z;
}
}
float radius = 0;
Vector3 center;

{
//camera viewport stuff

Vector3 center;

for (int j = 0; j < 8; j++) {
center += endpoints[j];
}
center /= 8.0;

//center=x_vec*(x_max-x_min)*0.5 + y_vec*(y_max-y_min)*0.5 + z_vec*(z_max-z_min)*0.5;

float radius = 0;

for (int j = 0; j < 8; j++) {
float d = center.distance_to(endpoints[j]);
if (d > radius) {
Expand All @@ -2656,17 +2650,10 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons

radius *= texture_size / (texture_size - 2.0); //add a texel by each side

if (i == 0) {
first_radius = radius;
} else {
bias_scale = radius / first_radius;
}

x_max_cam = x_vec.dot(center) + radius;
x_min_cam = x_vec.dot(center) - radius;
y_max_cam = y_vec.dot(center) + radius;
y_min_cam = y_vec.dot(center) - radius;
//z_max_cam = z_vec.dot(center) + radius;
z_min_cam = z_vec.dot(center) - radius;

if (depth_range_mode == VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) {
Expand Down Expand Up @@ -2703,6 +2690,7 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons

Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2));

float cull_max = 0;
for (int j = 0; j < cull_count; j++) {
float min, max;
Instance *instance = instance_shadow_cull_result[j];
Expand All @@ -2716,11 +2704,72 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons
instance->transformed_aabb.project_range_in_plane(Plane(z_vec, 0), min, max);
instance->depth = near_plane.distance_to(instance->transform.origin);
instance->depth_layer = 0;
if (max > z_max) {
z_max = max;
if (j == 0 || max > cull_max) {
cull_max = max;
}
}

if (cull_max > z_max) {
z_max = cull_max;
}

if (aspect != 1.0) {
// if the aspect is different, then the radius will become larger.
// if this happens, then bias needs to be adjusted too, as depth will increase
// to do this, compare the depth of one that would have resulted from a square frustum

CameraMatrix camera_matrix_square;
if (p_cam_orthogonal) {
Vector2 vp_he = camera_matrix.get_viewport_half_extents();
if (p_cam_vaspect) {
camera_matrix_square.set_orthogonal(vp_he.x * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true);
} else {
camera_matrix_square.set_orthogonal(vp_he.y * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
}
} else {
Vector2 vp_he = camera_matrix.get_viewport_half_extents();
if (p_cam_vaspect) {
camera_matrix_square.set_frustum(vp_he.x * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true);
} else {
camera_matrix_square.set_frustum(vp_he.y * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
}
}

Vector3 endpoints_square[8]; // frustum plane endpoints
res = camera_matrix_square.get_endpoints(p_cam_transform, endpoints_square);
ERR_CONTINUE(!res);
Vector3 center_square;
float z_max_square = 0;

for (int j = 0; j < 8; j++) {
center_square += endpoints_square[j];

float d_z = z_vec.dot(endpoints_square[j]);

if (j == 0 || d_z > z_max_square)
z_max_square = d_z;
}

if (cull_max > z_max_square) {
z_max_square = cull_max;
}

center_square /= 8.0;

float radius_square = 0;
Copy link
Member

@lawnjelly lawnjelly Apr 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entire block does nothing I think. radius_square is unused, instead radius is used later.

In fact maybe the entire block from if (aspect != 1.0) to radius_square *= ... has no side effects. 🤔

In 4.x, this equivalent code seems to write directly to radius, and doesn't seem to have a special case for aspect ratio outside 1.0.


for (int j = 0; j < 8; j++) {
float d = center_square.distance_to(endpoints_square[j]);
if (d > radius_square)
radius_square = d;
}

radius_square *= texture_size / (texture_size - 2.0); //add a texel by each side

// this is not entirely perfect, because the cull-adjusted z-max may be different
// but at least it's warranted that it results in a greater bias, so no acne should be present either way.
}

{
CameraMatrix ortho_camera;
real_t half_x = (x_max_cam - x_min_cam) * 0.5;
Expand All @@ -2732,7 +2781,14 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons
ortho_transform.basis = transform.basis;
ortho_transform.origin = x_vec * (x_min_cam + half_x) + y_vec * (y_min_cam + half_y) + z_vec * z_max;

VSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, 0, distances[i + 1], i, bias_scale);
VSG::scene_render->light_instance_set_shadow_transform(
light->instance,
ortho_camera,
ortho_transform,
z_max - z_min_cam,
distances[i + 1],
i,
radius * 2.0 / texture_size);
Copy link
Member

@lawnjelly lawnjelly Apr 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem anything like the bias scale from before (which was bias_scale = radius / first_radius). Maybe this is intentional, but wanted to check this was correct.

In master this value is shadow_texel_size, and bias_scale is z_max - z_min_cam.

}

// Do a secondary cull to remove casters that don't intersect with the camera frustum.
Expand Down Expand Up @@ -2787,7 +2843,7 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons
}
}

VSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i);
VSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i, 0);
VSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count);
}
} else { //shadow cube
Expand Down Expand Up @@ -2843,12 +2899,12 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons
}
}

VSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i);
VSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0);
VSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count);
}

//restore the regular DP matrix
VSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0);
VSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0, 0);
}

} break;
Expand Down Expand Up @@ -2883,7 +2939,7 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons
}
}

VSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0);
VSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0);
VSG::scene_render->render_shadow(light->instance, p_shadow_atlas, 0, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count);

} break;
Expand Down Expand Up @@ -2937,7 +2993,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_view

Transform camera_transform = _interpolation_data.interpolation_enabled ? camera->get_transform_interpolated() : camera->transform;

_prepare_scene(camera_transform, camera_matrix, ortho, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), camera->previous_room_id_hint);
_prepare_scene(camera_transform, camera_matrix, ortho, camera->vaspect, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), camera->previous_room_id_hint);
_render_scene(camera_transform, camera_matrix, 0, ortho, camera->env, p_scenario, p_shadow_atlas, RID(), -1);
#endif
}
Expand Down Expand Up @@ -3016,17 +3072,17 @@ void VisualServerScene::render_camera(Ref<ARVRInterface> &p_interface, ARVRInter
mono_transform *= apply_z_shift;

// now prepare our scene with our adjusted transform projection matrix
_prepare_scene(mono_transform, combined_matrix, false, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), camera->previous_room_id_hint);
_prepare_scene(mono_transform, combined_matrix, false, false, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), camera->previous_room_id_hint);
} else if (p_eye == ARVRInterface::EYE_MONO) {
// For mono render, prepare as per usual
_prepare_scene(cam_transform, camera_matrix, false, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), camera->previous_room_id_hint);
_prepare_scene(cam_transform, camera_matrix, false, false, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), camera->previous_room_id_hint);
}

// And render our scene...
_render_scene(cam_transform, camera_matrix, p_eye, false, camera->env, p_scenario, p_shadow_atlas, RID(), -1);
};

void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int32_t &r_previous_room_id_hint) {
void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int32_t &r_previous_room_id_hint) {
// Prepare the light - camera volume culling system.
light_culler->prepare_camera(p_cam_transform, p_cam_projection);

Expand Down Expand Up @@ -3235,7 +3291,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca
VSG::scene_render->set_directional_shadow_count(directional_shadow_count);

for (int i = 0; i < directional_shadow_count; i++) {
_light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_shadow_atlas, scenario, p_visible_layers);
_light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario, p_visible_layers);
}
}

Expand Down Expand Up @@ -3353,7 +3409,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca

if (redraw) {
//must redraw!
if (_light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_shadow_atlas, scenario, p_visible_layers)) {
if (_light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario, p_visible_layers)) {
// If the light requests another update (animated material?)...
light->make_shadow_dirty();
}
Expand Down Expand Up @@ -3470,7 +3526,7 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int
shadow_atlas = scenario->reflection_probe_shadow_atlas;
}

_prepare_scene(xform, cm, false, RID(), VSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, reflection_probe->previous_room_id_hint);
_prepare_scene(xform, cm, false, false, RID(), VSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, reflection_probe->previous_room_id_hint);

bool async_forbidden_backup = VSG::storage->is_shader_async_hidden_forbidden();
VSG::storage->set_shader_async_hidden_forbidden(true);
Expand Down
4 changes: 2 additions & 2 deletions servers/visual/visual_server_scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -900,9 +900,9 @@ class VisualServerScene {
_FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance);
_FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance);

_FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario, uint32_t p_visible_layers = 0xFFFFFF);
_FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, uint32_t p_visible_layers = 0xFFFFFF);

void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int32_t &r_previous_room_id_hint);
void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int32_t &r_previous_room_id_hint);
void _render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, const int p_eye, bool p_cam_orthogonal, RID p_force_environment, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
void render_empty_scene(RID p_scenario, RID p_shadow_atlas);

Expand Down