Merge pull request #53354 from reduz/remove-clipped-camera
This commit is contained in:
commit
7722048ed0
7 changed files with 66 additions and 419 deletions
|
@ -26,7 +26,7 @@
|
|||
<method name="get_camera_transform" qualifiers="const">
|
||||
<return type="Transform3D" />
|
||||
<description>
|
||||
Returns the transform of the camera plus the vertical ([member v_offset]) and horizontal ([member h_offset]) offsets; and any other adjustments made to the position and orientation of the camera by subclassed cameras such as [ClippedCamera3D] and [XRCamera3D].
|
||||
Returns the transform of the camera plus the vertical ([member v_offset]) and horizontal ([member h_offset]) offsets; and any other adjustments made to the position and orientation of the camera by subclassed cameras such as [XRCamera3D].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_cull_mask_value" qualifiers="const">
|
||||
|
@ -42,6 +42,12 @@
|
|||
Returns the camera's frustum planes in world space units as an array of [Plane]s in the following order: near, far, left, top, right, bottom. Not to be confused with [member frustum_offset].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_pyramid_shape_rid">
|
||||
<return type="RID" />
|
||||
<description>
|
||||
Returns the RID of a pyramid shape encompassing the camera's view frustum, ignoring the camera's near plane. The tip of the pyramid represents the position of the camera.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_position_behind" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<argument index="0" name="world_point" type="Vector3" />
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="ClippedCamera3D" inherits="Camera3D" version="4.0">
|
||||
<brief_description>
|
||||
A [Camera3D] that includes collision.
|
||||
</brief_description>
|
||||
<description>
|
||||
This node extends [Camera3D] to add collisions with [Area3D] and/or [PhysicsBody3D] nodes. The camera cannot move through colliding objects.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="add_exception">
|
||||
<return type="void" />
|
||||
<argument index="0" name="node" type="Object" />
|
||||
<description>
|
||||
Adds a collision exception so the camera does not collide with the specified node.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_exception_rid">
|
||||
<return type="void" />
|
||||
<argument index="0" name="rid" type="RID" />
|
||||
<description>
|
||||
Adds a collision exception so the camera does not collide with the specified [RID].
|
||||
</description>
|
||||
</method>
|
||||
<method name="clear_exceptions">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Removes all collision exceptions.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_clip_offset" qualifiers="const">
|
||||
<return type="float" />
|
||||
<description>
|
||||
Returns the distance the camera has been offset due to a collision.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_collision_mask_value" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<argument index="0" name="layer_number" type="int" />
|
||||
<description>
|
||||
Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
|
||||
</description>
|
||||
</method>
|
||||
<method name="remove_exception">
|
||||
<return type="void" />
|
||||
<argument index="0" name="node" type="Object" />
|
||||
<description>
|
||||
Removes a collision exception with the specified node.
|
||||
</description>
|
||||
</method>
|
||||
<method name="remove_exception_rid">
|
||||
<return type="void" />
|
||||
<argument index="0" name="rid" type="RID" />
|
||||
<description>
|
||||
Removes a collision exception with the specified [RID].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_collision_mask_value">
|
||||
<return type="void" />
|
||||
<argument index="0" name="layer_number" type="int" />
|
||||
<argument index="1" name="value" type="bool" />
|
||||
<description>
|
||||
Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="clip_to_areas" type="bool" setter="set_clip_to_areas" getter="is_clip_to_areas_enabled" default="false">
|
||||
If [code]true[/code], the camera stops on contact with [Area3D]s.
|
||||
</member>
|
||||
<member name="clip_to_bodies" type="bool" setter="set_clip_to_bodies" getter="is_clip_to_bodies_enabled" default="true">
|
||||
If [code]true[/code], the camera stops on contact with [PhysicsBody3D]s.
|
||||
</member>
|
||||
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
|
||||
The camera's collision mask. Only objects in at least one collision layer matching the mask will be detected. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
|
||||
</member>
|
||||
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0">
|
||||
The camera's collision margin. The camera can't get closer than this distance to a colliding object.
|
||||
</member>
|
||||
<member name="process_callback" type="int" setter="set_process_callback" getter="get_process_callback" enum="ClippedCamera3D.ClipProcessCallback" default="0">
|
||||
The camera's process callback. See [enum ClipProcessCallback].
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
<constant name="CLIP_PROCESS_PHYSICS" value="0" enum="ClipProcessCallback">
|
||||
The camera updates with the [code]_physics_process[/code] callback.
|
||||
</constant>
|
||||
<constant name="CLIP_PROCESS_IDLE" value="1" enum="ClipProcessCallback">
|
||||
The camera updates with the [code]_process[/code] callback.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
|
@ -1840,47 +1840,6 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
|
|||
|
||||
p_gizmo->add_lines(lines, material);
|
||||
p_gizmo->add_handles(handles, get_material("handles"));
|
||||
|
||||
ClippedCamera3D *clipcam = Object::cast_to<ClippedCamera3D>(camera);
|
||||
if (clipcam) {
|
||||
Node3D *parent = Object::cast_to<Node3D>(camera->get_parent());
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
Vector3 cam_normal = -camera->get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized();
|
||||
Vector3 cam_x = camera->get_global_transform().basis.get_axis(Vector3::AXIS_X).normalized();
|
||||
Vector3 cam_y = camera->get_global_transform().basis.get_axis(Vector3::AXIS_Y).normalized();
|
||||
Vector3 cam_pos = camera->get_global_transform().origin;
|
||||
Vector3 parent_pos = parent->get_global_transform().origin;
|
||||
|
||||
Plane parent_plane(parent_pos, cam_normal);
|
||||
Vector3 ray_from = parent_plane.project(cam_pos);
|
||||
|
||||
lines.clear();
|
||||
lines.push_back(ray_from + cam_x * 0.5 + cam_y * 0.5);
|
||||
lines.push_back(ray_from + cam_x * 0.5 + cam_y * -0.5);
|
||||
|
||||
lines.push_back(ray_from + cam_x * 0.5 + cam_y * -0.5);
|
||||
lines.push_back(ray_from + cam_x * -0.5 + cam_y * -0.5);
|
||||
|
||||
lines.push_back(ray_from + cam_x * -0.5 + cam_y * -0.5);
|
||||
lines.push_back(ray_from + cam_x * -0.5 + cam_y * 0.5);
|
||||
|
||||
lines.push_back(ray_from + cam_x * -0.5 + cam_y * 0.5);
|
||||
lines.push_back(ray_from + cam_x * 0.5 + cam_y * 0.5);
|
||||
|
||||
if (parent_plane.distance_to(cam_pos) < 0) {
|
||||
lines.push_back(ray_from);
|
||||
lines.push_back(cam_pos);
|
||||
}
|
||||
|
||||
Transform3D local = camera->get_global_transform().affine_inverse();
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
lines.write[i] = local.xform(lines[i]);
|
||||
}
|
||||
|
||||
p_gizmo->add_lines(lines, material);
|
||||
}
|
||||
}
|
||||
|
||||
//////
|
||||
|
|
|
@ -492,6 +492,7 @@ void Camera3D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_frustum"), &Camera3D::get_frustum);
|
||||
ClassDB::bind_method(D_METHOD("is_position_in_frustum", "world_point"), &Camera3D::is_position_in_frustum);
|
||||
ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera3D::get_camera);
|
||||
ClassDB::bind_method(D_METHOD("get_pyramid_shape_rid"), &Camera3D::get_pyramid_shape_rid);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_cull_mask_value", "layer_number", "value"), &Camera3D::set_cull_mask_value);
|
||||
ClassDB::bind_method(D_METHOD("get_cull_mask_value", "layer_number"), &Camera3D::get_cull_mask_value);
|
||||
|
@ -654,6 +655,33 @@ Vector3 Camera3D::get_doppler_tracked_velocity() const {
|
|||
}
|
||||
}
|
||||
|
||||
RID Camera3D::get_pyramid_shape_rid() {
|
||||
if (pyramid_shape == RID()) {
|
||||
pyramid_shape_points = get_near_plane_points();
|
||||
pyramid_shape = PhysicsServer3D::get_singleton()->convex_polygon_shape_create();
|
||||
PhysicsServer3D::get_singleton()->shape_set_data(pyramid_shape, pyramid_shape_points);
|
||||
|
||||
} else { //check if points changed
|
||||
Vector<Vector3> local_points = get_near_plane_points();
|
||||
|
||||
bool all_equal = true;
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (local_points[i] != pyramid_shape_points[i]) {
|
||||
all_equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!all_equal) {
|
||||
PhysicsServer3D::get_singleton()->shape_set_data(pyramid_shape, local_points);
|
||||
pyramid_shape_points = local_points;
|
||||
}
|
||||
}
|
||||
|
||||
return pyramid_shape;
|
||||
}
|
||||
|
||||
Camera3D::Camera3D() {
|
||||
camera = RenderingServer::get_singleton()->camera_create();
|
||||
set_perspective(75.0, 0.05, 4000.0);
|
||||
|
@ -666,221 +694,7 @@ Camera3D::Camera3D() {
|
|||
|
||||
Camera3D::~Camera3D() {
|
||||
RenderingServer::get_singleton()->free(camera);
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
void ClippedCamera3D::set_margin(real_t p_margin) {
|
||||
margin = p_margin;
|
||||
}
|
||||
|
||||
real_t ClippedCamera3D::get_margin() const {
|
||||
return margin;
|
||||
}
|
||||
|
||||
void ClippedCamera3D::set_process_callback(ClipProcessCallback p_mode) {
|
||||
if (process_callback == p_mode) {
|
||||
return;
|
||||
}
|
||||
process_callback = p_mode;
|
||||
set_process_internal(process_callback == CLIP_PROCESS_IDLE);
|
||||
set_physics_process_internal(process_callback == CLIP_PROCESS_PHYSICS);
|
||||
}
|
||||
|
||||
ClippedCamera3D::ClipProcessCallback ClippedCamera3D::get_process_callback() const {
|
||||
return process_callback;
|
||||
}
|
||||
|
||||
Transform3D ClippedCamera3D::get_camera_transform() const {
|
||||
Transform3D t = Camera3D::get_camera_transform();
|
||||
t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset;
|
||||
return t;
|
||||
}
|
||||
|
||||
void ClippedCamera3D::_notification(int p_what) {
|
||||
if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
|
||||
Node3D *parent = Object::cast_to<Node3D>(get_parent());
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
PhysicsDirectSpaceState3D *dspace = get_world_3d()->get_direct_space_state();
|
||||
ERR_FAIL_COND(!dspace); // most likely physics set to threads
|
||||
|
||||
Vector3 cam_fw = -get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized();
|
||||
Vector3 cam_pos = get_global_transform().origin;
|
||||
Vector3 parent_pos = parent->get_global_transform().origin;
|
||||
|
||||
Plane parent_plane(parent_pos, cam_fw);
|
||||
|
||||
if (parent_plane.is_point_over(cam_pos)) {
|
||||
//cam is beyond parent plane
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 ray_from = parent_plane.project(cam_pos);
|
||||
|
||||
clip_offset = 0; //reset by default
|
||||
|
||||
{ //check if points changed
|
||||
Vector<Vector3> local_points = get_near_plane_points();
|
||||
|
||||
bool all_equal = true;
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (points[i] != local_points[i]) {
|
||||
all_equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!all_equal) {
|
||||
PhysicsServer3D::get_singleton()->shape_set_data(pyramid_shape, local_points);
|
||||
points = local_points;
|
||||
}
|
||||
}
|
||||
|
||||
Transform3D xf = get_global_transform();
|
||||
xf.origin = ray_from;
|
||||
xf.orthonormalize();
|
||||
|
||||
real_t closest_safe = 1.0f, closest_unsafe = 1.0f;
|
||||
if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, closest_safe, closest_unsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) {
|
||||
clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from) * closest_safe);
|
||||
}
|
||||
|
||||
_update_camera();
|
||||
}
|
||||
|
||||
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
|
||||
update_gizmos();
|
||||
if (pyramid_shape.is_valid()) {
|
||||
PhysicsServer3D::get_singleton()->free(pyramid_shape);
|
||||
}
|
||||
}
|
||||
|
||||
void ClippedCamera3D::set_collision_mask(uint32_t p_mask) {
|
||||
collision_mask = p_mask;
|
||||
}
|
||||
|
||||
uint32_t ClippedCamera3D::get_collision_mask() const {
|
||||
return collision_mask;
|
||||
}
|
||||
|
||||
void ClippedCamera3D::set_collision_mask_value(int p_layer_number, bool p_value) {
|
||||
ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
|
||||
ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
|
||||
uint32_t mask = get_collision_mask();
|
||||
if (p_value) {
|
||||
mask |= 1 << (p_layer_number - 1);
|
||||
} else {
|
||||
mask &= ~(1 << (p_layer_number - 1));
|
||||
}
|
||||
set_collision_mask(mask);
|
||||
}
|
||||
|
||||
bool ClippedCamera3D::get_collision_mask_value(int p_layer_number) const {
|
||||
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
|
||||
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
|
||||
return get_collision_mask() & (1 << (p_layer_number - 1));
|
||||
}
|
||||
|
||||
void ClippedCamera3D::add_exception_rid(const RID &p_rid) {
|
||||
exclude.insert(p_rid);
|
||||
}
|
||||
|
||||
void ClippedCamera3D::add_exception(const Object *p_object) {
|
||||
ERR_FAIL_NULL(p_object);
|
||||
const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object);
|
||||
if (!co) {
|
||||
return;
|
||||
}
|
||||
add_exception_rid(co->get_rid());
|
||||
}
|
||||
|
||||
void ClippedCamera3D::remove_exception_rid(const RID &p_rid) {
|
||||
exclude.erase(p_rid);
|
||||
}
|
||||
|
||||
void ClippedCamera3D::remove_exception(const Object *p_object) {
|
||||
ERR_FAIL_NULL(p_object);
|
||||
const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object);
|
||||
if (!co) {
|
||||
return;
|
||||
}
|
||||
remove_exception_rid(co->get_rid());
|
||||
}
|
||||
|
||||
void ClippedCamera3D::clear_exceptions() {
|
||||
exclude.clear();
|
||||
}
|
||||
|
||||
real_t ClippedCamera3D::get_clip_offset() const {
|
||||
return clip_offset;
|
||||
}
|
||||
|
||||
void ClippedCamera3D::set_clip_to_areas(bool p_clip) {
|
||||
clip_to_areas = p_clip;
|
||||
}
|
||||
|
||||
bool ClippedCamera3D::is_clip_to_areas_enabled() const {
|
||||
return clip_to_areas;
|
||||
}
|
||||
|
||||
void ClippedCamera3D::set_clip_to_bodies(bool p_clip) {
|
||||
clip_to_bodies = p_clip;
|
||||
}
|
||||
|
||||
bool ClippedCamera3D::is_clip_to_bodies_enabled() const {
|
||||
return clip_to_bodies;
|
||||
}
|
||||
|
||||
void ClippedCamera3D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &ClippedCamera3D::set_margin);
|
||||
ClassDB::bind_method(D_METHOD("get_margin"), &ClippedCamera3D::get_margin);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_process_callback", "process_callback"), &ClippedCamera3D::set_process_callback);
|
||||
ClassDB::bind_method(D_METHOD("get_process_callback"), &ClippedCamera3D::get_process_callback);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ClippedCamera3D::set_collision_mask);
|
||||
ClassDB::bind_method(D_METHOD("get_collision_mask"), &ClippedCamera3D::get_collision_mask);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &ClippedCamera3D::set_collision_mask_value);
|
||||
ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &ClippedCamera3D::get_collision_mask_value);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &ClippedCamera3D::add_exception_rid);
|
||||
ClassDB::bind_method(D_METHOD("add_exception", "node"), &ClippedCamera3D::add_exception);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &ClippedCamera3D::remove_exception_rid);
|
||||
ClassDB::bind_method(D_METHOD("remove_exception", "node"), &ClippedCamera3D::remove_exception);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_clip_to_areas", "enable"), &ClippedCamera3D::set_clip_to_areas);
|
||||
ClassDB::bind_method(D_METHOD("is_clip_to_areas_enabled"), &ClippedCamera3D::is_clip_to_areas_enabled);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_clip_offset"), &ClippedCamera3D::get_clip_offset);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_clip_to_bodies", "enable"), &ClippedCamera3D::set_clip_to_bodies);
|
||||
ClassDB::bind_method(D_METHOD("is_clip_to_bodies_enabled"), &ClippedCamera3D::is_clip_to_bodies_enabled);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("clear_exceptions"), &ClippedCamera3D::clear_exceptions);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_margin", "get_margin");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
|
||||
|
||||
ADD_GROUP("Clip To", "clip_to");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_areas", "is_clip_to_areas_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_bodies", "is_clip_to_bodies_enabled");
|
||||
|
||||
BIND_ENUM_CONSTANT(CLIP_PROCESS_PHYSICS);
|
||||
BIND_ENUM_CONSTANT(CLIP_PROCESS_IDLE);
|
||||
}
|
||||
|
||||
ClippedCamera3D::ClippedCamera3D() {
|
||||
set_physics_process_internal(true);
|
||||
set_notify_local_transform(Engine::get_singleton()->is_editor_hint());
|
||||
points.resize(5);
|
||||
pyramid_shape = PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CONVEX_POLYGON);
|
||||
}
|
||||
|
||||
ClippedCamera3D::~ClippedCamera3D() {
|
||||
PhysicsServer3D::get_singleton()->free(pyramid_shape);
|
||||
}
|
||||
|
|
|
@ -86,6 +86,9 @@ private:
|
|||
DopplerTracking doppler_tracking = DOPPLER_TRACKING_DISABLED;
|
||||
Ref<VelocityTracker3D> velocity_tracker;
|
||||
|
||||
RID pyramid_shape;
|
||||
Vector<Vector3> pyramid_shape_points;
|
||||
|
||||
protected:
|
||||
void _update_camera();
|
||||
virtual void _request_camera_update();
|
||||
|
@ -168,6 +171,8 @@ public:
|
|||
|
||||
Vector3 get_doppler_tracked_velocity() const;
|
||||
|
||||
RID get_pyramid_shape_rid();
|
||||
|
||||
Camera3D();
|
||||
~Camera3D();
|
||||
};
|
||||
|
@ -176,63 +181,4 @@ VARIANT_ENUM_CAST(Camera3D::Projection);
|
|||
VARIANT_ENUM_CAST(Camera3D::KeepAspect);
|
||||
VARIANT_ENUM_CAST(Camera3D::DopplerTracking);
|
||||
|
||||
class ClippedCamera3D : public Camera3D {
|
||||
GDCLASS(ClippedCamera3D, Camera3D);
|
||||
|
||||
public:
|
||||
enum ClipProcessCallback {
|
||||
CLIP_PROCESS_PHYSICS,
|
||||
CLIP_PROCESS_IDLE,
|
||||
};
|
||||
|
||||
private:
|
||||
ClipProcessCallback process_callback = CLIP_PROCESS_PHYSICS;
|
||||
RID pyramid_shape;
|
||||
real_t margin = 0.0;
|
||||
real_t clip_offset = 0.0;
|
||||
uint32_t collision_mask = 1;
|
||||
bool clip_to_areas = false;
|
||||
bool clip_to_bodies = true;
|
||||
|
||||
Set<RID> exclude;
|
||||
|
||||
Vector<Vector3> points;
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
virtual Transform3D get_camera_transform() const override;
|
||||
|
||||
public:
|
||||
void set_clip_to_areas(bool p_clip);
|
||||
bool is_clip_to_areas_enabled() const;
|
||||
|
||||
void set_clip_to_bodies(bool p_clip);
|
||||
bool is_clip_to_bodies_enabled() const;
|
||||
|
||||
void set_margin(real_t p_margin);
|
||||
real_t get_margin() const;
|
||||
|
||||
void set_process_callback(ClipProcessCallback p_mode);
|
||||
ClipProcessCallback get_process_callback() const;
|
||||
|
||||
void set_collision_mask(uint32_t p_mask);
|
||||
uint32_t get_collision_mask() const;
|
||||
|
||||
void set_collision_mask_value(int p_layer_number, bool p_value);
|
||||
bool get_collision_mask_value(int p_layer_number) const;
|
||||
|
||||
void add_exception_rid(const RID &p_rid);
|
||||
void add_exception(const Object *p_object);
|
||||
void remove_exception_rid(const RID &p_rid);
|
||||
void remove_exception(const Object *p_object);
|
||||
void clear_exceptions();
|
||||
|
||||
real_t get_clip_offset() const;
|
||||
|
||||
ClippedCamera3D();
|
||||
~ClippedCamera3D();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(ClippedCamera3D::ClipProcessCallback);
|
||||
#endif
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
/*************************************************************************/
|
||||
|
||||
#include "spring_arm_3d.h"
|
||||
#include "scene/3d/camera_3d.h"
|
||||
|
||||
void SpringArm3D::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
|
@ -133,17 +134,32 @@ void SpringArm3D::process_spring() {
|
|||
Vector3 motion;
|
||||
const Vector3 cast_direction(get_global_transform().basis.xform(Vector3(0, 0, 1)));
|
||||
|
||||
motion = Vector3(cast_direction * (spring_length));
|
||||
|
||||
if (shape.is_null()) {
|
||||
motion = Vector3(cast_direction * (spring_length));
|
||||
PhysicsDirectSpaceState3D::RayResult r;
|
||||
bool intersected = get_world_3d()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask);
|
||||
if (intersected) {
|
||||
real_t dist = get_global_transform().origin.distance_to(r.position);
|
||||
dist -= margin;
|
||||
motion_delta = dist / (spring_length);
|
||||
Camera3D *camera = nullptr;
|
||||
for (int i = get_child_count() - 1; 0 <= i; --i) {
|
||||
camera = Object::cast_to<Camera3D>(get_child(i));
|
||||
if (camera) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (camera != nullptr) {
|
||||
//use camera rotation, but spring arm position
|
||||
Transform3D base_transform = camera->get_global_transform();
|
||||
base_transform.origin = get_global_transform().origin;
|
||||
get_world_3d()->get_direct_space_state()->cast_motion(camera->get_pyramid_shape_rid(), base_transform, motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask);
|
||||
} else {
|
||||
PhysicsDirectSpaceState3D::RayResult r;
|
||||
bool intersected = get_world_3d()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask);
|
||||
if (intersected) {
|
||||
real_t dist = get_global_transform().origin.distance_to(r.position);
|
||||
dist -= margin;
|
||||
motion_delta = dist / (spring_length);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
motion = Vector3(cast_direction * spring_length);
|
||||
get_world_3d()->get_direct_space_state()->cast_motion(shape->get_rid(), get_global_transform(), motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask);
|
||||
}
|
||||
|
||||
|
|
|
@ -448,7 +448,6 @@ void register_scene_types() {
|
|||
GDREGISTER_VIRTUAL_CLASS(VisualInstance3D);
|
||||
GDREGISTER_VIRTUAL_CLASS(GeometryInstance3D);
|
||||
GDREGISTER_CLASS(Camera3D);
|
||||
GDREGISTER_CLASS(ClippedCamera3D);
|
||||
GDREGISTER_CLASS(AudioListener3D);
|
||||
GDREGISTER_CLASS(XRCamera3D);
|
||||
GDREGISTER_CLASS(XRController3D);
|
||||
|
|
Loading…
Reference in a new issue