diff options
Diffstat (limited to 'servers/rendering/rendering_server_scene.cpp')
-rw-r--r-- | servers/rendering/rendering_server_scene.cpp | 189 |
1 files changed, 137 insertions, 52 deletions
diff --git a/servers/rendering/rendering_server_scene.cpp b/servers/rendering/rendering_server_scene.cpp index 65823e11aa..a367d4522c 100644 --- a/servers/rendering/rendering_server_scene.cpp +++ b/servers/rendering/rendering_server_scene.cpp @@ -1334,7 +1334,7 @@ void RenderingServerScene::_update_instance_lightmap_captures(Instance *p_instan } } -bool RenderingServerScene::_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) { +bool RenderingServerScene::_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) { InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); @@ -1347,16 +1347,18 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c case RS::LIGHT_DIRECTIONAL: { - float max_distance = p_cam_projection.get_z_far(); - float shadow_max = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE); + real_t max_distance = p_cam_projection.get_z_far(); + real_t shadow_max = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE); if (shadow_max > 0 && !p_cam_orthogonal) { //its impractical (and leads to unwanted behaviors) to set max distance in orthogonal camera max_distance = MIN(shadow_max, max_distance); } max_distance = MAX(max_distance, p_cam_projection.get_z_near() + 0.001); - float min_distance = MIN(p_cam_projection.get_z_near(), max_distance); + real_t min_distance = MIN(p_cam_projection.get_z_near(), max_distance); RS::LightDirectionalShadowDepthRangeMode depth_range_mode = RSG::storage->light_directional_get_shadow_depth_range_mode(p_instance->base); + real_t pancake_size = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE); + if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED) { //optimize min/max Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform); @@ -1365,8 +1367,8 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c //check distance max and min bool found_items = false; - float z_max = -1e20; - float z_min = 1e20; + real_t z_max = -1e20; + real_t z_min = 1e20; for (int i = 0; i < cull_count; i++) { @@ -1379,7 +1381,7 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c animated_material_found = true; } - float max, min; + real_t max, min; instance->transformed_aabb.project_range_in_plane(base, min, max); if (max > z_max) { @@ -1399,7 +1401,7 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c } } - float range = max_distance - min_distance; + real_t range = max_distance - min_distance; int splits = 0; switch (RSG::storage->light_directional_get_shadow_mode(p_instance->base)) { @@ -1408,7 +1410,7 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: splits = 4; break; } - float distances[5]; + real_t distances[5]; distances[0] = min_distance; for (int i = 0; i < splits; i++) { @@ -1417,11 +1419,13 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c distances[splits] = max_distance; - float texture_size = RSG::scene_render->get_directional_light_shadow_size(light->instance); + real_t texture_size = RSG::scene_render->get_directional_light_shadow_size(light->instance); bool overlap = RSG::storage->light_directional_get_blend_splits(p_instance->base); - float first_radius = 0.0; + real_t first_radius = 0.0; + + real_t min_distance_bias_scale = pancake_size > 0 ? distances[1] / 10.0 : 0; for (int i = 0; i < splits; i++) { @@ -1430,7 +1434,7 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c // setup a camera matrix for that range! CameraMatrix camera_matrix; - float aspect = p_cam_projection.get_aspect(); + real_t aspect = p_cam_projection.get_aspect(); if (p_cam_orthogonal) { @@ -1439,8 +1443,8 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c 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); + real_t 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 @@ -1458,26 +1462,27 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c Vector3 z_vec = transform.basis.get_axis(Vector3::AXIS_Z).normalized(); //z_vec points agsint the camera, like in default opengl - float x_min = 0.f, x_max = 0.f; - float y_min = 0.f, y_max = 0.f; - float z_min = 0.f, z_max = 0.f; + real_t x_min = 0.f, x_max = 0.f; + real_t y_min = 0.f, y_max = 0.f; + real_t z_min = 0.f, z_max = 0.f; // FIXME: z_max_cam is defined, computed, but not used below when setting up // ortho_camera. Commented out for now to fix warnings but should be investigated. - float x_min_cam = 0.f, x_max_cam = 0.f; - float y_min_cam = 0.f, y_max_cam = 0.f; - float z_min_cam = 0.f; - //float z_max_cam = 0.f; + real_t x_min_cam = 0.f, x_max_cam = 0.f; + real_t y_min_cam = 0.f, y_max_cam = 0.f; + real_t z_min_cam = 0.f; + //real_t z_max_cam = 0.f; - float bias_scale = 1.0; + real_t bias_scale = 1.0; + real_t aspect_bias_scale = 1.0; //used for culling for (int j = 0; j < 8; j++) { - float d_x = x_vec.dot(endpoints[j]); - float d_y = y_vec.dot(endpoints[j]); - float d_z = z_vec.dot(endpoints[j]); + real_t d_x = x_vec.dot(endpoints[j]); + real_t d_y = y_vec.dot(endpoints[j]); + real_t d_z = z_vec.dot(endpoints[j]); if (j == 0 || d_x < x_min) x_min = d_x; @@ -1494,12 +1499,12 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c if (j == 0 || d_z > z_max) z_max = d_z; } + real_t radius = 0; + Vector3 center; { //camera viewport stuff - Vector3 center; - for (int j = 0; j < 8; j++) { center += endpoints[j]; @@ -1508,11 +1513,9 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c //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]); + real_t d = center.distance_to(endpoints[j]); if (d > radius) radius = d; } @@ -1529,14 +1532,13 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c 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 == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) { //this trick here is what stabilizes the shadow (make potential jaggies to not move) //at the cost of some wasted resolution. Still the quality increase is very well worth it - float unit = radius * 2.0 / texture_size; + real_t unit = radius * 2.0 / texture_size; x_max_cam = Math::stepify(x_max_cam, unit); x_min_cam = Math::stepify(x_min_cam, unit); @@ -1566,9 +1568,10 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2)); + real_t cull_max = 0; for (int j = 0; j < cull_count; j++) { - float min, max; + real_t min, max; Instance *instance = instance_shadow_cull_result[j]; if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { cull_count--; @@ -1580,8 +1583,90 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c 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 (pancake_size > 0) { + z_max = z_vec.dot(center) + radius + pancake_size; + } + + 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); + } + + if (i == 0) { + //print_line("prev he: " + vp_he + " new he: " + camera_matrix_square.get_viewport_half_extents()); + } + } + + Vector3 endpoints_square[8]; // frustum plane endpoints + res = camera_matrix_square.get_endpoints(p_cam_transform, endpoints_square); + ERR_CONTINUE(!res); + Vector3 center_square; + real_t z_max_square = 0; + + for (int j = 0; j < 8; j++) { + + center_square += endpoints_square[j]; + + real_t 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; + + real_t radius_square = 0; + + for (int j = 0; j < 8; j++) { + + real_t 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 + + if (pancake_size > 0) { + z_max_square = z_vec.dot(center_square) + radius_square + pancake_size; + } + + real_t z_min_cam_square = z_vec.dot(center_square) - radius_square; + + aspect_bias_scale = (z_max - z_min_cam) / (z_max_square - z_min_cam_square); + + // 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. + // pancaking also helps with this. } { @@ -1596,7 +1681,7 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c 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; - RSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, 0, distances[i + 1], i, bias_scale); + RSG::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, bias_scale * aspect_bias_scale * min_distance_bias_scale); } RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); @@ -1614,9 +1699,9 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c //using this one ensures that raster deferred will have it RENDER_TIMESTAMP("Culling Shadow Paraboloid" + itos(i)); - float radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); - float z = i == 0 ? -1 : 1; + real_t z = i == 0 ? -1 : 1; Vector<Plane> planes; planes.resize(5); planes.write[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius)); @@ -1645,12 +1730,12 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c } } - RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i); + RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i, 0); RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); } } else { //shadow cube - float radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); CameraMatrix cm; cm.set_perspective(90, 1, 0.01, radius); @@ -1699,12 +1784,12 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c } } - RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i); + RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0); RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); } //restore the regular DP matrix - RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0); + RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0, 0); } } break; @@ -1712,8 +1797,8 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c RENDER_TIMESTAMP("Culling Spot Light"); - float radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); - float angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); + real_t angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); CameraMatrix cm; cm.set_perspective(angle * 2.0, 1.0, 0.01, radius); @@ -1738,7 +1823,7 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c } } - RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0); + RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0); RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, 0, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); } break; @@ -1793,7 +1878,7 @@ void RenderingServerScene::render_camera(RID p_render_buffers, RID p_camera, RID } break; } - _prepare_scene(camera->transform, camera_matrix, ortho, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); + _prepare_scene(camera->transform, camera_matrix, ortho, camera->vaspect, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); _render_scene(p_render_buffers, camera->transform, camera_matrix, ortho, camera->env, camera->effects, p_scenario, p_shadow_atlas, RID(), -1); #endif } @@ -1872,17 +1957,17 @@ void RenderingServerScene::render_camera(RID p_render_buffers, Ref<ARVRInterface 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->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); + _prepare_scene(mono_transform, combined_matrix, false, false, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); } else if (p_eye == ARVRInterface::EYE_MONO) { // For mono render, prepare as per usual - _prepare_scene(cam_transform, camera_matrix, false, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); + _prepare_scene(cam_transform, camera_matrix, false, false, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); } // And render our scene... _render_scene(p_render_buffers, cam_transform, camera_matrix, false, camera->env, camera->effects, p_scenario, p_shadow_atlas, RID(), -1); }; -void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows) { +void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_force_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows) { // Note, in stereo rendering: // - p_cam_transform will be a transform in the middle of our two eyes // - p_cam_projection is a wider frustrum that encompasses both eyes @@ -2112,7 +2197,7 @@ void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const RENDER_TIMESTAMP(">Rendering Directional Light " + itos(i)); - _light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_shadow_atlas, scenario); + _light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario); RENDER_TIMESTAMP("<Rendering Directional Light " + itos(i)); } @@ -2214,7 +2299,7 @@ void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const if (redraw) { //must redraw! RENDER_TIMESTAMP(">Rendering Light " + itos(i)); - light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_shadow_atlas, scenario); + light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario); RENDER_TIMESTAMP("<Rendering Light " + itos(i)); } } @@ -2324,7 +2409,7 @@ bool RenderingServerScene::_render_reflection_probe_step(Instance *p_instance, i } RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step)); - _prepare_scene(xform, cm, false, RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, use_shadows); + _prepare_scene(xform, cm, false, false, RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, use_shadows); _render_scene(RID(), xform, cm, false, RID(), RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step); } else { |