Removed PhysicsServer.

This commit is contained in:
Relintai 2023-12-15 09:24:57 +01:00
parent c809e0d588
commit 8adb27eb0f
117 changed files with 20 additions and 33235 deletions

View File

@ -66,7 +66,6 @@
#include "servers/navigation_2d_server.h"
#include "servers/navigation_server.h"
#include "servers/physics_2d_server.h"
#include "servers/physics_server.h"
#include "servers/register_server_types.h"
#include "servers/rendering_server_callbacks.h"
@ -111,7 +110,6 @@ static MessageQueue *message_queue = nullptr;
// Initialized in setup2()
static AudioServer *audio_server = nullptr;
static PhysicsServer *physics_server = nullptr;
static Physics2DServer *physics_2d_server = nullptr;
static RenderingServerCallbacks *rendering_server_callbacks = nullptr;
static NavigationMeshGeneratorManager *navigation_mesh_generator_manager = nullptr;
@ -197,15 +195,6 @@ void initialize_physics() {
GLOBAL_DEF("physics/3d/pandemonium_physics/bvh_collision_margin", 0.1);
ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/pandemonium_physics/bvh_collision_margin", PropertyInfo(Variant::REAL, "physics/3d/pandemonium_physics/bvh_collision_margin", PROPERTY_HINT_RANGE, "0.0,2.0,0.01"));
/// 3D Physics Server
physics_server = PhysicsServerManager::new_server(ProjectSettings::get_singleton()->get(PhysicsServerManager::setting_property_name));
if (!physics_server) {
// Physics server not found, Use the default physics
physics_server = PhysicsServerManager::new_default_server();
}
ERR_FAIL_COND(!physics_server);
physics_server->init();
/// 2D Physics server
physics_2d_server = Physics2DServerManager::new_server(ProjectSettings::get_singleton()->get(Physics2DServerManager::setting_property_name));
if (!physics_2d_server) {
@ -217,9 +206,6 @@ void initialize_physics() {
}
void finalize_physics() {
physics_server->finish();
memdelete(physics_server);
physics_2d_server->finish();
memdelete(physics_2d_server);
}
@ -2286,8 +2272,6 @@ bool Main::iteration() {
uint64_t physics_begin = OS::get_singleton()->get_ticks_usec();
PhysicsServer::get_singleton()->flush_queries();
// Prepare the fixed timestep interpolated nodes
// BEFORE they are updated by the physics 2D,
// otherwise the current and previous transforms
@ -2312,8 +2296,6 @@ bool Main::iteration() {
message_queue->flush();
PhysicsServer::get_singleton()->step(frame_slice * time_scale);
Physics2DServer::get_singleton()->end_sync();
Physics2DServer::get_singleton()->step(frame_slice * time_scale);

View File

@ -37,7 +37,6 @@
#include "servers/audio_server.h"
#include "servers/navigation_server.h"
#include "servers/physics_2d_server.h"
#include "servers/physics_server.h"
#include "servers/rendering_server.h"
Performance *Performance::singleton = nullptr;
@ -73,9 +72,6 @@ void Performance::_bind_methods() {
BIND_ENUM_CONSTANT(PHYSICS_2D_ACTIVE_OBJECTS);
BIND_ENUM_CONSTANT(PHYSICS_2D_COLLISION_PAIRS);
BIND_ENUM_CONSTANT(PHYSICS_2D_ISLAND_COUNT);
BIND_ENUM_CONSTANT(PHYSICS_3D_ACTIVE_OBJECTS);
BIND_ENUM_CONSTANT(PHYSICS_3D_COLLISION_PAIRS);
BIND_ENUM_CONSTANT(PHYSICS_3D_ISLAND_COUNT);
BIND_ENUM_CONSTANT(AUDIO_OUTPUT_LATENCY);
BIND_ENUM_CONSTANT(NAVIGATION_ACTIVE_MAPS);
BIND_ENUM_CONSTANT(NAVIGATION_REGION_COUNT);
@ -131,9 +127,6 @@ String Performance::get_monitor_name(Monitor p_monitor) const {
"physics_2d/active_objects",
"physics_2d/collision_pairs",
"physics_2d/islands",
"physics_3d/active_objects",
"physics_3d/collision_pairs",
"physics_3d/islands",
"audio/output_latency",
"navigation/active_maps",
"navigation/regions",
@ -208,12 +201,6 @@ float Performance::get_monitor(Monitor p_monitor) const {
return Physics2DServer::get_singleton()->get_process_info(Physics2DServer::INFO_COLLISION_PAIRS);
case PHYSICS_2D_ISLAND_COUNT:
return Physics2DServer::get_singleton()->get_process_info(Physics2DServer::INFO_ISLAND_COUNT);
case PHYSICS_3D_ACTIVE_OBJECTS:
return PhysicsServer::get_singleton()->get_process_info(PhysicsServer::INFO_ACTIVE_OBJECTS);
case PHYSICS_3D_COLLISION_PAIRS:
return PhysicsServer::get_singleton()->get_process_info(PhysicsServer::INFO_COLLISION_PAIRS);
case PHYSICS_3D_ISLAND_COUNT:
return PhysicsServer::get_singleton()->get_process_info(PhysicsServer::INFO_ISLAND_COUNT);
case AUDIO_OUTPUT_LATENCY:
return AudioServer::get_singleton()->get_output_latency();
case NAVIGATION_ACTIVE_MAPS:
@ -275,9 +262,6 @@ Performance::MonitorType Performance::get_monitor_type(Monitor p_monitor) const
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_TIME,
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,

View File

@ -78,9 +78,6 @@ public:
PHYSICS_2D_ACTIVE_OBJECTS,
PHYSICS_2D_COLLISION_PAIRS,
PHYSICS_2D_ISLAND_COUNT,
PHYSICS_3D_ACTIVE_OBJECTS,
PHYSICS_3D_COLLISION_PAIRS,
PHYSICS_3D_ISLAND_COUNT,
AUDIO_OUTPUT_LATENCY,
NAVIGATION_ACTIVE_MAPS,
NAVIGATION_REGION_COUNT,

View File

@ -1,188 +0,0 @@
/**************************************************************************/
/* staticbody3d_navigation_geometry_parser_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "staticbody3d_navigation_geometry_parser_3d.h"
#include "core/math/convex_hull.h"
#include "scene/3d/mesh_instance.h"
#include "scene/3d/physics_body.h"
#include "scene/resources/shapes/box_shape.h"
#include "scene/resources/shapes/capsule_shape.h"
#include "scene/resources/shapes/concave_polygon_shape.h"
#include "scene/resources/shapes/convex_polygon_shape.h"
#include "scene/resources/shapes/cylinder_shape.h"
#include "scene/resources/shapes/height_map_shape.h"
#include "scene/resources/shapes/plane_shape.h"
#include "scene/resources/mesh/primitive_meshes.h"
#include "scene/resources/shapes/shape.h"
#include "scene/resources/shapes/sphere_shape.h"
#include "scene/resources/navigation/navigation_mesh.h"
#include "scene/resources/navigation/navigation_mesh_source_geometry_data_3d.h"
bool StaticBody3DNavigationGeometryParser3D::parses_node(Node *p_node) {
return (Object::cast_to<StaticBody>(p_node) != nullptr);
}
void StaticBody3DNavigationGeometryParser3D::parse_geometry(Node *p_node, Ref<NavigationMesh> p_navigationmesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry) {
NavigationMesh::ParsedGeometryType parsed_geometry_type = p_navigationmesh->get_parsed_geometry_type();
uint32_t navigationmesh_collision_mask = p_navigationmesh->get_collision_mask();
if (Object::cast_to<StaticBody>(p_node) && parsed_geometry_type != NavigationMesh::PARSED_GEOMETRY_MESH_INSTANCES) {
StaticBody *static_body = Object::cast_to<StaticBody>(p_node);
if (static_body->get_collision_layer() & navigationmesh_collision_mask) {
List<uint32_t> shape_owners;
static_body->get_shape_owners(&shape_owners);
for (List<uint32_t>::Element *E = shape_owners.front(); E; E = E->next()) {
uint32_t shape_owner = E->get();
if (static_body->is_shape_owner_disabled(shape_owner)) {
continue;
}
const int shape_count = static_body->shape_owner_get_shape_count(shape_owner);
for (int shape_index = 0; shape_index < shape_count; shape_index++) {
Ref<Shape> s = static_body->shape_owner_get_shape(shape_owner, shape_index);
if (s.is_null()) {
continue;
}
const Transform transform = static_body->get_global_transform() * static_body->shape_owner_get_transform(shape_owner);
BoxShape *box = Object::cast_to<BoxShape>(*s);
if (box) {
Array arr;
arr.resize(RS::ARRAY_MAX);
CubeMesh::create_mesh_array(arr, box->get_extents());
p_source_geometry->add_mesh_array(arr, transform);
}
CapsuleShape *capsule = Object::cast_to<CapsuleShape>(*s);
if (capsule) {
Array arr;
arr.resize(RS::ARRAY_MAX);
CapsuleMesh::create_mesh_array(arr, capsule->get_radius(), capsule->get_height());
p_source_geometry->add_mesh_array(arr, transform);
}
CylinderShape *cylinder = Object::cast_to<CylinderShape>(*s);
if (cylinder) {
Array arr;
arr.resize(RS::ARRAY_MAX);
CylinderMesh::create_mesh_array(arr, cylinder->get_radius(), cylinder->get_radius(), cylinder->get_height());
p_source_geometry->add_mesh_array(arr, transform);
}
SphereShape *sphere = Object::cast_to<SphereShape>(*s);
if (sphere) {
Array arr;
arr.resize(RS::ARRAY_MAX);
SphereMesh::create_mesh_array(arr, sphere->get_radius(), sphere->get_radius() * 2.0);
p_source_geometry->add_mesh_array(arr, transform);
}
ConcavePolygonShape *concave_polygon = Object::cast_to<ConcavePolygonShape>(*s);
if (concave_polygon) {
p_source_geometry->add_faces(concave_polygon->get_faces(), transform);
}
ConvexPolygonShape *convex_polygon = Object::cast_to<ConvexPolygonShape>(*s);
if (convex_polygon) {
Vector<Vector3> varr = Variant(convex_polygon->get_points());
Geometry::MeshData md;
Error err = ConvexHullComputer::convex_hull(varr, md);
if (err == OK) {
PoolVector3Array faces;
for (int i = 0; i < md.faces.size(); ++i) {
const Geometry::MeshData::Face &face = md.faces[i];
for (int k = 2; k < face.indices.size(); ++k) {
faces.push_back(md.vertices[face.indices[0]]);
faces.push_back(md.vertices[face.indices[k - 1]]);
faces.push_back(md.vertices[face.indices[k]]);
}
}
p_source_geometry->add_faces(faces, transform);
}
}
HeightMapShape *heightmap_shape = Object::cast_to<HeightMapShape>(*s);
if (heightmap_shape) {
int heightmap_depth = heightmap_shape->get_map_depth();
int heightmap_width = heightmap_shape->get_map_width();
if (heightmap_depth >= 2 && heightmap_width >= 2) {
const PoolVector<real_t> &map_data = heightmap_shape->get_map_data();
Vector2 heightmap_gridsize(heightmap_width - 1, heightmap_depth - 1);
Vector2 start = heightmap_gridsize * -0.5;
PoolVector<Vector3> vertex_array;
vertex_array.resize((heightmap_depth - 1) * (heightmap_width - 1) * 6);
int map_data_current_index = 0;
for (int d = 0; d < heightmap_depth; d++) {
for (int w = 0; w < heightmap_width; w++) {
if (map_data_current_index + 1 + heightmap_depth < map_data.size()) {
float top_left_height = map_data[map_data_current_index];
float top_right_height = map_data[map_data_current_index + 1];
float bottom_left_height = map_data[map_data_current_index + heightmap_depth];
float bottom_right_height = map_data[map_data_current_index + 1 + heightmap_depth];
Vector3 top_left = Vector3(start.x + w, top_left_height, start.y + d);
Vector3 top_right = Vector3(start.x + w + 1.0, top_right_height, start.y + d);
Vector3 bottom_left = Vector3(start.x + w, bottom_left_height, start.y + d + 1.0);
Vector3 bottom_right = Vector3(start.x + w + 1.0, bottom_right_height, start.y + d + 1.0);
vertex_array.push_back(top_right);
vertex_array.push_back(bottom_left);
vertex_array.push_back(top_left);
vertex_array.push_back(top_right);
vertex_array.push_back(bottom_right);
vertex_array.push_back(bottom_left);
}
map_data_current_index += 1;
}
}
if (vertex_array.size() > 0) {
p_source_geometry->add_faces(vertex_array, transform);
}
}
}
}
}
}
}
}

View File

@ -1,43 +0,0 @@
/**************************************************************************/
/* staticbody3d_navigation_geometry_parser_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef STATICBODY3D_NAVIGATION_GEOMETRY_PARSER_3D_H
#define STATICBODY3D_NAVIGATION_GEOMETRY_PARSER_3D_H
#include "scene/3d/navigation_geometry_parser_3d.h"
class StaticBody3DNavigationGeometryParser3D : public NavigationGeometryParser3D {
public:
virtual bool parses_node(Node *p_node) ;
virtual void parse_geometry(Node *p_node, Ref<NavigationMesh> p_navigationmesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry) ;
};
#endif // STATICBODY3D_NAVIGATION_GEOMETRY_PARSER_3D_H

View File

@ -42,7 +42,6 @@
#ifndef _3D_DISABLED
#include "geometry_parser_3d/meshinstance3d_navigation_geometry_parser_3d.h"
#include "geometry_parser_3d/multimeshinstance3d_navigation_geometry_parser_3d.h"
#include "geometry_parser_3d/staticbody3d_navigation_geometry_parser_3d.h"
#endif // _3D_DISABLED
void register_navigation_geometry_parsers_types(ModuleRegistrationLevel p_level) {
@ -54,7 +53,6 @@ void register_navigation_geometry_parsers_types(ModuleRegistrationLevel p_level)
#ifndef _3D_DISABLED
NavigationMeshGenerator::get_singleton()->register_geometry_parser_3d(memnew(MeshInstance3DNavigationGeometryParser3D));
NavigationMeshGenerator::get_singleton()->register_geometry_parser_3d(memnew(MultiMeshInstance3DNavigationGeometryParser3D));
NavigationMeshGenerator::get_singleton()->register_geometry_parser_3d(memnew(StaticBody3DNavigationGeometryParser3D));
#endif // _3D_DISABLED
}
}

View File

@ -1,644 +0,0 @@
/*************************************************************************/
/* area.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "area.h"
#include "scene/resources/shapes/shape.h"
#include "scene/main/scene_string_names.h"
#include "servers/audio_server.h"
#include "servers/physics_server.h"
void Area::set_space_override_mode(SpaceOverride p_mode) {
space_override = p_mode;
PhysicsServer::get_singleton()->area_set_space_override_mode(get_rid(), PhysicsServer::AreaSpaceOverrideMode(p_mode));
}
Area::SpaceOverride Area::get_space_override_mode() const {
return space_override;
}
void Area::set_gravity_is_point(bool p_enabled) {
gravity_is_point = p_enabled;
PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT, p_enabled);
}
bool Area::is_gravity_a_point() const {
return gravity_is_point;
}
void Area::set_gravity_distance_scale(real_t p_scale) {
gravity_distance_scale = p_scale;
PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE, p_scale);
}
real_t Area::get_gravity_distance_scale() const {
return gravity_distance_scale;
}
void Area::set_gravity_vector(const Vector3 &p_vec) {
gravity_vec = p_vec;
PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_GRAVITY_VECTOR, p_vec);
}
Vector3 Area::get_gravity_vector() const {
return gravity_vec;
}
void Area::set_gravity(real_t p_gravity) {
gravity = p_gravity;
PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_GRAVITY, p_gravity);
}
real_t Area::get_gravity() const {
return gravity;
}
void Area::set_linear_damp(real_t p_linear_damp) {
linear_damp = p_linear_damp;
PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_LINEAR_DAMP, p_linear_damp);
}
real_t Area::get_linear_damp() const {
return linear_damp;
}
void Area::set_angular_damp(real_t p_angular_damp) {
angular_damp = p_angular_damp;
PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_ANGULAR_DAMP, p_angular_damp);
}
real_t Area::get_angular_damp() const {
return angular_damp;
}
void Area::set_priority(real_t p_priority) {
priority = p_priority;
PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_PRIORITY, p_priority);
}
real_t Area::get_priority() const {
return priority;
}
void Area::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
RBMap<ObjectID, BodyState>::Element *E = body_map.find(p_id);
ERR_FAIL_COND(!E);
ERR_FAIL_COND(E->get().in_tree);
E->get().in_tree = true;
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
for (int i = 0; i < E->get().shapes.size(); i++) {
emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
}
}
void Area::_body_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
RBMap<ObjectID, BodyState>::Element *E = body_map.find(p_id);
ERR_FAIL_COND(!E);
ERR_FAIL_COND(!E->get().in_tree);
E->get().in_tree = false;
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
for (int i = 0; i < E->get().shapes.size(); i++) {
emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
}
}
void Area::_body_inout(int p_status, const RID &p_body, int p_instance, int p_body_shape, int p_area_shape) {
bool body_in = p_status == PhysicsServer::AREA_BODY_ADDED;
ObjectID objid = p_instance;
Object *obj = ObjectDB::get_instance(objid);
Node *node = Object::cast_to<Node>(obj);
RBMap<ObjectID, BodyState>::Element *E = body_map.find(objid);
if (!body_in && !E) {
return; //likely removed from the tree
}
locked = true;
if (body_in) {
if (!E) {
E = body_map.insert(objid, BodyState());
E->get().rid = p_body;
E->get().rc = 0;
E->get().in_tree = node && node->is_inside_tree();
if (node) {
node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree, make_binds(objid));
node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid));
if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
}
}
E->get().rc++;
if (node) {
E->get().shapes.insert(ShapePair(p_body_shape, p_area_shape));
}
if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_area_shape);
}
} else {
E->get().rc--;
if (node) {
E->get().shapes.erase(ShapePair(p_body_shape, p_area_shape));
}
bool in_tree = E->get().in_tree;
if (E->get().rc == 0) {
body_map.erase(E);
if (node) {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree);
node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree);
if (in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
}
}
}
if (node && in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_area_shape);
}
}
locked = false;
}
void Area::_clear_monitoring() {
ERR_FAIL_COND_MSG(locked, "This function can't be used during the in/out signal.");
{
RBMap<ObjectID, BodyState> bmcopy = body_map;
body_map.clear();
//disconnect all monitored stuff
for (RBMap<ObjectID, BodyState>::Element *E = bmcopy.front(); E; E = E->next()) {
Object *obj = ObjectDB::get_instance(E->key());
Node *node = Object::cast_to<Node>(obj);
if (!node) { //node may have been deleted in previous frame or at other legiminate point
continue;
}
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree);
node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree);
if (!E->get().in_tree) {
continue;
}
for (int i = 0; i < E->get().shapes.size(); i++) {
emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
}
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
}
}
{
RBMap<ObjectID, AreaState> bmcopy = area_map;
area_map.clear();
//disconnect all monitored stuff
for (RBMap<ObjectID, AreaState>::Element *E = bmcopy.front(); E; E = E->next()) {
Object *obj = ObjectDB::get_instance(E->key());
Node *node = Object::cast_to<Node>(obj);
if (!node) { //node may have been deleted in previous frame or at other legiminate point
continue;
}
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree);
node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree);
if (!E->get().in_tree) {
continue;
}
for (int i = 0; i < E->get().shapes.size(); i++) {
emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
}
emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
}
}
}
void Area::_notification(int p_what) {
if (p_what == NOTIFICATION_EXIT_TREE) {
_clear_monitoring();
}
}
void Area::set_monitoring(bool p_enable) {
ERR_FAIL_COND_MSG(locked, "Function blocked during in/out signal. Use set_deferred(\"monitoring\", true/false).");
if (p_enable == monitoring) {
return;
}
monitoring = p_enable;
if (monitoring) {
PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(), this, SceneStringNames::get_singleton()->_body_inout);
PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(), this, SceneStringNames::get_singleton()->_area_inout);
} else {
PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(), nullptr, StringName());
PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(), nullptr, StringName());
_clear_monitoring();
}
}
void Area::_area_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
RBMap<ObjectID, AreaState>::Element *E = area_map.find(p_id);
ERR_FAIL_COND(!E);
ERR_FAIL_COND(E->get().in_tree);
E->get().in_tree = true;
emit_signal(SceneStringNames::get_singleton()->area_entered, node);
for (int i = 0; i < E->get().shapes.size(); i++) {
emit_signal(SceneStringNames::get_singleton()->area_shape_entered, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
}
}
void Area::_area_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
RBMap<ObjectID, AreaState>::Element *E = area_map.find(p_id);
ERR_FAIL_COND(!E);
ERR_FAIL_COND(!E->get().in_tree);
E->get().in_tree = false;
emit_signal(SceneStringNames::get_singleton()->area_exited, node);
for (int i = 0; i < E->get().shapes.size(); i++) {
emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
}
}
void Area::_area_inout(int p_status, const RID &p_area, int p_instance, int p_area_shape, int p_self_shape) {
bool area_in = p_status == PhysicsServer::AREA_BODY_ADDED;
ObjectID objid = p_instance;
Object *obj = ObjectDB::get_instance(objid);
Node *node = Object::cast_to<Node>(obj);
RBMap<ObjectID, AreaState>::Element *E = area_map.find(objid);
if (!area_in && !E) {
return; //likely removed from the tree
}
locked = true;
if (area_in) {
if (!E) {
E = area_map.insert(objid, AreaState());
E->get().rid = p_area;
E->get().rc = 0;
E->get().in_tree = node && node->is_inside_tree();
if (node) {
node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree, make_binds(objid));
node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree, make_binds(objid));
if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->area_entered, node);
}
}
}
E->get().rc++;
if (node) {
E->get().shapes.insert(AreaShapePair(p_area_shape, p_self_shape));
}
if (!node || E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->area_shape_entered, p_area, node, p_area_shape, p_self_shape);
}
} else {
E->get().rc--;
if (node) {
E->get().shapes.erase(AreaShapePair(p_area_shape, p_self_shape));
}
bool in_tree = E->get().in_tree;
if (E->get().rc == 0) {
area_map.erase(E);
if (node) {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree);
node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree);
if (in_tree) {
emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
}
}
}
if (!node || in_tree) {
emit_signal(SceneStringNames::get_singleton()->area_shape_exited, p_area, obj, p_area_shape, p_self_shape);
}
}
locked = false;
}
bool Area::is_monitoring() const {
return monitoring;
}
Array Area::get_overlapping_bodies() const {
ERR_FAIL_COND_V(!monitoring, Array());
Array ret;
ret.resize(body_map.size());
int idx = 0;
for (const RBMap<ObjectID, BodyState>::Element *E = body_map.front(); E; E = E->next()) {
Object *obj = ObjectDB::get_instance(E->key());
if (!obj) {
ret.resize(ret.size() - 1); //ops
} else {
ret[idx++] = obj;
}
}
return ret;
}
void Area::set_monitorable(bool p_enable) {
ERR_FAIL_COND_MSG(locked || (is_inside_tree() && PhysicsServer::get_singleton()->is_flushing_queries()), "Function blocked during in/out signal. Use set_deferred(\"monitorable\", true/false).");
if (p_enable == monitorable) {
return;
}
monitorable = p_enable;
PhysicsServer::get_singleton()->area_set_monitorable(get_rid(), monitorable);
}
bool Area::is_monitorable() const {
return monitorable;
}
Array Area::get_overlapping_areas() const {
ERR_FAIL_COND_V(!monitoring, Array());
Array ret;
ret.resize(area_map.size());
int idx = 0;
for (const RBMap<ObjectID, AreaState>::Element *E = area_map.front(); E; E = E->next()) {
Object *obj = ObjectDB::get_instance(E->key());
if (!obj) {
ret.resize(ret.size() - 1); //ops
} else {
ret[idx++] = obj;
}
}
return ret;
}
bool Area::overlaps_area(Node *p_area) const {
ERR_FAIL_NULL_V(p_area, false);
const RBMap<ObjectID, AreaState>::Element *E = area_map.find(p_area->get_instance_id());
if (!E) {
return false;
}
return E->get().in_tree;
}
bool Area::overlaps_body(Node *p_body) const {
ERR_FAIL_NULL_V(p_body, false);
const RBMap<ObjectID, BodyState>::Element *E = body_map.find(p_body->get_instance_id());
if (!E) {
return false;
}
return E->get().in_tree;
}
void Area::set_audio_bus_override(bool p_override) {
audio_bus_override = p_override;
}
bool Area::is_overriding_audio_bus() const {
return audio_bus_override;
}
void Area::set_audio_bus(const StringName &p_audio_bus) {
audio_bus = p_audio_bus;
}
StringName Area::get_audio_bus() const {
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (AudioServer::get_singleton()->get_bus_name(i) == audio_bus) {
return audio_bus;
}
}
return "Master";
}
void Area::set_use_reverb_bus(bool p_enable) {
use_reverb_bus = p_enable;
}
bool Area::is_using_reverb_bus() const {
return use_reverb_bus;
}
void Area::set_reverb_bus(const StringName &p_audio_bus) {
reverb_bus = p_audio_bus;
}
StringName Area::get_reverb_bus() const {
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (AudioServer::get_singleton()->get_bus_name(i) == reverb_bus) {
return reverb_bus;
}
}
return "Master";
}
void Area::set_reverb_amount(float p_amount) {
reverb_amount = p_amount;
}
float Area::get_reverb_amount() const {
return reverb_amount;
}
void Area::set_reverb_uniformity(float p_uniformity) {
reverb_uniformity = p_uniformity;
}
float Area::get_reverb_uniformity() const {
return reverb_uniformity;
}
void Area::_validate_property(PropertyInfo &property) const {
if (property.name == "audio_bus_name" || property.name == "reverb_bus_name") {
String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (i > 0) {
options += ",";
}
String name = AudioServer::get_singleton()->get_bus_name(i);
options += name;
}
property.hint_string = options;
}
}
void Area::_bind_methods() {
ClassDB::bind_method(D_METHOD("_body_enter_tree", "id"), &Area::_body_enter_tree);
ClassDB::bind_method(D_METHOD("_body_exit_tree", "id"), &Area::_body_exit_tree);
ClassDB::bind_method(D_METHOD("_area_enter_tree", "id"), &Area::_area_enter_tree);
ClassDB::bind_method(D_METHOD("_area_exit_tree", "id"), &Area::_area_exit_tree);
ClassDB::bind_method(D_METHOD("set_space_override_mode", "enable"), &Area::set_space_override_mode);
ClassDB::bind_method(D_METHOD("get_space_override_mode"), &Area::get_space_override_mode);
ClassDB::bind_method(D_METHOD("set_gravity_is_point", "enable"), &Area::set_gravity_is_point);
ClassDB::bind_method(D_METHOD("is_gravity_a_point"), &Area::is_gravity_a_point);
ClassDB::bind_method(D_METHOD("set_gravity_distance_scale", "distance_scale"), &Area::set_gravity_distance_scale);
ClassDB::bind_method(D_METHOD("get_gravity_distance_scale"), &Area::get_gravity_distance_scale);
ClassDB::bind_method(D_METHOD("set_gravity_vector", "vector"), &Area::set_gravity_vector);
ClassDB::bind_method(D_METHOD("get_gravity_vector"), &Area::get_gravity_vector);
ClassDB::bind_method(D_METHOD("set_gravity", "gravity"), &Area::set_gravity);
ClassDB::bind_method(D_METHOD("get_gravity"), &Area::get_gravity);
ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &Area::set_angular_damp);
ClassDB::bind_method(D_METHOD("get_angular_damp"), &Area::get_angular_damp);
ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &Area::set_linear_damp);
ClassDB::bind_method(D_METHOD("get_linear_damp"), &Area::get_linear_damp);
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &Area::set_priority);
ClassDB::bind_method(D_METHOD("get_priority"), &Area::get_priority);
ClassDB::bind_method(D_METHOD("set_monitorable", "enable"), &Area::set_monitorable);
ClassDB::bind_method(D_METHOD("is_monitorable"), &Area::is_monitorable);
ClassDB::bind_method(D_METHOD("set_monitoring", "enable"), &Area::set_monitoring);
ClassDB::bind_method(D_METHOD("is_monitoring"), &Area::is_monitoring);
ClassDB::bind_method(D_METHOD("get_overlapping_bodies"), &Area::get_overlapping_bodies);
ClassDB::bind_method(D_METHOD("get_overlapping_areas"), &Area::get_overlapping_areas);
ClassDB::bind_method(D_METHOD("overlaps_body", "body"), &Area::overlaps_body);
ClassDB::bind_method(D_METHOD("overlaps_area", "area"), &Area::overlaps_area);
ClassDB::bind_method(D_METHOD("_body_inout"), &Area::_body_inout);
ClassDB::bind_method(D_METHOD("_area_inout"), &Area::_area_inout);
ClassDB::bind_method(D_METHOD("set_audio_bus_override", "enable"), &Area::set_audio_bus_override);
ClassDB::bind_method(D_METHOD("is_overriding_audio_bus"), &Area::is_overriding_audio_bus);
ClassDB::bind_method(D_METHOD("set_audio_bus", "name"), &Area::set_audio_bus);
ClassDB::bind_method(D_METHOD("get_audio_bus"), &Area::get_audio_bus);
ClassDB::bind_method(D_METHOD("set_use_reverb_bus", "enable"), &Area::set_use_reverb_bus);
ClassDB::bind_method(D_METHOD("is_using_reverb_bus"), &Area::is_using_reverb_bus);
ClassDB::bind_method(D_METHOD("set_reverb_bus", "name"), &Area::set_reverb_bus);
ClassDB::bind_method(D_METHOD("get_reverb_bus"), &Area::get_reverb_bus);
ClassDB::bind_method(D_METHOD("set_reverb_amount", "amount"), &Area::set_reverb_amount);
ClassDB::bind_method(D_METHOD("get_reverb_amount"), &Area::get_reverb_amount);
ClassDB::bind_method(D_METHOD("set_reverb_uniformity", "amount"), &Area::set_reverb_uniformity);
ClassDB::bind_method(D_METHOD("get_reverb_uniformity"), &Area::get_reverb_uniformity);
ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index")));
ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index")));
ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area"), PropertyInfo(Variant::INT, "area_shape_index"), PropertyInfo(Variant::INT, "local_shape_index")));
ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area"), PropertyInfo(Variant::INT, "area_shape_index"), PropertyInfo(Variant::INT, "local_shape_index")));
ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area")));
ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area")));
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
ADD_GROUP("Physics Overrides", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_vec"), "set_gravity_vector", "get_gravity_vector");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity", PROPERTY_HINT_RANGE, "-32,32,0.001,or_lesser,or_greater"), "set_gravity", "get_gravity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
ADD_GROUP("Audio Bus", "audio_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus", "get_audio_bus");
ADD_GROUP("Reverb Bus", "reverb_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enable"), "set_use_reverb_bus", "is_using_reverb_bus");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus", "get_reverb_bus");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "reverb_bus_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_amount", "get_reverb_amount");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "reverb_bus_uniformity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_uniformity", "get_reverb_uniformity");
BIND_ENUM_CONSTANT(SPACE_OVERRIDE_DISABLED);
BIND_ENUM_CONSTANT(SPACE_OVERRIDE_COMBINE);
BIND_ENUM_CONSTANT(SPACE_OVERRIDE_COMBINE_REPLACE);
BIND_ENUM_CONSTANT(SPACE_OVERRIDE_REPLACE);
BIND_ENUM_CONSTANT(SPACE_OVERRIDE_REPLACE_COMBINE);
}
Area::Area() :
CollisionObject(RID_PRIME(PhysicsServer::get_singleton()->area_create()), true) {
space_override = SPACE_OVERRIDE_DISABLED;
set_gravity(9.8);
locked = false;
set_gravity_vector(Vector3(0, -1, 0));
gravity_is_point = false;
gravity_distance_scale = 0;
linear_damp = 0.1;
angular_damp = 0.1;
priority = 0;
monitoring = false;
monitorable = false;
set_monitoring(true);
set_monitorable(true);
audio_bus_override = false;
audio_bus = "Master";
use_reverb_bus = false;
reverb_bus = "Master";
reverb_amount = 0.0;
reverb_uniformity = 0.0;
}
Area::~Area() {
}

View File

@ -1,201 +0,0 @@
#ifndef AREA_H
#define AREA_H
/*************************************************************************/
/* area.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/containers/vset.h"
#include "scene/3d/collision_object.h"
class Area : public CollisionObject {
GDCLASS(Area, CollisionObject);
public:
enum SpaceOverride {
SPACE_OVERRIDE_DISABLED,
SPACE_OVERRIDE_COMBINE,
SPACE_OVERRIDE_COMBINE_REPLACE,
SPACE_OVERRIDE_REPLACE,
SPACE_OVERRIDE_REPLACE_COMBINE
};
private:
SpaceOverride space_override;
Vector3 gravity_vec;
real_t gravity;
bool gravity_is_point;
real_t gravity_distance_scale;
real_t angular_damp;
real_t linear_damp;
int priority;
bool monitoring;
bool monitorable;
bool locked;
void _body_inout(int p_status, const RID &p_body, int p_instance, int p_body_shape, int p_area_shape);
void _body_enter_tree(ObjectID p_id);
void _body_exit_tree(ObjectID p_id);
struct ShapePair {
int body_shape;
int area_shape;
bool operator<(const ShapePair &p_sp) const {
if (body_shape == p_sp.body_shape) {
return area_shape < p_sp.area_shape;
} else {
return body_shape < p_sp.body_shape;
}
}
ShapePair() {}
ShapePair(int p_bs, int p_as) {
body_shape = p_bs;
area_shape = p_as;
}
};
struct BodyState {
RID rid;
int rc;
bool in_tree;
VSet<ShapePair> shapes;
};
RBMap<ObjectID, BodyState> body_map;
void _area_inout(int p_status, const RID &p_area, int p_instance, int p_area_shape, int p_self_shape);
void _area_enter_tree(ObjectID p_id);
void _area_exit_tree(ObjectID p_id);
struct AreaShapePair {
int area_shape;
int self_shape;
bool operator<(const AreaShapePair &p_sp) const {
if (area_shape == p_sp.area_shape) {
return self_shape < p_sp.self_shape;
} else {
return area_shape < p_sp.area_shape;
}
}
AreaShapePair() {}
AreaShapePair(int p_bs, int p_as) {
area_shape = p_bs;
self_shape = p_as;
}
};
struct AreaState {
RID rid;
int rc;
bool in_tree;
VSet<AreaShapePair> shapes;
};
RBMap<ObjectID, AreaState> area_map;
void _clear_monitoring();
bool audio_bus_override;
StringName audio_bus;
bool use_reverb_bus;
StringName reverb_bus;
float reverb_amount;
float reverb_uniformity;
void _validate_property(PropertyInfo &property) const;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
void set_space_override_mode(SpaceOverride p_mode);
SpaceOverride get_space_override_mode() const;
void set_gravity_is_point(bool p_enabled);
bool is_gravity_a_point() const;
void set_gravity_distance_scale(real_t p_scale);
real_t get_gravity_distance_scale() const;
void set_gravity_vector(const Vector3 &p_vec);
Vector3 get_gravity_vector() const;
void set_gravity(real_t p_gravity);
real_t get_gravity() const;
void set_angular_damp(real_t p_angular_damp);
real_t get_angular_damp() const;
void set_linear_damp(real_t p_linear_damp);
real_t get_linear_damp() const;
void set_priority(real_t p_priority);
real_t get_priority() const;
void set_monitoring(bool p_enable);
bool is_monitoring() const;
void set_monitorable(bool p_enable);
bool is_monitorable() const;
Array get_overlapping_bodies() const;
Array get_overlapping_areas() const; //function for script
bool overlaps_area(Node *p_area) const;
bool overlaps_body(Node *p_body) const;
void set_audio_bus_override(bool p_override);
bool is_overriding_audio_bus() const;
void set_audio_bus(const StringName &p_audio_bus);
StringName get_audio_bus() const;
void set_use_reverb_bus(bool p_enable);
bool is_using_reverb_bus() const;
void set_reverb_bus(const StringName &p_audio_bus);
StringName get_reverb_bus() const;
void set_reverb_amount(float p_amount);
float get_reverb_amount() const;
void set_reverb_uniformity(float p_uniformity);
float get_reverb_uniformity() const;
Area();
~Area();
};
VARIANT_ENUM_CAST(Area::SpaceOverride);
#endif // AREA__H

View File

@ -31,15 +31,11 @@
#include "audio_stream_player_3d.h"
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "scene/3d/area.h"
#include "scene/3d/camera.h"
#include "scene/3d/listener.h"
#include "scene/3d/spatial_velocity_tracker.h"
#include "scene/main/viewport.h"
#include "scene/resources/shapes/shape.h"
#include "scene/resources/world_3d.h"
#include "servers/audio/audio_stream.h"
#include "servers/physics_server.h"
// Based on "A Novel Multichannel Panning Method for Standard and Arbitrary Loudspeaker Configurations" by Ramy Sadek and Chris Kyriakakis (2004)
// Speaker-Placement Correction Amplitude Panning (SPCAP)
@ -365,266 +361,21 @@ void AudioStreamPlayer3D::_notification(int p_what) {
}
}
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
//update anything related to position first, if possible of course
//start playing if requested
if (setplay.get() >= 0.0) {
setseek.set(setplay.get());
active.set();
setplay.set(-1);
//do not update, this makes it easier to animate (will shut off otherwise)
///_change_notify("playing"); //update property in editor
}
if (!output_ready.is_set()) {
Vector3 linear_velocity;
//compute linear velocity for doppler
if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
linear_velocity = velocity_tracker->get_tracked_linear_velocity();
}
Ref<World3D> world = get_world_3d();
ERR_FAIL_COND(world.is_null());
int new_output_count = 0;
Vector3 global_pos = get_global_transform().origin;
int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
//check if any area is diverting sound into a bus
PhysicsDirectSpaceState *space_state = PhysicsServer::get_singleton()->space_get_direct_state(world->get_space());
PhysicsDirectSpaceState::ShapeResult sr[MAX_INTERSECT_AREAS];
int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, RBSet<RID>(), area_mask, false, true);
Area *area = nullptr;
for (int i = 0; i < areas; i++) {
if (!sr[i].collider) {
continue;
}
Area *tarea = Object::cast_to<Area>(sr[i].collider);
if (!tarea) {
continue;
}
if (!tarea->is_overriding_audio_bus() && !tarea->is_using_reverb_bus()) {
continue;
}
area = tarea;
break;
}
List<Camera *> cameras;
world->get_camera_list(&cameras);
for (List<Camera *>::Element *E = cameras.front(); E; E = E->next()) {
Camera *camera = E->get();
Viewport *vp = camera->get_viewport();
if (!vp->is_audio_listener()) {
continue;
}
bool listener_is_camera = true;
Spatial *listener_node = camera;
Listener *listener = vp->get_listener();
if (listener) {
listener_node = listener;
listener_is_camera = false;
}
Vector3 local_pos = listener_node->get_global_transform().orthonormalized().affine_inverse().xform(global_pos);
float dist = local_pos.length();
Vector3 area_sound_pos;
Vector3 listener_area_pos;
if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) {
area_sound_pos = space_state->get_closest_point_to_object_volume(area->get_rid(), listener_node->get_global_transform().origin);
listener_area_pos = listener_node->get_global_transform().affine_inverse().xform(area_sound_pos);
}
if (max_distance > 0) {
float total_max = max_distance;
if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) {
total_max = MAX(total_max, listener_area_pos.length());
}
if (total_max > max_distance) {
continue; //can't hear this sound in this listener
}
}
float multiplier = Math::db2linear(_get_attenuation_db(dist));
if (max_distance > 0) {
multiplier *= MAX(0, 1.0 - (dist / max_distance));
}
Output output;
output.bus_index = bus_index;
output.reverb_bus_index = -1; //no reverb by default
output.viewport = vp;
float db_att = (1.0 - MIN(1.0, multiplier)) * attenuation_filter_db;
if (emission_angle_enabled) {
Vector3 listenertopos = global_pos - listener_node->get_global_transform().origin;
float c = listenertopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative
float angle = Math::rad2deg(Math::acos(c));
if (angle > emission_angle) {
db_att -= -emission_angle_filter_attenuation_db;
}
}
output.filter_gain = Math::db2linear(db_att);
// Bake in a constant factor here to allow the project setting defaults for 2d and 3d to be normalized to 1.0.
float tightness = cached_global_panning_strength * 2.0f;
tightness *= panning_strength;
_calc_output_vol(local_pos.normalized(), tightness, output);
unsigned int cc = AudioServer::get_singleton()->get_channel_count();
for (unsigned int k = 0; k < cc; k++) {
output.vol[k] *= multiplier;
}
bool filled_reverb = false;
int vol_index_max = AudioServer::get_singleton()->get_speaker_mode() + 1;
if (area) {
if (area->is_overriding_audio_bus()) {
//override audio bus
StringName bus_name = area->get_audio_bus();
output.bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name);
}
if (area->is_using_reverb_bus()) {
filled_reverb = true;
StringName bus_name = area->get_reverb_bus();
output.reverb_bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name);
float uniformity = area->get_reverb_uniformity();
float area_send = area->get_reverb_amount();
if (uniformity > 0.0) {
float distance = listener_area_pos.length();
float attenuation = Math::db2linear(_get_attenuation_db(distance));
//float dist_att_db = -20 * Math::log(dist + 0.00001); //logarithmic attenuation, like in real life
float center_val[3] = { 0.5f, 0.25f, 0.16666f };
AudioFrame center_frame(center_val[vol_index_max - 1], center_val[vol_index_max - 1]);
if (attenuation < 1.0) {
//pan the uniform sound
Vector3 rev_pos = listener_area_pos;
rev_pos.y = 0;
rev_pos.normalize();
if (cc >= 1) {
// Stereo pair
float c = rev_pos.x * 0.5 + 0.5;
output.reverb_vol[0].l = 1.0 - c;
output.reverb_vol[0].r = c;
}
if (cc >= 3) {
// Center pair + Side pair
float xl = Vector3(-1, 0, -1).normalized().dot(rev_pos) * 0.5 + 0.5;
float xr = Vector3(1, 0, -1).normalized().dot(rev_pos) * 0.5 + 0.5;
output.reverb_vol[1].l = xl;
output.reverb_vol[1].r = xr;
output.reverb_vol[2].l = 1.0 - xr;
output.reverb_vol[2].r = 1.0 - xl;
}
if (cc >= 4) {
// Rear pair
// FIXME: Not sure what math should be done here
float c = rev_pos.x * 0.5 + 0.5;
output.reverb_vol[3].l = 1.0 - c;
output.reverb_vol[3].r = c;
}
for (int i = 0; i < vol_index_max; i++) {
output.reverb_vol[i] = output.reverb_vol[i].linear_interpolate(center_frame, attenuation);
}
} else {
for (int i = 0; i < vol_index_max; i++) {
output.reverb_vol[i] = center_frame;
}
}
for (int i = 0; i < vol_index_max; i++) {
output.reverb_vol[i] = output.vol[i].linear_interpolate(output.reverb_vol[i] * attenuation, uniformity);
output.reverb_vol[i] *= area_send;
}
} else {
for (int i = 0; i < vol_index_max; i++) {
output.reverb_vol[i] = output.vol[i] * area_send;
}
}
}
}
if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
Vector3 listener_velocity;
if (listener_is_camera) {
listener_velocity = camera->get_doppler_tracked_velocity();
}
Vector3 local_velocity = listener_node->get_global_transform().orthonormalized().basis.xform_inv(linear_velocity - listener_velocity);
if (local_velocity == Vector3()) {
output.pitch_scale = 1.0;
} else {
float approaching = local_pos.normalized().dot(local_velocity.normalized());
float velocity = local_velocity.length();
float speed_of_sound = 343.0;
output.pitch_scale = speed_of_sound / (speed_of_sound + velocity * approaching);
output.pitch_scale = CLAMP(output.pitch_scale, (1 / 8.0), 8.0); //avoid crazy stuff
}
} else {
output.pitch_scale = 1.0;
}
if (!filled_reverb) {
for (int i = 0; i < vol_index_max; i++) {
output.reverb_vol[i] = AudioFrame(0, 0);
}
}
outputs[new_output_count] = output;
new_output_count++;
if (new_output_count == MAX_OUTPUTS) {
break;
}
}
output_count.set(new_output_count);
output_ready.set();
}
//start playing if requested
if (setplay.get() >= 0.0) {
setseek.set(setplay.get());
active.set();
setplay.set(-1);
//do not update, this makes it easier to animate (will shut off otherwise)
///_change_notify("playing"); //update property in editor
}
//stop playing if no longer active
if (!active.is_set()) {
set_physics_process_internal(false);
//do not update, this makes it easier to animate (will shut off otherwise)
//_change_notify("playing"); //update property in editor
emit_signal("finished");
}
//stop playing if no longer active
if (!active.is_set()) {
set_physics_process_internal(false);
//do not update, this makes it easier to animate (will shut off otherwise)
//_change_notify("playing"); //update property in editor
emit_signal("finished");
}
}

View File

@ -30,7 +30,6 @@
#include "camera.h"
#include "collision_object.h"
#include "core/config/engine.h"
#include "core/math/projection.h"
#include "scene/3d/spatial_velocity_tracker.h"
@ -684,215 +683,3 @@ Camera::Camera() {
Camera::~Camera() {
RenderingServer::get_singleton()->free(camera);
}
////////////////////////////////////////
void ClippedCamera::set_margin(float p_margin) {
margin = p_margin;
}
float ClippedCamera::get_margin() const {
return margin;
}
void ClippedCamera::set_process_mode(ProcessMode p_mode) {
if (process_mode == p_mode) {
return;
}
process_mode = p_mode;
set_process_internal(process_mode == CLIP_PROCESS_IDLE);
set_physics_process_internal(process_mode == CLIP_PROCESS_PHYSICS);
}
ClippedCamera::ProcessMode ClippedCamera::get_process_mode() const {
return process_mode;
}
Transform ClippedCamera::get_camera_transform() const {
Transform t = Camera::get_camera_transform();
t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset;
return t;
}
void ClippedCamera::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
Spatial *parent = Object::cast_to<Spatial>(get_parent());
if (!parent) {
return;
}
PhysicsDirectSpaceState *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 defau;t
{ //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) {
PhysicsServer::get_singleton()->shape_set_data(pyramid_shape, local_points);
points = local_points;
}
}
Transform xf = get_global_transform();
xf.origin = ray_from;
xf.orthonormalize();
float 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();
}
}
void ClippedCamera::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
}
uint32_t ClippedCamera::get_collision_mask() const {
return collision_mask;
}
void ClippedCamera::set_collision_mask_bit(int p_bit, bool p_value) {
ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
} else {
mask &= ~(1 << p_bit);
}
set_collision_mask(mask);
}
bool ClippedCamera::get_collision_mask_bit(int p_bit) const {
ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
void ClippedCamera::add_exception_rid(const RID &p_rid) {
exclude.insert(p_rid);
}
void ClippedCamera::add_exception(const Object *p_object) {
ERR_FAIL_NULL(p_object);
const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
ERR_FAIL_COND_MSG(!co, "The passed Node must be an instance of CollisionObject.");
add_exception_rid(co->get_rid());
}
void ClippedCamera::remove_exception_rid(const RID &p_rid) {
exclude.erase(p_rid);
}
void ClippedCamera::remove_exception(const Object *p_object) {
ERR_FAIL_NULL(p_object);
const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
ERR_FAIL_COND_MSG(!co, "The passed Node must be an instance of CollisionObject.");
remove_exception_rid(co->get_rid());
}
void ClippedCamera::clear_exceptions() {
exclude.clear();
}
float ClippedCamera::get_clip_offset() const {
return clip_offset;
}
void ClippedCamera::set_clip_to_areas(bool p_clip) {
clip_to_areas = p_clip;
}
bool ClippedCamera::is_clip_to_areas_enabled() const {
return clip_to_areas;
}
void ClippedCamera::set_clip_to_bodies(bool p_clip) {
clip_to_bodies = p_clip;
}
bool ClippedCamera::is_clip_to_bodies_enabled() const {
return clip_to_bodies;
}
void ClippedCamera::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &ClippedCamera::set_margin);
ClassDB::bind_method(D_METHOD("get_margin"), &ClippedCamera::get_margin);
ClassDB::bind_method(D_METHOD("set_process_mode", "process_mode"), &ClippedCamera::set_process_mode);
ClassDB::bind_method(D_METHOD("get_process_mode"), &ClippedCamera::get_process_mode);
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ClippedCamera::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &ClippedCamera::get_collision_mask);
ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &ClippedCamera::set_collision_mask_bit);
ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &ClippedCamera::get_collision_mask_bit);
ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &ClippedCamera::add_exception_rid);
ClassDB::bind_method(D_METHOD("add_exception", "node"), &ClippedCamera::add_exception);
ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &ClippedCamera::remove_exception_rid);
ClassDB::bind_method(D_METHOD("remove_exception", "node"), &ClippedCamera::remove_exception);
ClassDB::bind_method(D_METHOD("set_clip_to_areas", "enable"), &ClippedCamera::set_clip_to_areas);
ClassDB::bind_method(D_METHOD("is_clip_to_areas_enabled"), &ClippedCamera::is_clip_to_areas_enabled);
ClassDB::bind_method(D_METHOD("get_clip_offset"), &ClippedCamera::get_clip_offset);
ClassDB::bind_method(D_METHOD("set_clip_to_bodies", "enable"), &ClippedCamera::set_clip_to_bodies);
ClassDB::bind_method(D_METHOD("is_clip_to_bodies_enabled"), &ClippedCamera::is_clip_to_bodies_enabled);
ClassDB::bind_method(D_METHOD("clear_exceptions"), &ClippedCamera::clear_exceptions);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_margin", "get_margin");
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode");
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);
}
ClippedCamera::ClippedCamera() {
margin = 0;
clip_offset = 0;
process_mode = CLIP_PROCESS_PHYSICS;
set_physics_process_internal(true);
collision_mask = 1;
set_notify_local_transform(Engine::get_singleton()->is_editor_hint());
points.resize(5);
pyramid_shape = RID_PRIME(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CONVEX_POLYGON));
clip_to_areas = false;
clip_to_bodies = true;
}
ClippedCamera::~ClippedCamera() {
PhysicsServer::get_singleton()->free(pyramid_shape);
}

View File

@ -180,63 +180,5 @@ VARIANT_ENUM_CAST(Camera::ProjectionMode);
VARIANT_ENUM_CAST(Camera::KeepAspect);
VARIANT_ENUM_CAST(Camera::DopplerTracking);
class ClippedCamera : public Camera {
GDCLASS(ClippedCamera, Camera);
public:
enum ProcessMode {
CLIP_PROCESS_PHYSICS,
CLIP_PROCESS_IDLE,
};
private:
ProcessMode process_mode;
RID pyramid_shape;
float margin;
float clip_offset;
uint32_t collision_mask;
bool clip_to_areas;
bool clip_to_bodies;
RBSet<RID> exclude;
Vector<Vector3> points;
protected:
void _notification(int p_what);
static void _bind_methods();
virtual Transform get_camera_transform() const;
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(float p_margin);
float get_margin() const;
void set_process_mode(ProcessMode p_mode);
ProcessMode get_process_mode() const;
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) 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();
float get_clip_offset() const;
ClippedCamera();
~ClippedCamera();
};
VARIANT_ENUM_CAST(ClippedCamera::ProcessMode);
#endif

View File

@ -1,593 +0,0 @@
/*************************************************************************/
/* collision_object.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "collision_object.h"
#include "core/config/engine.h"
#include "mesh_instance.h"
#include "scene/resources/mesh/mesh.h"
#include "scene/resources/world_3d.h"
#include "scene/main/scene_string_names.h"
#include "servers/physics_server.h"
void CollisionObject::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
if (_are_collision_shapes_visible()) {
debug_shape_old_transform = get_global_transform();
for (RBMap<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
debug_shapes_to_update.insert(E->key());
}
_update_debug_shapes();
}
} break;
case NOTIFICATION_EXIT_TREE: {
if (debug_shapes_count > 0) {
_clear_debug_shapes();
}
} break;
case NOTIFICATION_ENTER_WORLD: {
if (area) {
PhysicsServer::get_singleton()->area_set_transform(rid, get_global_transform());
} else {
PhysicsServer::get_singleton()->body_set_state(rid, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform());
}
Ref<World3D> world_ref = get_world_3d();
ERR_FAIL_COND(!world_ref.is_valid());
RID space = world_ref->get_space();
if (area) {
PhysicsServer::get_singleton()->area_set_space(rid, space);
} else {
PhysicsServer::get_singleton()->body_set_space(rid, space);
}
_update_pickable();
//get space
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
if (only_update_transform_changes) {
return;
}
if (area) {
PhysicsServer::get_singleton()->area_set_transform(rid, get_global_transform());
} else {
PhysicsServer::get_singleton()->body_set_state(rid, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform());
}
_on_transform_changed();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
_update_pickable();
} break;
case NOTIFICATION_EXIT_WORLD: {
if (area) {
PhysicsServer::get_singleton()->area_set_space(rid, RID());
} else {
PhysicsServer::get_singleton()->body_set_space(rid, RID());
}
} break;
}
}
void CollisionObject::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
if (area) {
PhysicsServer::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
} else {
PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
}
}
uint32_t CollisionObject::get_collision_layer() const {
return collision_layer;
}
void CollisionObject::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
if (area) {
PhysicsServer::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
} else {
PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
}
}
uint32_t CollisionObject::get_collision_mask() const {
return collision_mask;
}
void CollisionObject::set_collision_layer_bit(int p_bit, bool p_value) {
ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
uint32_t collision_layer = get_collision_layer();
if (p_value) {
collision_layer |= 1 << p_bit;
} else {
collision_layer &= ~(1 << p_bit);
}
set_collision_layer(collision_layer);
}
bool CollisionObject::get_collision_layer_bit(int p_bit) const {
ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
return get_collision_layer() & (1 << p_bit);
}
void CollisionObject::set_collision_mask_bit(int p_bit, bool p_value) {
ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
} else {
mask &= ~(1 << p_bit);
}
set_collision_mask(mask);
}
bool CollisionObject::get_collision_mask_bit(int p_bit) const {
ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
void CollisionObject::_input_event(Node *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
if (get_script_instance()) {
get_script_instance()->call(SceneStringNames::get_singleton()->_input_event, p_camera, p_input_event, p_pos, p_normal, p_shape);
}
emit_signal(SceneStringNames::get_singleton()->input_event, p_camera, p_input_event, p_pos, p_normal, p_shape);
}
void CollisionObject::_mouse_enter() {
if (get_script_instance()) {
get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_enter);
}
emit_signal(SceneStringNames::get_singleton()->mouse_entered);
}
void CollisionObject::_mouse_exit() {
if (get_script_instance()) {
get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_exit);
}
emit_signal(SceneStringNames::get_singleton()->mouse_exited);
}
void CollisionObject::set_only_update_transform_changes(bool p_enable) {
only_update_transform_changes = p_enable;
}
void CollisionObject::_update_pickable() {
if (!is_inside_tree()) {
return;
}
bool pickable = ray_pickable && is_visible_in_tree();
if (area) {
PhysicsServer::get_singleton()->area_set_ray_pickable(rid, pickable);
} else {
PhysicsServer::get_singleton()->body_set_ray_pickable(rid, pickable);
}
}
bool CollisionObject::_are_collision_shapes_visible() {
return is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !Engine::get_singleton()->is_editor_hint();
}
void CollisionObject::_update_shape_data(uint32_t p_owner) {
if (_are_collision_shapes_visible()) {
if (debug_shapes_to_update.empty()) {
call_deferred("_update_debug_shapes");
}
debug_shapes_to_update.insert(p_owner);
}
}
void CollisionObject::_shape_changed(const Ref<Shape> &p_shape) {
for (RBMap<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
ShapeData &shapedata = E->get();
ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
for (int i = 0; i < shapedata.shapes.size(); i++) {
ShapeData::ShapeBase &s = shapes[i];
if (s.shape == p_shape && s.debug_shape.is_valid()) {
Ref<Mesh> mesh = s.shape->get_debug_mesh();
RS::get_singleton()->instance_set_base(s.debug_shape, mesh->get_rid());
}
}
}
}
void CollisionObject::_update_debug_shapes() {
if (!is_inside_tree()) {
debug_shapes_to_update.clear();
return;
}
for (RBSet<uint32_t>::Element *shapedata_idx = debug_shapes_to_update.front(); shapedata_idx; shapedata_idx = shapedata_idx->next()) {
if (shapes.has(shapedata_idx->get())) {
ShapeData &shapedata = shapes[shapedata_idx->get()];
ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
for (int i = 0; i < shapedata.shapes.size(); i++) {
ShapeData::ShapeBase &s = shapes[i];
if (s.shape.is_null() || shapedata.disabled) {
if (s.debug_shape.is_valid()) {
RS::get_singleton()->free(s.debug_shape);
s.debug_shape = RID();
--debug_shapes_count;
}
}
if (!s.debug_shape.is_valid()) {
s.debug_shape = RID_PRIME(RS::get_singleton()->instance_create());
RS::get_singleton()->instance_set_scenario(s.debug_shape, get_world_3d()->get_scenario());
if (!s.shape->is_connected("changed", this, "_shape_changed")) {
s.shape->connect("changed", this, "_shape_changed", varray(s.shape), CONNECT_DEFERRED);
}
++debug_shapes_count;
}
Ref<Mesh> mesh = s.shape->get_debug_mesh();
RS::get_singleton()->instance_set_base(s.debug_shape, mesh->get_rid());
RS::get_singleton()->instance_set_transform(s.debug_shape, get_global_transform() * shapedata.xform);
RS::get_singleton()->instance_set_portal_mode(s.debug_shape, RenderingServer::INSTANCE_PORTAL_MODE_GLOBAL);
}
}
}
debug_shapes_to_update.clear();
}
void CollisionObject::_clear_debug_shapes() {
for (RBMap<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
ShapeData &shapedata = E->get();
ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
for (int i = 0; i < shapedata.shapes.size(); i++) {
ShapeData::ShapeBase &s = shapes[i];
if (s.debug_shape.is_valid()) {
RS::get_singleton()->free(s.debug_shape);
s.debug_shape = RID();
if (s.shape.is_valid() && s.shape->is_connected("changed", this, "_shape_changed")) {
s.shape->disconnect("changed", this, "_shape_changed");
}
}
}
}
debug_shapes_count = 0;
}
void CollisionObject::_on_transform_changed() {
if (debug_shapes_count > 0 && !debug_shape_old_transform.is_equal_approx(get_global_transform())) {
debug_shape_old_transform = get_global_transform();
for (RBMap<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
ShapeData &shapedata = E->get();
const ShapeData::ShapeBase *shapes = shapedata.shapes.ptr();
for (int i = 0; i < shapedata.shapes.size(); i++) {
RS::get_singleton()->instance_set_transform(shapes[i].debug_shape, debug_shape_old_transform * shapedata.xform);
}
}
}
}
void CollisionObject::set_ray_pickable(bool p_ray_pickable) {
ray_pickable = p_ray_pickable;
_update_pickable();
}
bool CollisionObject::is_ray_pickable() const {
return ray_pickable;
}
void CollisionObject::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &CollisionObject::set_collision_layer);
ClassDB::bind_method(D_METHOD("get_collision_layer"), &CollisionObject::get_collision_layer);
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CollisionObject::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &CollisionObject::get_collision_mask);
ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CollisionObject::set_collision_layer_bit);
ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CollisionObject::get_collision_layer_bit);
ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CollisionObject::set_collision_mask_bit);
ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CollisionObject::get_collision_mask_bit);
ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &CollisionObject::set_ray_pickable);
ClassDB::bind_method(D_METHOD("is_ray_pickable"), &CollisionObject::is_ray_pickable);
ClassDB::bind_method(D_METHOD("set_capture_input_on_drag", "enable"), &CollisionObject::set_capture_input_on_drag);
ClassDB::bind_method(D_METHOD("get_capture_input_on_drag"), &CollisionObject::get_capture_input_on_drag);
ClassDB::bind_method(D_METHOD("get_rid"), &CollisionObject::get_rid);
ClassDB::bind_method(D_METHOD("create_shape_owner", "owner"), &CollisionObject::create_shape_owner);
ClassDB::bind_method(D_METHOD("remove_shape_owner", "owner_id"), &CollisionObject::remove_shape_owner);
ClassDB::bind_method(D_METHOD("get_shape_owners"), &CollisionObject::_get_shape_owners);
ClassDB::bind_method(D_METHOD("shape_owner_set_transform", "owner_id", "transform"), &CollisionObject::shape_owner_set_transform);
ClassDB::bind_method(D_METHOD("shape_owner_get_transform", "owner_id"), &CollisionObject::shape_owner_get_transform);
ClassDB::bind_method(D_METHOD("shape_owner_get_owner", "owner_id"), &CollisionObject::shape_owner_get_owner);
ClassDB::bind_method(D_METHOD("shape_owner_set_disabled", "owner_id", "disabled"), &CollisionObject::shape_owner_set_disabled);
ClassDB::bind_method(D_METHOD("is_shape_owner_disabled", "owner_id"), &CollisionObject::is_shape_owner_disabled);
ClassDB::bind_method(D_METHOD("shape_owner_add_shape", "owner_id", "shape"), &CollisionObject::shape_owner_add_shape);
ClassDB::bind_method(D_METHOD("shape_owner_get_shape_count", "owner_id"), &CollisionObject::shape_owner_get_shape_count);
ClassDB::bind_method(D_METHOD("shape_owner_get_shape", "owner_id", "shape_id"), &CollisionObject::shape_owner_get_shape);
ClassDB::bind_method(D_METHOD("shape_owner_get_shape_index", "owner_id", "shape_id"), &CollisionObject::shape_owner_get_shape_index);
ClassDB::bind_method(D_METHOD("shape_owner_remove_shape", "owner_id", "shape_id"), &CollisionObject::shape_owner_remove_shape);
ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject::shape_owner_clear_shapes);
ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject::shape_find_owner);
ClassDB::bind_method(D_METHOD("_update_debug_shapes"), &CollisionObject::_update_debug_shapes);
ClassDB::bind_method(D_METHOD("_shape_changed", "shape"), &CollisionObject::_shape_changed);
BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "position"), PropertyInfo(Variant::VECTOR3, "normal"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "position"), PropertyInfo(Variant::VECTOR3, "normal"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
ADD_SIGNAL(MethodInfo("mouse_exited"));
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_GROUP("Input", "input_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_ray_pickable"), "set_ray_pickable", "is_ray_pickable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_capture_on_drag"), "set_capture_input_on_drag", "get_capture_input_on_drag");
}
uint32_t CollisionObject::create_shape_owner(Object *p_owner) {
ShapeData sd;
uint32_t id;
if (shapes.size() == 0) {
id = 0;
} else {
id = shapes.back()->key() + 1;
}
sd.owner_id = p_owner ? p_owner->get_instance_id() : 0;
shapes[id] = sd;
return id;
}
void CollisionObject::remove_shape_owner(uint32_t owner) {
ERR_FAIL_COND(!shapes.has(owner));
shape_owner_clear_shapes(owner);
shapes.erase(owner);
}
void CollisionObject::shape_owner_set_disabled(uint32_t p_owner, bool p_disabled) {
ERR_FAIL_COND(!shapes.has(p_owner));
ShapeData &sd = shapes[p_owner];
if (sd.disabled == p_disabled) {
return;
}
sd.disabled = p_disabled;
for (int i = 0; i < sd.shapes.size(); i++) {
if (area) {
PhysicsServer::get_singleton()->area_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
} else {
PhysicsServer::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
}
}
_update_shape_data(p_owner);
}
bool CollisionObject::is_shape_owner_disabled(uint32_t p_owner) const {
ERR_FAIL_COND_V(!shapes.has(p_owner), false);
return shapes[p_owner].disabled;
}
void CollisionObject::get_shape_owners(List<uint32_t> *r_owners) {
for (RBMap<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
r_owners->push_back(E->key());
}
}
Array CollisionObject::_get_shape_owners() {
Array ret;
for (RBMap<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
ret.push_back(E->key());
}
return ret;
}
void CollisionObject::shape_owner_set_transform(uint32_t p_owner, const Transform &p_transform) {
ERR_FAIL_COND(!shapes.has(p_owner));
ShapeData &sd = shapes[p_owner];
sd.xform = p_transform;
for (int i = 0; i < sd.shapes.size(); i++) {
if (area) {
PhysicsServer::get_singleton()->area_set_shape_transform(rid, sd.shapes[i].index, p_transform);
} else {
PhysicsServer::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, p_transform);
}
}
_update_shape_data(p_owner);
}
Transform CollisionObject::shape_owner_get_transform(uint32_t p_owner) const {
ERR_FAIL_COND_V(!shapes.has(p_owner), Transform());
return shapes[p_owner].xform;
}
Object *CollisionObject::shape_owner_get_owner(uint32_t p_owner) const {
ERR_FAIL_COND_V(!shapes.has(p_owner), nullptr);
return ObjectDB::get_instance(shapes[p_owner].owner_id);
}
void CollisionObject::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape> &p_shape) {
ERR_FAIL_COND(!shapes.has(p_owner));
ERR_FAIL_COND(p_shape.is_null());
ShapeData &sd = shapes[p_owner];
ShapeData::ShapeBase s;
s.index = total_subshapes;
s.shape = p_shape;
if (area) {
PhysicsServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
} else {
PhysicsServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
}
sd.shapes.push_back(s);
total_subshapes++;
_update_shape_data(p_owner);
}
int CollisionObject::shape_owner_get_shape_count(uint32_t p_owner) const {
ERR_FAIL_COND_V(!shapes.has(p_owner), 0);
return shapes[p_owner].shapes.size();
}
Ref<Shape> CollisionObject::shape_owner_get_shape(uint32_t p_owner, int p_shape) const {
ERR_FAIL_COND_V(!shapes.has(p_owner), Ref<Shape>());
ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), Ref<Shape>());
return shapes[p_owner].shapes[p_shape].shape;
}
int CollisionObject::shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const {
ERR_FAIL_COND_V(!shapes.has(p_owner), -1);
ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), -1);
return shapes[p_owner].shapes[p_shape].index;
}
void CollisionObject::shape_owner_remove_shape(uint32_t p_owner, int p_shape) {
ERR_FAIL_COND(!shapes.has(p_owner));
ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size());
ShapeData::ShapeBase &s = shapes[p_owner].shapes.write[p_shape];
int index_to_remove = s.index;
if (area) {
PhysicsServer::get_singleton()->area_remove_shape(rid, index_to_remove);
} else {
PhysicsServer::get_singleton()->body_remove_shape(rid, index_to_remove);
}
if (s.debug_shape.is_valid()) {
RS::get_singleton()->free(s.debug_shape);
if (s.shape.is_valid() && s.shape->is_connected("changed", this, "_shape_changed")) {
s.shape->disconnect("changed", this, "_shape_changed");
}
--debug_shapes_count;
}
shapes[p_owner].shapes.remove(p_shape);
for (RBMap<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
for (int i = 0; i < E->get().shapes.size(); i++) {
if (E->get().shapes[i].index > index_to_remove) {
E->get().shapes.write[i].index -= 1;
}
}
}
total_subshapes--;
}
void CollisionObject::shape_owner_clear_shapes(uint32_t p_owner) {
ERR_FAIL_COND(!shapes.has(p_owner));
while (shape_owner_get_shape_count(p_owner) > 0) {
shape_owner_remove_shape(p_owner, 0);
}
}
uint32_t CollisionObject::shape_find_owner(int p_shape_index) const {
ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, UINT32_MAX);
for (const RBMap<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
for (int i = 0; i < E->get().shapes.size(); i++) {
if (E->get().shapes[i].index == p_shape_index) {
return E->key();
}
}
}
//in theory it should be unreachable
ERR_FAIL_V_MSG(UINT32_MAX, "Can't find owner for shape index " + itos(p_shape_index) + ".");
}
CollisionObject::CollisionObject(RID p_rid, bool p_area) {
rid = p_rid;
area = p_area;
capture_input_on_drag = false;
ray_pickable = true;
set_notify_transform(true);
total_subshapes = 0;
if (p_area) {
PhysicsServer::get_singleton()->area_attach_object_instance_id(rid, get_instance_id());
} else {
PhysicsServer::get_singleton()->body_attach_object_instance_id(rid, get_instance_id());
}
//set_transform_notify(true);
}
void CollisionObject::set_capture_input_on_drag(bool p_capture) {
capture_input_on_drag = p_capture;
}
bool CollisionObject::get_capture_input_on_drag() const {
return capture_input_on_drag;
}
String CollisionObject::get_configuration_warning() const {
String warning = Spatial::get_configuration_warning();
if (shapes.empty()) {
if (!warning.empty()) {
warning += "\n\n";
}
warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape or CollisionPolygon as a child to define its shape.");
}
return warning;
}
CollisionObject::CollisionObject() {
capture_input_on_drag = false;
ray_pickable = true;
set_notify_transform(true);
//owner=
//set_transform_notify(true);
}
CollisionObject::~CollisionObject() {
PhysicsServer::get_singleton()->free(rid);
}

View File

@ -1,148 +0,0 @@
#ifndef COLLISION_OBJECT_H
#define COLLISION_OBJECT_H
/*************************************************************************/
/* collision_object.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/object/reference.h"
#include "scene/main/spatial.h"
#include "scene/resources/shapes/shape.h"
class CollisionObject : public Spatial {
GDCLASS(CollisionObject, Spatial);
uint32_t collision_layer = 1;
uint32_t collision_mask = 1;
bool area;
RID rid;
struct ShapeData {
ObjectID owner_id;
Transform xform;
struct ShapeBase {
RID debug_shape;
Ref<Shape> shape;
int index;
};
Vector<ShapeBase> shapes;
bool disabled;
ShapeData() {
disabled = false;
owner_id = 0;
}
};
int total_subshapes;
RBMap<uint32_t, ShapeData> shapes;
bool only_update_transform_changes = false; //this is used for sync physics in KinematicBody
bool capture_input_on_drag;
bool ray_pickable;
RBSet<uint32_t> debug_shapes_to_update;
int debug_shapes_count = 0;
Transform debug_shape_old_transform;
void _update_pickable();
bool _are_collision_shapes_visible();
void _update_shape_data(uint32_t p_owner);
void _shape_changed(const Ref<Shape> &p_shape);
void _update_debug_shapes();
void _clear_debug_shapes();
protected:
CollisionObject(RID p_rid, bool p_area);
void _notification(int p_what);
static void _bind_methods();
friend class Viewport;
virtual void _input_event(Node *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
virtual void _mouse_enter();
virtual void _mouse_exit();
void set_only_update_transform_changes(bool p_enable);
void _on_transform_changed();
public:
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
void set_collision_layer_bit(int p_bit, bool p_value);
bool get_collision_layer_bit(int p_bit) const;
void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) const;
uint32_t create_shape_owner(Object *p_owner);
void remove_shape_owner(uint32_t owner);
void get_shape_owners(List<uint32_t> *r_owners);
Array _get_shape_owners();
void shape_owner_set_transform(uint32_t p_owner, const Transform &p_transform);
Transform shape_owner_get_transform(uint32_t p_owner) const;
Object *shape_owner_get_owner(uint32_t p_owner) const;
void shape_owner_set_disabled(uint32_t p_owner, bool p_disabled);
bool is_shape_owner_disabled(uint32_t p_owner) const;
void shape_owner_add_shape(uint32_t p_owner, const Ref<Shape> &p_shape);
int shape_owner_get_shape_count(uint32_t p_owner) const;
Ref<Shape> shape_owner_get_shape(uint32_t p_owner, int p_shape) const;
int shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const;
void shape_owner_remove_shape(uint32_t p_owner, int p_shape);
void shape_owner_clear_shapes(uint32_t p_owner);
uint32_t shape_find_owner(int p_shape_index) const;
void set_ray_pickable(bool p_ray_pickable);
bool is_ray_pickable() const;
void set_capture_input_on_drag(bool p_capture);
bool get_capture_input_on_drag() const;
_FORCE_INLINE_ RID get_rid() const { return rid; }
virtual String get_configuration_warning() const;
CollisionObject();
~CollisionObject();
};
#endif // COLLISION_OBJECT__H

View File

@ -1,221 +0,0 @@
/*************************************************************************/
/* collision_polygon.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "collision_polygon.h"
#include "collision_object.h"
#include "core/math/geometry.h"
#include "scene/resources/shapes/concave_polygon_shape.h"
#include "scene/resources/shapes/convex_polygon_shape.h"
#include "scene/resources/shapes/shape.h"
void CollisionPolygon::_build_polygon() {
if (!parent) {
return;
}
parent->shape_owner_clear_shapes(owner_id);
if (polygon.size() == 0) {
return;
}
Vector<Vector<Vector2>> decomp = Geometry::decompose_polygon_in_convex(polygon);
if (decomp.size() == 0) {
return;
}
//here comes the sun, lalalala
//decompose concave into multiple convex polygons and add them
for (int i = 0; i < decomp.size(); i++) {
Ref<ConvexPolygonShape> convex = memnew(ConvexPolygonShape);
PoolVector<Vector3> cp;
int cs = decomp[i].size();
cp.resize(cs * 2);
{
PoolVector<Vector3>::Write w = cp.write();
int idx = 0;
for (int j = 0; j < cs; j++) {
Vector2 d = decomp[i][j];
w[idx++] = Vector3(d.x, d.y, depth * 0.5);
w[idx++] = Vector3(d.x, d.y, -depth * 0.5);
}
}
convex->set_points(cp);
convex->set_margin(margin);
parent->shape_owner_add_shape(owner_id, convex);
parent->shape_owner_set_disabled(owner_id, disabled);
}
}
void CollisionPolygon::_update_in_shape_owner(bool p_xform_only) {
parent->shape_owner_set_transform(owner_id, get_transform());
if (p_xform_only) {
return;
}
parent->shape_owner_set_disabled(owner_id, disabled);
}
void CollisionPolygon::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_PARENTED: {
parent = Object::cast_to<CollisionObject>(get_parent());
if (parent) {
owner_id = parent->create_shape_owner(this);
_build_polygon();
_update_in_shape_owner();
}
} break;
case NOTIFICATION_ENTER_TREE: {
if (parent) {
_update_in_shape_owner();
}
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (parent) {
_update_in_shape_owner(true);
}
} break;
case NOTIFICATION_UNPARENTED: {
if (parent) {
parent->remove_shape_owner(owner_id);
}
owner_id = 0;
parent = nullptr;
} break;
}
}
void CollisionPolygon::set_polygon(const Vector<Point2> &p_polygon) {
polygon = p_polygon;
if (parent) {
_build_polygon();
}
update_configuration_warning();
update_gizmos();
}
Vector<Point2> CollisionPolygon::get_polygon() const {
return polygon;
}
AABB CollisionPolygon::get_item_rect() const {
return aabb;
}
void CollisionPolygon::set_depth(float p_depth) {
depth = p_depth;
_build_polygon();
update_gizmos();
}
float CollisionPolygon::get_depth() const {
return depth;
}
void CollisionPolygon::set_disabled(bool p_disabled) {
disabled = p_disabled;
update_gizmos();
if (parent) {
parent->shape_owner_set_disabled(owner_id, p_disabled);
}
}
bool CollisionPolygon::is_disabled() const {
return disabled;
}
real_t CollisionPolygon::get_margin() const {
return margin;
}
void CollisionPolygon::set_margin(real_t p_margin) {
margin = p_margin;
if (parent) {
_build_polygon();
}
}
String CollisionPolygon::get_configuration_warning() const {
String warning = Spatial::get_configuration_warning();
if (!Object::cast_to<CollisionObject>(get_parent())) {
if (warning != String()) {
warning += "\n\n";
}
warning += TTR("CollisionPolygon only serves to provide a collision shape to a CollisionObject derived node. Please only use it as a child of Area, StaticBody, RigidBody, KinematicBody, etc. to give them a shape.");
}
if (polygon.empty()) {
if (warning != String()) {
warning += "\n\n";
}
warning += TTR("An empty CollisionPolygon has no effect on collision.");
}
return warning;
}
bool CollisionPolygon::_is_editable_3d_polygon() const {
return true;
}
void CollisionPolygon::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CollisionPolygon::set_depth);
ClassDB::bind_method(D_METHOD("get_depth"), &CollisionPolygon::get_depth);
ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &CollisionPolygon::set_polygon);
ClassDB::bind_method(D_METHOD("get_polygon"), &CollisionPolygon::get_polygon);
ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon::set_disabled);
ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon::is_disabled);
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &CollisionPolygon::set_margin);
ClassDB::bind_method(D_METHOD("get_margin"), &CollisionPolygon::get_margin);
ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CollisionPolygon::_is_editable_3d_polygon);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth"), "set_depth", "get_depth");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_margin", "get_margin");
}
CollisionPolygon::CollisionPolygon() {
aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
depth = 1.0;
set_notify_local_transform(true);
parent = nullptr;
owner_id = 0;
disabled = false;
}

View File

@ -1,83 +0,0 @@
#ifndef COLLISION_POLYGON_H
#define COLLISION_POLYGON_H
/*************************************************************************/
/* collision_polygon.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/object/reference.h"
#include "scene/main/spatial.h"
class CollisionObject;
class Shape;
class CollisionPolygon : public Spatial {
GDCLASS(CollisionPolygon, Spatial);
real_t margin = 0.04;
protected:
float depth;
AABB aabb;
Vector<Point2> polygon;
uint32_t owner_id;
CollisionObject *parent;
bool disabled;
void _build_polygon();
void _update_in_shape_owner(bool p_xform_only = false);
bool _is_editable_3d_polygon() const;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
void set_depth(float p_depth);
float get_depth() const;
void set_polygon(const Vector<Point2> &p_polygon);
Vector<Point2> get_polygon() const;
void set_disabled(bool p_disabled);
bool is_disabled() const;
virtual AABB get_item_rect() const;
real_t get_margin() const;
void set_margin(real_t p_margin);
String get_configuration_warning() const;
CollisionPolygon();
};
#endif // COLLISION_POLYGON_H

View File

@ -1,227 +0,0 @@
/*************************************************************************/
/* collision_shape.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "collision_shape.h"
#include "core/math/quick_hull.h"
#include "mesh_instance.h"
#include "physics_body.h"
#include "scene/resources/shapes/box_shape.h"
#include "scene/resources/shapes/capsule_shape.h"
#include "scene/resources/shapes/concave_polygon_shape.h"
#include "scene/resources/shapes/convex_polygon_shape.h"
#include "scene/resources/mesh/mesh.h"
#include "scene/resources/shapes/plane_shape.h"
#include "scene/resources/shapes/ray_shape.h"
#include "scene/resources/shapes/shape.h"
#include "scene/resources/shapes/sphere_shape.h"
#include "servers/rendering_server.h"
void CollisionShape::make_convex_from_brothers() {
Node *p = get_parent();
if (!p) {
return;
}
for (int i = 0; i < p->get_child_count(); i++) {
Node *n = p->get_child(i);
MeshInstance *mi = Object::cast_to<MeshInstance>(n);
if (mi) {
Ref<Mesh> m = mi->get_mesh();
if (m.is_valid()) {
Ref<Shape> s = m->create_convex_shape();
set_shape(s);
}
}
}
}
void CollisionShape::_update_in_shape_owner(bool p_xform_only) {
parent->shape_owner_set_transform(owner_id, get_transform());
if (p_xform_only) {
return;
}
parent->shape_owner_set_disabled(owner_id, disabled);
}
void CollisionShape::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_PARENTED: {
parent = Object::cast_to<CollisionObject>(get_parent());
if (parent) {
owner_id = parent->create_shape_owner(this);
if (shape.is_valid()) {
parent->shape_owner_add_shape(owner_id, shape);
}
_update_in_shape_owner();
}
} break;
case NOTIFICATION_ENTER_TREE: {
if (parent) {
_update_in_shape_owner();
}
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (parent) {
_update_in_shape_owner(true);
}
} break;
case NOTIFICATION_UNPARENTED: {
if (parent) {
parent->remove_shape_owner(owner_id);
}
owner_id = 0;
parent = nullptr;
} break;
}
}
void CollisionShape::resource_changed(RES res) {
update_gizmos();
}
String CollisionShape::get_configuration_warning() const {
String warning = Spatial::get_configuration_warning();
if (!Object::cast_to<CollisionObject>(get_parent())) {
if (warning != String()) {
warning += "\n\n";
}
warning += TTR("CollisionShape only serves to provide a collision shape to a CollisionObject derived node. Please only use it as a child of Area, StaticBody, RigidBody, KinematicBody, etc. to give them a shape.");
}
if (!shape.is_valid()) {
if (warning != String()) {
warning += "\n\n";
}
warning += TTR("A shape must be provided for CollisionShape to function. Please create a shape resource for it.");
} else {
if (shape->is_class("PlaneShape")) {
if (warning != String()) {
warning += "\n\n";
}
warning += TTR("Plane shapes don't work well and will be removed in future versions. Please don't use them.");
}
if (Object::cast_to<RigidBody>(get_parent()) &&
Object::cast_to<ConcavePolygonShape>(*shape) &&
Object::cast_to<RigidBody>(get_parent())->get_mode() != RigidBody::MODE_STATIC) {
if (warning != String()) {
warning += "\n\n";
}
warning += TTR("ConcavePolygonShape doesn't support RigidBody in another mode than static.");
}
}
return warning;
}
#ifdef TOOLS_ENABLED
AABB CollisionShape::get_fallback_gizmo_aabb() const {
if (shape.is_null()) {
return Spatial::get_fallback_gizmo_aabb();
}
// get_debug_mesh() is not const because the mesh is lazy initialized and cached.
// It would be better if we can mark the cache mutable and make get_debug_mesh() const.
return const_cast<CollisionShape *>(this)->shape->get_debug_mesh()->get_aabb();
}
#endif
void CollisionShape::_bind_methods() {
//not sure if this should do anything
ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &CollisionShape::resource_changed);
ClassDB::bind_method(D_METHOD("set_shape", "shape"), &CollisionShape::set_shape);
ClassDB::bind_method(D_METHOD("get_shape"), &CollisionShape::get_shape);
ClassDB::bind_method(D_METHOD("set_disabled", "enable"), &CollisionShape::set_disabled);
ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionShape::is_disabled);
ClassDB::bind_method(D_METHOD("make_convex_from_brothers"), &CollisionShape::make_convex_from_brothers);
ClassDB::set_method_flags("CollisionShape", "make_convex_from_brothers", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
}
void CollisionShape::set_shape(const Ref<Shape> &p_shape) {
if (p_shape == shape) {
return;
}
if (!shape.is_null()) {
shape->unregister_owner(this);
}
shape = p_shape;
if (!shape.is_null()) {
shape->register_owner(this);
}
update_gizmos();
if (parent) {
parent->shape_owner_clear_shapes(owner_id);
if (shape.is_valid()) {
parent->shape_owner_add_shape(owner_id, shape);
}
}
if (is_inside_tree() && parent) {
// If this is a heightfield shape our center may have changed
_update_in_shape_owner(true);
}
update_configuration_warning();
}
Ref<Shape> CollisionShape::get_shape() const {
return shape;
}
void CollisionShape::set_disabled(bool p_disabled) {
disabled = p_disabled;
update_gizmos();
if (parent) {
parent->shape_owner_set_disabled(owner_id, p_disabled);
}
}
bool CollisionShape::is_disabled() const {
return disabled;
}
CollisionShape::CollisionShape() {
//indicator = RID_PRIME(RenderingServer::get_singleton()->mesh_create());
disabled = false;
parent = nullptr;
owner_id = 0;
set_notify_local_transform(true);
}
CollisionShape::~CollisionShape() {
if (!shape.is_null()) {
shape->unregister_owner(this);
}
//RenderingServer::get_singleton()->free(indicator);
}

View File

@ -1,77 +0,0 @@
#ifndef COLLISION_SHAPE_H
#define COLLISION_SHAPE_H
/*************************************************************************/
/* collision_shape.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/object/reference.h"
#include "scene/main/spatial.h"
class CollisionObject;
class Shape;
class CollisionShape : public Spatial {
GDCLASS(CollisionShape, Spatial);
OBJ_CATEGORY("3D Physics Nodes");
Ref<Shape> shape;
uint32_t owner_id;
CollisionObject *parent;
void resource_changed(RES res);
bool disabled;
protected:
void _update_in_shape_owner(bool p_xform_only = false);
protected:
void _notification(int p_what);
static void _bind_methods();
public:
void make_convex_from_brothers();
void set_shape(const Ref<Shape> &p_shape);
Ref<Shape> get_shape() const;
void set_disabled(bool p_disabled);
bool is_disabled() const;
String get_configuration_warning() const;
#ifdef TOOLS_ENABLED
virtual AABB get_fallback_gizmo_aabb() const;
#endif
CollisionShape();
~CollisionShape();
};
#endif // BODY_VOLUME_H

View File

@ -30,23 +30,14 @@
#include "mesh_instance.h"
#include "collision_shape.h"
#include "core/config/project_settings.h"
#include "core/core_string_names.h"
#include "physics_body.h"
#include "scene/resources/material/material.h"
#include "scene/resources/material/spatial_material.h"
#include "scene/resources/mesh/mesh.h"
#include "scene/main/scene_string_names.h"
#include "servers/rendering/rendering_server_globals.h"
#include "modules/modules_enabled.gen.h"
#ifdef MODULE_SKELETON_3D_ENABLED
#include "modules/skeleton_3d/nodes/skeleton.h"
#include "modules/skeleton_3d/resources/skin.h"
#endif
bool MeshInstance::_set(const StringName &p_name, const Variant &p_value) {
//this is not _too_ bad performance wise, really. it only arrives here if the property was not set anywhere else.
//add to it that it's probably found on first call to _set anyway.
@ -125,20 +116,6 @@ void MeshInstance::set_mesh(const Ref<Mesh> &p_mesh) {
mesh->disconnect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->_mesh_changed);
}
#ifdef MODULE_SKELETON_3D_ENABLED
if (skin_ref.is_valid() && mesh.is_valid() && _is_software_skinning_enabled() && is_visible_in_tree()) {
ERR_FAIL_COND(!skin_ref->get_skeleton_node());
skin_ref->get_skeleton_node()->disconnect("pose_updated", this, "_update_skinning");
}
#endif
#ifdef MODULE_SKELETON_3D_ENABLED
if (software_skinning) {
memdelete(software_skinning);
software_skinning = nullptr;
}
#endif
mesh = p_mesh;
blend_shape_tracks.clear();
@ -168,402 +145,6 @@ Ref<Mesh> MeshInstance::get_mesh() const {
return mesh;
}
#ifdef MODULE_SKELETON_3D_ENABLED
void MeshInstance::_resolve_skeleton_path() {
Ref<SkinReference> new_skin_reference;
if (!skeleton_path.is_empty()) {
Skeleton *skeleton = Object::cast_to<Skeleton>(get_node(skeleton_path));
if (skeleton) {
if (skin_internal.is_null()) {
new_skin_reference = skeleton->register_skin(skeleton->create_skin_from_rest_transforms());
//a skin was created for us
skin_internal = new_skin_reference->get_skin();
_change_notify();
} else {
new_skin_reference = skeleton->register_skin(skin_internal);
}
}
}
if (skin_ref.is_valid() && mesh.is_valid() && _is_software_skinning_enabled() && is_visible_in_tree()) {
ERR_FAIL_COND(!skin_ref->get_skeleton_node());
skin_ref->get_skeleton_node()->disconnect("pose_updated", this, "_update_skinning");
}
skin_ref = new_skin_reference;
software_skinning_flags &= ~SoftwareSkinning::FLAG_BONES_READY;
_initialize_skinning();
}
bool MeshInstance::_is_global_software_skinning_enabled() {
// Check if forced in project settings.
if (GLOBAL_GET("rendering/quality/skinning/force_software_skinning")) {
return true;
}
// Check if enabled in project settings.
if (!GLOBAL_GET("rendering/quality/skinning/software_skinning_fallback")) {
return false;
}
// Check if requested by renderer settings.
return RSG::storage->has_os_feature("skinning_fallback");
}
bool MeshInstance::_is_software_skinning_enabled() const {
// Using static local variable which will be initialized only once,
// so _is_global_software_skinning_enabled can be only called once on first use.
static bool global_software_skinning = _is_global_software_skinning_enabled();
return global_software_skinning;
}
void MeshInstance::_initialize_skinning(bool p_force_reset, bool p_call_attach_skeleton) {
if (mesh.is_null()) {
return;
}
RenderingServer *rendering_server = RenderingServer::get_singleton();
bool update_mesh = false;
if (skin_ref.is_valid()) {
if (_is_software_skinning_enabled()) {
if (is_visible_in_tree()) {
ERR_FAIL_COND(!skin_ref->get_skeleton_node());
if (!skin_ref->get_skeleton_node()->is_connected("pose_updated", this, "_update_skinning")) {
skin_ref->get_skeleton_node()->connect("pose_updated", this, "_update_skinning");
}
}
if (p_force_reset && software_skinning) {
memdelete(software_skinning);
software_skinning = nullptr;
}
if (!software_skinning) {
software_skinning = memnew(SoftwareSkinning);
if (mesh->get_blend_shape_count() > 0) {
ERR_PRINT("Blend shapes are not supported for software skinning.");
}
Ref<ArrayMesh> software_mesh;
software_mesh.instance();
RID mesh_rid = software_mesh->get_rid();
// Initialize mesh for dynamic update.
int surface_count = mesh->get_surface_count();
software_skinning->surface_data.resize(surface_count);
for (int surface_index = 0; surface_index < surface_count; ++surface_index) {
ERR_CONTINUE(Mesh::PRIMITIVE_TRIANGLES != mesh->surface_get_primitive_type(surface_index));
SoftwareSkinning::SurfaceData &surface_data = software_skinning->surface_data[surface_index];
surface_data.transform_tangents = false;
surface_data.ensure_correct_normals = false;
uint32_t format = mesh->surface_get_format(surface_index);
ERR_CONTINUE(0 == (format & Mesh::ARRAY_FORMAT_VERTEX));
ERR_CONTINUE(0 == (format & Mesh::ARRAY_FORMAT_BONES));
ERR_CONTINUE(0 == (format & Mesh::ARRAY_FORMAT_WEIGHTS));
format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
format &= ~Mesh::ARRAY_COMPRESS_VERTEX;
format &= ~Mesh::ARRAY_COMPRESS_WEIGHTS;
format &= ~Mesh::ARRAY_FLAG_USE_16_BIT_BONES;
Array write_arrays = mesh->surface_get_arrays(surface_index);
Array read_arrays;
read_arrays.resize(Mesh::ARRAY_MAX);
read_arrays[Mesh::ARRAY_VERTEX] = write_arrays[Mesh::ARRAY_VERTEX];
read_arrays[Mesh::ARRAY_BONES] = write_arrays[Mesh::ARRAY_BONES];
read_arrays[Mesh::ARRAY_WEIGHTS] = write_arrays[Mesh::ARRAY_WEIGHTS];
write_arrays[Mesh::ARRAY_BONES] = Variant();
write_arrays[Mesh::ARRAY_WEIGHTS] = Variant();
if (software_skinning_flags & SoftwareSkinning::FLAG_TRANSFORM_NORMALS) {
ERR_CONTINUE(0 == (format & Mesh::ARRAY_FORMAT_NORMAL));
format &= ~Mesh::ARRAY_COMPRESS_NORMAL;
read_arrays[Mesh::ARRAY_NORMAL] = write_arrays[Mesh::ARRAY_NORMAL];
Ref<Material> mat = get_active_material(surface_index);
if (mat.is_valid()) {
Ref<SpatialMaterial> spatial_mat = mat;
if (spatial_mat.is_valid()) {
// Spatial material, check from material settings.
surface_data.transform_tangents = spatial_mat->get_feature(SpatialMaterial::FEATURE_NORMAL_MAPPING);
surface_data.ensure_correct_normals = spatial_mat->get_flag(SpatialMaterial::FLAG_ENSURE_CORRECT_NORMALS);
} else {
// Custom shader, must check for compiled flags.
surface_data.transform_tangents = RSG::storage->material_uses_tangents(mat->get_rid());
surface_data.ensure_correct_normals = RSG::storage->material_uses_ensure_correct_normals(mat->get_rid());
}
}
if (surface_data.transform_tangents) {
ERR_CONTINUE(0 == (format & Mesh::ARRAY_FORMAT_TANGENT));
format &= ~Mesh::ARRAY_COMPRESS_TANGENT;
read_arrays[Mesh::ARRAY_TANGENT] = write_arrays[Mesh::ARRAY_TANGENT];
}
}
// 1. Temporarily add surface with bone data to create the read buffer.
software_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, read_arrays, Array(), format);
PoolByteArray buffer_read = rendering_server->mesh_surface_get_array(mesh_rid, surface_index);
surface_data.source_buffer.append_array(buffer_read);
surface_data.source_format = software_mesh->surface_get_format(surface_index);
software_mesh->surface_remove(surface_index);
// 2. Create the surface again without the bone data for the write buffer.
software_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, write_arrays, Array(), format);
Ref<Material> material = mesh->surface_get_material(surface_index);
software_mesh->surface_set_material(surface_index, material);
surface_data.buffer = rendering_server->mesh_surface_get_array(mesh_rid, surface_index);
surface_data.buffer_write = surface_data.buffer.write();
}
software_skinning->mesh_instance = software_mesh;
update_mesh = true;
}
if (p_call_attach_skeleton) {
rendering_server->instance_attach_skeleton(get_instance(), RID());
}
if (is_visible_in_tree() && (software_skinning_flags & SoftwareSkinning::FLAG_BONES_READY)) {
// Initialize from current skeleton pose.
_update_skinning();
}
} else {
ERR_FAIL_COND(!skin_ref->get_skeleton_node());
if (skin_ref->get_skeleton_node()->is_connected("pose_updated", this, "_update_skinning")) {
skin_ref->get_skeleton_node()->disconnect("pose_updated", this, "_update_skinning");
}
if (p_call_attach_skeleton) {
rendering_server->instance_attach_skeleton(get_instance(), skin_ref->get_skeleton());
}
if (software_skinning) {
memdelete(software_skinning);
software_skinning = nullptr;
update_mesh = true;
}
}
} else {
if (p_call_attach_skeleton) {
rendering_server->instance_attach_skeleton(get_instance(), RID());
}
if (software_skinning) {
memdelete(software_skinning);
software_skinning = nullptr;
update_mesh = true;
}
}
RID render_mesh = software_skinning ? software_skinning->mesh_instance->get_rid() : mesh->get_rid();
if (update_mesh || (render_mesh != get_base())) {
set_base(render_mesh);
// Update instance materials after switching mesh.
int surface_count = mesh->get_surface_count();
for (int surface_index = 0; surface_index < surface_count; ++surface_index) {
if (materials[surface_index].is_valid()) {
rendering_server->instance_set_surface_material(get_instance(), surface_index, materials[surface_index]->get_rid());
}
}
}
}
void MeshInstance::_update_skinning() {
ERR_FAIL_COND(!_is_software_skinning_enabled());
#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
ERR_FAIL_COND(!is_visible_in_tree());
#else
ERR_FAIL_COND(!is_visible());
#endif
ERR_FAIL_COND(!software_skinning);
Ref<Mesh> software_skinning_mesh = software_skinning->mesh_instance;
ERR_FAIL_COND(!software_skinning_mesh.is_valid());
RID mesh_rid = software_skinning_mesh->get_rid();
ERR_FAIL_COND(!mesh_rid.is_valid());
ERR_FAIL_COND(!mesh.is_valid());
RID source_mesh_rid = mesh->get_rid();
ERR_FAIL_COND(!source_mesh_rid.is_valid());
ERR_FAIL_COND(skin_ref.is_null());
RID skeleton = skin_ref->get_skeleton();
ERR_FAIL_COND(!skeleton.is_valid());
Vector3 aabb_min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
Vector3 aabb_max = Vector3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
RenderingServer *rendering_server = RenderingServer::get_singleton();
// Prepare bone transforms.
const int num_bones = rendering_server->skeleton_get_bone_count(skeleton);
ERR_FAIL_COND(num_bones <= 0);
Transform *bone_transforms = (Transform *)alloca(sizeof(Transform) * num_bones);
for (int bone_index = 0; bone_index < num_bones; ++bone_index) {
bone_transforms[bone_index] = rendering_server->skeleton_bone_get_transform(skeleton, bone_index);
}
// Apply skinning.
int surface_count = software_skinning_mesh->get_surface_count();
for (int surface_index = 0; surface_index < surface_count; ++surface_index) {
ERR_CONTINUE((uint32_t)surface_index >= software_skinning->surface_data.size());
const SoftwareSkinning::SurfaceData &surface_data = software_skinning->surface_data[surface_index];
const bool transform_tangents = surface_data.transform_tangents;
const bool ensure_correct_normals = surface_data.ensure_correct_normals;
const uint32_t format_write = software_skinning_mesh->surface_get_format(surface_index);
const int vertex_count_write = software_skinning_mesh->surface_get_array_len(surface_index);
const int index_count_write = software_skinning_mesh->surface_get_array_index_len(surface_index);
uint32_t array_offsets_write[Mesh::ARRAY_MAX];
uint32_t array_strides_write[Mesh::ARRAY_MAX];
rendering_server->mesh_surface_make_offsets_from_format(format_write, vertex_count_write, index_count_write, array_offsets_write, array_strides_write);
ERR_FAIL_COND(array_strides_write[Mesh::ARRAY_VERTEX] != array_strides_write[Mesh::ARRAY_NORMAL]);
const uint32_t stride_write = array_strides_write[Mesh::ARRAY_VERTEX];
const uint32_t offset_vertices_write = array_offsets_write[Mesh::ARRAY_VERTEX];
const uint32_t offset_normals_write = array_offsets_write[Mesh::ARRAY_NORMAL];
const uint32_t offset_tangents_write = array_offsets_write[Mesh::ARRAY_TANGENT];
PoolByteArray buffer_source = surface_data.source_buffer;
PoolByteArray::Read buffer_read = buffer_source.read();
const uint32_t format_read = surface_data.source_format;
ERR_CONTINUE(0 == (format_read & Mesh::ARRAY_FORMAT_BONES));
ERR_CONTINUE(0 == (format_read & Mesh::ARRAY_FORMAT_WEIGHTS));
const int vertex_count = mesh->surface_get_array_len(surface_index);
const int index_count = mesh->surface_get_array_index_len(surface_index);
ERR_CONTINUE(vertex_count != vertex_count_write);
uint32_t array_offsets[Mesh::ARRAY_MAX];
uint32_t array_strides[Mesh::ARRAY_MAX];
rendering_server->mesh_surface_make_offsets_from_format(format_read, vertex_count, index_count, array_offsets, array_strides);
ERR_FAIL_COND(array_strides[Mesh::ARRAY_VERTEX] != array_strides[Mesh::ARRAY_NORMAL]);
const uint32_t stride = array_strides[Mesh::ARRAY_VERTEX];
const uint32_t offset_vertices = array_offsets[Mesh::ARRAY_VERTEX];
const uint32_t offset_normals = array_offsets[Mesh::ARRAY_NORMAL];
const uint32_t offset_tangents = array_offsets[Mesh::ARRAY_TANGENT];
const uint32_t offset_bones = array_offsets[Mesh::ARRAY_BONES];
const uint32_t offset_weights = array_offsets[Mesh::ARRAY_WEIGHTS];
PoolByteArray buffer = surface_data.buffer;
PoolByteArray::Write buffer_write = surface_data.buffer_write;
for (int vertex_index = 0; vertex_index < vertex_count; ++vertex_index) {
const uint32_t vertex_offset = vertex_index * stride;
const uint32_t vertex_offset_write = vertex_index * stride_write;
float bone_weights[4];
const float *weight_ptr = (const float *)(buffer_read.ptr() + offset_weights + vertex_offset);
bone_weights[0] = weight_ptr[0];
bone_weights[1] = weight_ptr[1];
bone_weights[2] = weight_ptr[2];
bone_weights[3] = weight_ptr[3];
const uint8_t *bones_ptr = buffer_read.ptr() + offset_bones + vertex_offset;
const int b0 = bones_ptr[0];
const int b1 = bones_ptr[1];
const int b2 = bones_ptr[2];
const int b3 = bones_ptr[3];
Transform transform;
transform.origin =
bone_weights[0] * bone_transforms[b0].origin +
bone_weights[1] * bone_transforms[b1].origin +
bone_weights[2] * bone_transforms[b2].origin +
bone_weights[3] * bone_transforms[b3].origin;
transform.basis =
bone_transforms[b0].basis * bone_weights[0] +
bone_transforms[b1].basis * bone_weights[1] +
bone_transforms[b2].basis * bone_weights[2] +
bone_transforms[b3].basis * bone_weights[3];
const Vector3 &vertex_read = (const Vector3 &)buffer_read[vertex_offset + offset_vertices];
Vector3 &vertex = (Vector3 &)buffer_write[vertex_offset_write + offset_vertices_write];
vertex = transform.xform(vertex_read);
if (software_skinning_flags & SoftwareSkinning::FLAG_TRANSFORM_NORMALS) {
if (ensure_correct_normals) {
transform.basis.invert();
transform.basis.transpose();
}
const Vector3 &normal_read = (const Vector3 &)buffer_read[vertex_offset + offset_normals];
Vector3 &normal = (Vector3 &)buffer_write[vertex_offset_write + offset_normals_write];
normal = transform.basis.xform(normal_read);
if (transform_tangents) {
const Vector3 &tangent_read = (const Vector3 &)buffer_read[vertex_offset + offset_tangents];
Vector3 &tangent = (Vector3 &)buffer_write[vertex_offset_write + offset_tangents_write];
tangent = transform.basis.xform(tangent_read);
}
}
aabb_min.x = MIN(aabb_min.x, vertex.x);
aabb_min.y = MIN(aabb_min.y, vertex.y);
aabb_min.z = MIN(aabb_min.z, vertex.z);
aabb_max.x = MAX(aabb_max.x, vertex.x);
aabb_max.y = MAX(aabb_max.y, vertex.y);
aabb_max.z = MAX(aabb_max.z, vertex.z);
}
rendering_server->mesh_surface_update_region(mesh_rid, surface_index, 0, buffer);
}
rendering_server->mesh_set_custom_aabb(mesh_rid, AABB(aabb_min, aabb_max - aabb_min));
software_skinning_flags |= SoftwareSkinning::FLAG_BONES_READY;
}
#endif
#ifdef MODULE_SKELETON_3D_ENABLED
void MeshInstance::set_skin(const Ref<Skin> &p_skin) {
skin_internal = p_skin;
skin = p_skin;
if (!is_inside_tree()) {
return;
}
_resolve_skeleton_path();
}
Ref<Skin> MeshInstance::get_skin() const {
return skin;
}
void MeshInstance::set_skeleton_path(const NodePath &p_skeleton) {
skeleton_path = p_skeleton;
if (!is_inside_tree()) {
return;
}
_resolve_skeleton_path();
}
NodePath MeshInstance::get_skeleton_path() {
return skeleton_path;
}
#endif
AABB MeshInstance::get_aabb() const {
if (!mesh.is_null()) {
return mesh->get_aabb();
@ -585,123 +166,27 @@ PoolVector<Face3> MeshInstance::get_faces(uint32_t p_usage_flags) const {
}
Node *MeshInstance::create_trimesh_collision_node() {
if (mesh.is_null()) {
return nullptr;
}
Ref<Shape> shape = mesh->create_trimesh_shape();
if (shape.is_null()) {
return nullptr;
}
StaticBody *static_body = memnew(StaticBody);
CollisionShape *cshape = memnew(CollisionShape);
cshape->set_shape(shape);
static_body->add_child(cshape);
return static_body;
return NULL;
}
void MeshInstance::create_trimesh_collision() {
StaticBody *static_body = Object::cast_to<StaticBody>(create_trimesh_collision_node());
ERR_FAIL_COND(!static_body);
static_body->set_name(String(get_name()) + "_col");
add_child(static_body);
if (get_owner()) {
CollisionShape *cshape = Object::cast_to<CollisionShape>(static_body->get_child(0));
static_body->set_owner(get_owner());
cshape->set_owner(get_owner());
}
}
Node *MeshInstance::create_multiple_convex_collisions_node() {
if (mesh.is_null()) {
return nullptr;
}
Vector<Ref<Shape>> shapes = mesh->convex_decompose();
if (!shapes.size()) {
return nullptr;
}
StaticBody *static_body = memnew(StaticBody);
for (int i = 0; i < shapes.size(); i++) {
CollisionShape *cshape = memnew(CollisionShape);
cshape->set_shape(shapes[i]);
static_body->add_child(cshape);
}
return static_body;
return NULL;
}
void MeshInstance::create_multiple_convex_collisions() {
StaticBody *static_body = Object::cast_to<StaticBody>(create_multiple_convex_collisions_node());
ERR_FAIL_COND(!static_body);
static_body->set_name(String(get_name()) + "_col");
add_child(static_body);
if (get_owner()) {
static_body->set_owner(get_owner());
int count = static_body->get_child_count();
for (int i = 0; i < count; i++) {
CollisionShape *cshape = Object::cast_to<CollisionShape>(static_body->get_child(i));
cshape->set_owner(get_owner());
}
}
}
Node *MeshInstance::create_convex_collision_node(bool p_clean, bool p_simplify) {
if (mesh.is_null()) {
return nullptr;
}
Ref<Shape> shape = mesh->create_convex_shape(p_clean, p_simplify);
if (shape.is_null()) {
return nullptr;
}
StaticBody *static_body = memnew(StaticBody);
CollisionShape *cshape = memnew(CollisionShape);
cshape->set_shape(shape);
static_body->add_child(cshape);
return static_body;
return NULL;
}
void MeshInstance::create_convex_collision(bool p_clean, bool p_simplify) {
StaticBody *static_body = Object::cast_to<StaticBody>(create_convex_collision_node(p_clean, p_simplify));
ERR_FAIL_COND(!static_body);
static_body->set_name(String(get_name()) + "_col");
add_child(static_body);
if (get_owner()) {
CollisionShape *cshape = Object::cast_to<CollisionShape>(static_body->get_child(0));
static_body->set_owner(get_owner());
cshape->set_owner(get_owner());
}
}
void MeshInstance::_notification(int p_what) {
#ifdef MODULE_SKELETON_3D_ENABLED
if (p_what == NOTIFICATION_ENTER_TREE) {
_resolve_skeleton_path();
}
if (p_what == NOTIFICATION_TRANSLATION_CHANGED) {
if (mesh.is_valid()) {
mesh->notification(NOTIFICATION_TRANSLATION_CHANGED);
}
}
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
if (skin_ref.is_valid() && mesh.is_valid() && _is_software_skinning_enabled()) {
ERR_FAIL_COND(!skin_ref->get_skeleton_node());
if (is_visible_in_tree()) {
skin_ref->get_skeleton_node()->connect("pose_updated", this, "_update_skinning");
} else {
skin_ref->get_skeleton_node()->disconnect("pose_updated", this, "_update_skinning");
}
}
}
#endif
}
int MeshInstance::get_surface_material_count() const {
@ -718,12 +203,6 @@ void MeshInstance::set_surface_material(int p_surface, const Ref<Material> &p_ma
} else {
RS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, RID());
}
#ifdef MODULE_SKELETON_3D_ENABLED
if (software_skinning) {
_initialize_skinning(true);
}
#endif
}
Ref<Material> MeshInstance::get_surface_material(int p_surface) const {
@ -757,12 +236,6 @@ void MeshInstance::set_material_override(const Ref<Material> &p_material) {
}
GeometryInstance::set_material_override(p_material);
#ifdef MODULE_SKELETON_3D_ENABLED
if (software_skinning) {
_initialize_skinning(true);
}
#endif
}
void MeshInstance::set_material_overlay(const Ref<Material> &p_material) {
@ -773,37 +246,9 @@ void MeshInstance::set_material_overlay(const Ref<Material> &p_material) {
GeometryInstance::set_material_overlay(p_material);
}
#ifdef MODULE_SKELETON_3D_ENABLED
void MeshInstance::set_software_skinning_transform_normals(bool p_enabled) {
if (p_enabled == is_software_skinning_transform_normals_enabled()) {
return;
}
if (p_enabled) {
software_skinning_flags |= SoftwareSkinning::FLAG_TRANSFORM_NORMALS;
} else {
software_skinning_flags &= ~SoftwareSkinning::FLAG_TRANSFORM_NORMALS;
}
if (software_skinning) {
_initialize_skinning(true);
}
}
bool MeshInstance::is_software_skinning_transform_normals_enabled() const {
return 0 != (software_skinning_flags & SoftwareSkinning::FLAG_TRANSFORM_NORMALS);
}
#endif
void MeshInstance::_mesh_changed() {
ERR_FAIL_COND(mesh.is_null());
materials.resize(mesh->get_surface_count());
#ifdef MODULE_SKELETON_3D_ENABLED
if (software_skinning) {
_initialize_skinning(true);
}
#endif
}
void MeshInstance::create_debug_tangents() {
@ -872,14 +317,6 @@ void MeshInstance::create_debug_tangents() {
mi->set_mesh(am);
mi->set_name("DebugTangents");
add_child(mi);
#ifdef TOOLS_ENABLED
if (is_inside_tree() && this == get_tree()->get_edited_scene_root()) {
mi->set_owner(this);
} else {
mi->set_owner(get_owner());
}
#endif
}
}
@ -1376,28 +813,11 @@ void MeshInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_mesh"), &MeshInstance::get_mesh);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
#ifdef MODULE_SKELETON_3D_ENABLED
ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &MeshInstance::set_skeleton_path);
ClassDB::bind_method(D_METHOD("get_skeleton_path"), &MeshInstance::get_skeleton_path);
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path");
ClassDB::bind_method(D_METHOD("set_skin", "skin"), &MeshInstance::set_skin);
ClassDB::bind_method(D_METHOD("get_skin"), &MeshInstance::get_skin);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
#endif
ClassDB::bind_method(D_METHOD("get_surface_material_count"), &MeshInstance::get_surface_material_count);
ClassDB::bind_method(D_METHOD("set_surface_material", "surface", "material"), &MeshInstance::set_surface_material);
ClassDB::bind_method(D_METHOD("get_surface_material", "surface"), &MeshInstance::get_surface_material);
ClassDB::bind_method(D_METHOD("get_active_material", "surface"), &MeshInstance::get_active_material);
#ifdef MODULE_SKELETON_3D_ENABLED
ADD_GROUP("Software Skinning", "software_skinning");
ClassDB::bind_method(D_METHOD("set_software_skinning_transform_normals", "enabled"), &MeshInstance::set_software_skinning_transform_normals);
ClassDB::bind_method(D_METHOD("is_software_skinning_transform_normals_enabled"), &MeshInstance::is_software_skinning_transform_normals_enabled);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "software_skinning_transform_normals"), "set_software_skinning_transform_normals", "is_software_skinning_transform_normals_enabled");
#endif
ClassDB::bind_method(D_METHOD("create_trimesh_collision"), &MeshInstance::create_trimesh_collision);
ClassDB::set_method_flags("MeshInstance", "create_trimesh_collision", METHOD_FLAGS_DEFAULT);
ClassDB::bind_method(D_METHOD("create_multiple_convex_collisions"), &MeshInstance::create_multiple_convex_collisions);
@ -1406,10 +826,6 @@ void MeshInstance::_bind_methods() {
ClassDB::set_method_flags("MeshInstance", "create_convex_collision", METHOD_FLAGS_DEFAULT);
ClassDB::bind_method(D_METHOD("_mesh_changed"), &MeshInstance::_mesh_changed);
#ifdef MODULE_SKELETON_3D_ENABLED
ClassDB::bind_method(D_METHOD("_update_skinning"), &MeshInstance::_update_skinning);
#endif
ClassDB::bind_method(D_METHOD("create_debug_tangents"), &MeshInstance::create_debug_tangents);
ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
@ -1419,18 +835,7 @@ void MeshInstance::_bind_methods() {
}
MeshInstance::MeshInstance() {
#ifdef MODULE_SKELETON_3D_ENABLED
skeleton_path = NodePath("..");
software_skinning = nullptr;
software_skinning_flags = SoftwareSkinning::FLAG_TRANSFORM_NORMALS;
#endif
}
MeshInstance::~MeshInstance() {
#ifdef MODULE_SKELETON_3D_ENABLED
if (software_skinning) {
memdelete(software_skinning);
software_skinning = nullptr;
}
#endif
}

View File

@ -35,13 +35,6 @@
#include "core/containers/local_vector.h"
#include "core/object/reference.h"
#include "modules/modules_enabled.gen.h"
#ifdef MODULE_SKELETON_3D_ENABLED
class Skin;
class SkinReference;
#endif
class Mesh;
class NodePath;
@ -51,38 +44,6 @@ class MeshInstance : public GeometryInstance {
protected:
Ref<Mesh> mesh;
#ifdef MODULE_SKELETON_3D_ENABLED
Ref<Skin> skin;
Ref<Skin> skin_internal;
Ref<SkinReference> skin_ref;
NodePath skeleton_path;
struct SoftwareSkinning {
enum Flags {
// Data flags.
FLAG_TRANSFORM_NORMALS = 1 << 0,
// Runtime flags.
FLAG_BONES_READY = 1 << 1,
};
struct SurfaceData {
PoolByteArray source_buffer;
uint32_t source_format;
PoolByteArray buffer;
PoolByteArray::Write buffer_write;
bool transform_tangents;
bool ensure_correct_normals;
};
Ref<Mesh> mesh_instance;
LocalVector<SurfaceData> surface_data;
};
SoftwareSkinning *software_skinning;
uint32_t software_skinning_flags;
#endif
struct BlendShapeTrack {
int idx;
float value;
@ -97,16 +58,6 @@ protected:
void _mesh_changed();
#ifdef MODULE_SKELETON_3D_ENABLED
void _resolve_skeleton_path();
bool _is_software_skinning_enabled() const;
static bool _is_global_software_skinning_enabled();
void _initialize_skinning(bool p_force_reset = false, bool p_call_attach_skeleton = true);
void _update_skinning();
#endif
private:
// merging
bool _merge_meshes(Vector<MeshInstance *> p_list, bool p_use_global_space, bool p_check_compatibility);
@ -129,14 +80,6 @@ public:
void set_mesh(const Ref<Mesh> &p_mesh);
Ref<Mesh> get_mesh() const;
#ifdef MODULE_SKELETON_3D_ENABLED
void set_skin(const Ref<Skin> &p_skin);
Ref<Skin> get_skin() const;
void set_skeleton_path(const NodePath &p_skeleton);
NodePath get_skeleton_path();
#endif
int get_surface_material_count() const;
void set_surface_material(int p_surface, const Ref<Material> &p_material);
Ref<Material> get_surface_material(int p_surface) const;

View File

@ -1,609 +0,0 @@
/*************************************************************************/
/* navigation_obstacle.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "navigation_obstacle.h"
#include "core/config/engine.h"
#include "scene/3d/collision_shape.h"
#include "scene/3d/navigation.h"
#include "scene/3d/physics_body.h"
#include "scene/main/spatial.h"
#include "scene/resources/material/material.h"
#include "scene/resources/material/spatial_material.h"
#include "scene/resources/mesh/mesh.h"
#include "scene/resources/shapes/shape.h"
#include "scene/resources/world_3d.h"
#include "servers/navigation_server.h"
#include "servers/rendering_server.h"
void NavigationObstacle::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle::get_rid);
ClassDB::bind_method(D_METHOD("set_avoidance_enabled", "enabled"), &NavigationObstacle::set_avoidance_enabled);
ClassDB::bind_method(D_METHOD("get_avoidance_enabled"), &NavigationObstacle::get_avoidance_enabled);
ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationObstacle::set_navigation_map);
ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationObstacle::get_navigation_map);
ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationObstacle::set_navigation_node);
ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationObstacle::get_navigation_node);
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationObstacle::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &NavigationObstacle::get_radius);
ClassDB::bind_method(D_METHOD("set_height", "height"), &NavigationObstacle::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &NavigationObstacle::get_height);
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationObstacle::set_velocity);
ClassDB::bind_method(D_METHOD("get_velocity"), &NavigationObstacle::get_velocity);
ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationObstacle::set_vertices);
ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationObstacle::get_vertices);
ClassDB::bind_method(D_METHOD("set_avoidance_layers", "layers"), &NavigationObstacle::set_avoidance_layers);
ClassDB::bind_method(D_METHOD("get_avoidance_layers"), &NavigationObstacle::get_avoidance_layers);
ClassDB::bind_method(D_METHOD("set_avoidance_layer_value", "layer_number", "value"), &NavigationObstacle::set_avoidance_layer_value);
ClassDB::bind_method(D_METHOD("get_avoidance_layer_value", "layer_number"), &NavigationObstacle::get_avoidance_layer_value);
ClassDB::bind_method(D_METHOD("set_use_3d_avoidance", "enabled"), &NavigationObstacle::set_use_3d_avoidance);
ClassDB::bind_method(D_METHOD("get_use_3d_avoidance"), &NavigationObstacle::get_use_3d_avoidance);
#ifdef DEBUG_ENABLED
ClassDB::bind_method(D_METHOD("_update_fake_agent_radius_debug"), &NavigationObstacle::_update_fake_agent_radius_debug);
ClassDB::bind_method(D_METHOD("_update_static_obstacle_debug"), &NavigationObstacle::_update_static_obstacle_debug);
#endif // DEBUG_ENABLED
ADD_GROUP("Avoidance", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_velocity", "get_velocity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.0,100,0.01,suffix:m"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.0,100,0.01,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices"), "set_vertices", "get_vertices");
ADD_PROPERTY(PropertyInfo(Variant::INT, "avoidance_layers", PROPERTY_HINT_LAYERS_AVOIDANCE), "set_avoidance_layers", "get_avoidance_layers");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_3d_avoidance"), "set_use_3d_avoidance", "get_use_3d_avoidance");
}
void NavigationObstacle::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_POST_ENTER_TREE: {
// Search the navigation node and set it
{
Navigation *nav = nullptr;
Node *p = get_parent();
while (p != nullptr) {
nav = Object::cast_to<Navigation>(p);
if (nav != nullptr) {
p = nullptr;
} else {
p = p->get_parent();
}
}
set_navigation(nav);
}
_update_map(get_navigation_map());
previous_transform = get_global_transform();
// need to trigger map controlled agent assignment somehow for the fake_agent since obstacles use no callback like regular agents
NavigationServer::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled);
_update_position(get_global_transform().origin);
set_physics_process_internal(true);
#ifdef DEBUG_ENABLED
if ((NavigationServer::get_singleton()->get_debug_avoidance_enabled()) &&
(NavigationServer::get_singleton()->get_debug_navigation_avoidance_enable_obstacles_radius())) {
_update_fake_agent_radius_debug();
_update_static_obstacle_debug();
}
#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_PAUSED: {
if (!can_process()) {
map_before_pause = map_current;
_update_map(RID());
} else if (can_process() && !(map_before_pause == RID())) {
_update_map(map_before_pause);
map_before_pause = RID();
}
NavigationServer::get_singleton()->obstacle_set_paused(obstacle, !can_process());
} break;
case NOTIFICATION_UNPAUSED: {
if (!can_process()) {
map_before_pause = map_current;
_update_map(RID());
} else if (can_process() && !(map_before_pause == RID())) {
_update_map(map_before_pause);
map_before_pause = RID();
}
NavigationServer::get_singleton()->obstacle_set_paused(obstacle, !can_process());
} break;
case NOTIFICATION_EXIT_TREE: {
set_navigation(nullptr);
set_physics_process_internal(false);
request_ready(); // required to solve an issue with losing the navigation
_update_map(RID());
#ifdef DEBUG_ENABLED
if (fake_agent_radius_debug_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(fake_agent_radius_debug_instance, false);
}
if (static_obstacle_debug_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(static_obstacle_debug_instance, false);
}
#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (is_inside_tree()) {
_update_position(get_global_transform().origin);
if (velocity_submitted) {
velocity_submitted = false;
// only update if there is a noticeable change, else the rvo agent preferred velocity stays the same
if (!previous_velocity.is_equal_approx(velocity)) {
NavigationServer::get_singleton()->obstacle_set_velocity(obstacle, velocity);
}
previous_velocity = velocity;
}
#ifdef DEBUG_ENABLED
if (fake_agent_radius_debug_instance.is_valid() && radius > 0.0) {
RS::get_singleton()->instance_set_transform(fake_agent_radius_debug_instance, get_global_transform());
}
if (static_obstacle_debug_instance.is_valid() && get_vertices().size() > 0) {
RS::get_singleton()->instance_set_transform(static_obstacle_debug_instance, get_global_transform());
}
#endif // DEBUG_ENABLED
}
} break;
}
}
NavigationObstacle::NavigationObstacle() {
navigation = nullptr;
height = 1.0;
radius = 0.0;
avoidance_layers = 1;
use_3d_avoidance = false;
velocity_submitted = false;
avoidance_enabled = true;
obstacle = NavigationServer::get_singleton()->obstacle_create();
set_radius(radius);
set_height(height);
set_vertices(vertices);
set_avoidance_layers(avoidance_layers);
set_avoidance_enabled(avoidance_enabled);
set_use_3d_avoidance(use_3d_avoidance);
#ifdef DEBUG_ENABLED
NavigationServer::get_singleton()->connect("avoidance_debug_changed", this, "_update_fake_agent_radius_debug");
NavigationServer::get_singleton()->connect("avoidance_debug_changed", this, "_update_static_obstacle_debug");
_update_fake_agent_radius_debug();
_update_static_obstacle_debug();
#endif // DEBUG_ENABLED
}
NavigationObstacle::~NavigationObstacle() {
ERR_FAIL_NULL(NavigationServer::get_singleton());
NavigationServer::get_singleton()->free(obstacle);
obstacle = RID();
#ifdef DEBUG_ENABLED
NavigationServer::get_singleton()->disconnect("avoidance_debug_changed", this, "_update_fake_agent_radius_debug");
NavigationServer::get_singleton()->disconnect("avoidance_debug_changed", this, "_update_static_obstacle_debug");
if (fake_agent_radius_debug_instance.is_valid()) {
RenderingServer::get_singleton()->free(fake_agent_radius_debug_instance);
}
if (fake_agent_radius_debug_mesh.is_valid()) {
RenderingServer::get_singleton()->free(fake_agent_radius_debug_mesh->get_rid());
}
if (static_obstacle_debug_instance.is_valid()) {
RenderingServer::get_singleton()->free(static_obstacle_debug_instance);
}
if (static_obstacle_debug_mesh.is_valid()) {
RenderingServer::get_singleton()->free(static_obstacle_debug_mesh->get_rid());
}
#endif // DEBUG_ENABLED
}
void NavigationObstacle::set_navigation(Navigation *p_nav) {
if (navigation == p_nav && navigation != nullptr) {
return; // Pointless
}
navigation = p_nav;
NavigationServer::get_singleton()->obstacle_set_map(obstacle, get_navigation_map());
}
void NavigationObstacle::set_navigation_node(Node *p_nav) {
Navigation *nav = Object::cast_to<Navigation>(p_nav);
ERR_FAIL_NULL(nav);
set_navigation(nav);
}
Node *NavigationObstacle::get_navigation_node() const {
return Object::cast_to<Node>(navigation);
}
void NavigationObstacle::set_navigation_map(RID p_navigation_map) {
if (map_override == p_navigation_map) {
return;
}
map_override = p_navigation_map;
_update_map(get_navigation_map());
}
RID NavigationObstacle::get_navigation_map() const {
if (navigation) {
navigation->get_rid();
} else if (map_override.is_valid()) {
return map_override;
} else if (is_inside_tree()) {
return get_world_3d()->get_navigation_map();
}
return RID();
}
void NavigationObstacle::set_vertices(const Vector<Vector3> &p_vertices) {
vertices = p_vertices;
NavigationServer::get_singleton()->obstacle_set_vertices(obstacle, vertices);
#ifdef DEBUG_ENABLED
_update_static_obstacle_debug();
#endif // DEBUG_ENABLED
}
void NavigationObstacle::set_radius(real_t p_radius) {
ERR_FAIL_COND_MSG(p_radius < 0.0, "Radius must be positive.");
if (Math::is_equal_approx(radius, p_radius)) {
return;
}
radius = p_radius;
NavigationServer::get_singleton()->obstacle_set_radius(obstacle, radius);
#ifdef DEBUG_ENABLED
_update_fake_agent_radius_debug();
#endif // DEBUG_ENABLED
}
void NavigationObstacle::set_height(real_t p_height) {
ERR_FAIL_COND_MSG(p_height < 0.0, "Height must be positive.");
if (Math::is_equal_approx(height, p_height)) {
return;
}
height = p_height;
NavigationServer::get_singleton()->obstacle_set_height(obstacle, height);
#ifdef DEBUG_ENABLED
_update_static_obstacle_debug();
#endif // DEBUG_ENABLED
}
void NavigationObstacle::set_avoidance_layers(uint32_t p_layers) {
avoidance_layers = p_layers;
NavigationServer::get_singleton()->obstacle_set_avoidance_layers(obstacle, avoidance_layers);
}
uint32_t NavigationObstacle::get_avoidance_layers() const {
return avoidance_layers;
}
void NavigationObstacle::set_avoidance_layer_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Avoidance layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Avoidance layer number must be between 1 and 32 inclusive.");
uint32_t avoidance_layers_new = get_avoidance_layers();
if (p_value) {
avoidance_layers_new |= 1 << (p_layer_number - 1);
} else {
avoidance_layers_new &= ~(1 << (p_layer_number - 1));
}
set_avoidance_layers(avoidance_layers_new);
}
bool NavigationObstacle::get_avoidance_layer_value(int p_layer_number) const {
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Avoidance layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Avoidance layer number must be between 1 and 32 inclusive.");
return get_avoidance_layers() & (1 << (p_layer_number - 1));
}
void NavigationObstacle::set_avoidance_enabled(bool p_enabled) {
if (avoidance_enabled == p_enabled) {
return;
}
avoidance_enabled = p_enabled;
NavigationServer::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled);
}
bool NavigationObstacle::get_avoidance_enabled() const {
return avoidance_enabled;
}
void NavigationObstacle::set_use_3d_avoidance(bool p_use_3d_avoidance) {
use_3d_avoidance = p_use_3d_avoidance;
_update_use_3d_avoidance(use_3d_avoidance);
property_list_changed_notify();
}
void NavigationObstacle::set_velocity(const Vector3 p_velocity) {
velocity = p_velocity;
velocity_submitted = true;
}
void NavigationObstacle::_update_map(RID p_map) {
NavigationServer::get_singleton()->obstacle_set_map(obstacle, p_map);
map_current = p_map;
}
void NavigationObstacle::_update_position(const Vector3 p_position) {
NavigationServer::get_singleton()->obstacle_set_position(obstacle, p_position);
}
void NavigationObstacle::_update_use_3d_avoidance(bool p_use_3d_avoidance) {
NavigationServer::get_singleton()->obstacle_set_use_3d_avoidance(obstacle, use_3d_avoidance);
_update_map(map_current);
}
#ifdef DEBUG_ENABLED
void NavigationObstacle::_update_fake_agent_radius_debug() {
bool is_debug_enabled = false;
if (Engine::get_singleton()->is_editor_hint()) {
is_debug_enabled = true;
} else if (NavigationServer::get_singleton()->get_debug_enabled() &&
NavigationServer::get_singleton()->get_debug_avoidance_enabled() &&
NavigationServer::get_singleton()->get_debug_navigation_avoidance_enable_obstacles_radius()) {
is_debug_enabled = true;
}
if (is_debug_enabled == false) {
if (fake_agent_radius_debug_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(fake_agent_radius_debug_instance, false);
}
return;
}
if (!fake_agent_radius_debug_instance.is_valid()) {
fake_agent_radius_debug_instance = RenderingServer::get_singleton()->instance_create();
}
if (!fake_agent_radius_debug_mesh.is_valid()) {
fake_agent_radius_debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
}
fake_agent_radius_debug_mesh->clear_surfaces();
Vector<Vector3> face_vertex_array;
Vector<int> face_indices_array;
int i, j, prevrow, thisrow, point;
float x, y, z;
int rings = 16;
int radial_segments = 32;
point = 0;
thisrow = 0;
prevrow = 0;
for (j = 0; j <= (rings + 1); j++) {
float v = j;
float w;
v /= (rings + 1);
w = sin(Math_PI * v);
y = (radius)*cos(Math_PI * v);
for (i = 0; i <= radial_segments; i++) {
float u = i;
u /= radial_segments;
x = sin(u * Math_TAU);
z = cos(u * Math_TAU);
Vector3 p = Vector3(x * radius * w, y, z * radius * w);
face_vertex_array.push_back(p);
point++;
if (i > 0 && j > 0) {
face_indices_array.push_back(prevrow + i - 1);
face_indices_array.push_back(prevrow + i);
face_indices_array.push_back(thisrow + i - 1);
face_indices_array.push_back(prevrow + i);
face_indices_array.push_back(thisrow + i);
face_indices_array.push_back(thisrow + i - 1);
};
};
prevrow = thisrow;
thisrow = point;
};
Array face_mesh_array;
face_mesh_array.resize(Mesh::ARRAY_MAX);
face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array;
face_mesh_array[Mesh::ARRAY_INDEX] = face_indices_array;
fake_agent_radius_debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array);
Ref<SpatialMaterial> face_material = NavigationServer::get_singleton()->get_debug_navigation_avoidance_obstacles_radius_material();
fake_agent_radius_debug_mesh->surface_set_material(0, face_material);
RS::get_singleton()->instance_set_base(fake_agent_radius_debug_instance, fake_agent_radius_debug_mesh->get_rid());
if (is_inside_tree()) {
RS::get_singleton()->instance_set_scenario(fake_agent_radius_debug_instance, get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_visible(fake_agent_radius_debug_instance, is_visible_in_tree());
}
}
#endif // DEBUG_ENABLED
#ifdef DEBUG_ENABLED
void NavigationObstacle::_update_static_obstacle_debug() {
bool is_debug_enabled = false;
if (Engine::get_singleton()->is_editor_hint()) {
is_debug_enabled = true;
} else if (NavigationServer::get_singleton()->get_debug_enabled() &&
NavigationServer::get_singleton()->get_debug_avoidance_enabled() &&
NavigationServer::get_singleton()->get_debug_navigation_avoidance_enable_obstacles_static()) {
is_debug_enabled = true;
}
if (is_debug_enabled == false) {
if (static_obstacle_debug_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(static_obstacle_debug_instance, false);
}
return;
}
if (vertices.size() < 3) {
if (static_obstacle_debug_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(static_obstacle_debug_instance, false);
}
return;
}
if (!static_obstacle_debug_instance.is_valid()) {
static_obstacle_debug_instance = RenderingServer::get_singleton()->instance_create();
}
if (!static_obstacle_debug_mesh.is_valid()) {
static_obstacle_debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
}
static_obstacle_debug_mesh->clear_surfaces();
Vector<Vector2> polygon_2d_vertices;
polygon_2d_vertices.resize(vertices.size());
Vector2 *polygon_2d_vertices_ptr = polygon_2d_vertices.ptrw();
for (int i = 0; i < vertices.size(); ++i) {
Vector3 obstacle_vertex = vertices[i];
Vector2 obstacle_vertex_2d = Vector2(obstacle_vertex.x, obstacle_vertex.z);
polygon_2d_vertices_ptr[i] = obstacle_vertex_2d;
}
Vector<int> triangulated_polygon_2d_indices = Geometry::triangulate_polygon(polygon_2d_vertices);
if (triangulated_polygon_2d_indices.empty()) {
// failed triangulation
return;
}
bool obstacle_pushes_inward = Geometry::is_polygon_clockwise(polygon_2d_vertices);
Vector<Vector3> face_vertex_array;
Vector<int> face_indices_array;
face_vertex_array.resize(polygon_2d_vertices.size());
face_indices_array.resize(triangulated_polygon_2d_indices.size());
Vector3 *face_vertex_array_ptr = face_vertex_array.ptrw();
int *face_indices_array_ptr = face_indices_array.ptrw();
for (int i = 0; i < triangulated_polygon_2d_indices.size(); ++i) {
int vertex_index = triangulated_polygon_2d_indices[i];
const Vector2 &vertex_2d = polygon_2d_vertices[vertex_index];
Vector3 vertex_3d = Vector3(vertex_2d.x, 0.0, vertex_2d.y);
face_vertex_array_ptr[vertex_index] = vertex_3d;
face_indices_array_ptr[i] = vertex_index;
}
Array face_mesh_array;
face_mesh_array.resize(Mesh::ARRAY_MAX);
face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array;
face_mesh_array[Mesh::ARRAY_INDEX] = face_indices_array;
static_obstacle_debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array);
Vector<Vector3> edge_vertex_array;
for (int i = 0; i < polygon_2d_vertices.size(); ++i) {
int from_index = i - 1;
int to_index = i;
if (i == 0) {
from_index = polygon_2d_vertices.size() - 1;
}
const Vector2 &vertex_2d_from = polygon_2d_vertices[from_index];
const Vector2 &vertex_2d_to = polygon_2d_vertices[to_index];
Vector3 vertex_3d_ground_from = Vector3(vertex_2d_from.x, 0.0, vertex_2d_from.y);
Vector3 vertex_3d_ground_to = Vector3(vertex_2d_to.x, 0.0, vertex_2d_to.y);
edge_vertex_array.push_back(vertex_3d_ground_from);
edge_vertex_array.push_back(vertex_3d_ground_to);
Vector3 vertex_3d_height_from = Vector3(vertex_2d_from.x, height, vertex_2d_from.y);
Vector3 vertex_3d_height_to = Vector3(vertex_2d_to.x, height, vertex_2d_to.y);
edge_vertex_array.push_back(vertex_3d_height_from);
edge_vertex_array.push_back(vertex_3d_height_to);
edge_vertex_array.push_back(vertex_3d_ground_from);
edge_vertex_array.push_back(vertex_3d_height_from);
}
Array edge_mesh_array;
edge_mesh_array.resize(Mesh::ARRAY_MAX);
edge_mesh_array[Mesh::ARRAY_VERTEX] = edge_vertex_array;
static_obstacle_debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, edge_mesh_array);
Ref<SpatialMaterial> face_material;
Ref<SpatialMaterial> edge_material;
if (obstacle_pushes_inward) {
face_material = NavigationServer::get_singleton()->get_debug_navigation_avoidance_static_obstacle_pushin_face_material();
edge_material = NavigationServer::get_singleton()->get_debug_navigation_avoidance_static_obstacle_pushin_edge_material();
} else {
face_material = NavigationServer::get_singleton()->get_debug_navigation_avoidance_static_obstacle_pushout_face_material();
edge_material = NavigationServer::get_singleton()->get_debug_navigation_avoidance_static_obstacle_pushout_edge_material();
}
static_obstacle_debug_mesh->surface_set_material(0, face_material);
static_obstacle_debug_mesh->surface_set_material(1, edge_material);
RS::get_singleton()->instance_set_base(static_obstacle_debug_instance, static_obstacle_debug_mesh->get_rid());
if (is_inside_tree()) {
RS::get_singleton()->instance_set_scenario(static_obstacle_debug_instance, get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_visible(static_obstacle_debug_instance, is_visible_in_tree());
}
}
#endif // DEBUG_ENABLED

View File

@ -1,132 +0,0 @@
#ifndef NAVIGATION_OBSTACLE_H
#define NAVIGATION_OBSTACLE_H
/*************************************************************************/
/* navigation_obstacle.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/main/spatial.h"
class Navigation;
class Spatial;
class NavigationObstacle : public Spatial {
GDCLASS(NavigationObstacle, Spatial);
Navigation *navigation;
RID obstacle;
RID map_before_pause;
RID map_override;
RID map_current;
real_t height;
real_t radius;
Vector<Vector3> vertices;
bool avoidance_enabled;
uint32_t avoidance_layers;
bool use_3d_avoidance;
Transform previous_transform;
Vector3 velocity;
Vector3 previous_velocity;
bool velocity_submitted;
#ifdef DEBUG_ENABLED
RID fake_agent_radius_debug_instance;
Ref<ArrayMesh> fake_agent_radius_debug_mesh;
RID static_obstacle_debug_instance;
Ref<ArrayMesh> static_obstacle_debug_mesh;
private:
void _update_fake_agent_radius_debug();
void _update_static_obstacle_debug();
#endif // DEBUG_ENABLED
protected:
static void _bind_methods();
void _notification(int p_what);
public:
NavigationObstacle();
virtual ~NavigationObstacle();
void set_navigation(Navigation *p_nav);
const Navigation *get_navigation() const {
return navigation;
}
void set_navigation_node(Node *p_nav);
Node *get_navigation_node() const;
RID get_rid() const { return obstacle; }
void set_avoidance_enabled(bool p_enabled);
bool get_avoidance_enabled() const;
void set_navigation_map(RID p_navigation_map);
RID get_navigation_map() const;
void set_radius(real_t p_radius);
real_t get_radius() const {
return radius;
}
void set_height(real_t p_height);
real_t get_height() const { return height; }
void set_vertices(const Vector<Vector3> &p_vertices);
Vector<Vector3> get_vertices() const { return vertices; };
void set_avoidance_layers(uint32_t p_layers);
uint32_t get_avoidance_layers() const;
void set_avoidance_layer_value(int p_layer_number, bool p_value);
bool get_avoidance_layer_value(int p_layer_number) const;
void set_use_3d_avoidance(bool p_use_3d_avoidance);
bool get_use_3d_avoidance() const { return use_3d_avoidance; }
void set_velocity(const Vector3 p_velocity);
Vector3 get_velocity() const { return velocity; };
void _avoidance_done(Vector3 p_new_velocity); // Dummy
private:
void _update_map(RID p_map);
void _update_position(const Vector3 p_position);
void _update_use_3d_avoidance(bool p_use_3d_avoidance);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,386 +0,0 @@
#ifndef PHYSICS_BODY__H
#define PHYSICS_BODY__H
/*************************************************************************/
/* physics_body.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/containers/vset.h"
#include "core/object/reference.h"
#include "scene/3d/collision_object.h"
#include "servers/physics_server.h"
class PhysicsMaterial;
class Skeleton;
class PhysicsBody : public CollisionObject {
GDCLASS(PhysicsBody, CollisionObject);
void _set_layers(uint32_t p_mask);
uint32_t _get_layers() const;
protected:
static void _bind_methods();
void _notification(int p_what);
PhysicsBody(PhysicsServer::BodyMode p_mode);
~PhysicsBody();
public:
virtual Vector3 get_linear_velocity() const;
virtual Vector3 get_angular_velocity() const;
virtual float get_inverse_mass() const;
Array get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
void remove_collision_exception_with(Node *p_node);
};
class StaticBody : public PhysicsBody {
GDCLASS(StaticBody, PhysicsBody);
Vector3 constant_linear_velocity;
Vector3 constant_angular_velocity;
Ref<PhysicsMaterial> physics_material_override;
protected:
static void _bind_methods();
public:
#ifndef DISABLE_DEPRECATED
void set_friction(real_t p_friction);
real_t get_friction() const;
void set_bounce(real_t p_bounce);
real_t get_bounce() const;
#endif
void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
Ref<PhysicsMaterial> get_physics_material_override() const;
void set_constant_linear_velocity(const Vector3 &p_vel);
void set_constant_angular_velocity(const Vector3 &p_vel);
Vector3 get_constant_linear_velocity() const;
Vector3 get_constant_angular_velocity() const;
StaticBody();
~StaticBody();
private:
void _reload_physics_characteristics();
};
class RigidBody : public PhysicsBody {
GDCLASS(RigidBody, PhysicsBody);
public:
enum Mode {
MODE_RIGID,
MODE_STATIC,
MODE_CHARACTER,
MODE_KINEMATIC,
};
protected:
bool can_sleep;
PhysicsDirectBodyState *state;
Mode mode;
real_t mass;
Ref<PhysicsMaterial> physics_material_override;
Vector3 linear_velocity;
Vector3 angular_velocity;
Basis inverse_inertia_tensor;
real_t gravity_scale;
real_t linear_damp;
real_t angular_damp;
bool sleeping;
bool ccd;
int max_contacts_reported;
bool custom_integrator;
struct ShapePair {
int body_shape;
int local_shape;
bool tagged;
bool operator<(const ShapePair &p_sp) const {
if (body_shape == p_sp.body_shape) {
return local_shape < p_sp.local_shape;
} else {
return body_shape < p_sp.body_shape;
}
}
ShapePair() {}
ShapePair(int p_bs, int p_ls) {
body_shape = p_bs;
local_shape = p_ls;
tagged = false;
}
};
struct RigidBody_RemoveAction {
RID rid;
ObjectID body_id;
ShapePair pair;
};
struct BodyState {
RID rid;
bool in_tree;
VSet<ShapePair> shapes;
};
struct ContactMonitor {
bool locked;
RBMap<ObjectID, BodyState> body_map;
};
ContactMonitor *contact_monitor;
void _body_enter_tree(ObjectID p_id);
void _body_exit_tree(ObjectID p_id);
void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape);
virtual void _direct_state_changed(Object *p_state);
void _notification(int p_what);
static void _bind_methods();
public:
void set_mode(Mode p_mode);
Mode get_mode() const;
void set_mass(real_t p_mass);
real_t get_mass() const;
virtual float get_inverse_mass() const { return 1.0 / mass; }
void set_weight(real_t p_weight);
real_t get_weight() const;
#ifndef DISABLE_DEPRECATED
void set_friction(real_t p_friction);
real_t get_friction() const;
void set_bounce(real_t p_bounce);
real_t get_bounce() const;
#endif
void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
Ref<PhysicsMaterial> get_physics_material_override() const;
void set_linear_velocity(const Vector3 &p_velocity);
Vector3 get_linear_velocity() const;
void set_axis_velocity(const Vector3 &p_axis);
void set_angular_velocity(const Vector3 &p_velocity);
Vector3 get_angular_velocity() const;
Basis get_inverse_inertia_tensor();
void set_gravity_scale(real_t p_gravity_scale);
real_t get_gravity_scale() const;
void set_linear_damp(real_t p_linear_damp);
real_t get_linear_damp() const;
void set_angular_damp(real_t p_angular_damp);
real_t get_angular_damp() const;
void set_use_custom_integrator(bool p_enable);
bool is_using_custom_integrator();
void set_sleeping(bool p_sleeping);
bool is_sleeping() const;
void set_can_sleep(bool p_active);
bool is_able_to_sleep() const;
void set_contact_monitor(bool p_enabled);
bool is_contact_monitor_enabled() const;
void set_max_contacts_reported(int p_amount);
int get_max_contacts_reported() const;
void set_use_continuous_collision_detection(bool p_enable);
bool is_using_continuous_collision_detection() const;
void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock);
bool get_axis_lock(PhysicsServer::BodyAxis p_axis) const;
Array get_colliding_bodies() const;
void add_central_force(const Vector3 &p_force);
void add_force(const Vector3 &p_force, const Vector3 &p_pos);
void add_torque(const Vector3 &p_torque);
void apply_central_impulse(const Vector3 &p_impulse);
void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
void apply_torque_impulse(const Vector3 &p_impulse);
virtual String get_configuration_warning() const;
RigidBody();
~RigidBody();
private:
void _reload_physics_characteristics();
};
VARIANT_ENUM_CAST(RigidBody::Mode);
class KinematicCollision;
class KinematicBody : public PhysicsBody {
GDCLASS(KinematicBody, PhysicsBody);
public:
enum MovingPlatformApplyVelocityOnLeave {
PLATFORM_VEL_ON_LEAVE_ALWAYS,
PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY,
PLATFORM_VEL_ON_LEAVE_NEVER,
};
struct Collision {
Vector3 collision;
Vector3 normal;
Vector3 collider_vel;
ObjectID collider;
RID collider_rid;
int collider_shape;
Variant collider_metadata;
Vector3 remainder;
Vector3 travel;
int local_shape;
real_t collision_safe_fraction;
real_t get_angle(const Vector3 &p_up_direction) const {
return Math::acos(normal.dot(p_up_direction));
}
};
private:
uint16_t locked_axis;
float margin;
Vector3 floor_normal;
Vector3 floor_velocity;
RID on_floor_body;
bool on_floor;
bool on_ceiling;
bool on_wall;
bool sync_to_physics = false;
MovingPlatformApplyVelocityOnLeave moving_platform_apply_velocity_on_leave = PLATFORM_VEL_ON_LEAVE_ALWAYS;
Vector<Collision> colliders;
Vector<Ref<KinematicCollision>> slide_colliders;
Ref<KinematicCollision> motion_cache;
Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
Ref<KinematicCollision> _get_slide_collision(int p_bounce);
Ref<KinematicCollision> _get_last_slide_collision();
Transform last_valid_transform;
void _direct_state_changed(Object *p_state);
Vector3 _move_and_slide_internal(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true);
void _set_collision_direction(const Collision &p_collision, const Vector3 &p_up_direction, float p_floor_max_angle);
void set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_velocity);
MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() const;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes = true, bool p_test_only = false, bool p_cancel_sliding = true, const RBSet<RID> &p_exclude = RBSet<RID>());
bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia);
bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision);
void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock);
bool get_axis_lock(PhysicsServer::BodyAxis p_axis) const;
void set_safe_margin(float p_margin);
float get_safe_margin() const;
Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true);
Vector3 move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true);
bool is_on_floor() const;
bool is_on_wall() const;
bool is_on_ceiling() const;
Vector3 get_floor_normal() const;
real_t get_floor_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
Vector3 get_floor_velocity() const;
int get_slide_count() const;
Collision get_slide_collision(int p_bounce) const;
void set_sync_to_physics(bool p_enable);
bool is_sync_to_physics_enabled() const;
KinematicBody();
~KinematicBody();
};
VARIANT_ENUM_CAST(KinematicBody::MovingPlatformApplyVelocityOnLeave);
class KinematicCollision : public Reference {
GDCLASS(KinematicCollision, Reference);
KinematicBody *owner;
friend class KinematicBody;
KinematicBody::Collision collision;
protected:
static void _bind_methods();
public:
Vector3 get_position() const;
Vector3 get_normal() const;
Vector3 get_travel() const;
Vector3 get_remainder() const;
real_t get_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
Object *get_local_shape() const;
Object *get_collider() const;
ObjectID get_collider_id() const;
RID get_collider_rid() const;
Object *get_collider_shape() const;
int get_collider_shape_index() const;
Vector3 get_collider_velocity() const;
Variant get_collider_metadata() const;
KinematicCollision();
~KinematicCollision();
};
#endif // PHYSICS_BODY__H

File diff suppressed because it is too large Load Diff

View File

@ -1,336 +0,0 @@
#ifndef PHYSICS_JOINT_H
#define PHYSICS_JOINT_H
/*************************************************************************/
/* physics_joint.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/main/spatial.h"
#include "servers/physics_server.h"
class PhysicsBody;
class Joint : public Spatial {
GDCLASS(Joint, Spatial);
RID ba, bb;
RID joint;
NodePath a;
NodePath b;
int solver_priority;
bool exclude_from_collision;
String warning;
protected:
void _disconnect_signals();
void _body_exit_tree();
void _update_joint(bool p_only_free = false);
void _notification(int p_what);
virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b) = 0;
static void _bind_methods();
public:
virtual String get_configuration_warning() const;
void set_node_a(const NodePath &p_node_a);
NodePath get_node_a() const;
void set_node_b(const NodePath &p_node_b);
NodePath get_node_b() const;
void set_solver_priority(int p_priority);
int get_solver_priority() const;
void set_exclude_nodes_from_collision(bool p_enable);
bool get_exclude_nodes_from_collision() const;
RID get_joint() const { return joint; }
Joint();
};
///////////////////////////////////////////
class PinJoint : public Joint {
GDCLASS(PinJoint, Joint);
public:
enum Param {
PARAM_BIAS = PhysicsServer::PIN_JOINT_BIAS,
PARAM_DAMPING = PhysicsServer::PIN_JOINT_DAMPING,
PARAM_IMPULSE_CLAMP = PhysicsServer::PIN_JOINT_IMPULSE_CLAMP
};
protected:
float params[3];
virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
static void _bind_methods();
public:
void set_param(Param p_param, float p_value);
float get_param(Param p_param) const;
PinJoint();
};
VARIANT_ENUM_CAST(PinJoint::Param);
class HingeJoint : public Joint {
GDCLASS(HingeJoint, Joint);
public:
enum Param {
PARAM_BIAS = PhysicsServer::HINGE_JOINT_BIAS,
PARAM_LIMIT_UPPER = PhysicsServer::HINGE_JOINT_LIMIT_UPPER,
PARAM_LIMIT_LOWER = PhysicsServer::HINGE_JOINT_LIMIT_LOWER,
PARAM_LIMIT_BIAS = PhysicsServer::HINGE_JOINT_LIMIT_BIAS,
PARAM_LIMIT_SOFTNESS = PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS,
PARAM_LIMIT_RELAXATION = PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION,
PARAM_MOTOR_TARGET_VELOCITY = PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY,
PARAM_MOTOR_MAX_IMPULSE = PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE,
PARAM_MAX = PhysicsServer::HINGE_JOINT_MAX
};
enum Flag {
FLAG_USE_LIMIT = PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT,
FLAG_ENABLE_MOTOR = PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR,
FLAG_MAX = PhysicsServer::HINGE_JOINT_FLAG_MAX
};
protected:
float params[PARAM_MAX];
bool flags[FLAG_MAX];
virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
static void _bind_methods();
void _set_upper_limit(float p_limit);
float _get_upper_limit() const;
void _set_lower_limit(float p_limit);
float _get_lower_limit() const;
public:
void set_param(Param p_param, float p_value);
float get_param(Param p_param) const;
void set_flag(Flag p_flag, bool p_value);
bool get_flag(Flag p_flag) const;
HingeJoint();
};
VARIANT_ENUM_CAST(HingeJoint::Param);
VARIANT_ENUM_CAST(HingeJoint::Flag);
class SliderJoint : public Joint {
GDCLASS(SliderJoint, Joint);
public:
enum Param {
PARAM_LINEAR_LIMIT_UPPER = PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER,
PARAM_LINEAR_LIMIT_LOWER = PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER,
PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS,
PARAM_LINEAR_LIMIT_RESTITUTION = PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION,
PARAM_LINEAR_LIMIT_DAMPING = PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING,
PARAM_LINEAR_MOTION_SOFTNESS = PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS,
PARAM_LINEAR_MOTION_RESTITUTION = PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION,
PARAM_LINEAR_MOTION_DAMPING = PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_DAMPING,
PARAM_LINEAR_ORTHOGONAL_SOFTNESS = PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS,
PARAM_LINEAR_ORTHOGONAL_RESTITUTION = PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION,
PARAM_LINEAR_ORTHOGONAL_DAMPING = PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING,
PARAM_ANGULAR_LIMIT_UPPER = PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER,
PARAM_ANGULAR_LIMIT_LOWER = PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER,
PARAM_ANGULAR_LIMIT_SOFTNESS = PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS,
PARAM_ANGULAR_LIMIT_RESTITUTION = PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION,
PARAM_ANGULAR_LIMIT_DAMPING = PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING,
PARAM_ANGULAR_MOTION_SOFTNESS = PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS,
PARAM_ANGULAR_MOTION_RESTITUTION = PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION,
PARAM_ANGULAR_MOTION_DAMPING = PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_DAMPING,
PARAM_ANGULAR_ORTHOGONAL_SOFTNESS = PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS,
PARAM_ANGULAR_ORTHOGONAL_RESTITUTION = PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION,
PARAM_ANGULAR_ORTHOGONAL_DAMPING = PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING,
PARAM_MAX = PhysicsServer::SLIDER_JOINT_MAX
};
protected:
void _set_upper_limit_angular(float p_limit_angular);
float _get_upper_limit_angular() const;
void _set_lower_limit_angular(float p_limit_angular);
float _get_lower_limit_angular() const;
float params[PARAM_MAX];
virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
static void _bind_methods();
public:
void set_param(Param p_param, float p_value);
float get_param(Param p_param) const;
SliderJoint();
};
VARIANT_ENUM_CAST(SliderJoint::Param);
class ConeTwistJoint : public Joint {
GDCLASS(ConeTwistJoint, Joint);
public:
enum Param {
PARAM_SWING_SPAN,
PARAM_TWIST_SPAN,
PARAM_BIAS,
PARAM_SOFTNESS,
PARAM_RELAXATION,
PARAM_MAX
};
protected:
void _set_swing_span(float p_limit_angular);
float _get_swing_span() const;
void _set_twist_span(float p_limit_angular);
float _get_twist_span() const;
float params[PARAM_MAX];
virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
static void _bind_methods();
public:
void set_param(Param p_param, float p_value);
float get_param(Param p_param) const;
ConeTwistJoint();
};
VARIANT_ENUM_CAST(ConeTwistJoint::Param);
class Generic6DOFJoint : public Joint {
GDCLASS(Generic6DOFJoint, Joint);
public:
enum Param {
PARAM_LINEAR_LOWER_LIMIT = PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT,
PARAM_LINEAR_UPPER_LIMIT = PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT,
PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS,
PARAM_LINEAR_RESTITUTION = PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION,
PARAM_LINEAR_DAMPING = PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING,
PARAM_LINEAR_MOTOR_TARGET_VELOCITY = PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY,
PARAM_LINEAR_MOTOR_FORCE_LIMIT = PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT,
PARAM_LINEAR_SPRING_STIFFNESS = PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS,
PARAM_LINEAR_SPRING_DAMPING = PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING,
PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT = PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT,
PARAM_ANGULAR_LOWER_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT,
PARAM_ANGULAR_UPPER_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT,
PARAM_ANGULAR_LIMIT_SOFTNESS = PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS,
PARAM_ANGULAR_DAMPING = PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING,
PARAM_ANGULAR_RESTITUTION = PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION,
PARAM_ANGULAR_FORCE_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT,
PARAM_ANGULAR_ERP = PhysicsServer::G6DOF_JOINT_ANGULAR_ERP,
PARAM_ANGULAR_MOTOR_TARGET_VELOCITY = PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY,
PARAM_ANGULAR_MOTOR_FORCE_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT,
PARAM_ANGULAR_SPRING_STIFFNESS = PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS,
PARAM_ANGULAR_SPRING_DAMPING = PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING,
PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT = PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT,
PARAM_MAX = PhysicsServer::G6DOF_JOINT_MAX,
};
enum Flag {
FLAG_ENABLE_LINEAR_LIMIT = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT,
FLAG_ENABLE_ANGULAR_LIMIT = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT,
FLAG_ENABLE_LINEAR_SPRING = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING,
FLAG_ENABLE_ANGULAR_SPRING = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING,
FLAG_ENABLE_MOTOR = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR,
FLAG_ENABLE_LINEAR_MOTOR = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR,
FLAG_MAX = PhysicsServer::G6DOF_JOINT_FLAG_MAX
};
protected:
void _set_angular_hi_limit_x(float p_limit_angular);
float _get_angular_hi_limit_x() const;
void _set_angular_hi_limit_y(float p_limit_angular);
float _get_angular_hi_limit_y() const;
void _set_angular_hi_limit_z(float p_limit_angular);
float _get_angular_hi_limit_z() const;
void _set_angular_lo_limit_x(float p_limit_angular);
float _get_angular_lo_limit_x() const;
void _set_angular_lo_limit_y(float p_limit_angular);
float _get_angular_lo_limit_y() const;
void _set_angular_lo_limit_z(float p_limit_angular);
float _get_angular_lo_limit_z() const;
float params_x[PARAM_MAX];
bool flags_x[FLAG_MAX];
float params_y[PARAM_MAX];
bool flags_y[FLAG_MAX];
float params_z[PARAM_MAX];
bool flags_z[FLAG_MAX];
virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
static void _bind_methods();
public:
void set_param_x(Param p_param, float p_value);
float get_param_x(Param p_param) const;
void set_param_y(Param p_param, float p_value);
float get_param_y(Param p_param) const;
void set_param_z(Param p_param, float p_value);
float get_param_z(Param p_param) const;
void set_flag_x(Flag p_flag, bool p_enabled);
bool get_flag_x(Flag p_flag) const;
void set_flag_y(Flag p_flag, bool p_enabled);
bool get_flag_y(Flag p_flag) const;
void set_flag_z(Flag p_flag, bool p_enabled);
bool get_flag_z(Flag p_flag) const;
Generic6DOFJoint();
};
VARIANT_ENUM_CAST(Generic6DOFJoint::Param);
VARIANT_ENUM_CAST(Generic6DOFJoint::Flag);
#endif // PHYSICS_JOINT_H

View File

@ -1,526 +0,0 @@
/*************************************************************************/
/* ray_cast.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "ray_cast.h"
#include "collision_object.h"
#include "core/config/engine.h"
#include "mesh_instance.h"
#include "scene/resources/material/material.h"
#include "scene/resources/material/spatial_material.h"
#include "scene/resources/mesh/mesh.h"
#include "scene/resources/world_3d.h"
#include "servers/physics_server.h"
void RayCast::set_cast_to(const Vector3 &p_point) {
cast_to = p_point;
update_gizmos();
if (Engine::get_singleton()->is_editor_hint()) {
if (is_inside_tree()) {
_update_debug_shape_vertices();
}
} else if (debug_shape) {
_update_debug_shape();
}
}
Vector3 RayCast::get_cast_to() const {
return cast_to;
}
void RayCast::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
}
uint32_t RayCast::get_collision_mask() const {
return collision_mask;
}
void RayCast::set_collision_mask_bit(int p_bit, bool p_value) {
ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
} else {
mask &= ~(1 << p_bit);
}
set_collision_mask(mask);
}
bool RayCast::get_collision_mask_bit(int p_bit) const {
ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
bool RayCast::is_colliding() const {
return collided;
}
Object *RayCast::get_collider() const {
if (against == 0) {
return nullptr;
}
return ObjectDB::get_instance(against);
}
int RayCast::get_collider_shape() const {
return against_shape;
}
Vector3 RayCast::get_collision_point() const {
return collision_point;
}
Vector3 RayCast::get_collision_normal() const {
return collision_normal;
}
void RayCast::set_enabled(bool p_enabled) {
enabled = p_enabled;
update_gizmos();
if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) {
set_physics_process_internal(p_enabled);
}
if (!p_enabled) {
collided = false;
}
if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
if (p_enabled) {
_update_debug_shape();
} else {
_clear_debug_shape();
}
}
}
bool RayCast::is_enabled() const {
return enabled;
}
void RayCast::set_exclude_parent_body(bool p_exclude_parent_body) {
if (exclude_parent_body == p_exclude_parent_body) {
return;
}
exclude_parent_body = p_exclude_parent_body;
if (!is_inside_tree()) {
return;
}
if (Object::cast_to<CollisionObject>(get_parent())) {
if (exclude_parent_body) {
exclude.insert(Object::cast_to<CollisionObject>(get_parent())->get_rid());
} else {
exclude.erase(Object::cast_to<CollisionObject>(get_parent())->get_rid());
}
}
}
bool RayCast::get_exclude_parent_body() const {
return exclude_parent_body;
}
void RayCast::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
if (Engine::get_singleton()->is_editor_hint()) {
_update_debug_shape_vertices();
}
if (enabled && !Engine::get_singleton()->is_editor_hint()) {
set_physics_process_internal(true);
} else {
set_physics_process_internal(false);
}
if (get_tree()->is_debugging_collisions_hint()) {
_update_debug_shape();
}
if (Object::cast_to<CollisionObject>(get_parent())) {
if (exclude_parent_body) {
exclude.insert(Object::cast_to<CollisionObject>(get_parent())->get_rid());
} else {
exclude.erase(Object::cast_to<CollisionObject>(get_parent())->get_rid());
}
}
} break;
case NOTIFICATION_EXIT_TREE: {
if (enabled) {
set_physics_process_internal(false);
}
if (debug_shape) {
_clear_debug_shape();
}
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (!enabled) {
break;
}
bool prev_collision_state = collided;
_update_raycast_state();
if (prev_collision_state != collided && get_tree()->is_debugging_collisions_hint()) {
_update_debug_shape_material(true);
}
} break;
}
}
void RayCast::_update_raycast_state() {
Ref<World3D> w3d = get_world_3d();
ERR_FAIL_COND(w3d.is_null());
PhysicsDirectSpaceState *dss = PhysicsServer::get_singleton()->space_get_direct_state(w3d->get_space());
ERR_FAIL_COND(!dss);
Transform gt = get_global_transform();
Vector3 to = cast_to;
if (to == Vector3()) {
to = Vector3(0, 0.01, 0);
}
PhysicsDirectSpaceState::RayResult rr;
if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask, collide_with_bodies, collide_with_areas)) {
collided = true;
against = rr.collider_id;
collision_point = rr.position;
collision_normal = rr.normal;
against_shape = rr.shape;
} else {
collided = false;
against = 0;
against_shape = 0;
}
}
void RayCast::force_raycast_update() {
_update_raycast_state();
}
void RayCast::add_exception_rid(const RID &p_rid) {
exclude.insert(p_rid);
}
void RayCast::add_exception(const Object *p_object) {
ERR_FAIL_NULL(p_object);
const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
ERR_FAIL_COND_MSG(!co, "The passed Node must be an instance of CollisionObject.");
add_exception_rid(co->get_rid());
}
void RayCast::remove_exception_rid(const RID &p_rid) {
exclude.erase(p_rid);
}
void RayCast::remove_exception(const Object *p_object) {
ERR_FAIL_NULL(p_object);
const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
ERR_FAIL_COND_MSG(!co, "The passed Node must be an instance of CollisionObject.");
remove_exception_rid(co->get_rid());
}
void RayCast::clear_exceptions() {
exclude.clear();
if (exclude_parent_body && is_inside_tree()) {
CollisionObject *parent = Object::cast_to<CollisionObject>(get_parent());
if (parent) {
exclude.insert(parent->get_rid());
}
}
}
void RayCast::set_collide_with_areas(bool p_clip) {
collide_with_areas = p_clip;
}
bool RayCast::is_collide_with_areas_enabled() const {
return collide_with_areas;
}
void RayCast::set_collide_with_bodies(bool p_clip) {
collide_with_bodies = p_clip;
}
bool RayCast::is_collide_with_bodies_enabled() const {
return collide_with_bodies;
}
void RayCast::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast::is_enabled);
ClassDB::bind_method(D_METHOD("set_cast_to", "local_point"), &RayCast::set_cast_to);
ClassDB::bind_method(D_METHOD("get_cast_to"), &RayCast::get_cast_to);
ClassDB::bind_method(D_METHOD("is_colliding"), &RayCast::is_colliding);
ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast::force_raycast_update);
ClassDB::bind_method(D_METHOD("get_collider"), &RayCast::get_collider);
ClassDB::bind_method(D_METHOD("get_collider_shape"), &RayCast::get_collider_shape);
ClassDB::bind_method(D_METHOD("get_collision_point"), &RayCast::get_collision_point);
ClassDB::bind_method(D_METHOD("get_collision_normal"), &RayCast::get_collision_normal);
ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &RayCast::add_exception_rid);
ClassDB::bind_method(D_METHOD("add_exception", "node"), &RayCast::add_exception);
ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &RayCast::remove_exception_rid);
ClassDB::bind_method(D_METHOD("remove_exception", "node"), &RayCast::remove_exception);
ClassDB::bind_method(D_METHOD("clear_exceptions"), &RayCast::clear_exceptions);
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &RayCast::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &RayCast::get_collision_mask);
ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &RayCast::set_collision_mask_bit);
ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &RayCast::get_collision_mask_bit);
ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &RayCast::set_exclude_parent_body);
ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &RayCast::get_exclude_parent_body);
ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &RayCast::set_collide_with_areas);
ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &RayCast::is_collide_with_areas_enabled);
ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &RayCast::set_collide_with_bodies);
ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &RayCast::is_collide_with_bodies_enabled);
ClassDB::bind_method(D_METHOD("set_debug_shape_custom_color", "debug_shape_custom_color"), &RayCast::set_debug_shape_custom_color);
ClassDB::bind_method(D_METHOD("get_debug_shape_custom_color"), &RayCast::get_debug_shape_custom_color);
ClassDB::bind_method(D_METHOD("set_debug_shape_thickness", "debug_shape_thickness"), &RayCast::set_debug_shape_thickness);
ClassDB::bind_method(D_METHOD("get_debug_shape_thickness"), &RayCast::get_debug_shape_thickness);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cast_to"), "set_cast_to", "get_cast_to");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_GROUP("Collide With", "collide_with");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
ADD_GROUP("Debug Shape", "debug_shape");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_shape_custom_color"), "set_debug_shape_custom_color", "get_debug_shape_custom_color");
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_shape_thickness", PROPERTY_HINT_RANGE, "1,5"), "set_debug_shape_thickness", "get_debug_shape_thickness");
}
int RayCast::get_debug_shape_thickness() const {
return debug_shape_thickness;
}
void RayCast::_update_debug_shape_vertices() {
debug_shape_vertices.clear();
debug_line_vertices.clear();
if (cast_to == Vector3()) {
return;
}
debug_line_vertices.push_back(Vector3());
debug_line_vertices.push_back(cast_to);
if (debug_shape_thickness > 1) {
float scale_factor = 100.0;
Vector3 dir = Vector3(cast_to).normalized();
// Draw truncated pyramid
Vector3 normal = (fabs(dir.x) + fabs(dir.y) > CMP_EPSILON) ? Vector3(-dir.y, dir.x, 0).normalized() : Vector3(0, -dir.z, dir.y).normalized();
normal *= debug_shape_thickness / scale_factor;
int vertices_strip_order[14] = { 4, 5, 0, 1, 2, 5, 6, 4, 7, 0, 3, 2, 7, 6 };
for (int v = 0; v < 14; v++) {
Vector3 vertex = vertices_strip_order[v] < 4 ? normal : normal / 3.0 + cast_to;
debug_shape_vertices.push_back(vertex.rotated(dir, Math_PI * (0.5 * (vertices_strip_order[v] % 4) + 0.25)));
}
}
}
void RayCast::set_debug_shape_thickness(const int p_debug_shape_thickness) {
debug_shape_thickness = p_debug_shape_thickness;
update_gizmos();
if (Engine::get_singleton()->is_editor_hint()) {
if (is_inside_tree()) {
_update_debug_shape_vertices();
}
} else if (debug_shape) {
_update_debug_shape();
}
}
const Vector<Vector3> &RayCast::get_debug_shape_vertices() const {
return debug_shape_vertices;
}
const Vector<Vector3> &RayCast::get_debug_line_vertices() const {
return debug_line_vertices;
}
void RayCast::set_debug_shape_custom_color(const Color &p_color) {
debug_shape_custom_color = p_color;
if (debug_material.is_valid()) {
_update_debug_shape_material();
}
}
Ref<SpatialMaterial> RayCast::get_debug_material() {
_update_debug_shape_material();
return debug_material;
}
const Color &RayCast::get_debug_shape_custom_color() const {
return debug_shape_custom_color;
}
void RayCast::_create_debug_shape() {
_update_debug_shape_material();
Ref<ArrayMesh> mesh = memnew(ArrayMesh);
MeshInstance *mi = memnew(MeshInstance);
#ifdef TOOLS_ENABLED
// This enables the debug helper to show up in editor runs.
// However it should not show up during export, because global mode
// can slow the portal system, and this should only be used for debugging.
mi->set_portal_mode(CullInstance::PORTAL_MODE_GLOBAL);
#endif
mi->set_mesh(mesh);
add_child(mi);
debug_shape = mi;
}
void RayCast::_update_debug_shape_material(bool p_check_collision) {
if (!debug_material.is_valid()) {
Ref<SpatialMaterial> material = memnew(SpatialMaterial);
debug_material = material;
material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
// Use double-sided rendering so that the RayCast can be seen if the camera is inside.
material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
}
Color color = debug_shape_custom_color;
if (color == Color(0.0, 0.0, 0.0)) {
// Use the default debug shape color defined in the Project Settings.
color = get_tree()->get_debug_collisions_color();
}
if (p_check_collision && collided) {
if ((color.get_h() < 0.055 || color.get_h() > 0.945) && color.get_s() > 0.5 && color.get_v() > 0.5) {
// If base color is already quite reddish, highlight collision with green color
color = Color(0.0, 1.0, 0.0, color.a);
} else {
// Else, highlight collision with red color
color = Color(1.0, 0, 0, color.a);
}
}
Ref<SpatialMaterial> material = static_cast<Ref<SpatialMaterial>>(debug_material);
material->set_albedo(color);
}
void RayCast::_update_debug_shape() {
if (!enabled) {
return;
}
if (!debug_shape) {
_create_debug_shape();
}
MeshInstance *mi = static_cast<MeshInstance *>(debug_shape);
Ref<ArrayMesh> mesh = mi->get_mesh();
if (!mesh.is_valid()) {
return;
}
_update_debug_shape_vertices();
mesh->clear_surfaces();
Array a;
a.resize(Mesh::ARRAY_MAX);
uint32_t flags = 0;
int surface_count = 0;
if (!debug_line_vertices.empty()) {
a[Mesh::ARRAY_VERTEX] = debug_line_vertices;
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), flags);
mesh->surface_set_material(surface_count, debug_material);
++surface_count;
}
if (!debug_shape_vertices.empty()) {
a[Mesh::ARRAY_VERTEX] = debug_shape_vertices;
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLE_STRIP, a, Array(), flags);
mesh->surface_set_material(surface_count, debug_material);
++surface_count;
}
}
void RayCast::_clear_debug_shape() {
if (!debug_shape) {
return;
}
MeshInstance *mi = static_cast<MeshInstance *>(debug_shape);
if (mi->is_inside_tree()) {
mi->queue_delete();
} else {
memdelete(mi);
}
debug_shape = nullptr;
}
RayCast::RayCast() {
enabled = false;
against = 0;
collided = false;
against_shape = 0;
collision_mask = 1;
cast_to = Vector3(0, -1, 0);
debug_shape = nullptr;
exclude_parent_body = true;
collide_with_areas = false;
collide_with_bodies = true;
}
RayCast::~RayCast() {
}

View File

@ -1,124 +0,0 @@
#ifndef RAY_CAST_H
#define RAY_CAST_H
/*************************************************************************/
/* ray_cast.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/main/spatial.h"
class SpatialMaterial;
class RayCast : public Spatial {
GDCLASS(RayCast, Spatial);
bool enabled;
bool collided;
ObjectID against;
int against_shape;
Vector3 collision_point;
Vector3 collision_normal;
Vector3 cast_to;
RBSet<RID> exclude;
uint32_t collision_mask;
bool exclude_parent_body;
Node *debug_shape;
Ref<Material> debug_material;
Color debug_shape_custom_color = Color(0.0, 0.0, 0.0);
int debug_shape_thickness = 2;
Vector<Vector3> debug_shape_vertices;
Vector<Vector3> debug_line_vertices;
void _create_debug_shape();
void _update_debug_shape();
void _update_debug_shape_material(bool p_check_collision = false);
void _update_debug_shape_vertices();
void _clear_debug_shape();
bool collide_with_areas;
bool collide_with_bodies;
protected:
void _notification(int p_what);
void _update_raycast_state();
static void _bind_methods();
public:
void set_collide_with_areas(bool p_clip);
bool is_collide_with_areas_enabled() const;
void set_collide_with_bodies(bool p_clip);
bool is_collide_with_bodies_enabled() const;
void set_enabled(bool p_enabled);
bool is_enabled() const;
void set_cast_to(const Vector3 &p_point);
Vector3 get_cast_to() const;
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) const;
void set_exclude_parent_body(bool p_exclude_parent_body);
bool get_exclude_parent_body() const;
const Color &get_debug_shape_custom_color() const;
void set_debug_shape_custom_color(const Color &p_color);
const Vector<Vector3> &get_debug_shape_vertices() const;
const Vector<Vector3> &get_debug_line_vertices() const;
Ref<SpatialMaterial> get_debug_material();
int get_debug_shape_thickness() const;
void set_debug_shape_thickness(const int p_debug_thickness);
void force_raycast_update();
bool is_colliding() const;
Object *get_collider() const;
int get_collider_shape() const;
Vector3 get_collision_point() const;
Vector3 get_collision_normal() 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();
RayCast();
~RayCast();
};
#endif // RAY_CAST_H

View File

@ -1,638 +0,0 @@
/*************************************************************************/
/* shape_cast.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "shape_cast.h"
#include "collision_object.h"
#include "core/config/engine.h"
#include "mesh_instance.h"
#include "scene/resources/shapes/concave_polygon_shape.h"
#include "scene/resources/material/material.h"
#include "scene/resources/material/spatial_material.h"
#include "scene/resources/mesh/mesh.h"
#include "scene/resources/world_3d.h"
void ShapeCast::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
if (Engine::get_singleton()->is_editor_hint()) {
_update_debug_shape_vertices();
}
if (enabled && !Engine::get_singleton()->is_editor_hint()) {
set_physics_process_internal(true);
} else {
set_physics_process_internal(false);
}
if (get_tree()->is_debugging_collisions_hint()) {
_update_debug_shape();
}
if (Object::cast_to<CollisionObject>(get_parent())) {
if (exclude_parent_body) {
exclude.insert(Object::cast_to<CollisionObject>(get_parent())->get_rid());
} else {
exclude.erase(Object::cast_to<CollisionObject>(get_parent())->get_rid());
}
}
} break;
case NOTIFICATION_EXIT_TREE: {
if (enabled) {
set_physics_process_internal(false);
}
if (debug_shape) {
_clear_debug_shape();
}
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (!enabled) {
break;
}
bool prev_collision_state = collided;
_update_shapecast_state();
if (get_tree()->is_debugging_collisions_hint()) {
if (prev_collision_state != collided) {
_update_debug_shape_material(true);
}
if (collided) {
_update_debug_shape();
}
if (prev_collision_state == collided && !collided) {
_update_debug_shape();
}
}
} break;
}
}
void ShapeCast::_bind_methods() {
ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &ShapeCast::resource_changed);
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &ShapeCast::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &ShapeCast::is_enabled);
ClassDB::bind_method(D_METHOD("set_shape", "shape"), &ShapeCast::set_shape);
ClassDB::bind_method(D_METHOD("get_shape"), &ShapeCast::get_shape);
ClassDB::bind_method(D_METHOD("set_target_position", "local_point"), &ShapeCast::set_target_position);
ClassDB::bind_method(D_METHOD("get_target_position"), &ShapeCast::get_target_position);
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &ShapeCast::set_margin);
ClassDB::bind_method(D_METHOD("get_margin"), &ShapeCast::get_margin);
ClassDB::bind_method(D_METHOD("set_max_results", "max_results"), &ShapeCast::set_max_results);
ClassDB::bind_method(D_METHOD("get_max_results"), &ShapeCast::get_max_results);
ClassDB::bind_method(D_METHOD("is_colliding"), &ShapeCast::is_colliding);
ClassDB::bind_method(D_METHOD("get_collision_count"), &ShapeCast::get_collision_count);
ClassDB::bind_method(D_METHOD("force_shapecast_update"), &ShapeCast::force_shapecast_update);
ClassDB::bind_method(D_METHOD("get_collider", "index"), &ShapeCast::get_collider);
ClassDB::bind_method(D_METHOD("get_collider_rid", "index"), &ShapeCast::get_collider_rid);
ClassDB::bind_method(D_METHOD("get_collider_shape", "index"), &ShapeCast::get_collider_shape);
ClassDB::bind_method(D_METHOD("get_collision_point", "index"), &ShapeCast::get_collision_point);
ClassDB::bind_method(D_METHOD("get_collision_normal", "index"), &ShapeCast::get_collision_normal);
ClassDB::bind_method(D_METHOD("get_closest_collision_safe_fraction"), &ShapeCast::get_closest_collision_safe_fraction);
ClassDB::bind_method(D_METHOD("get_closest_collision_unsafe_fraction"), &ShapeCast::get_closest_collision_unsafe_fraction);
ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &ShapeCast::add_exception_rid);
ClassDB::bind_method(D_METHOD("add_exception", "node"), &ShapeCast::add_exception);
ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &ShapeCast::remove_exception_rid);
ClassDB::bind_method(D_METHOD("remove_exception", "node"), &ShapeCast::remove_exception);
ClassDB::bind_method(D_METHOD("clear_exceptions"), &ShapeCast::clear_exceptions);
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ShapeCast::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &ShapeCast::get_collision_mask);
ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &ShapeCast::set_collision_mask_value);
ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &ShapeCast::get_collision_mask_value);
ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &ShapeCast::set_exclude_parent_body);
ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &ShapeCast::get_exclude_parent_body);
ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &ShapeCast::set_collide_with_areas);
ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &ShapeCast::is_collide_with_areas_enabled);
ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &ShapeCast::set_collide_with_bodies);
ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &ShapeCast::is_collide_with_bodies_enabled);
ClassDB::bind_method(D_METHOD("_get_collision_result"), &ShapeCast::_get_collision_result);
ClassDB::bind_method(D_METHOD("set_debug_shape_custom_color", "debug_shape_custom_color"), &ShapeCast::set_debug_shape_custom_color);
ClassDB::bind_method(D_METHOD("get_debug_shape_custom_color"), &ShapeCast::get_debug_shape_custom_color);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position", PROPERTY_HINT_NONE), "set_target_position", "get_target_position");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_results"), "set_max_results", "get_max_results");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "collision_result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE), "", "_get_collision_result");
ADD_GROUP("Collide With", "collide_with");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
ADD_GROUP("Debug Shape", "debug_shape");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_shape_custom_color"), "set_debug_shape_custom_color", "get_debug_shape_custom_color");
}
String ShapeCast::get_configuration_warning() const {
String warning = Spatial::get_configuration_warning();
if (shape.is_null()) {
if (warning != String()) {
warning += "\n\n";
}
warning += TTR("This node cannot interact with other objects unless a Shape is assigned.");
}
if (shape.is_valid() && Object::cast_to<ConcavePolygonShape>(*shape)) {
if (warning != String()) {
warning += "\n\n";
}
warning += TTR("ShapeCast does not support ConcavePolygonShapes. Collisions will not be reported.");
}
return warning;
}
void ShapeCast::set_enabled(bool p_enabled) {
enabled = p_enabled;
update_gizmos();
if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) {
set_physics_process_internal(p_enabled);
}
if (!p_enabled) {
collided = false;
}
if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
if (p_enabled) {
_update_debug_shape();
} else {
_clear_debug_shape();
}
}
}
bool ShapeCast::is_enabled() const {
return enabled;
}
void ShapeCast::set_target_position(const Vector3 &p_point) {
target_position = p_point;
if (is_inside_tree()) {
_update_debug_shape();
}
update_gizmos();
if (Engine::get_singleton()->is_editor_hint()) {
if (is_inside_tree()) {
_update_debug_shape_vertices();
}
} else if (debug_shape) {
_update_debug_shape();
}
}
Vector3 ShapeCast::get_target_position() const {
return target_position;
}
void ShapeCast::set_margin(real_t p_margin) {
margin = p_margin;
}
real_t ShapeCast::get_margin() const {
return margin;
}
void ShapeCast::set_max_results(int p_max_results) {
max_results = p_max_results;
}
int ShapeCast::get_max_results() const {
return max_results;
}
void ShapeCast::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
}
uint32_t ShapeCast::get_collision_mask() const {
return collision_mask;
}
void ShapeCast::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 ShapeCast::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));
}
int ShapeCast::get_collision_count() const {
return result.size();
}
bool ShapeCast::is_colliding() const {
return collided;
}
Object *ShapeCast::get_collider(int p_idx) const {
ERR_FAIL_INDEX_V_MSG(p_idx, result.size(), nullptr, "No collider found.");
if (result[p_idx].collider_id == 0) {
return nullptr;
}
return ObjectDB::get_instance(result[p_idx].collider_id);
}
RID ShapeCast::get_collider_rid(int p_idx) const {
ERR_FAIL_INDEX_V_MSG(p_idx, result.size(), RID(), "No collider RID found.");
return result[p_idx].rid;
}
int ShapeCast::get_collider_shape(int p_idx) const {
ERR_FAIL_INDEX_V_MSG(p_idx, result.size(), -1, "No collider shape found.");
return result[p_idx].shape;
}
Vector3 ShapeCast::get_collision_point(int p_idx) const {
ERR_FAIL_INDEX_V_MSG(p_idx, result.size(), Vector3(), "No collision point found.");
return result[p_idx].point;
}
Vector3 ShapeCast::get_collision_normal(int p_idx) const {
ERR_FAIL_INDEX_V_MSG(p_idx, result.size(), Vector3(), "No collision normal found.");
return result[p_idx].normal;
}
real_t ShapeCast::get_closest_collision_safe_fraction() const {
return collision_safe_fraction;
}
real_t ShapeCast::get_closest_collision_unsafe_fraction() const {
return collision_unsafe_fraction;
}
void ShapeCast::resource_changed(Ref<Resource> p_res) {
if (is_inside_tree()) {
_update_debug_shape();
}
update_gizmos();
}
void ShapeCast::set_shape(const Ref<Shape> &p_shape) {
if (p_shape == shape) {
return;
}
if (!shape.is_null()) {
shape->unregister_owner(this);
}
shape = p_shape;
if (!shape.is_null()) {
shape->register_owner(this);
}
if (p_shape.is_valid()) {
shape_rid = shape->get_rid();
}
if (is_inside_tree()) {
_update_debug_shape();
}
update_gizmos();
update_configuration_warning();
}
Ref<Shape> ShapeCast::get_shape() const {
return shape;
}
void ShapeCast::set_exclude_parent_body(bool p_exclude_parent_body) {
if (exclude_parent_body == p_exclude_parent_body) {
return;
}
exclude_parent_body = p_exclude_parent_body;
if (!is_inside_tree()) {
return;
}
if (Object::cast_to<CollisionObject>(get_parent())) {
if (exclude_parent_body) {
exclude.insert(Object::cast_to<CollisionObject>(get_parent())->get_rid());
} else {
exclude.erase(Object::cast_to<CollisionObject>(get_parent())->get_rid());
}
}
}
bool ShapeCast::get_exclude_parent_body() const {
return exclude_parent_body;
}
void ShapeCast::_update_shapecast_state() {
result.clear();
ERR_FAIL_COND_MSG(shape.is_null(), "Null reference to shape. ShapeCast requires a Shape3D to sweep for collisions.");
Ref<World3D> w3d = get_world_3d();
ERR_FAIL_COND(w3d.is_null());
PhysicsDirectSpaceState *dss = PhysicsServer::get_singleton()->space_get_direct_state(w3d->get_space());
ERR_FAIL_COND(!dss);
Transform gt = get_global_transform();
collision_safe_fraction = 0.0;
collision_unsafe_fraction = 0.0;
if (target_position != Vector3()) {
dss->cast_motion(shape_rid, gt, target_position, margin, collision_safe_fraction, collision_unsafe_fraction, exclude, collision_mask, collide_with_bodies, collide_with_areas);
if (collision_unsafe_fraction < 1.0) {
// Move shape transform to the point of impact,
// so we can collect contact info at that point.
gt.set_origin(gt.get_origin() + target_position * (collision_unsafe_fraction + CMP_EPSILON));
}
}
// Regardless of whether the shape is stuck or it's moved along
// the motion vector, we'll only consider static collisions from now on.
bool intersected = true;
RBSet<RID> intersected_objects = exclude;
while (intersected && result.size() < max_results) {
PhysicsDirectSpaceState::ShapeRestInfo info;
intersected = dss->rest_info(shape_rid, gt, margin, &info, intersected_objects, collision_mask, collide_with_bodies, collide_with_areas);
if (intersected) {
result.push_back(info);
intersected_objects.insert(info.rid);
}
}
collided = !result.empty();
}
void ShapeCast::force_shapecast_update() {
_update_shapecast_state();
}
void ShapeCast::add_exception_rid(const RID &p_rid) {
exclude.insert(p_rid);
}
void ShapeCast::add_exception(const Object *p_object) {
ERR_FAIL_NULL(p_object);
const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
ERR_FAIL_COND_MSG(!co, "The passed Node must be an instance of CollisionObject.");
add_exception_rid(co->get_rid());
}
void ShapeCast::remove_exception_rid(const RID &p_rid) {
exclude.erase(p_rid);
}
void ShapeCast::remove_exception(const Object *p_object) {
ERR_FAIL_NULL(p_object);
const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
ERR_FAIL_COND_MSG(!co, "The passed Node must be an instance of CollisionObject.");
remove_exception_rid(co->get_rid());
}
void ShapeCast::clear_exceptions() {
exclude.clear();
}
void ShapeCast::set_collide_with_areas(bool p_clip) {
collide_with_areas = p_clip;
}
bool ShapeCast::is_collide_with_areas_enabled() const {
return collide_with_areas;
}
void ShapeCast::set_collide_with_bodies(bool p_clip) {
collide_with_bodies = p_clip;
}
bool ShapeCast::is_collide_with_bodies_enabled() const {
return collide_with_bodies;
}
Array ShapeCast::_get_collision_result() const {
Array ret;
for (int i = 0; i < result.size(); ++i) {
const PhysicsDirectSpaceState::ShapeRestInfo &sri = result[i];
Dictionary col;
col["point"] = sri.point;
col["normal"] = sri.normal;
col["rid"] = sri.rid;
col["collider"] = ObjectDB::get_instance(sri.collider_id);
col["collider_id"] = sri.collider_id;
col["shape"] = sri.shape;
col["linear_velocity"] = sri.linear_velocity;
ret.push_back(col);
}
return ret;
}
void ShapeCast::_update_debug_shape_vertices() {
debug_shape_vertices.clear();
debug_line_vertices.clear();
if (!shape.is_null()) {
debug_shape_vertices.append_array(shape->get_debug_mesh_lines());
for (int i = 0; i < debug_shape_vertices.size(); i++) {
debug_shape_vertices.set(i, debug_shape_vertices[i] + Vector3(target_position * get_closest_collision_safe_fraction()));
}
}
if (target_position == Vector3()) {
return;
}
debug_line_vertices.push_back(Vector3());
debug_line_vertices.push_back(target_position);
}
const Vector<Vector3> &ShapeCast::get_debug_shape_vertices() const {
return debug_shape_vertices;
}
const Vector<Vector3> &ShapeCast::get_debug_line_vertices() const {
return debug_line_vertices;
}
void ShapeCast::set_debug_shape_custom_color(const Color &p_color) {
debug_shape_custom_color = p_color;
if (debug_material.is_valid()) {
_update_debug_shape_material();
}
}
Ref<SpatialMaterial> ShapeCast::get_debug_material() {
_update_debug_shape_material();
return debug_material;
}
const Color &ShapeCast::get_debug_shape_custom_color() const {
return debug_shape_custom_color;
}
void ShapeCast::_create_debug_shape() {
_update_debug_shape_material();
Ref<ArrayMesh> mesh = memnew(ArrayMesh);
MeshInstance *mi = memnew(MeshInstance);
mi->set_mesh(mesh);
add_child(mi);
debug_shape = mi;
}
void ShapeCast::_update_debug_shape_material(bool p_check_collision) {
if (!debug_material.is_valid()) {
Ref<SpatialMaterial> material = memnew(SpatialMaterial);
debug_material = material;
material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
// Use double-sided rendering so that the RayCast can be seen if the camera is inside.
material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
}
Color color = debug_shape_custom_color;
if (color == Color(0.0, 0.0, 0.0)) {
// Use the default debug shape color defined in the Project Settings.
color = get_tree()->get_debug_collisions_color();
}
if (p_check_collision && collided) {
if ((color.get_h() < 0.055 || color.get_h() > 0.945) && color.get_s() > 0.5 && color.get_v() > 0.5) {
// If base color is already quite reddish, highlight collision with green color
color = Color(0.0, 1.0, 0.0, color.a);
} else {
// Else, highlight collision with red color
color = Color(1.0, 0, 0, color.a);
}
}
Ref<SpatialMaterial> material = static_cast<Ref<SpatialMaterial>>(debug_material);
material->set_albedo(color);
}
void ShapeCast::_update_debug_shape() {
if (!enabled) {
return;
}
if (!debug_shape) {
_create_debug_shape();
}
_update_debug_shape_vertices();
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
MeshInstance *mi = static_cast<MeshInstance *>(debug_shape);
Ref<ArrayMesh> mesh = mi->get_mesh();
if (!mesh.is_valid()) {
return;
}
mesh->clear_surfaces();
Array a;
a.resize(Mesh::ARRAY_MAX);
uint32_t flags = 0;
int surface_count = 0;
if (!debug_shape_vertices.empty()) {
a[Mesh::ARRAY_VERTEX] = debug_shape_vertices;
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), flags);
mesh->surface_set_material(surface_count, debug_material);
++surface_count;
}
if (!debug_line_vertices.empty()) {
a[Mesh::ARRAY_VERTEX] = debug_line_vertices;
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), flags);
mesh->surface_set_material(surface_count, debug_material);
++surface_count;
}
}
void ShapeCast::_clear_debug_shape() {
if (!debug_shape) {
return;
}
MeshInstance *mi = static_cast<MeshInstance *>(debug_shape);
if (mi->is_inside_tree()) {
mi->queue_delete();
} else {
memdelete(mi);
}
debug_shape = nullptr;
}
ShapeCast::~ShapeCast() {
if (!shape.is_null()) {
shape->unregister_owner(this);
}
}

View File

@ -1,148 +0,0 @@
/*************************************************************************/
/* shape_cast.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef SHAPE_CAST_H
#define SHAPE_CAST_H
#include "core/math/color.h"
#include "scene/main/spatial.h"
#include "scene/resources/shapes/shape.h"
#include "servers/physics_server.h"
class SpatialMaterial;
class ShapeCast : public Spatial {
GDCLASS(ShapeCast, Spatial);
bool enabled = true;
void resource_changed(Ref<Resource> p_res);
Ref<Shape> shape;
RID shape_rid;
Vector3 target_position = Vector3(0, -1, 0);
RBSet<RID> exclude;
real_t margin = 0.0;
uint32_t collision_mask = 1;
bool exclude_parent_body = true;
bool collide_with_areas = false;
bool collide_with_bodies = true;
Node *debug_shape = nullptr;
Ref<Material> debug_material;
Color debug_shape_custom_color = Color(0.0, 0.0, 0.0);
Vector<Vector3> debug_shape_vertices;
Vector<Vector3> debug_line_vertices;
void _create_debug_shape();
void _update_debug_shape();
void _update_debug_shape_material(bool p_check_collision = false);
void _update_debug_shape_vertices();
void _clear_debug_shape();
// Result
int max_results = 32;
Vector<PhysicsDirectSpaceState::ShapeRestInfo> result;
bool collided = false;
real_t collision_safe_fraction = 1.0;
real_t collision_unsafe_fraction = 1.0;
Array _get_collision_result() const;
~ShapeCast();
protected:
void _notification(int p_what);
void _update_shapecast_state();
static void _bind_methods();
public:
void set_collide_with_areas(bool p_clip);
bool is_collide_with_areas_enabled() const;
void set_collide_with_bodies(bool p_clip);
bool is_collide_with_bodies_enabled() const;
void set_enabled(bool p_enabled);
bool is_enabled() const;
void set_shape(const Ref<Shape> &p_shape);
Ref<Shape> get_shape() const;
void set_target_position(const Vector3 &p_point);
Vector3 get_target_position() const;
void set_margin(real_t p_margin);
real_t get_margin() const;
void set_max_results(int p_max_results);
int get_max_results() 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 set_exclude_parent_body(bool p_exclude_parent_body);
bool get_exclude_parent_body() const;
const Color &get_debug_shape_custom_color() const;
void set_debug_shape_custom_color(const Color &p_color);
const Vector<Vector3> &get_debug_shape_vertices() const;
const Vector<Vector3> &get_debug_line_vertices() const;
Ref<SpatialMaterial> get_debug_material();
int get_collision_count() const;
Object *get_collider(int p_idx) const;
RID get_collider_rid(int p_idx) const;
int get_collider_shape(int p_idx) const;
Vector3 get_collision_point(int p_idx) const;
Vector3 get_collision_normal(int p_idx) const;
real_t get_closest_collision_safe_fraction() const;
real_t get_closest_collision_unsafe_fraction() const;
void force_shapecast_update();
bool is_colliding() 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();
virtual String get_configuration_warning() const;
};
#endif // SHAPE_CAST_H

View File

@ -1,856 +0,0 @@
/*************************************************************************/
/* soft_body.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "soft_body.h"
#include "core/containers/list.h"
#include "core/object/object.h"
#include "core/os/os.h"
#include "core/containers/rid.h"
#include "scene/3d/collision_object.h"
#include "scene/3d/physics_body.h"
#include "scene/resources/mesh/mesh.h"
#include "scene/resources/world_3d.h"
#include "servers/physics_server.h"
SoftBodyRenderingServerHandler::SoftBodyRenderingServerHandler() {}
void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
clear();
ERR_FAIL_COND(!p_mesh.is_valid());
mesh = p_mesh;
surface = p_surface;
const uint32_t surface_format = RS::get_singleton()->mesh_surface_get_format(mesh, surface);
const int surface_vertex_len = RS::get_singleton()->mesh_surface_get_array_len(mesh, p_surface);
const int surface_index_len = RS::get_singleton()->mesh_surface_get_array_index_len(mesh, p_surface);
uint32_t surface_offsets[RS::ARRAY_MAX];
uint32_t surface_strides[RS::ARRAY_MAX];
buffer = RS::get_singleton()->mesh_surface_get_array(mesh, surface);
RS::get_singleton()->mesh_surface_make_offsets_from_format(surface_format, surface_vertex_len, surface_index_len, surface_offsets, surface_strides);
ERR_FAIL_COND(surface_strides[RS::ARRAY_VERTEX] != surface_strides[RS::ARRAY_NORMAL]);
stride = surface_strides[RS::ARRAY_VERTEX];
offset_vertices = surface_offsets[RS::ARRAY_VERTEX];
offset_normal = surface_offsets[RS::ARRAY_NORMAL];
}
void SoftBodyRenderingServerHandler::clear() {
if (mesh.is_valid()) {
buffer.resize(0);
}
mesh = RID();
}
void SoftBodyRenderingServerHandler::open() {
write_buffer = buffer.write();
}
void SoftBodyRenderingServerHandler::close() {
write_buffer.release();
}
void SoftBodyRenderingServerHandler::commit_changes() {
RS::get_singleton()->mesh_surface_update_region(mesh, surface, 0, buffer);
}
void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
memcpy(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
}
void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
Vector2 normal_oct = RenderingServer::get_singleton()->norm_to_oct(*(Vector3 *)p_vector3);
int16_t v_normal[2] = {
(int16_t)CLAMP(normal_oct.x * 32767, -32768, 32767),
(int16_t)CLAMP(normal_oct.y * 32767, -32768, 32767),
};
memcpy(&write_buffer[p_vertex_id * stride + offset_normal], v_normal, sizeof(uint16_t) * 2);
}
void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
RS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb);
}
SoftBody::PinnedPoint::PinnedPoint() :
point_index(-1),
spatial_attachment(nullptr) {
}
SoftBody::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
point_index = obj_tocopy.point_index;
spatial_attachment_path = obj_tocopy.spatial_attachment_path;
spatial_attachment = obj_tocopy.spatial_attachment;
offset = obj_tocopy.offset;
}
SoftBody::PinnedPoint SoftBody::PinnedPoint::operator=(const PinnedPoint &obj) {
point_index = obj.point_index;
spatial_attachment_path = obj.spatial_attachment_path;
spatial_attachment = obj.spatial_attachment;
offset = obj.offset;
return *this;
}
void SoftBody::_update_pickable() {
if (!is_inside_tree()) {
return;
}
bool pickable = ray_pickable && is_visible_in_tree();
PhysicsServer::get_singleton()->soft_body_set_ray_pickable(physics_rid, pickable);
}
bool SoftBody::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
String which = name.get_slicec('/', 0);
if ("pinned_points" == which) {
return _set_property_pinned_points_indices(p_value);
} else if ("attachments" == which) {
int idx = name.get_slicec('/', 1).to_int();
String what = name.get_slicec('/', 2);
return _set_property_pinned_points_attachment(idx, what, p_value);
}
return false;
}
bool SoftBody::_get(const StringName &p_name, Variant &r_ret) const {
String name = p_name;
String which = name.get_slicec('/', 0);
if ("pinned_points" == which) {
Array arr_ret;
const int pinned_points_indices_size = pinned_points.size();
PoolVector<PinnedPoint>::Read r = pinned_points.read();
arr_ret.resize(pinned_points_indices_size);
for (int i = 0; i < pinned_points_indices_size; ++i) {
arr_ret[i] = r[i].point_index;
}
r_ret = arr_ret;
return true;
} else if ("attachments" == which) {
int idx = name.get_slicec('/', 1).to_int();
String what = name.get_slicec('/', 2);
return _get_property_pinned_points(idx, what, r_ret);
}
return false;
}
void SoftBody::_get_property_list(List<PropertyInfo> *p_list) const {
const int pinned_points_indices_size = pinned_points.size();
p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "pinned_points"));
for (int i = 0; i < pinned_points_indices_size; ++i) {
p_list->push_back(PropertyInfo(Variant::INT, "attachments/" + itos(i) + "/point_index"));
p_list->push_back(PropertyInfo(Variant::NODE_PATH, "attachments/" + itos(i) + "/spatial_attachment_path"));
p_list->push_back(PropertyInfo(Variant::VECTOR3, "attachments/" + itos(i) + "/offset"));
}
}
bool SoftBody::_set_property_pinned_points_indices(const Array &p_indices) {
const int p_indices_size = p_indices.size();
{ // Remove the pined points on physics server that will be removed by resize
PoolVector<PinnedPoint>::Read r = pinned_points.read();
if (p_indices_size < pinned_points.size()) {
for (int i = pinned_points.size() - 1; i >= p_indices_size; --i) {
pin_point(r[i].point_index, false);
}
}
}
pinned_points.resize(p_indices_size);
PoolVector<PinnedPoint>::Write w = pinned_points.write();
int point_index;
for (int i = 0; i < p_indices_size; ++i) {
point_index = p_indices.get(i);
if (w[i].point_index != point_index) {
if (-1 != w[i].point_index) {
pin_point(w[i].point_index, false);
}
w[i].point_index = point_index;
pin_point(w[i].point_index, true);
}
}
return true;
}
bool SoftBody::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) {
if (pinned_points.size() <= p_item) {
return false;
}
if ("spatial_attachment_path" == p_what) {
PoolVector<PinnedPoint>::Write w = pinned_points.write();
pin_point(w[p_item].point_index, true, p_value);
_make_cache_dirty();
} else if ("offset" == p_what) {
PoolVector<PinnedPoint>::Write w = pinned_points.write();
w[p_item].offset = p_value;
} else {
return false;
}
return true;
}
bool SoftBody::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const {
if (pinned_points.size() <= p_item) {
return false;
}
PoolVector<PinnedPoint>::Read r = pinned_points.read();
if ("point_index" == p_what) {
r_ret = r[p_item].point_index;
} else if ("spatial_attachment_path" == p_what) {
r_ret = r[p_item].spatial_attachment_path;
} else if ("offset" == p_what) {
r_ret = r[p_item].offset;
} else {
return false;
}
return true;
}
void SoftBody::_changed_callback(Object *p_changed, const char *p_prop) {
_prepare_physics_server();
_reset_points_offsets();
#ifdef TOOLS_ENABLED
if (p_changed == this) {
update_configuration_warning();
}
#endif
}
void SoftBody::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_WORLD: {
if (Engine::get_singleton()->is_editor_hint()) {
add_change_receptor(this);
}
RID space = get_world_3d()->get_space();
PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, space);
_prepare_physics_server();
} break;
case NOTIFICATION_READY: {
if (!parent_collision_ignore.is_empty()) {
add_collision_exception_with(get_node(parent_collision_ignore));
}
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
if (Engine::get_singleton()->is_editor_hint()) {
_reset_points_offsets();
return;
}
PhysicsServer::get_singleton()->soft_body_set_transform(physics_rid, get_global_transform());
set_notify_transform(false);
// Required to be top level with Transform at center of world in order to modify RenderingServer only to support custom Transform
set_as_toplevel(true);
set_transform(Transform());
set_notify_transform(true);
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
_update_pickable();
} break;
case NOTIFICATION_EXIT_WORLD: {
PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, RID());
} break;
}
#ifdef TOOLS_ENABLED
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (Engine::get_singleton()->is_editor_hint()) {
update_configuration_warning();
}
}
#endif
}
void SoftBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("_draw_soft_mesh"), &SoftBody::_draw_soft_mesh);
ClassDB::bind_method(D_METHOD("set_physics_enabled", "enabled"), &SoftBody::set_physics_enabled);
ClassDB::bind_method(D_METHOD("is_physics_enabled"), &SoftBody::is_physics_enabled);
ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody::get_collision_mask);
ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftBody::set_collision_layer);
ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftBody::get_collision_layer);
ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &SoftBody::set_collision_mask_bit);
ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &SoftBody::get_collision_mask_bit);
ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &SoftBody::set_collision_layer_bit);
ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &SoftBody::get_collision_layer_bit);
ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody::set_parent_collision_ignore);
ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody::get_parent_collision_ignore);
ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &SoftBody::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody::add_collision_exception_with);
ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody::remove_collision_exception_with);
ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftBody::set_simulation_precision);
ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftBody::get_simulation_precision);
ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftBody::set_total_mass);
ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftBody::get_total_mass);
ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftBody::set_linear_stiffness);
ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftBody::get_linear_stiffness);
ClassDB::bind_method(D_METHOD("set_areaAngular_stiffness", "areaAngular_stiffness"), &SoftBody::set_areaAngular_stiffness);
ClassDB::bind_method(D_METHOD("get_areaAngular_stiffness"), &SoftBody::get_areaAngular_stiffness);
ClassDB::bind_method(D_METHOD("set_volume_stiffness", "volume_stiffness"), &SoftBody::set_volume_stiffness);
ClassDB::bind_method(D_METHOD("get_volume_stiffness"), &SoftBody::get_volume_stiffness);
ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftBody::set_pressure_coefficient);
ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftBody::get_pressure_coefficient);
ClassDB::bind_method(D_METHOD("set_pose_matching_coefficient", "pose_matching_coefficient"), &SoftBody::set_pose_matching_coefficient);
ClassDB::bind_method(D_METHOD("get_pose_matching_coefficient"), &SoftBody::get_pose_matching_coefficient);
ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftBody::set_damping_coefficient);
ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftBody::get_damping_coefficient);
ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftBody::set_drag_coefficient);
ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftBody::get_drag_coefficient);
ClassDB::bind_method(D_METHOD("get_point_transform", "point_index"), &SoftBody::get_point_transform);
ClassDB::bind_method(D_METHOD("set_point_pinned", "point_index", "pinned", "attachment_path"), &SoftBody::pin_point, DEFVAL(NodePath()));
ClassDB::bind_method(D_METHOD("is_point_pinned", "point_index"), &SoftBody::is_point_pinned);
ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftBody::set_ray_pickable);
ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftBody::is_ray_pickable);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_enabled"), "set_physics_enabled", "is_physics_enabled");
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "parent_collision_ignore", PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE, "Parent collision object"), "set_parent_collision_ignore", "get_parent_collision_ignore");
ADD_PROPERTY(PropertyInfo(Variant::INT, "simulation_precision", PROPERTY_HINT_RANGE, "1,100,1"), "set_simulation_precision", "get_simulation_precision");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "total_mass", PROPERTY_HINT_RANGE, "0.01,10000,1"), "set_total_mass", "get_total_mass");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_linear_stiffness", "get_linear_stiffness");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "areaAngular_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_areaAngular_stiffness", "get_areaAngular_stiffness");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_volume_stiffness", "get_volume_stiffness");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "pressure_coefficient"), "set_pressure_coefficient", "get_pressure_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "damping_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_damping_coefficient", "get_damping_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "pose_matching_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_pose_matching_coefficient", "get_pose_matching_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable");
}
String SoftBody::get_configuration_warning() const {
String warning = MeshInstance::get_configuration_warning();
if (mesh.is_null()) {
if (!warning.empty()) {
warning += "\n\n";
}
warning += TTR("This body will be ignored until you set a mesh.");
}
Transform t = get_transform();
if ((ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) {
if (!warning.empty()) {
warning += "\n\n";
}
warning += TTR("Size changes to SoftBody will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
}
return warning;
}
void SoftBody::_update_physics_server() {
if (!simulation_started) {
return;
}
_update_cache_pin_points_datas();
// Submit bone attachment
const int pinned_points_indices_size = pinned_points.size();
PoolVector<PinnedPoint>::Read r = pinned_points.read();
for (int i = 0; i < pinned_points_indices_size; ++i) {
if (r[i].spatial_attachment) {
PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, r[i].spatial_attachment->get_global_transform().xform(r[i].offset));
}
}
}
void SoftBody::_draw_soft_mesh() {
if (mesh.is_null()) {
return;
}
RID mesh_rid = mesh->get_rid();
if (owned_mesh != mesh_rid) {
_become_mesh_owner();
mesh_rid = mesh->get_rid();
PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, mesh);
}
if (!rendering_server_handler.is_ready(mesh_rid)) {
rendering_server_handler.prepare(mesh_rid, 0);
/// Necessary in order to render the mesh correctly (Soft body nodes are in global space)
simulation_started = true;
call_deferred("set_as_toplevel", true);
call_deferred("set_transform", Transform());
}
_update_physics_server();
rendering_server_handler.open();
PhysicsServer::get_singleton()->soft_body_update_rendering_server(physics_rid, &rendering_server_handler);
rendering_server_handler.close();
rendering_server_handler.commit_changes();
}
void SoftBody::_prepare_physics_server() {
if (Engine::get_singleton()->is_editor_hint()) {
if (mesh.is_valid()) {
PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, mesh);
} else {
PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, nullptr);
}
return;
}
if (mesh.is_valid() && physics_enabled) {
if (owned_mesh != mesh->get_rid()) {
_become_mesh_owner();
}
PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, mesh);
RS::get_singleton()->connect("frame_pre_draw", this, "_draw_soft_mesh");
} else {
PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, nullptr);
if (RS::get_singleton()->is_connected("frame_pre_draw", this, "_draw_soft_mesh")) {
RS::get_singleton()->disconnect("frame_pre_draw", this, "_draw_soft_mesh");
}
}
}
void SoftBody::_become_mesh_owner() {
Vector<Ref<Material>> copy_materials;
copy_materials.append_array(materials);
ERR_FAIL_COND(!mesh->get_surface_count());
// Get current mesh array and create new mesh array with necessary flag for softbody
Array surface_arrays = mesh->surface_get_arrays(0);
Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0);
uint32_t surface_format = mesh->surface_get_format(0);
surface_format &= ~(Mesh::ARRAY_COMPRESS_VERTEX | Mesh::ARRAY_COMPRESS_NORMAL);
surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
Ref<ArrayMesh> soft_mesh;
soft_mesh.instance();
soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_format);
soft_mesh->surface_set_material(0, mesh->surface_get_material(0));
set_mesh(soft_mesh);
for (int i = copy_materials.size() - 1; 0 <= i; --i) {
set_surface_material(i, copy_materials[i]);
}
owned_mesh = soft_mesh->get_rid();
}
void SoftBody::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
PhysicsServer::get_singleton()->soft_body_set_collision_mask(physics_rid, p_mask);
}
uint32_t SoftBody::get_collision_mask() const {
return collision_mask;
}
void SoftBody::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
PhysicsServer::get_singleton()->soft_body_set_collision_layer(physics_rid, p_layer);
}
uint32_t SoftBody::get_collision_layer() const {
return collision_layer;
}
void SoftBody::set_collision_mask_bit(int p_bit, bool p_value) {
ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
} else {
mask &= ~(1 << p_bit);
}
set_collision_mask(mask);
}
bool SoftBody::get_collision_mask_bit(int p_bit) const {
ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
void SoftBody::set_collision_layer_bit(int p_bit, bool p_value) {
ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
uint32_t layer = get_collision_layer();
if (p_value) {
layer |= 1 << p_bit;
} else {
layer &= ~(1 << p_bit);
}
set_collision_layer(layer);
}
bool SoftBody::get_collision_layer_bit(int p_bit) const {
ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
return get_collision_layer() & (1 << p_bit);
}
void SoftBody::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
parent_collision_ignore = p_parent_collision_ignore;
}
const NodePath &SoftBody::get_parent_collision_ignore() const {
return parent_collision_ignore;
}
void SoftBody::set_physics_enabled(bool p_enabled) {
if (p_enabled == physics_enabled) {
return;
}
physics_enabled = p_enabled;
if (is_inside_tree()) {
_prepare_physics_server();
}
}
bool SoftBody::is_physics_enabled() const {
return physics_enabled;
}
void SoftBody::set_pinned_points_indices(PoolVector<SoftBody::PinnedPoint> p_pinned_points_indices) {
pinned_points = p_pinned_points_indices;
PoolVector<PinnedPoint>::Read w = pinned_points.read();
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
pin_point(p_pinned_points_indices[i].point_index, true);
}
}
PoolVector<SoftBody::PinnedPoint> SoftBody::get_pinned_points_indices() {
return pinned_points;
}
Array SoftBody::get_collision_exceptions() {
List<RID> exceptions;
PhysicsServer::get_singleton()->soft_body_get_collision_exceptions(physics_rid, &exceptions);
Array ret;
for (List<RID>::Element *E = exceptions.front(); E; E = E->next()) {
RID body = E->get();
ObjectID instance_id = PhysicsServer::get_singleton()->body_get_object_instance_id(body);
Object *obj = ObjectDB::get_instance(instance_id);
PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(obj);
ret.append(physics_body);
}
return ret;
}
void SoftBody::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two nodes that inherit from CollisionObject (such as Area or PhysicsBody).");
PhysicsServer::get_singleton()->soft_body_add_collision_exception(physics_rid, collision_object->get_rid());
}
void SoftBody::remove_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two nodes that inherit from CollisionObject (such as Area or PhysicsBody).");
PhysicsServer::get_singleton()->soft_body_remove_collision_exception(physics_rid, collision_object->get_rid());
}
int SoftBody::get_simulation_precision() {
return PhysicsServer::get_singleton()->soft_body_get_simulation_precision(physics_rid);
}
void SoftBody::set_simulation_precision(int p_simulation_precision) {
PhysicsServer::get_singleton()->soft_body_set_simulation_precision(physics_rid, p_simulation_precision);
}
real_t SoftBody::get_total_mass() {
return PhysicsServer::get_singleton()->soft_body_get_total_mass(physics_rid);
}
void SoftBody::set_total_mass(real_t p_total_mass) {
PhysicsServer::get_singleton()->soft_body_set_total_mass(physics_rid, p_total_mass);
}
void SoftBody::set_linear_stiffness(real_t p_linear_stiffness) {
PhysicsServer::get_singleton()->soft_body_set_linear_stiffness(physics_rid, p_linear_stiffness);
}
real_t SoftBody::get_linear_stiffness() {
return PhysicsServer::get_singleton()->soft_body_get_linear_stiffness(physics_rid);
}
void SoftBody::set_areaAngular_stiffness(real_t p_areaAngular_stiffness) {
PhysicsServer::get_singleton()->soft_body_set_areaAngular_stiffness(physics_rid, p_areaAngular_stiffness);
}
real_t SoftBody::get_areaAngular_stiffness() {
return PhysicsServer::get_singleton()->soft_body_get_areaAngular_stiffness(physics_rid);
}
void SoftBody::set_volume_stiffness(real_t p_volume_stiffness) {
PhysicsServer::get_singleton()->soft_body_set_volume_stiffness(physics_rid, p_volume_stiffness);
}
real_t SoftBody::get_volume_stiffness() {
return PhysicsServer::get_singleton()->soft_body_get_volume_stiffness(physics_rid);
}
real_t SoftBody::get_pressure_coefficient() {
return PhysicsServer::get_singleton()->soft_body_get_pressure_coefficient(physics_rid);
}
void SoftBody::set_pose_matching_coefficient(real_t p_pose_matching_coefficient) {
PhysicsServer::get_singleton()->soft_body_set_pose_matching_coefficient(physics_rid, p_pose_matching_coefficient);
}
real_t SoftBody::get_pose_matching_coefficient() {
return PhysicsServer::get_singleton()->soft_body_get_pose_matching_coefficient(physics_rid);
}
void SoftBody::set_pressure_coefficient(real_t p_pressure_coefficient) {
PhysicsServer::get_singleton()->soft_body_set_pressure_coefficient(physics_rid, p_pressure_coefficient);
}
real_t SoftBody::get_damping_coefficient() {
return PhysicsServer::get_singleton()->soft_body_get_damping_coefficient(physics_rid);
}
void SoftBody::set_damping_coefficient(real_t p_damping_coefficient) {
PhysicsServer::get_singleton()->soft_body_set_damping_coefficient(physics_rid, p_damping_coefficient);
}
real_t SoftBody::get_drag_coefficient() {
return PhysicsServer::get_singleton()->soft_body_get_drag_coefficient(physics_rid);
}
void SoftBody::set_drag_coefficient(real_t p_drag_coefficient) {
PhysicsServer::get_singleton()->soft_body_set_drag_coefficient(physics_rid, p_drag_coefficient);
}
Vector3 SoftBody::get_point_transform(int p_point_index) {
return PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, p_point_index);
}
void SoftBody::pin_point_toggle(int p_point_index) {
pin_point(p_point_index, !(-1 != _has_pinned_point(p_point_index)));
}
void SoftBody::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) {
_pin_point_on_physics_server(p_point_index, pin);
if (pin) {
_add_pinned_point(p_point_index, p_spatial_attachment_path);
} else {
_remove_pinned_point(p_point_index);
}
}
bool SoftBody::is_point_pinned(int p_point_index) const {
return -1 != _has_pinned_point(p_point_index);
}
void SoftBody::set_ray_pickable(bool p_ray_pickable) {
ray_pickable = p_ray_pickable;
_update_pickable();
}
bool SoftBody::is_ray_pickable() const {
return ray_pickable;
}
SoftBody::SoftBody() :
physics_rid(RID_PRIME(PhysicsServer::get_singleton()->soft_body_create())),
collision_mask(1),
collision_layer(1),
simulation_started(false),
pinned_points_cache_dirty(true),
ray_pickable(true) {
PhysicsServer::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id());
}
SoftBody::~SoftBody() {
PhysicsServer::get_singleton()->free(physics_rid);
}
void SoftBody::reset_softbody_pin() {
PhysicsServer::get_singleton()->soft_body_remove_all_pinned_points(physics_rid);
PoolVector<PinnedPoint>::Read pps = pinned_points.read();
for (int i = pinned_points.size() - 1; 0 < i; --i) {
PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, pps[i].point_index, true);
}
}
void SoftBody::_make_cache_dirty() {
pinned_points_cache_dirty = true;
}
void SoftBody::_update_cache_pin_points_datas() {
if (!pinned_points_cache_dirty) {
return;
}
pinned_points_cache_dirty = false;
PoolVector<PinnedPoint>::Write w = pinned_points.write();
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
if (!w[i].spatial_attachment_path.is_empty()) {
w[i].spatial_attachment = Object::cast_to<Spatial>(get_node(w[i].spatial_attachment_path));
}
if (!w[i].spatial_attachment) {
ERR_PRINT("Spatial node not defined in the pinned point, this is undefined behavior for SoftBody!");
}
}
}
void SoftBody::_pin_point_on_physics_server(int p_point_index, bool pin) {
PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, p_point_index, pin);
}
void SoftBody::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) {
SoftBody::PinnedPoint *pinned_point;
if (-1 == _get_pinned_point(p_point_index, pinned_point)) {
// Create new
PinnedPoint pp;
pp.point_index = p_point_index;
pp.spatial_attachment_path = p_spatial_attachment_path;
if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) {
pp.spatial_attachment = Object::cast_to<Spatial>(get_node(p_spatial_attachment_path));
pp.offset = (pp.spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pp.point_index));
}
pinned_points.push_back(pp);
} else {
pinned_point->point_index = p_point_index;
pinned_point->spatial_attachment_path = p_spatial_attachment_path;
if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) {
pinned_point->spatial_attachment = Object::cast_to<Spatial>(get_node(p_spatial_attachment_path));
pinned_point->offset = (pinned_point->spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pinned_point->point_index));
}
}
}
void SoftBody::_reset_points_offsets() {
if (!Engine::get_singleton()->is_editor_hint()) {
return;
}
PoolVector<PinnedPoint>::Read r = pinned_points.read();
PoolVector<PinnedPoint>::Write w = pinned_points.write();
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
if (!r[i].spatial_attachment) {
if (!r[i].spatial_attachment_path.is_empty() && has_node(r[i].spatial_attachment_path)) {
w[i].spatial_attachment = Object::cast_to<Spatial>(get_node(r[i].spatial_attachment_path));
}
}
if (!r[i].spatial_attachment) {
continue;
}
w[i].offset = (r[i].spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, r[i].point_index));
}
}
void SoftBody::_remove_pinned_point(int p_point_index) {
const int id(_has_pinned_point(p_point_index));
if (-1 != id) {
pinned_points.remove(id);
}
}
int SoftBody::_get_pinned_point(int p_point_index, SoftBody::PinnedPoint *&r_point) const {
const int id = _has_pinned_point(p_point_index);
if (-1 == id) {
r_point = nullptr;
return -1;
} else {
r_point = const_cast<SoftBody::PinnedPoint *>(&pinned_points.read()[id]);
return id;
}
}
int SoftBody::_has_pinned_point(int p_point_index) const {
PoolVector<PinnedPoint>::Read r = pinned_points.read();
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
if (p_point_index == r[i].point_index) {
return i;
}
}
return -1;
}

View File

@ -1,204 +0,0 @@
#ifndef SOFT_PHYSICS_BODY_H
#define SOFT_PHYSICS_BODY_H
/*************************************************************************/
/* soft_body.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/3d/mesh_instance.h"
class SoftBody;
class SoftBodyRenderingServerHandler {
friend class SoftBody;
RID mesh;
int surface;
PoolVector<uint8_t> buffer;
uint32_t stride;
uint32_t offset_vertices;
uint32_t offset_normal;
PoolVector<uint8_t>::Write write_buffer;
private:
SoftBodyRenderingServerHandler();
bool is_ready(RID p_mesh_rid) const { return mesh.is_valid() && mesh == p_mesh_rid; }
void prepare(RID p_mesh_rid, int p_surface);
void clear();
void open();
void close();
void commit_changes();
public:
void set_vertex(int p_vertex_id, const void *p_vector3);
void set_normal(int p_vertex_id, const void *p_vector3);
void set_aabb(const AABB &p_aabb);
};
class SoftBody : public MeshInstance {
GDCLASS(SoftBody, MeshInstance);
public:
struct PinnedPoint {
int point_index;
NodePath spatial_attachment_path;
Spatial *spatial_attachment; // Cache
Vector3 offset;
PinnedPoint();
PinnedPoint(const PinnedPoint &obj_tocopy);
PinnedPoint operator=(const PinnedPoint &obj);
};
private:
SoftBodyRenderingServerHandler rendering_server_handler;
RID physics_rid;
bool physics_enabled = true;
RID owned_mesh;
uint32_t collision_mask;
uint32_t collision_layer;
NodePath parent_collision_ignore;
PoolVector<PinnedPoint> pinned_points;
bool simulation_started;
bool pinned_points_cache_dirty;
Ref<ArrayMesh> debug_mesh_cache;
class MeshInstance *debug_mesh;
bool capture_input_on_drag;
bool ray_pickable;
void _update_pickable();
void _update_physics_server();
void _draw_soft_mesh();
void _prepare_physics_server();
void _become_mesh_owner();
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
bool _set_property_pinned_points_indices(const Array &p_indices);
bool _set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value);
bool _get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const;
virtual void _changed_callback(Object *p_changed, const char *p_prop);
void _notification(int p_what);
static void _bind_methods();
virtual String get_configuration_warning() const;
public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) const;
void set_collision_layer_bit(int p_bit, bool p_value);
bool get_collision_layer_bit(int p_bit) const;
void set_parent_collision_ignore(const NodePath &p_parent_collision_ignore);
const NodePath &get_parent_collision_ignore() const;
void set_physics_enabled(bool p_enabled);
bool is_physics_enabled() const;
void set_pinned_points_indices(PoolVector<PinnedPoint> p_pinned_points_indices);
PoolVector<PinnedPoint> get_pinned_points_indices();
void set_simulation_precision(int p_simulation_precision);
int get_simulation_precision();
void set_total_mass(real_t p_total_mass);
real_t get_total_mass();
void set_linear_stiffness(real_t p_linear_stiffness);
real_t get_linear_stiffness();
void set_areaAngular_stiffness(real_t p_areaAngular_stiffness);
real_t get_areaAngular_stiffness();
void set_volume_stiffness(real_t p_volume_stiffness);
real_t get_volume_stiffness();
void set_pressure_coefficient(real_t p_pressure_coefficient);
real_t get_pressure_coefficient();
void set_pose_matching_coefficient(real_t p_pose_matching_coefficient);
real_t get_pose_matching_coefficient();
void set_damping_coefficient(real_t p_damping_coefficient);
real_t get_damping_coefficient();
void set_drag_coefficient(real_t p_drag_coefficient);
real_t get_drag_coefficient();
Array get_collision_exceptions();
void add_collision_exception_with(Node *p_node);
void remove_collision_exception_with(Node *p_node);
Vector3 get_point_transform(int p_point_index);
void pin_point_toggle(int p_point_index);
void pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path = NodePath());
bool is_point_pinned(int p_point_index) const;
void set_ray_pickable(bool p_ray_pickable);
bool is_ray_pickable() const;
SoftBody();
~SoftBody();
private:
void reset_softbody_pin();
void _make_cache_dirty();
void _update_cache_pin_points_datas();
void _pin_point_on_physics_server(int p_point_index, bool pin);
void _add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path);
void _reset_points_offsets();
void _remove_pinned_point(int p_point_index);
int _get_pinned_point(int p_point_index, PinnedPoint *&r_point) const;
int _has_pinned_point(int p_point_index) const;
};
#endif // SOFT_PHYSICS_BODY_H

View File

@ -1,174 +0,0 @@
/*************************************************************************/
/* spring_arm.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "spring_arm.h"
#include "core/config/engine.h"
#include "scene/3d/collision_object.h"
#include "scene/resources/shapes/shape.h"
#include "scene/resources/shapes/sphere_shape.h"
#include "scene/resources/world_3d.h"
#include "servers/physics_server.h"
SpringArm::SpringArm() :
spring_length(1),
current_spring_length(0),
keep_child_basis(false),
mask(1),
margin(0.01) {}
void SpringArm::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
if (!Engine::get_singleton()->is_editor_hint()) {
set_physics_process_internal(true);
}
break;
case NOTIFICATION_EXIT_TREE:
if (!Engine::get_singleton()->is_editor_hint()) {
set_physics_process_internal(false);
}
break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS:
process_spring();
break;
}
}
void SpringArm::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_hit_length"), &SpringArm::get_hit_length);
ClassDB::bind_method(D_METHOD("set_length", "length"), &SpringArm::set_length);
ClassDB::bind_method(D_METHOD("get_length"), &SpringArm::get_length);
ClassDB::bind_method(D_METHOD("set_shape", "shape"), &SpringArm::set_shape);
ClassDB::bind_method(D_METHOD("get_shape"), &SpringArm::get_shape);
ClassDB::bind_method(D_METHOD("add_excluded_object", "RID"), &SpringArm::add_excluded_object);
ClassDB::bind_method(D_METHOD("remove_excluded_object", "RID"), &SpringArm::remove_excluded_object);
ClassDB::bind_method(D_METHOD("clear_excluded_objects"), &SpringArm::clear_excluded_objects);
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &SpringArm::set_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &SpringArm::get_mask);
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &SpringArm::set_margin);
ClassDB::bind_method(D_METHOD("get_margin"), &SpringArm::get_margin);
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "spring_length"), "set_length", "get_length");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin"), "set_margin", "get_margin");
}
float SpringArm::get_length() const {
return spring_length;
}
void SpringArm::set_length(float p_length) {
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) {
update_gizmos();
}
spring_length = p_length;
}
void SpringArm::set_shape(Ref<Shape> p_shape) {
shape = p_shape;
}
Ref<Shape> SpringArm::get_shape() const {
return shape;
}
void SpringArm::set_mask(uint32_t p_mask) {
mask = p_mask;
}
uint32_t SpringArm::get_mask() {
return mask;
}
float SpringArm::get_margin() {
return margin;
}
void SpringArm::set_margin(float p_margin) {
margin = p_margin;
}
void SpringArm::add_excluded_object(RID p_rid) {
excluded_objects.insert(p_rid);
}
bool SpringArm::remove_excluded_object(RID p_rid) {
return excluded_objects.erase(p_rid);
}
void SpringArm::clear_excluded_objects() {
excluded_objects.clear();
}
float SpringArm::get_hit_length() {
return current_spring_length;
}
void SpringArm::process_spring() {
// From
real_t motion_delta(1);
real_t motion_delta_unsafe(1);
Vector3 motion;
const Vector3 cast_direction(get_global_transform().basis.xform(Vector3(0, 0, 1)));
if (shape.is_null()) {
motion = Vector3(cast_direction * (spring_length));
PhysicsDirectSpaceState::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) {
float 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);
}
current_spring_length = spring_length * motion_delta;
Transform childs_transform;
childs_transform.origin = get_global_transform().origin + cast_direction * (spring_length * motion_delta);
for (int i = get_child_count() - 1; 0 <= i; --i) {
Spatial *child = Object::cast_to<Spatial>(get_child(i));
if (child) {
childs_transform.basis = child->get_global_transform().basis;
child->set_global_transform(childs_transform);
}
}
}

View File

@ -1,73 +0,0 @@
#ifndef SPRING_ARM_H
#define SPRING_ARM_H
/*************************************************************************/
/* spring_arm.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/object/reference.h"
#include "scene/main/spatial.h"
class Shape;
class SpringArm : public Spatial {
GDCLASS(SpringArm, Spatial);
Ref<Shape> shape;
RBSet<RID> excluded_objects;
float spring_length;
float current_spring_length;
bool keep_child_basis;
uint32_t mask;
float margin;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
void set_length(float p_length);
float get_length() const;
void set_shape(Ref<Shape> p_shape);
Ref<Shape> get_shape() const;
void set_mask(uint32_t p_mask);
uint32_t get_mask();
void add_excluded_object(RID p_rid);
bool remove_excluded_object(RID p_rid);
void clear_excluded_objects();
float get_hit_length();
void set_margin(float p_margin);
float get_margin();
SpringArm();
private:
void process_spring();
};
#endif

View File

@ -1,965 +0,0 @@
/*************************************************************************/
/* vehicle_body.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "vehicle_body.h"
#include "scene/resources/shapes/shape.h"
#define ROLLING_INFLUENCE_FIX
class btVehicleJacobianEntry {
public:
Vector3 m_linearJointAxis;
Vector3 m_aJ;
Vector3 m_bJ;
Vector3 m_0MinvJt;
Vector3 m_1MinvJt;
//Optimization: can be stored in the w/last component of one of the vectors
real_t m_Adiag;
real_t getDiagonal() const { return m_Adiag; }
btVehicleJacobianEntry(){};
//constraint between two different rigidbodies
btVehicleJacobianEntry(
const Basis &world2A,
const Basis &world2B,
const Vector3 &rel_pos1,
const Vector3 &rel_pos2,
const Vector3 &jointAxis,
const Vector3 &inertiaInvA,
const real_t massInvA,
const Vector3 &inertiaInvB,
const real_t massInvB) :
m_linearJointAxis(jointAxis) {
m_aJ = world2A.xform(rel_pos1.cross(m_linearJointAxis));
m_bJ = world2B.xform(rel_pos2.cross(-m_linearJointAxis));
m_0MinvJt = inertiaInvA * m_aJ;
m_1MinvJt = inertiaInvB * m_bJ;
m_Adiag = massInvA + m_0MinvJt.dot(m_aJ) + massInvB + m_1MinvJt.dot(m_bJ);
//btAssert(m_Adiag > real_t(0.0));
}
real_t getRelativeVelocity(const Vector3 &linvelA, const Vector3 &angvelA, const Vector3 &linvelB, const Vector3 &angvelB) {
Vector3 linrel = linvelA - linvelB;
Vector3 angvela = angvelA * m_aJ;
Vector3 angvelb = angvelB * m_bJ;
linrel *= m_linearJointAxis;
angvela += angvelb;
angvela += linrel;
real_t rel_vel2 = angvela[0] + angvela[1] + angvela[2];
return rel_vel2 + CMP_EPSILON;
}
};
void VehicleWheel::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
VehicleBody *cb = Object::cast_to<VehicleBody>(get_parent());
if (!cb) {
return;
}
body = cb;
local_xform = get_transform();
cb->wheels.push_back(this);
m_chassisConnectionPointCS = get_transform().origin;
m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized();
m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized();
}
if (p_what == NOTIFICATION_EXIT_TREE) {
VehicleBody *cb = Object::cast_to<VehicleBody>(get_parent());
if (!cb) {
return;
}
cb->wheels.erase(this);
body = nullptr;
}
}
String VehicleWheel::get_configuration_warning() const {
String warning = Spatial::get_configuration_warning();
if (!Object::cast_to<VehicleBody>(get_parent())) {
if (warning != String()) {
warning += "\n\n";
}
warning += TTR("VehicleWheel serves to provide a wheel system to a VehicleBody. Please use it as a child of a VehicleBody.");
}
return warning;
}
void VehicleWheel::_update(PhysicsDirectBodyState *s) {
if (m_raycastInfo.m_isInContact)
{
real_t project = m_raycastInfo.m_contactNormalWS.dot(m_raycastInfo.m_wheelDirectionWS);
Vector3 chassis_velocity_at_contactPoint;
Vector3 relpos = m_raycastInfo.m_contactPointWS - s->get_transform().origin;
chassis_velocity_at_contactPoint = s->get_linear_velocity() +
(s->get_angular_velocity()).cross(relpos); // * mPos);
real_t projVel = m_raycastInfo.m_contactNormalWS.dot(chassis_velocity_at_contactPoint);
if (project >= real_t(-0.1)) {
m_suspensionRelativeVelocity = real_t(0.0);
m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1);
} else {
real_t inv = real_t(-1.) / project;
m_suspensionRelativeVelocity = projVel * inv;
m_clippedInvContactDotSuspension = inv;
}
}
else // Not in contact : position wheel in a nice (rest length) position
{
m_raycastInfo.m_suspensionLength = m_suspensionRestLength;
m_suspensionRelativeVelocity = real_t(0.0);
m_raycastInfo.m_contactNormalWS = -m_raycastInfo.m_wheelDirectionWS;
m_clippedInvContactDotSuspension = real_t(1.0);
}
}
void VehicleWheel::set_radius(float p_radius) {
m_wheelRadius = p_radius;
update_gizmos();
}
float VehicleWheel::get_radius() const {
return m_wheelRadius;
}
void VehicleWheel::set_suspension_rest_length(float p_length) {
m_suspensionRestLength = p_length;
update_gizmos();
}
float VehicleWheel::get_suspension_rest_length() const {
return m_suspensionRestLength;
}
void VehicleWheel::set_suspension_travel(float p_length) {
m_maxSuspensionTravelCm = p_length / 0.01;
}
float VehicleWheel::get_suspension_travel() const {
return m_maxSuspensionTravelCm * 0.01;
}
void VehicleWheel::set_suspension_stiffness(float p_value) {
m_suspensionStiffness = p_value;
}
float VehicleWheel::get_suspension_stiffness() const {
return m_suspensionStiffness;
}
void VehicleWheel::set_suspension_max_force(float p_value) {
m_maxSuspensionForce = p_value;
}
float VehicleWheel::get_suspension_max_force() const {
return m_maxSuspensionForce;
}
void VehicleWheel::set_damping_compression(float p_value) {
m_wheelsDampingCompression = p_value;
}
float VehicleWheel::get_damping_compression() const {
return m_wheelsDampingCompression;
}
void VehicleWheel::set_damping_relaxation(float p_value) {
m_wheelsDampingRelaxation = p_value;
}
float VehicleWheel::get_damping_relaxation() const {
return m_wheelsDampingRelaxation;
}
void VehicleWheel::set_friction_slip(float p_value) {
m_frictionSlip = p_value;
}
float VehicleWheel::get_friction_slip() const {
return m_frictionSlip;
}
void VehicleWheel::set_roll_influence(float p_value) {
m_rollInfluence = p_value;
}
float VehicleWheel::get_roll_influence() const {
return m_rollInfluence;
}
bool VehicleWheel::is_in_contact() const {
return m_raycastInfo.m_isInContact;
}
Spatial *VehicleWheel::get_contact_body() const {
return m_raycastInfo.m_groundObject;
}
void VehicleWheel::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "length"), &VehicleWheel::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &VehicleWheel::get_radius);
ClassDB::bind_method(D_METHOD("set_suspension_rest_length", "length"), &VehicleWheel::set_suspension_rest_length);
ClassDB::bind_method(D_METHOD("get_suspension_rest_length"), &VehicleWheel::get_suspension_rest_length);
ClassDB::bind_method(D_METHOD("set_suspension_travel", "length"), &VehicleWheel::set_suspension_travel);
ClassDB::bind_method(D_METHOD("get_suspension_travel"), &VehicleWheel::get_suspension_travel);
ClassDB::bind_method(D_METHOD("set_suspension_stiffness", "length"), &VehicleWheel::set_suspension_stiffness);
ClassDB::bind_method(D_METHOD("get_suspension_stiffness"), &VehicleWheel::get_suspension_stiffness);
ClassDB::bind_method(D_METHOD("set_suspension_max_force", "length"), &VehicleWheel::set_suspension_max_force);
ClassDB::bind_method(D_METHOD("get_suspension_max_force"), &VehicleWheel::get_suspension_max_force);
ClassDB::bind_method(D_METHOD("set_damping_compression", "length"), &VehicleWheel::set_damping_compression);
ClassDB::bind_method(D_METHOD("get_damping_compression"), &VehicleWheel::get_damping_compression);
ClassDB::bind_method(D_METHOD("set_damping_relaxation", "length"), &VehicleWheel::set_damping_relaxation);
ClassDB::bind_method(D_METHOD("get_damping_relaxation"), &VehicleWheel::get_damping_relaxation);
ClassDB::bind_method(D_METHOD("set_use_as_traction", "enable"), &VehicleWheel::set_use_as_traction);
ClassDB::bind_method(D_METHOD("is_used_as_traction"), &VehicleWheel::is_used_as_traction);
ClassDB::bind_method(D_METHOD("set_use_as_steering", "enable"), &VehicleWheel::set_use_as_steering);
ClassDB::bind_method(D_METHOD("is_used_as_steering"), &VehicleWheel::is_used_as_steering);
ClassDB::bind_method(D_METHOD("set_friction_slip", "length"), &VehicleWheel::set_friction_slip);
ClassDB::bind_method(D_METHOD("get_friction_slip"), &VehicleWheel::get_friction_slip);
ClassDB::bind_method(D_METHOD("is_in_contact"), &VehicleWheel::is_in_contact);
ClassDB::bind_method(D_METHOD("get_contact_body"), &VehicleWheel::get_contact_body);
ClassDB::bind_method(D_METHOD("set_roll_influence", "roll_influence"), &VehicleWheel::set_roll_influence);
ClassDB::bind_method(D_METHOD("get_roll_influence"), &VehicleWheel::get_roll_influence);
ClassDB::bind_method(D_METHOD("get_skidinfo"), &VehicleWheel::get_skidinfo);
ClassDB::bind_method(D_METHOD("get_rpm"), &VehicleWheel::get_rpm);
ClassDB::bind_method(D_METHOD("set_engine_force", "engine_force"), &VehicleWheel::set_engine_force);
ClassDB::bind_method(D_METHOD("get_engine_force"), &VehicleWheel::get_engine_force);
ClassDB::bind_method(D_METHOD("set_brake", "brake"), &VehicleWheel::set_brake);
ClassDB::bind_method(D_METHOD("get_brake"), &VehicleWheel::get_brake);
ClassDB::bind_method(D_METHOD("set_steering", "steering"), &VehicleWheel::set_steering);
ClassDB::bind_method(D_METHOD("get_steering"), &VehicleWheel::get_steering);
ADD_GROUP("Per-Wheel Motion", "");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "engine_force", PROPERTY_HINT_RANGE, "-1024,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering");
ADD_GROUP("VehicleBody Motion", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_traction"), "set_use_as_traction", "is_used_as_traction");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_steering"), "set_use_as_steering", "is_used_as_steering");
ADD_GROUP("Wheel", "wheel_");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "wheel_roll_influence"), "set_roll_influence", "get_roll_influence");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "wheel_radius"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "wheel_rest_length"), "set_suspension_rest_length", "get_suspension_rest_length");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "wheel_friction_slip"), "set_friction_slip", "get_friction_slip");
ADD_GROUP("Suspension", "suspension_");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "suspension_travel"), "set_suspension_travel", "get_suspension_travel");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "suspension_stiffness"), "set_suspension_stiffness", "get_suspension_stiffness");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "suspension_max_force"), "set_suspension_max_force", "get_suspension_max_force");
ADD_GROUP("Damping", "damping_");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "damping_compression"), "set_damping_compression", "get_damping_compression");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "damping_relaxation"), "set_damping_relaxation", "get_damping_relaxation");
}
void VehicleWheel::set_engine_force(float p_engine_force) {
m_engineForce = p_engine_force;
}
float VehicleWheel::get_engine_force() const {
return m_engineForce;
}
void VehicleWheel::set_brake(float p_brake) {
m_brake = p_brake;
}
float VehicleWheel::get_brake() const {
return m_brake;
}
void VehicleWheel::set_steering(float p_steering) {
m_steering = p_steering;
}
float VehicleWheel::get_steering() const {
return m_steering;
}
void VehicleWheel::set_use_as_traction(bool p_enable) {
engine_traction = p_enable;
}
bool VehicleWheel::is_used_as_traction() const {
return engine_traction;
}
void VehicleWheel::set_use_as_steering(bool p_enabled) {
steers = p_enabled;
}
bool VehicleWheel::is_used_as_steering() const {
return steers;
}
float VehicleWheel::get_skidinfo() const {
return m_skidInfo;
}
float VehicleWheel::get_rpm() const {
return m_rpm;
}
VehicleWheel::VehicleWheel() {
steers = false;
engine_traction = false;
m_steering = real_t(0.);
m_engineForce = real_t(0.);
m_rotation = real_t(0.);
m_deltaRotation = real_t(0.);
m_brake = real_t(0.);
m_rollInfluence = real_t(0.1);
m_suspensionRestLength = 0.15;
m_wheelRadius = 0.5; //0.28;
m_suspensionStiffness = 5.88;
m_wheelsDampingCompression = 0.83;
m_wheelsDampingRelaxation = 0.88;
m_frictionSlip = 10.5;
m_bIsFrontWheel = false;
m_maxSuspensionTravelCm = 500;
m_maxSuspensionForce = 6000;
m_suspensionRelativeVelocity = 0;
m_clippedInvContactDotSuspension = 1.0;
m_raycastInfo.m_isInContact = false;
m_raycastInfo.m_groundObject = nullptr;
m_raycastInfo.m_suspensionLength = 0.0;
body = nullptr;
}
void VehicleBody::_update_wheel_transform(VehicleWheel &wheel, PhysicsDirectBodyState *s) {
wheel.m_raycastInfo.m_isInContact = false;
Transform chassisTrans = s->get_transform();
/*
if (interpolatedTransform && (getRigidBody()->getMotionState())) {
getRigidBody()->getMotionState()->getWorldTransform(chassisTrans);
}
*/
wheel.m_raycastInfo.m_hardPointWS = chassisTrans.xform(wheel.m_chassisConnectionPointCS);
//wheel.m_raycastInfo.m_hardPointWS+=s->get_linear_velocity()*s->get_step();
wheel.m_raycastInfo.m_wheelDirectionWS = chassisTrans.get_basis().xform(wheel.m_wheelDirectionCS).normalized();
wheel.m_raycastInfo.m_wheelAxleWS = chassisTrans.get_basis().xform(wheel.m_wheelAxleCS).normalized();
}
void VehicleBody::_update_wheel(int p_idx, PhysicsDirectBodyState *s) {
VehicleWheel &wheel = *wheels[p_idx];
_update_wheel_transform(wheel, s);
Vector3 up = -wheel.m_raycastInfo.m_wheelDirectionWS;
const Vector3 &right = wheel.m_raycastInfo.m_wheelAxleWS;
Vector3 fwd = up.cross(right);
fwd = fwd.normalized();
Basis steeringMat(up, wheel.m_steering);
Basis rotatingMat(right, wheel.m_rotation);
Basis basis2(
right[0], up[0], fwd[0],
right[1], up[1], fwd[1],
right[2], up[2], fwd[2]);
wheel.m_worldTransform.set_basis(steeringMat * rotatingMat * basis2);
//wheel.m_worldTransform.set_basis(basis2 * (steeringMat * rotatingMat));
wheel.m_worldTransform.set_origin(
wheel.m_raycastInfo.m_hardPointWS + wheel.m_raycastInfo.m_wheelDirectionWS * wheel.m_raycastInfo.m_suspensionLength);
}
real_t VehicleBody::_ray_cast(int p_idx, PhysicsDirectBodyState *s) {
VehicleWheel &wheel = *wheels[p_idx];
_update_wheel_transform(wheel, s);
real_t depth = -1;
real_t raylen = wheel.m_suspensionRestLength + wheel.m_wheelRadius;
Vector3 rayvector = wheel.m_raycastInfo.m_wheelDirectionWS * (raylen);
Vector3 source = wheel.m_raycastInfo.m_hardPointWS;
wheel.m_raycastInfo.m_contactPointWS = source + rayvector;
const Vector3 &target = wheel.m_raycastInfo.m_contactPointWS;
source -= wheel.m_wheelRadius * wheel.m_raycastInfo.m_wheelDirectionWS;
real_t param = real_t(0.);
PhysicsDirectSpaceState::RayResult rr;
PhysicsDirectSpaceState *ss = s->get_space_state();
wheel.m_raycastInfo.m_groundObject = nullptr;
bool col = ss->intersect_ray(source, target, rr, exclude, get_collision_mask());
if (col) {
param = source.distance_to(rr.position) / source.distance_to(target);
depth = raylen * param;
wheel.m_raycastInfo.m_contactNormalWS = rr.normal;
wheel.m_raycastInfo.m_isInContact = true;
if (rr.collider) {
wheel.m_raycastInfo.m_groundObject = Object::cast_to<PhysicsBody>(rr.collider);
}
real_t hitDistance = param * raylen;
wheel.m_raycastInfo.m_suspensionLength = hitDistance - wheel.m_wheelRadius;
//clamp on max suspension travel
real_t minSuspensionLength = wheel.m_suspensionRestLength - wheel.m_maxSuspensionTravelCm * real_t(0.01);
real_t maxSuspensionLength = wheel.m_suspensionRestLength + wheel.m_maxSuspensionTravelCm * real_t(0.01);
if (wheel.m_raycastInfo.m_suspensionLength < minSuspensionLength) {
wheel.m_raycastInfo.m_suspensionLength = minSuspensionLength;
}
if (wheel.m_raycastInfo.m_suspensionLength > maxSuspensionLength) {
wheel.m_raycastInfo.m_suspensionLength = maxSuspensionLength;
}
wheel.m_raycastInfo.m_contactPointWS = rr.position;
real_t denominator = wheel.m_raycastInfo.m_contactNormalWS.dot(wheel.m_raycastInfo.m_wheelDirectionWS);
Vector3 chassis_velocity_at_contactPoint;
//Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS-getRigidBody()->getCenterOfMassPosition();
//chassis_velocity_at_contactPoint = getRigidBody()->getVelocityInLocalPoint(relpos);
chassis_velocity_at_contactPoint = s->get_linear_velocity() +
(s->get_angular_velocity()).cross(wheel.m_raycastInfo.m_contactPointWS - s->get_transform().origin); // * mPos);
real_t projVel = wheel.m_raycastInfo.m_contactNormalWS.dot(chassis_velocity_at_contactPoint);
if (denominator >= real_t(-0.1)) {
wheel.m_suspensionRelativeVelocity = real_t(0.0);
wheel.m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1);
} else {
real_t inv = real_t(-1.) / denominator;
wheel.m_suspensionRelativeVelocity = projVel * inv;
wheel.m_clippedInvContactDotSuspension = inv;
}
} else {
wheel.m_raycastInfo.m_isInContact = false;
//put wheel info as in rest position
wheel.m_raycastInfo.m_suspensionLength = wheel.m_suspensionRestLength;
wheel.m_suspensionRelativeVelocity = real_t(0.0);
wheel.m_raycastInfo.m_contactNormalWS = -wheel.m_raycastInfo.m_wheelDirectionWS;
wheel.m_clippedInvContactDotSuspension = real_t(1.0);
}
return depth;
}
void VehicleBody::_update_suspension(PhysicsDirectBodyState *s) {
real_t chassisMass = mass;
for (int w_it = 0; w_it < wheels.size(); w_it++) {
VehicleWheel &wheel_info = *wheels[w_it];
if (wheel_info.m_raycastInfo.m_isInContact) {
real_t force;
//Spring
{
real_t susp_length = wheel_info.m_suspensionRestLength;
real_t current_length = wheel_info.m_raycastInfo.m_suspensionLength;
real_t length_diff = (susp_length - current_length);
force = wheel_info.m_suspensionStiffness * length_diff * wheel_info.m_clippedInvContactDotSuspension;
}
// Damper
{
real_t projected_rel_vel = wheel_info.m_suspensionRelativeVelocity;
{
real_t susp_damping;
if (projected_rel_vel < real_t(0.0)) {
susp_damping = wheel_info.m_wheelsDampingCompression;
} else {
susp_damping = wheel_info.m_wheelsDampingRelaxation;
}
force -= susp_damping * projected_rel_vel;
}
}
// RESULT
wheel_info.m_wheelsSuspensionForce = force * chassisMass;
if (wheel_info.m_wheelsSuspensionForce < real_t(0.)) {
wheel_info.m_wheelsSuspensionForce = real_t(0.);
}
} else {
wheel_info.m_wheelsSuspensionForce = real_t(0.0);
}
}
}
//bilateral constraint between two dynamic objects
void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1,
PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence) {
real_t normalLenSqr = normal.length_squared();
//ERR_FAIL_COND( normalLenSqr < real_t(1.1));
if (normalLenSqr > real_t(1.1)) {
impulse = real_t(0.);
return;
}
Vector3 rel_pos1 = pos1 - s->get_transform().origin;
Vector3 rel_pos2;
if (body2) {
rel_pos2 = pos2 - body2->get_global_transform().origin;
}
//this jacobian entry could be re-used for all iterations
Vector3 vel1 = s->get_linear_velocity() + (s->get_angular_velocity()).cross(rel_pos1); // * mPos);
Vector3 vel2;
if (body2) {
vel2 = body2->get_linear_velocity() + body2->get_angular_velocity().cross(rel_pos2);
}
Vector3 vel = vel1 - vel2;
Basis b2trans;
float b2invmass = 0;
Vector3 b2lv;
Vector3 b2av;
Vector3 b2invinertia; //todo
if (body2) {
b2trans = body2->get_global_transform().basis.transposed();
b2invmass = body2->get_inverse_mass();
b2lv = body2->get_linear_velocity();
b2av = body2->get_angular_velocity();
}
btVehicleJacobianEntry jac(s->get_transform().basis.transposed(),
b2trans,
rel_pos1,
rel_pos2,
normal,
s->get_inverse_inertia_tensor().get_main_diagonal(),
1.0 / mass,
b2invinertia,
b2invmass);
// FIXME: rel_vel assignment here is overwritten by the following assignment.
// What seems to be intended in the next next assignment is: rel_vel = normal.dot(rel_vel);
// Investigate why.
real_t rel_vel = jac.getRelativeVelocity(
s->get_linear_velocity(),
s->get_transform().basis.transposed().xform(s->get_angular_velocity()),
b2lv,
b2trans.xform(b2av));
rel_vel = normal.dot(vel);
// !BAS! We had this set to 0.4, in bullet its 0.2
real_t contactDamping = real_t(0.2);
if (p_rollInfluence > 0.0) {
// !BAS! But seeing we apply this frame by frame, makes more sense to me to make this time based
// keeping in mind our anti roll factor if it is set
contactDamping = MIN(contactDamping, s->get_step() / p_rollInfluence);
}
#define ONLY_USE_LINEAR_MASS
#ifdef ONLY_USE_LINEAR_MASS
real_t massTerm = real_t(1.) / ((1.0 / mass) + b2invmass);
impulse = -contactDamping * rel_vel * massTerm;
#else
real_t velocityImpulse = -contactDamping * rel_vel * jacDiagABInv;
impulse = velocityImpulse;
#endif
}
VehicleBody::btVehicleWheelContactPoint::btVehicleWheelContactPoint(PhysicsDirectBodyState *s, PhysicsBody *body1, const Vector3 &frictionPosWorld, const Vector3 &frictionDirectionWorld, real_t maxImpulse) :
m_s(s),
m_body1(body1),
m_frictionPositionWorld(frictionPosWorld),
m_frictionDirectionWorld(frictionDirectionWorld),
m_maxImpulse(maxImpulse) {
float denom0 = 0;
float denom1 = 0;
{
Vector3 r0 = frictionPosWorld - s->get_transform().origin;
Vector3 c0 = (r0).cross(frictionDirectionWorld);
Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0);
denom0 = s->get_inverse_mass() + frictionDirectionWorld.dot(vec);
}
/* TODO: Why is this code unused?
if (body1) {
Vector3 r0 = frictionPosWorld - body1->get_global_transform().origin;
Vector3 c0 = (r0).cross(frictionDirectionWorld);
Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0);
//denom1= body1->get_inverse_mass() + frictionDirectionWorld.dot(vec);
}
*/
real_t relaxation = 1.f;
m_jacDiagABInv = relaxation / (denom0 + denom1);
}
real_t VehicleBody::_calc_rolling_friction(btVehicleWheelContactPoint &contactPoint) {
real_t j1 = 0.f;
const Vector3 &contactPosWorld = contactPoint.m_frictionPositionWorld;
Vector3 rel_pos1 = contactPosWorld - contactPoint.m_s->get_transform().origin;
Vector3 rel_pos2;
if (contactPoint.m_body1) {
rel_pos2 = contactPosWorld - contactPoint.m_body1->get_global_transform().origin;
}
real_t maxImpulse = contactPoint.m_maxImpulse;
Vector3 vel1 = contactPoint.m_s->get_linear_velocity() + (contactPoint.m_s->get_angular_velocity()).cross(rel_pos1); // * mPos);
Vector3 vel2;
if (contactPoint.m_body1) {
vel2 = contactPoint.m_body1->get_linear_velocity() + contactPoint.m_body1->get_angular_velocity().cross(rel_pos2);
}
Vector3 vel = vel1 - vel2;
real_t vrel = contactPoint.m_frictionDirectionWorld.dot(vel);
// calculate j that moves us to zero relative velocity
j1 = -vrel * contactPoint.m_jacDiagABInv;
return CLAMP(j1, -maxImpulse, maxImpulse);
}
static const real_t sideFrictionStiffness2 = real_t(1.0);
void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
//calculate the impulse, so that the wheels don't move sidewards
int numWheel = wheels.size();
if (!numWheel) {
return;
}
m_forwardWS.resize(numWheel);
m_axle.resize(numWheel);
m_forwardImpulse.resize(numWheel);
m_sideImpulse.resize(numWheel);
//collapse all those loops into one!
for (int i = 0; i < wheels.size(); i++) {
m_sideImpulse.write[i] = real_t(0.);
m_forwardImpulse.write[i] = real_t(0.);
}
{
for (int i = 0; i < wheels.size(); i++) {
VehicleWheel &wheelInfo = *wheels[i];
if (wheelInfo.m_raycastInfo.m_isInContact) {
//const btTransform& wheelTrans = getWheelTransformWS( i );
Basis wheelBasis0 = wheelInfo.m_worldTransform.basis; //get_global_transform().basis;
m_axle.write[i] = wheelBasis0.get_axis(Vector3::AXIS_X);
//m_axle[i] = wheelInfo.m_raycastInfo.m_wheelAxleWS;
const Vector3 &surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS;
real_t proj = m_axle[i].dot(surfNormalWS);
m_axle.write[i] -= surfNormalWS * proj;
m_axle.write[i] = m_axle[i].normalized();
m_forwardWS.write[i] = surfNormalWS.cross(m_axle[i]);
m_forwardWS.write[i].normalize();
_resolve_single_bilateral(s, wheelInfo.m_raycastInfo.m_contactPointWS,
wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS,
m_axle[i], m_sideImpulse.write[i], wheelInfo.m_rollInfluence);
m_sideImpulse.write[i] *= sideFrictionStiffness2;
}
}
}
real_t sideFactor = real_t(1.);
real_t fwdFactor = 0.5;
bool sliding = false;
{
for (int wheel = 0; wheel < wheels.size(); wheel++) {
VehicleWheel &wheelInfo = *wheels[wheel];
//class btRigidBody* groundObject = (class btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject;
real_t rollingFriction = 0.f;
if (wheelInfo.m_raycastInfo.m_isInContact) {
if (wheelInfo.m_engineForce != 0.f) {
rollingFriction = -wheelInfo.m_engineForce * s->get_step();
} else {
real_t defaultRollingFrictionImpulse = 0.f;
real_t maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse;
btVehicleWheelContactPoint contactPt(s, wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS, m_forwardWS[wheel], maxImpulse);
rollingFriction = _calc_rolling_friction(contactPt);
}
}
//switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break)
m_forwardImpulse.write[wheel] = real_t(0.);
wheelInfo.m_skidInfo = real_t(1.);
if (wheelInfo.m_raycastInfo.m_isInContact) {
wheelInfo.m_skidInfo = real_t(1.);
real_t maximp = wheelInfo.m_wheelsSuspensionForce * s->get_step() * wheelInfo.m_frictionSlip;
real_t maximpSide = maximp;
real_t maximpSquared = maximp * maximpSide;
m_forwardImpulse.write[wheel] = rollingFriction; //wheelInfo.m_engineForce* timeStep;
real_t x = (m_forwardImpulse[wheel]) * fwdFactor;
real_t y = (m_sideImpulse[wheel]) * sideFactor;
real_t impulseSquared = (x * x + y * y);
if (impulseSquared > maximpSquared) {
sliding = true;
real_t factor = maximp / Math::sqrt(impulseSquared);
wheelInfo.m_skidInfo *= factor;
}
}
}
}
if (sliding) {
for (int wheel = 0; wheel < wheels.size(); wheel++) {
if (m_sideImpulse[wheel] != real_t(0.)) {
if (wheels[wheel]->m_skidInfo < real_t(1.)) {
m_forwardImpulse.write[wheel] *= wheels[wheel]->m_skidInfo;
m_sideImpulse.write[wheel] *= wheels[wheel]->m_skidInfo;
}
}
}
}
// apply the impulses
{
for (int wheel = 0; wheel < wheels.size(); wheel++) {
VehicleWheel &wheelInfo = *wheels[wheel];
Vector3 rel_pos = wheelInfo.m_raycastInfo.m_contactPointWS -
s->get_transform().origin;
if (m_forwardImpulse[wheel] != real_t(0.)) {
s->apply_impulse(rel_pos, m_forwardWS[wheel] * (m_forwardImpulse[wheel]));
}
if (m_sideImpulse[wheel] != real_t(0.)) {
PhysicsBody *groundObject = wheelInfo.m_raycastInfo.m_groundObject;
Vector3 rel_pos2;
if (groundObject) {
rel_pos2 = wheelInfo.m_raycastInfo.m_contactPointWS - groundObject->get_global_transform().origin;
}
Vector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel];
#if defined ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT.
Vector3 vChassisWorldUp = s->get_transform().basis.transposed()[1]; //getRigidBody()->getCenterOfMassTransform().getBasis().getColumn(m_indexUpAxis);
rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f - wheelInfo.m_rollInfluence));
#else
rel_pos[1] *= wheelInfo.m_rollInfluence; //?
#endif
s->apply_impulse(rel_pos, sideImp);
//apply friction impulse on the ground
//todo
//groundObject->applyImpulse(-sideImp,rel_pos2);
}
}
}
}
void VehicleBody::_direct_state_changed(Object *p_state) {
RigidBody::_direct_state_changed(p_state);
state = Object::cast_to<PhysicsDirectBodyState>(p_state);
ERR_FAIL_COND_MSG(!state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState object as argument");
float step = state->get_step();
for (int i = 0; i < wheels.size(); i++) {
_update_wheel(i, state);
}
for (int i = 0; i < wheels.size(); i++) {
_ray_cast(i, state);
wheels[i]->set_transform(state->get_transform().inverse() * wheels[i]->m_worldTransform);
}
_update_suspension(state);
for (int i = 0; i < wheels.size(); i++) {
//apply suspension force
VehicleWheel &wheel = *wheels[i];
real_t suspensionForce = wheel.m_wheelsSuspensionForce;
if (suspensionForce > wheel.m_maxSuspensionForce) {
suspensionForce = wheel.m_maxSuspensionForce;
}
Vector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step;
Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS - state->get_transform().origin;
state->apply_impulse(relpos, impulse);
//getRigidBody()->applyImpulse(impulse, relpos);
}
_update_friction(state);
for (int i = 0; i < wheels.size(); i++) {
VehicleWheel &wheel = *wheels[i];
Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - state->get_transform().origin;
Vector3 vel = state->get_linear_velocity() + (state->get_angular_velocity()).cross(relpos); // * mPos);
if (wheel.m_raycastInfo.m_isInContact) {
const Transform &chassisWorldTransform = state->get_transform();
Vector3 fwd(
chassisWorldTransform.basis[0][Vector3::AXIS_Z],
chassisWorldTransform.basis[1][Vector3::AXIS_Z],
chassisWorldTransform.basis[2][Vector3::AXIS_Z]);
real_t proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS);
fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj;
real_t proj2 = fwd.dot(vel);
wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelRadius);
}
wheel.m_rotation += wheel.m_deltaRotation;
wheel.m_rpm = ((wheel.m_deltaRotation / step) * 60) / Math_TAU;
wheel.m_deltaRotation *= real_t(0.99); //damping of rotation when not in contact
}
state = nullptr;
}
void VehicleBody::set_engine_force(float p_engine_force) {
engine_force = p_engine_force;
for (int i = 0; i < wheels.size(); i++) {
VehicleWheel &wheelInfo = *wheels[i];
if (wheelInfo.engine_traction) {
wheelInfo.m_engineForce = p_engine_force;
}
}
}
float VehicleBody::get_engine_force() const {
return engine_force;
}
void VehicleBody::set_brake(float p_brake) {
brake = p_brake;
for (int i = 0; i < wheels.size(); i++) {
VehicleWheel &wheelInfo = *wheels[i];
wheelInfo.m_brake = p_brake;
}
}
float VehicleBody::get_brake() const {
return brake;
}
void VehicleBody::set_steering(float p_steering) {
m_steeringValue = p_steering;
for (int i = 0; i < wheels.size(); i++) {
VehicleWheel &wheelInfo = *wheels[i];
if (wheelInfo.steers) {
wheelInfo.m_steering = p_steering;
}
}
}
float VehicleBody::get_steering() const {
return m_steeringValue;
}
void VehicleBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_engine_force", "engine_force"), &VehicleBody::set_engine_force);
ClassDB::bind_method(D_METHOD("get_engine_force"), &VehicleBody::get_engine_force);
ClassDB::bind_method(D_METHOD("set_brake", "brake"), &VehicleBody::set_brake);
ClassDB::bind_method(D_METHOD("get_brake"), &VehicleBody::get_brake);
ClassDB::bind_method(D_METHOD("set_steering", "steering"), &VehicleBody::set_steering);
ClassDB::bind_method(D_METHOD("get_steering"), &VehicleBody::get_steering);
ADD_GROUP("Motion", "");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "engine_force", PROPERTY_HINT_RANGE, "-1024,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering");
}
VehicleBody::VehicleBody() {
m_pitchControl = 0;
m_currentVehicleSpeedKmHour = real_t(0.);
m_steeringValue = real_t(0.);
engine_force = 0;
brake = 0;
state = nullptr;
ccd = false;
exclude.insert(get_rid());
//PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
set_mass(40);
}

View File

@ -1,211 +0,0 @@
#ifndef VEHICLE_BODY_H
#define VEHICLE_BODY_H
/*************************************************************************/
/* vehicle_body.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/3d/physics_body.h"
class VehicleBody;
class VehicleWheel : public Spatial {
GDCLASS(VehicleWheel, Spatial);
friend class VehicleBody;
Transform m_worldTransform;
Transform local_xform;
bool engine_traction;
bool steers;
Vector3 m_chassisConnectionPointCS; //const
Vector3 m_wheelDirectionCS; //const
Vector3 m_wheelAxleCS; // const or modified by steering
real_t m_suspensionRestLength;
real_t m_maxSuspensionTravelCm;
real_t m_wheelRadius;
real_t m_suspensionStiffness;
real_t m_wheelsDampingCompression;
real_t m_wheelsDampingRelaxation;
real_t m_frictionSlip;
real_t m_maxSuspensionForce;
bool m_bIsFrontWheel;
VehicleBody *body;
//btVector3 m_wheelAxleCS; // const or modified by steering ?
real_t m_steering;
real_t m_rotation;
real_t m_deltaRotation;
real_t m_rpm;
real_t m_rollInfluence;
real_t m_engineForce;
real_t m_brake;
real_t m_clippedInvContactDotSuspension;
real_t m_suspensionRelativeVelocity;
//calculated by suspension
real_t m_wheelsSuspensionForce;
real_t m_skidInfo;
struct RaycastInfo {
//set by raycaster
Vector3 m_contactNormalWS; //contactnormal
Vector3 m_contactPointWS; //raycast hitpoint
real_t m_suspensionLength;
Vector3 m_hardPointWS; //raycast starting point
Vector3 m_wheelDirectionWS; //direction in worldspace
Vector3 m_wheelAxleWS; // axle in worldspace
bool m_isInContact;
PhysicsBody *m_groundObject; //could be general void* ptr
} m_raycastInfo;
void _update(PhysicsDirectBodyState *s);
protected:
void _notification(int p_what);
static void _bind_methods();
public:
void set_radius(float p_radius);
float get_radius() const;
void set_suspension_rest_length(float p_length);
float get_suspension_rest_length() const;
void set_suspension_travel(float p_length);
float get_suspension_travel() const;
void set_suspension_stiffness(float p_value);
float get_suspension_stiffness() const;
void set_suspension_max_force(float p_value);
float get_suspension_max_force() const;
void set_damping_compression(float p_value);
float get_damping_compression() const;
void set_damping_relaxation(float p_value);
float get_damping_relaxation() const;
void set_friction_slip(float p_value);
float get_friction_slip() const;
void set_use_as_traction(bool p_enable);
bool is_used_as_traction() const;
void set_use_as_steering(bool p_enabled);
bool is_used_as_steering() const;
bool is_in_contact() const;
Spatial *get_contact_body() const;
void set_roll_influence(float p_value);
float get_roll_influence() const;
float get_skidinfo() const;
float get_rpm() const;
void set_engine_force(float p_engine_force);
float get_engine_force() const;
void set_brake(float p_brake);
float get_brake() const;
void set_steering(float p_steering);
float get_steering() const;
String get_configuration_warning() const;
VehicleWheel();
};
class VehicleBody : public RigidBody {
GDCLASS(VehicleBody, RigidBody);
float engine_force;
float brake;
real_t m_pitchControl;
real_t m_steeringValue;
real_t m_currentVehicleSpeedKmHour;
RBSet<RID> exclude;
Vector<Vector3> m_forwardWS;
Vector<Vector3> m_axle;
Vector<real_t> m_forwardImpulse;
Vector<real_t> m_sideImpulse;
struct btVehicleWheelContactPoint {
PhysicsDirectBodyState *m_s;
PhysicsBody *m_body1;
Vector3 m_frictionPositionWorld;
Vector3 m_frictionDirectionWorld;
real_t m_jacDiagABInv;
real_t m_maxImpulse;
btVehicleWheelContactPoint(PhysicsDirectBodyState *s, PhysicsBody *body1, const Vector3 &frictionPosWorld, const Vector3 &frictionDirectionWorld, real_t maxImpulse);
};
void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence);
real_t _calc_rolling_friction(btVehicleWheelContactPoint &contactPoint);
void _update_friction(PhysicsDirectBodyState *s);
void _update_suspension(PhysicsDirectBodyState *s);
real_t _ray_cast(int p_idx, PhysicsDirectBodyState *s);
void _update_wheel_transform(VehicleWheel &wheel, PhysicsDirectBodyState *s);
void _update_wheel(int p_idx, PhysicsDirectBodyState *s);
friend class VehicleWheel;
Vector<VehicleWheel *> wheels;
static void _bind_methods();
void _direct_state_changed(Object *p_state);
public:
void set_engine_force(float p_engine_force);
float get_engine_force() const;
void set_brake(float p_brake);
float get_brake() const;
void set_steering(float p_steering);
float get_steering() const;
VehicleBody();
};
#endif // VEHICLE_BODY_H

View File

@ -32,10 +32,8 @@
#include "core/config/engine.h"
#include "scene/3d/camera.h"
#include "scene/3d/physics_body.h"
#include "scene/animation/animation_player.h"
#include "scene/animation/animation_tree.h"
#include "scene/resources/shapes/shape.h"
#include "scene/resources/world_3d.h"
#include "scene/main/scene_string_names.h"
@ -269,14 +267,6 @@ void VisibilityEnabler::_find_nodes(Node *p_node) {
bool add = false;
Variant meta;
{
RigidBody *rb = Object::cast_to<RigidBody>(p_node);
if (rb && ((rb->get_mode() == RigidBody::MODE_CHARACTER || rb->get_mode() == RigidBody::MODE_RIGID))) {
add = true;
meta = rb->get_mode();
}
}
if (Object::cast_to<AnimationPlayer>(p_node) || Object::cast_to<AnimationTree>(p_node)) {
add = true;
}
@ -342,13 +332,6 @@ void VisibilityEnabler::_notification(int p_what) {
void VisibilityEnabler::_change_node_state(Node *p_node, bool p_enabled) {
ERR_FAIL_COND(!nodes.has(p_node));
if (enabler[ENABLER_FREEZE_BODIES]) {
RigidBody *rb = Object::cast_to<RigidBody>(p_node);
if (rb) {
rb->set_sleeping(!p_enabled);
}
}
if (enabler[ENABLER_PAUSE_ANIMATIONS]) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
if (ap) {

View File

@ -56,9 +56,7 @@
#include "servers/audio_server.h"
#include "servers/navigation_server.h"
#include "servers/physics_2d_server.h"
#include "servers/physics_server.h"
#include "viewport.h"
#include "modules/modules_enabled.gen.h" // For freetype.
#include "scene/resources/mesh/mesh.h"
#include "scene/resources/world_2d.h"
@ -1133,7 +1131,6 @@ void SceneTree::set_pause(bool p_enabled) {
}
pause = p_enabled;
PhysicsServer::get_singleton()->set_active(!p_enabled);
Physics2DServer::get_singleton()->set_active(!p_enabled);
if (get_root()) {

View File

@ -40,7 +40,6 @@
#include "scene/2d/collision_object_2d.h"
#include "scene/2d/listener_2d.h"
#include "scene/3d/camera.h"
#include "scene/3d/collision_object.h"
#include "scene/3d/listener.h"
#include "scene/main/spatial.h"
#include "scene/main/control.h"
@ -217,24 +216,6 @@ void Viewport::_update_stretch_transform() {
_update_global_transform();
}
void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
Transform object_transform = p_object->get_global_transform();
Transform camera_transform = p_camera->get_global_transform();
ObjectID id = p_object->get_instance_id();
//avoid sending the fake event unnecessarily if nothing really changed in the context
if (object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) {
Ref<InputEventMouseMotion> mm = p_input_event;
if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) {
return; //discarded
}
}
p_object->_input_event(camera, p_input_event, p_pos, p_normal, p_shape);
physics_last_object_transform = object_transform;
physics_last_camera_transform = camera_transform;
physics_last_id = id;
}
void Viewport::_own_world_3d_changed() {
ERR_FAIL_COND(world_3d.is_null());
ERR_FAIL_COND(own_world_3d.is_null());
@ -372,19 +353,6 @@ void Viewport::_notification(int p_what) {
}
}
if (get_tree()->is_debugging_collisions_hint() && contact_3d_debug_multimesh.is_valid()) {
Vector<Vector3> points = PhysicsServer::get_singleton()->space_get_contacts(find_world_3d()->get_space());
int point_count = PhysicsServer::get_singleton()->space_get_contact_count(find_world_3d()->get_space());
RS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count);
for (int i = 0; i < point_count; i++) {
Transform point_transform;
point_transform.origin = points[i];
RS::get_singleton()->multimesh_instance_set_transform(contact_3d_debug_multimesh, i, point_transform);
}
}
if (!GLOBAL_GET("physics/common/enable_pause_aware_picking")) {
_process_picking(false);
}
@ -423,12 +391,6 @@ void Viewport::_process_picking(bool p_ignore_paused) {
_drop_physics_mouseover(true);
}
#ifndef _3D_DISABLED
Vector2 last_pos(1e20, 1e20);
CollisionObject *last_object = nullptr;
ObjectID last_id = 0;
#endif
PhysicsDirectSpaceState::RayResult result;
Physics2DDirectSpaceState *ss2d = Physics2DServer::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
if (physics_has_last_mousepos) {
@ -600,81 +562,6 @@ void Viewport::_process_picking(bool p_ignore_paused) {
}
}
#ifndef _3D_DISABLED
bool captured = false;
if (physics_object_capture != 0) {
CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_capture));
if (co && camera) {
_collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0);
captured = true;
if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) {
physics_object_capture = 0;
}
} else {
physics_object_capture = 0;
}
}
if (captured) {
//none
} else if (pos == last_pos) {
if (last_id) {
if (ObjectDB::get_instance(last_id) && last_object) {
//good, exists
_collision_object_input_event(last_object, camera, ev, result.position, result.normal, result.shape);
if (last_object->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
physics_object_capture = last_id;
}
}
}
} else {
if (camera) {
Vector3 from = camera->project_ray_origin(pos);
Vector3 dir = camera->project_ray_normal(pos);
float far = camera->far;
PhysicsDirectSpaceState *space = PhysicsServer::get_singleton()->space_get_direct_state(find_world_3d()->get_space());
if (space) {
bool col = space->intersect_ray(from, from + dir * far, result, RBSet<RID>(), 0xFFFFFFFF, true, true, true);
ObjectID new_collider = 0;
if (col) {
CollisionObject *co = Object::cast_to<CollisionObject>(result.collider);
if (co && (!p_ignore_paused || co->can_process())) {
_collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape);
last_object = co;
last_id = result.collider_id;
new_collider = last_id;
if (co->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
physics_object_capture = last_id;
}
}
}
if (is_mouse && new_collider != physics_object_over) {
if (physics_object_over) {
CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over));
if (co) {
co->_mouse_exit();
}
}
if (new_collider) {
CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(new_collider));
if (co) {
co->_mouse_enter();
}
}
physics_object_over = new_collider;
}
}
last_pos = pos;
}
}
#endif
}
}
@ -826,25 +713,6 @@ void Viewport::_on_after_world_override_changed() {
}
RenderingServer::get_singleton()->canvas_item_set_parent(contact_2d_debug, find_world_2d()->get_canvas());
//3D
PhysicsServer::get_singleton()->space_set_debug_contacts(find_world_3d()->get_space(), get_tree()->get_collision_debug_contact_count());
if (contact_3d_debug_multimesh != RID()) {
contact_3d_debug_multimesh = RID_PRIME(RenderingServer::get_singleton()->multimesh_create());
}
RenderingServer::get_singleton()->multimesh_allocate(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), RS::MULTIMESH_TRANSFORM_3D, RS::MULTIMESH_COLOR_8BIT);
RenderingServer::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, 0);
RenderingServer::get_singleton()->multimesh_set_mesh(contact_3d_debug_multimesh, get_tree()->get_debug_contact_mesh()->get_rid());
if (contact_3d_debug_instance != RID()) {
contact_3d_debug_instance = RID_PRIME(RenderingServer::get_singleton()->instance_create());
}
RenderingServer::get_singleton()->instance_set_base(contact_3d_debug_instance, contact_3d_debug_multimesh);
RenderingServer::get_singleton()->instance_set_scenario(contact_3d_debug_instance, find_world_3d()->get_scenario());
//RenderingServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance, RS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, true);
}
}
@ -2714,20 +2582,6 @@ void Viewport::_drop_physics_mouseover(bool p_paused_only) {
physics_2d_mouseover.erase(to_erase.front()->get());
to_erase.pop_front();
}
#ifndef _3D_DISABLED
if (physics_object_over) {
CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over));
if (co) {
if (!co->is_inside_tree()) {
physics_object_over = physics_object_capture = 0;
} else if (!(p_paused_only && co->can_process())) {
co->_mouse_exit();
physics_object_over = physics_object_capture = 0;
}
}
}
#endif
}
List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {

View File

@ -49,7 +49,6 @@ class Panel;
class Label;
class Timer;
class Viewport;
class CollisionObject;
class SceneTreeTimer;
class ViewportTexture : public Texture {
@ -407,8 +406,6 @@ private:
} physics_last_mouse_state;
void _collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
bool handle_input_locally;
bool local_input_handled;

View File

@ -140,19 +140,13 @@
#include "scene/main/world.h"
#include "scene/audio/audio_stream_sample.h"
#include "scene/resources/bit_map.h"
#include "scene/resources/shapes/box_shape.h"
#include "scene/resources/shapes/capsule_shape.h"
#include "scene/resources/shapes_2d/capsule_shape_2d.h"
#include "scene/resources/shapes_2d/circle_shape_2d.h"
#include "scene/resources/shapes/concave_polygon_shape.h"
#include "scene/resources/shapes_2d/concave_polygon_shape_2d.h"
#include "scene/resources/shapes/convex_polygon_shape.h"
#include "scene/resources/shapes_2d/convex_polygon_shape_2d.h"
#include "scene/resources/shapes/cylinder_shape.h"
#include "scene/resources/default_theme/default_theme.h"
#include "scene/resources/font/dynamic_font.h"
#include "scene/resources/gradient.h"
#include "scene/resources/shapes/height_map_shape.h"
#include "scene/resources/mesh/immediate_mesh.h"
#include "scene/resources/shapes_2d/line_shape_2d.h"
#include "scene/resources/material/material.h"
@ -167,17 +161,15 @@
#include "scene/resources/navigation_2d/navigation_polygon.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/material/particles_material.h"
#include "scene/resources/physics_material.h"
#include "scene/resources/shapes/plane_shape.h"
#include "scene/resources/mesh/polygon_path_finder.h"
#include "scene/resources/mesh/primitive_meshes.h"
#include "scene/resources/shapes/ray_shape.h"
#include "scene/resources/shapes_2d/rectangle_shape_2d.h"
#include "scene/resources/resource_format_text.h"
#include "scene/resources/shapes_2d/segment_shape_2d.h"
#include "scene/resources/physics_material.h"
#include "scene/resources/sky.h"
#include "scene/resources/shapes/sphere_shape.h"
#include "scene/resources/mesh/surface_tool.h"
#include "scene/gui/resources/syntax_highlighter.h"
#include "scene/resources/text_file.h"
@ -188,11 +180,8 @@
#include "scene/main/scene_string_names.h"
#ifndef _3D_DISABLED
#include "scene/3d/area.h"
#include "scene/3d/audio_stream_player_3d.h"
#include "scene/3d/camera.h"
#include "scene/3d/collision_polygon.h"
#include "scene/3d/collision_shape.h"
#include "scene/3d/cpu_particles.h"
#include "scene/3d/immediate_geometry.h"
#include "scene/3d/interpolated_camera.h"
@ -205,26 +194,18 @@
#include "scene/3d/navigation_geometry_parser_3d.h"
#include "scene/3d/navigation_link_3d.h"
#include "scene/3d/navigation_mesh_instance.h"
#include "scene/3d/navigation_obstacle.h"
#include "scene/3d/occluder.h"
#include "scene/3d/path.h"
#include "scene/3d/physics_body.h"
#include "scene/3d/physics_joint.h"
#include "scene/3d/portal.h"
#include "scene/3d/position_3d.h"
#include "scene/3d/proximity_group.h"
#include "scene/3d/ray_cast.h"
#include "scene/3d/reflection_probe.h"
#include "scene/3d/remote_transform.h"
#include "scene/3d/room.h"
#include "scene/3d/room_group.h"
#include "scene/3d/room_manager.h"
#include "scene/3d/shape_cast.h"
#include "scene/3d/soft_body.h"
#include "scene/3d/spatial_velocity_tracker.h"
#include "scene/3d/spring_arm.h"
#include "scene/3d/sprite_3d.h"
#include "scene/3d/vehicle_body.h"
#include "scene/3d/visibility_notifier.h"
#include "scene/resources/environment_3d.h"
#include "scene/resources/mesh/multimesh.h"
@ -438,7 +419,6 @@ void register_scene_types() {
ClassDB::register_virtual_class<CullInstance>();
ClassDB::register_virtual_class<GeometryInstance>();
ClassDB::register_class<Camera>();
ClassDB::register_class<ClippedCamera>();
ClassDB::register_class<Listener>();
ClassDB::register_class<InterpolatedCamera>();
ClassDB::register_class<MeshInstance>();
@ -468,24 +448,7 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
ClassDB::register_virtual_class<CollisionObject>();
ClassDB::register_virtual_class<PhysicsBody>();
ClassDB::register_class<StaticBody>();
ClassDB::register_class<RigidBody>();
ClassDB::register_class<KinematicCollision>();
ClassDB::register_class<KinematicBody>();
ClassDB::register_class<SpringArm>();
ClassDB::register_class<SoftBody>();
ClassDB::register_class<VehicleBody>();
ClassDB::register_class<VehicleWheel>();
ClassDB::register_class<Area>();
ClassDB::register_class<ProximityGroup>();
ClassDB::register_class<CollisionShape>();
ClassDB::register_class<CollisionPolygon>();
ClassDB::register_class<RayCast>();
ClassDB::register_class<ShapeCast>();
ClassDB::register_class<MultiMeshInstance>();
ClassDB::register_class<Curve3D>();
@ -496,17 +459,10 @@ void register_scene_types() {
ClassDB::register_class<WorldEnvironment3D>();
ClassDB::register_class<RemoteTransform>();
ClassDB::register_virtual_class<Joint>();
ClassDB::register_class<PinJoint>();
ClassDB::register_class<HingeJoint>();
ClassDB::register_class<SliderJoint>();
ClassDB::register_class<ConeTwistJoint>();
ClassDB::register_class<Generic6DOFJoint>();
ClassDB::register_class<Navigation>();
ClassDB::register_class<NavigationMeshInstance>();
ClassDB::register_class<NavigationAgent>();
ClassDB::register_class<NavigationObstacle>();
ClassDB::register_class<NavigationLink3D>();
OS::get_singleton()->yield(); //may take time to init
@ -601,22 +557,6 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
ClassDB::register_virtual_class<Shape>();
ClassDB::register_class<RayShape>();
ClassDB::register_class<SphereShape>();
ClassDB::register_class<BoxShape>();
ClassDB::register_class<CapsuleShape>();
ClassDB::register_class<CylinderShape>();
ClassDB::register_class<HeightMapShape>();
ClassDB::register_class<PlaneShape>();
ClassDB::register_class<ConvexPolygonShape>();
ClassDB::register_class<ConcavePolygonShape>();
ClassDB::register_virtual_class<OccluderShape>();
ClassDB::register_class<OccluderShapeSphere>();
ClassDB::register_class<OccluderShapePolygon>();
OS::get_singleton()->yield(); //may take time to init
ClassDB::register_class<SpatialVelocityTracker>();
#endif

View File

@ -422,27 +422,6 @@ Vector<Face3> ImporterMesh::get_faces() const {
return faces;
}
Ref<Shape> ImporterMesh::create_trimesh_shape() const {
Vector<Face3> faces = get_faces();
if (faces.size() == 0) {
return Ref<Shape>();
}
PoolVector<Vector3> face_points;
face_points.resize(faces.size() * 3);
for (int i = 0; i < face_points.size(); i += 3) {
Face3 f = faces.get(i / 3);
face_points.set(i, f.vertex[0]);
face_points.set(i + 1, f.vertex[1]);
face_points.set(i + 2, f.vertex[2]);
}
Ref<ConcavePolygonShape> shape = memnew(ConcavePolygonShape);
shape->set_faces(face_points);
return shape;
}
Ref<NavigationMesh> ImporterMesh::create_navigation_mesh() {
Vector<Face3> faces = get_faces();
if (faces.size() == 0) {

View File

@ -33,8 +33,6 @@
#include "core/object/resource.h"
#include "core/containers/local_vector.h"
#include "scene/resources/shapes/concave_polygon_shape.h"
#include "scene/resources/shapes/convex_polygon_shape.h"
#include "scene/resources/mesh/mesh.h"
#include "scene/resources/navigation/navigation_mesh.h"
@ -116,7 +114,6 @@ public:
void set_surface_material(int p_surface, const Ref<Material> &p_material);
Vector<Face3> get_faces() const;
Ref<Shape> create_trimesh_shape() const;
Ref<NavigationMesh> create_navigation_mesh();
bool has_mesh() const;

View File

@ -34,8 +34,6 @@
#include "core/containers/local_vector.h"
#include "core/math/convex_hull.h"
#include "core/containers/pair.h"
#include "scene/resources/shapes/concave_polygon_shape.h"
#include "scene/resources/shapes/convex_polygon_shape.h"
#include "surface_tool.h"
#include <stdlib.h>
@ -202,68 +200,6 @@ PoolVector<Face3> Mesh::get_faces() const {
return PoolVector<Face3>();
}
Ref<Shape> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const {
if (p_simplify) {
Vector<Ref<Shape>> decomposed = convex_decompose(1);
if (decomposed.size() == 1) {
return decomposed[0];
} else {
ERR_PRINT("Convex shape simplification failed, falling back to simpler process.");
}
}
PoolVector<Vector3> vertices;
for (int i = 0; i < get_surface_count(); i++) {
Array a = surface_get_arrays(i);
ERR_FAIL_COND_V(a.empty(), Ref<ConvexPolygonShape>());
PoolVector<Vector3> v = a[ARRAY_VERTEX];
vertices.append_array(v);
}
Ref<ConvexPolygonShape> shape = memnew(ConvexPolygonShape);
if (p_clean) {
Geometry::MeshData md;
Error err = ConvexHullComputer::convex_hull(vertices, md);
if (err == OK) {
int vertex_count = md.vertices.size();
vertices.resize(vertex_count);
{
PoolVector<Vector3>::Write w = vertices.write();
for (int idx = 0; idx < vertex_count; ++idx) {
w[idx] = md.vertices[idx];
}
}
} else {
ERR_PRINT("Convex shape cleaning failed, falling back to simpler process.");
}
}
shape->set_points(vertices);
return shape;
}
Ref<Shape> Mesh::create_trimesh_shape() const {
PoolVector<Face3> faces = get_faces();
if (faces.size() == 0) {
return Ref<Shape>();
}
PoolVector<Vector3> face_points;
face_points.resize(faces.size() * 3);
for (int i = 0; i < face_points.size(); i += 3) {
Face3 f = faces.get(i / 3);
face_points.set(i, f.vertex[0]);
face_points.set(i + 1, f.vertex[1]);
face_points.set(i + 2, f.vertex[2]);
}
Ref<ConcavePolygonShape> shape = memnew(ConcavePolygonShape);
shape->set_faces(face_points);
return shape;
}
Ref<Mesh> Mesh::create_outline(float p_margin) const {
Array arrays;
int index_accum = 0;
@ -527,44 +463,6 @@ void Mesh::clear_cache() const {
debug_lines.clear();
}
Vector<Ref<Shape>> Mesh::convex_decompose(int p_max_convex_hulls) const {
ERR_FAIL_COND_V(!convex_decomposition_function, Vector<Ref<Shape>>());
Ref<TriangleMesh> tm = generate_triangle_mesh();
ERR_FAIL_COND_V(!tm.is_valid(), Vector<Ref<Shape>>());
const PoolVector<TriangleMesh::Triangle> &triangles = tm->get_triangles();
int triangle_count = triangles.size();
PoolVector<uint32_t> indices;
{
indices.resize(triangle_count * 3);
PoolVector<uint32_t>::Write w = indices.write();
PoolVector<TriangleMesh::Triangle>::Read triangles_read = triangles.read();
for (int i = 0; i < triangle_count; i++) {
for (int j = 0; j < 3; j++) {
w[i * 3 + j] = triangles_read[i].indices[j];
}
}
}
const PoolVector<Vector3> &vertices = tm->get_vertices();
int vertex_count = vertices.size();
Vector<PoolVector<Vector3>> decomposed = convex_decomposition_function((real_t *)vertices.read().ptr(), vertex_count, indices.read().ptr(), triangle_count, p_max_convex_hulls, nullptr);
Vector<Ref<Shape>> ret;
for (int i = 0; i < decomposed.size(); i++) {
Ref<ConvexPolygonShape> shape;
shape.instance();
shape->set_points(decomposed[i]);
ret.push_back(shape);
}
return ret;
}
Mesh::Mesh() {
}
@ -1081,8 +979,6 @@ void ArrayMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("surface_find_by_name", "name"), &ArrayMesh::surface_find_by_name);
ClassDB::bind_method(D_METHOD("surface_set_name", "surf_idx", "name"), &ArrayMesh::surface_set_name);
ClassDB::bind_method(D_METHOD("surface_get_name", "surf_idx"), &ArrayMesh::surface_get_name);
ClassDB::bind_method(D_METHOD("create_trimesh_shape"), &ArrayMesh::create_trimesh_shape);
ClassDB::bind_method(D_METHOD("create_convex_shape", "clean", "simplify"), &ArrayMesh::create_convex_shape, DEFVAL(true), DEFVAL(false));
ClassDB::bind_method(D_METHOD("create_outline", "margin"), &ArrayMesh::create_outline);
ClassDB::bind_method(D_METHOD("regen_normalmaps"), &ArrayMesh::regen_normalmaps);
ClassDB::set_method_flags(get_class_static(), _scs_create("regen_normalmaps"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);

View File

@ -35,7 +35,6 @@
#include "core/object/resource.h"
#include "scene/resources/material/material.h"
#include "scene/resources/shapes/shape.h"
#include "servers/rendering_server.h"
class Mesh : public Resource {
@ -136,9 +135,6 @@ public:
void generate_debug_mesh_lines(Vector<Vector3> &r_lines);
void generate_debug_mesh_indices(Vector<Vector3> &r_points);
Ref<Shape> create_trimesh_shape() const;
Ref<Shape> create_convex_shape(bool p_clean = true, bool p_simplify = false) const;
Ref<Mesh> create_outline(float p_margin) const;
virtual AABB get_aabb() const = 0;
@ -149,8 +145,6 @@ public:
static ConvexDecompositionFunc convex_decomposition_function;
Vector<Ref<Shape>> convex_decompose(int p_max_convex_hulls = -1) const;
Mesh();
};

View File

@ -31,7 +31,6 @@
/*************************************************************************/
#include "core/object/resource.h"
#include "servers/physics_server.h"
class PhysicsMaterial : public Resource {
GDCLASS(PhysicsMaterial, Resource);

View File

@ -1,80 +0,0 @@
/*************************************************************************/
/* box_shape.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "box_shape.h"
#include "servers/physics_server.h"
Vector<Vector3> BoxShape::get_debug_mesh_lines() {
Vector<Vector3> lines;
AABB aabb;
aabb.position = -get_extents();
aabb.size = aabb.position * -2;
for (int i = 0; i < 12; i++) {
Vector3 a, b;
aabb.get_edge(i, a, b);
lines.push_back(a);
lines.push_back(b);
}
return lines;
}
real_t BoxShape::get_enclosing_radius() const {
return extents.length();
}
void BoxShape::_update_shape() {
PhysicsServer::get_singleton()->shape_set_data(get_shape(), extents);
Shape::_update_shape();
}
void BoxShape::set_extents(const Vector3 &p_extents) {
extents = p_extents;
_update_shape();
notify_change_to_owners();
_change_notify("extents");
}
Vector3 BoxShape::get_extents() const {
return extents;
}
void BoxShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_extents", "extents"), &BoxShape::set_extents);
ClassDB::bind_method(D_METHOD("get_extents"), &BoxShape::get_extents);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents");
}
BoxShape::BoxShape() :
Shape(RID_PRIME(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_BOX))) {
set_extents(Vector3(1, 1, 1));
}

View File

@ -1,54 +0,0 @@
#ifndef BOX_SHAPE_H
#define BOX_SHAPE_H
/*************************************************************************/
/* box_shape.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/resources/shapes/shape.h"
class BoxShape : public Shape {
GDCLASS(BoxShape, Shape);
Vector3 extents;
protected:
static void _bind_methods();
virtual void _update_shape();
public:
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
virtual Vector<Vector3> get_debug_mesh_lines();
virtual real_t get_enclosing_radius() const;
BoxShape();
};
#endif // BOX_SHAPE_H

View File

@ -1,119 +0,0 @@
/*************************************************************************/
/* capsule_shape.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "capsule_shape.h"
#include "servers/physics_server.h"
Vector<Vector3> CapsuleShape::get_debug_mesh_lines() {
float radius = get_radius();
float height = get_height();
Vector<Vector3> points;
Vector3 d(0, 0, height * 0.5);
for (int i = 0; i < 360; i++) {
float ra = Math::deg2rad((float)i);
float rb = Math::deg2rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
points.push_back(Vector3(a.x, a.y, 0) + d);
points.push_back(Vector3(b.x, b.y, 0) + d);
points.push_back(Vector3(a.x, a.y, 0) - d);
points.push_back(Vector3(b.x, b.y, 0) - d);
if (i % 90 == 0) {
points.push_back(Vector3(a.x, a.y, 0) + d);
points.push_back(Vector3(a.x, a.y, 0) - d);
}
Vector3 dud = i < 180 ? d : -d;
points.push_back(Vector3(0, a.y, a.x) + dud);
points.push_back(Vector3(0, b.y, b.x) + dud);
points.push_back(Vector3(a.y, 0, a.x) + dud);
points.push_back(Vector3(b.y, 0, b.x) + dud);
}
return points;
}
real_t CapsuleShape::get_enclosing_radius() const {
return radius + height * 0.5;
}
void CapsuleShape::_update_shape() {
Dictionary d;
d["radius"] = radius;
d["height"] = height;
PhysicsServer::get_singleton()->shape_set_data(get_shape(), d);
Shape::_update_shape();
}
void CapsuleShape::set_radius(float p_radius) {
radius = p_radius;
_update_shape();
notify_change_to_owners();
_change_notify("radius");
}
float CapsuleShape::get_radius() const {
return radius;
}
void CapsuleShape::set_height(float p_height) {
height = p_height;
_update_shape();
notify_change_to_owners();
_change_notify("height");
}
float CapsuleShape::get_height() const {
return height;
}
void CapsuleShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CapsuleShape::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &CapsuleShape::get_radius);
ClassDB::bind_method(D_METHOD("set_height", "height"), &CapsuleShape::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &CapsuleShape::get_height);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_height", "get_height");
}
CapsuleShape::CapsuleShape() :
Shape(RID_PRIME(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CAPSULE))) {
radius = 1.0;
height = 1.0;
_update_shape();
}

View File

@ -1,57 +0,0 @@
#ifndef CAPSULE_SHAPE_H
#define CAPSULE_SHAPE_H
/*************************************************************************/
/* capsule_shape.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/resources/shapes/shape.h"
class CapsuleShape : public Shape {
GDCLASS(CapsuleShape, Shape);
float radius;
float height;
protected:
static void _bind_methods();
virtual void _update_shape();
public:
void set_radius(float p_radius);
float get_radius() const;
void set_height(float p_height);
float get_height() const;
virtual Vector<Vector3> get_debug_mesh_lines();
virtual real_t get_enclosing_radius() const;
CapsuleShape();
};
#endif // CAPSULE_SHAPE_H

View File

@ -1,96 +0,0 @@
/*************************************************************************/
/* concave_polygon_shape.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "concave_polygon_shape.h"
#include "servers/physics_server.h"
Vector<Vector3> ConcavePolygonShape::get_debug_mesh_lines() {
RBSet<DrawEdge> edges;
PoolVector<Vector3> data = get_faces();
int datalen = data.size();
ERR_FAIL_COND_V((datalen % 3) != 0, Vector<Vector3>());
PoolVector<Vector3>::Read r = data.read();
for (int i = 0; i < datalen; i += 3) {
for (int j = 0; j < 3; j++) {
DrawEdge de(r[i + j], r[i + ((j + 1) % 3)]);
edges.insert(de);
}
}
Vector<Vector3> points;
points.resize(edges.size() * 2);
int idx = 0;
for (RBSet<DrawEdge>::Element *E = edges.front(); E; E = E->next()) {
points.write[idx + 0] = E->get().a;
points.write[idx + 1] = E->get().b;
idx += 2;
}
return points;
}
real_t ConcavePolygonShape::get_enclosing_radius() const {
PoolVector<Vector3> data = get_faces();
PoolVector<Vector3>::Read read = data.read();
real_t r = 0;
for (int i(0); i < data.size(); i++) {
r = MAX(read[i].length_squared(), r);
}
return Math::sqrt(r);
}
void ConcavePolygonShape::_update_shape() {
Shape::_update_shape();
}
void ConcavePolygonShape::set_faces(const PoolVector<Vector3> &p_faces) {
PhysicsServer::get_singleton()->shape_set_data(get_shape(), p_faces);
_update_shape();
notify_change_to_owners();
}
PoolVector<Vector3> ConcavePolygonShape::get_faces() const {
return PhysicsServer::get_singleton()->shape_get_data(get_shape());
}
void ConcavePolygonShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_faces", "faces"), &ConcavePolygonShape::set_faces);
ClassDB::bind_method(D_METHOD("get_faces"), &ConcavePolygonShape::get_faces);
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_faces", "get_faces");
}
ConcavePolygonShape::ConcavePolygonShape() :
Shape(RID_PRIME(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CONCAVE_POLYGON))) {
//set_planes(Vector3(1,1,1));
}

View File

@ -1,73 +0,0 @@
#ifndef CONCAVE_POLYGON_SHAPE_H
#define CONCAVE_POLYGON_SHAPE_H
/*************************************************************************/
/* concave_polygon_shape.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/resources/shapes/shape.h"
class ConcavePolygonShape : public Shape {
GDCLASS(ConcavePolygonShape, Shape);
struct DrawEdge {
Vector3 a;
Vector3 b;
bool operator<(const DrawEdge &p_edge) const {
if (a == p_edge.a) {
return b < p_edge.b;
} else {
return a < p_edge.a;
}
}
DrawEdge(const Vector3 &p_a = Vector3(), const Vector3 &p_b = Vector3()) {
a = p_a;
b = p_b;
if (a < b) {
SWAP(a, b);
}
}
};
protected:
static void _bind_methods();
virtual void _update_shape();
public:
void set_faces(const PoolVector<Vector3> &p_faces);
PoolVector<Vector3> get_faces() const;
Vector<Vector3> get_debug_mesh_lines();
virtual real_t get_enclosing_radius() const;
ConcavePolygonShape();
};
#endif // CONCAVE_POLYGON_SHAPE_H

View File

@ -1,90 +0,0 @@
/*************************************************************************/
/* convex_polygon_shape.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "convex_polygon_shape.h"
#include "core/math/convex_hull.h"
#include "servers/physics_server.h"
Vector<Vector3> ConvexPolygonShape::get_debug_mesh_lines() {
PoolVector<Vector3> points = get_points();
if (points.size() > 3) {
Vector<Vector3> varr = Variant(points);
Geometry::MeshData md;
Error err = ConvexHullComputer::convex_hull(varr, md);
if (err == OK) {
Vector<Vector3> lines;
lines.resize(md.edges.size() * 2);
for (int i = 0; i < md.edges.size(); i++) {
lines.write[i * 2 + 0] = md.vertices[md.edges[i].a];
lines.write[i * 2 + 1] = md.vertices[md.edges[i].b];
}
return lines;
}
}
return Vector<Vector3>();
}
real_t ConvexPolygonShape::get_enclosing_radius() const {
PoolVector<Vector3> data = get_points();
PoolVector<Vector3>::Read read = data.read();
real_t r = 0;
for (int i(0); i < data.size(); i++) {
r = MAX(read[i].length_squared(), r);
}
return Math::sqrt(r);
}
void ConvexPolygonShape::_update_shape() {
PhysicsServer::get_singleton()->shape_set_data(get_shape(), points);
Shape::_update_shape();
}
void ConvexPolygonShape::set_points(const PoolVector<Vector3> &p_points) {
points = p_points;
_update_shape();
notify_change_to_owners();
}
PoolVector<Vector3> ConvexPolygonShape::get_points() const {
return points;
}
void ConvexPolygonShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_points", "points"), &ConvexPolygonShape::set_points);
ClassDB::bind_method(D_METHOD("get_points"), &ConvexPolygonShape::get_points);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "points"), "set_points", "get_points");
}
ConvexPolygonShape::ConvexPolygonShape() :
Shape(RID_PRIME(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CONVEX_POLYGON))) {
}

View File

@ -1,54 +0,0 @@
#ifndef CONVEX_POLYGON_SHAPE_H
#define CONVEX_POLYGON_SHAPE_H
/*************************************************************************/
/* convex_polygon_shape.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/resources/shapes/shape.h"
class ConvexPolygonShape : public Shape {
GDCLASS(ConvexPolygonShape, Shape);
PoolVector<Vector3> points;
protected:
static void _bind_methods();
virtual void _update_shape();
public:
void set_points(const PoolVector<Vector3> &p_points);
PoolVector<Vector3> get_points() const;
virtual Vector<Vector3> get_debug_mesh_lines();
virtual real_t get_enclosing_radius() const;
ConvexPolygonShape();
};
#endif // CONVEX_POLYGON_SHAPE_H

View File

@ -1,112 +0,0 @@
/*************************************************************************/
/* cylinder_shape.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "cylinder_shape.h"
#include "servers/physics_server.h"
Vector<Vector3> CylinderShape::get_debug_mesh_lines() {
float radius = get_radius();
float height = get_height();
Vector<Vector3> points;
Vector3 d(0, height * 0.5, 0);
for (int i = 0; i < 360; i++) {
float ra = Math::deg2rad((float)i);
float rb = Math::deg2rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(b.x, 0, b.y) + d);
points.push_back(Vector3(a.x, 0, a.y) - d);
points.push_back(Vector3(b.x, 0, b.y) - d);
if (i % 90 == 0) {
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(a.x, 0, a.y) - d);
}
}
return points;
}
real_t CylinderShape::get_enclosing_radius() const {
return Vector2(radius, height * 0.5).length();
}
void CylinderShape::_update_shape() {
Dictionary d;
d["radius"] = radius;
d["height"] = height;
PhysicsServer::get_singleton()->shape_set_data(get_shape(), d);
Shape::_update_shape();
}
void CylinderShape::set_radius(float p_radius) {
radius = p_radius;
_update_shape();
notify_change_to_owners();
_change_notify("radius");
}
float CylinderShape::get_radius() const {
return radius;
}
void CylinderShape::set_height(float p_height) {
height = p_height;
_update_shape();
notify_change_to_owners();
_change_notify("height");
}
float CylinderShape::get_height() const {
return height;
}
void CylinderShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CylinderShape::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &CylinderShape::get_radius);
ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderShape::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &CylinderShape::get_height);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_radius", "get_radius");
}
CylinderShape::CylinderShape() :
Shape(RID_PRIME(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CYLINDER))) {
radius = 1.0;
height = 2.0;
_update_shape();
}

View File

@ -1,56 +0,0 @@
#ifndef CYLINDER_SHAPE_H
#define CYLINDER_SHAPE_H
/*************************************************************************/
/* cylinder_shape.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/resources/shapes/shape.h"
class CylinderShape : public Shape {
GDCLASS(CylinderShape, Shape);
float radius;
float height;
protected:
static void _bind_methods();
virtual void _update_shape();
public:
void set_radius(float p_radius);
float get_radius() const;
void set_height(float p_height);
float get_height() const;
virtual Vector<Vector3> get_debug_mesh_lines();
virtual real_t get_enclosing_radius() const;
CylinderShape();
};
#endif // CYLINDER_SHAPE_H

View File

@ -1,214 +0,0 @@
/*************************************************************************/
/* height_map_shape.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "height_map_shape.h"
#include "servers/physics_server.h"
Vector<Vector3> HeightMapShape::get_debug_mesh_lines() {
Vector<Vector3> points;
if ((map_width != 0) && (map_depth != 0)) {
// This will be slow for large maps...
// also we'll have to figure out how well bullet centers this shape...
Vector2 size(map_width - 1, map_depth - 1);
Vector2 start = size * -0.5;
PoolRealArray::Read r = map_data.read();
// reserve some memory for our points..
points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2) + (map_width - 1) * (map_depth - 1) * 2);
// now set our points
int r_offset = 0;
int w_offset = 0;
for (int d = 0; d < map_depth; d++) {
Vector3 height(start.x, 0.0, start.y);
for (int w = 0; w < map_width; w++) {
height.y = r[r_offset++];
if (w != map_width - 1) {
points.write[w_offset++] = height;
points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);
}
if (d != map_depth - 1) {
points.write[w_offset++] = height;
points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
}
if ((w != map_width - 1) && (d != map_depth - 1)) {
points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);
points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
}
height.x += 1.0;
}
start.y += 1.0;
}
}
return points;
}
real_t HeightMapShape::get_enclosing_radius() const {
return Vector3(real_t(map_width), max_height - min_height, real_t(map_depth)).length();
}
void HeightMapShape::_update_shape() {
Dictionary d;
d["width"] = map_width;
d["depth"] = map_depth;
d["heights"] = map_data;
d["min_height"] = min_height;
d["max_height"] = max_height;
PhysicsServer::get_singleton()->shape_set_data(get_shape(), d);
Shape::_update_shape();
}
void HeightMapShape::set_map_width(int p_new) {
if (p_new < 1) {
// ignore
} else if (map_width != p_new) {
int was_size = map_width * map_depth;
map_width = p_new;
int new_size = map_width * map_depth;
map_data.resize(map_width * map_depth);
PoolRealArray::Write w = map_data.write();
while (was_size < new_size) {
w[was_size++] = 0.0;
}
_update_shape();
notify_change_to_owners();
_change_notify("map_width");
_change_notify("map_data");
}
}
int HeightMapShape::get_map_width() const {
return map_width;
}
void HeightMapShape::set_map_depth(int p_new) {
if (p_new < 1) {
// ignore
} else if (map_depth != p_new) {
int was_size = map_width * map_depth;
map_depth = p_new;
int new_size = map_width * map_depth;
map_data.resize(new_size);
PoolRealArray::Write w = map_data.write();
while (was_size < new_size) {
w[was_size++] = 0.0;
}
_update_shape();
notify_change_to_owners();
_change_notify("map_depth");
_change_notify("map_data");
}
}
int HeightMapShape::get_map_depth() const {
return map_depth;
}
void HeightMapShape::set_map_data(PoolRealArray p_new) {
int size = (map_width * map_depth);
if (p_new.size() != size) {
// fail
return;
}
// copy
PoolRealArray::Write w = map_data.write();
PoolRealArray::Read r = p_new.read();
for (int i = 0; i < size; i++) {
float val = r[i];
w[i] = val;
if (i == 0) {
min_height = val;
max_height = val;
} else {
if (min_height > val) {
min_height = val;
}
if (max_height < val) {
max_height = val;
}
}
}
_update_shape();
notify_change_to_owners();
_change_notify("map_data");
}
PoolRealArray HeightMapShape::get_map_data() const {
return map_data;
}
void HeightMapShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_map_width", "width"), &HeightMapShape::set_map_width);
ClassDB::bind_method(D_METHOD("get_map_width"), &HeightMapShape::get_map_width);
ClassDB::bind_method(D_METHOD("set_map_depth", "height"), &HeightMapShape::set_map_depth);
ClassDB::bind_method(D_METHOD("get_map_depth"), &HeightMapShape::get_map_depth);
ClassDB::bind_method(D_METHOD("set_map_data", "data"), &HeightMapShape::set_map_data);
ClassDB::bind_method(D_METHOD("get_map_data"), &HeightMapShape::get_map_data);
ADD_PROPERTY(PropertyInfo(Variant::INT, "map_width", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_map_width", "get_map_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "map_depth", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_map_depth", "get_map_depth");
ADD_PROPERTY(PropertyInfo(Variant::POOL_REAL_ARRAY, "map_data"), "set_map_data", "get_map_data");
}
HeightMapShape::HeightMapShape() :
Shape(RID_PRIME(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_HEIGHTMAP))) {
map_width = 2;
map_depth = 2;
map_data.resize(map_width * map_depth);
PoolRealArray::Write w = map_data.write();
w[0] = 0.0;
w[1] = 0.0;
w[2] = 0.0;
w[3] = 0.0;
min_height = 0.0;
max_height = 0.0;
_update_shape();
}

View File

@ -1,62 +0,0 @@
#ifndef HEIGHT_MAP_SHAPE_H
#define HEIGHT_MAP_SHAPE_H
/*************************************************************************/
/* height_map_shape.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/resources/shapes/shape.h"
class HeightMapShape : public Shape {
GDCLASS(HeightMapShape, Shape);
int map_width;
int map_depth;
PoolRealArray map_data;
float min_height;
float max_height;
protected:
static void _bind_methods();
virtual void _update_shape();
public:
void set_map_width(int p_new);
int get_map_width() const;
void set_map_depth(int p_new);
int get_map_depth() const;
void set_map_data(PoolRealArray p_new);
PoolRealArray get_map_data() const;
virtual Vector<Vector3> get_debug_mesh_lines();
virtual real_t get_enclosing_radius() const;
HeightMapShape();
};
#endif /* !HEIGHT_MAP_SHAPE_H */

View File

@ -1,89 +0,0 @@
/*************************************************************************/
/* plane_shape.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "plane_shape.h"
#include "servers/physics_server.h"
Vector<Vector3> PlaneShape::get_debug_mesh_lines() {
Plane p = get_plane();
Vector<Vector3> points;
Vector3 n1 = p.get_any_perpendicular_normal();
Vector3 n2 = p.normal.cross(n1).normalized();
Vector3 pface[4] = {
p.normal * p.d + n1 * 10.0 + n2 * 10.0,
p.normal * p.d + n1 * 10.0 + n2 * -10.0,
p.normal * p.d + n1 * -10.0 + n2 * -10.0,
p.normal * p.d + n1 * -10.0 + n2 * 10.0,
};
points.push_back(pface[0]);
points.push_back(pface[1]);
points.push_back(pface[1]);
points.push_back(pface[2]);
points.push_back(pface[2]);
points.push_back(pface[3]);
points.push_back(pface[3]);
points.push_back(pface[0]);
points.push_back(p.normal * p.d);
points.push_back(p.normal * p.d + p.normal * 3);
return points;
}
void PlaneShape::_update_shape() {
PhysicsServer::get_singleton()->shape_set_data(get_shape(), plane);
Shape::_update_shape();
}
void PlaneShape::set_plane(Plane p_plane) {
plane = p_plane;
_update_shape();
notify_change_to_owners();
_change_notify("plane");
}
Plane PlaneShape::get_plane() const {
return plane;
}
void PlaneShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_plane", "plane"), &PlaneShape::set_plane);
ClassDB::bind_method(D_METHOD("get_plane"), &PlaneShape::get_plane);
ADD_PROPERTY(PropertyInfo(Variant::PLANE, "plane"), "set_plane", "get_plane");
}
PlaneShape::PlaneShape() :
Shape(RID_PRIME(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_PLANE))) {
set_plane(Plane(0, 1, 0, 0));
}

View File

@ -1,55 +0,0 @@
#ifndef PLANE_SHAPE_H
#define PLANE_SHAPE_H
/*************************************************************************/
/* plane_shape.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/resources/shapes/shape.h"
class PlaneShape : public Shape {
GDCLASS(PlaneShape, Shape);
Plane plane;
protected:
static void _bind_methods();
virtual void _update_shape();
public:
void set_plane(Plane p_plane);
Plane get_plane() const;
virtual Vector<Vector3> get_debug_mesh_lines();
virtual real_t get_enclosing_radius() const {
// Should be infinite?
return 0;
};
PlaneShape();
};
#endif // PLANE_SHAPE_H

View File

@ -1,98 +0,0 @@
/*************************************************************************/
/* ray_shape.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "ray_shape.h"
#include "servers/physics_server.h"
Vector<Vector3> RayShape::get_debug_mesh_lines() {
Vector<Vector3> points;
points.push_back(Vector3());
points.push_back(Vector3(0, 0, get_length()));
return points;
}
real_t RayShape::get_enclosing_radius() const {
return length;
}
void RayShape::_update_shape() {
Dictionary d;
d["length"] = length;
d["slips_on_slope"] = slips_on_slope;
PhysicsServer::get_singleton()->shape_set_data(get_shape(), d);
Shape::_update_shape();
}
void RayShape::set_length(float p_length) {
length = p_length;
_update_shape();
notify_change_to_owners();
_change_notify("length");
}
float RayShape::get_length() const {
return length;
}
void RayShape::set_slips_on_slope(bool p_active) {
slips_on_slope = p_active;
_update_shape();
notify_change_to_owners();
_change_notify("slips_on_slope");
}
bool RayShape::get_slips_on_slope() const {
return slips_on_slope;
}
void RayShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_length", "length"), &RayShape::set_length);
ClassDB::bind_method(D_METHOD("get_length"), &RayShape::get_length);
ClassDB::bind_method(D_METHOD("set_slips_on_slope", "active"), &RayShape::set_slips_on_slope);
ClassDB::bind_method(D_METHOD("get_slips_on_slope"), &RayShape::get_slips_on_slope);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "length", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_length", "get_length");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slips_on_slope"), "set_slips_on_slope", "get_slips_on_slope");
}
RayShape::RayShape() :
Shape(RID_PRIME(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_RAY))) {
length = 1.0;
slips_on_slope = false;
/* Code copied from setters to prevent the use of uninitialized variables */
_update_shape();
notify_change_to_owners();
_change_notify("length");
_change_notify("slips_on_slope");
}

View File

@ -1,56 +0,0 @@
#ifndef RAY_SHAPE_H
#define RAY_SHAPE_H
/*************************************************************************/
/* ray_shape.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/resources/shapes/shape.h"
class RayShape : public Shape {
GDCLASS(RayShape, Shape);
float length;
bool slips_on_slope;
protected:
static void _bind_methods();
virtual void _update_shape();
public:
void set_length(float p_length);
float get_length() const;
void set_slips_on_slope(bool p_active);
bool get_slips_on_slope() const;
virtual Vector<Vector3> get_debug_mesh_lines();
virtual real_t get_enclosing_radius() const;
RayShape();
};
#endif // RAY_SHAPE_H

View File

@ -1,122 +0,0 @@
/*************************************************************************/
/* shape.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "shape.h"
#include "core/os/os.h"
#include "scene/main/scene_tree.h"
#include "scene/resources/mesh/mesh.h"
#include "servers/physics_server.h"
void Shape::add_vertices_to_array(PoolVector<Vector3> &array, const Transform &p_xform) {
Vector<Vector3> toadd = get_debug_mesh_lines();
if (toadd.size()) {
int base = array.size();
array.resize(base + toadd.size());
PoolVector<Vector3>::Write w = array.write();
for (int i = 0; i < toadd.size(); i++) {
w[i + base] = p_xform.xform(toadd[i]);
}
}
}
real_t Shape::get_margin() const {
return margin;
}
void Shape::set_margin(real_t p_margin) {
margin = p_margin;
PhysicsServer::get_singleton()->shape_set_margin(shape, margin);
}
Ref<ArrayMesh> Shape::get_debug_mesh() {
if (debug_mesh_cache.is_valid()) {
return debug_mesh_cache;
}
Vector<Vector3> lines = get_debug_mesh_lines();
debug_mesh_cache = Ref<ArrayMesh>(memnew(ArrayMesh));
if (!lines.empty()) {
//make mesh
PoolVector<Vector3> array;
array.resize(lines.size());
{
PoolVector<Vector3>::Write w = array.write();
for (int i = 0; i < lines.size(); i++) {
w[i] = lines[i];
}
}
Array arr;
arr.resize(Mesh::ARRAY_MAX);
arr[Mesh::ARRAY_VERTEX] = array;
SceneTree *st = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop());
debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arr);
if (st) {
debug_mesh_cache->surface_set_material(0, st->get_debug_collision_material());
}
}
return debug_mesh_cache;
}
void Shape::_update_shape() {
emit_changed();
debug_mesh_cache.unref();
}
void Shape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &Shape::set_margin);
ClassDB::bind_method(D_METHOD("get_margin"), &Shape::get_margin);
ClassDB::bind_method(D_METHOD("get_debug_mesh"), &Shape::get_debug_mesh);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_margin", "get_margin");
}
Shape::Shape() :
margin(0.04) {
ERR_PRINT("Constructor must not be called!");
}
Shape::Shape(RID p_shape) :
margin(0.04) {
shape = p_shape;
}
Shape::~Shape() {
PhysicsServer::get_singleton()->free(shape);
}

View File

@ -1,70 +0,0 @@
#ifndef SHAPE_H
#define SHAPE_H
/*************************************************************************/
/* shape.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/object/resource.h"
class ArrayMesh;
class Shape : public Resource {
GDCLASS(Shape, Resource);
OBJ_SAVE_TYPE(Shape);
RES_BASE_EXTENSION("shape");
RID shape;
real_t margin;
Ref<ArrayMesh> debug_mesh_cache;
protected:
static void _bind_methods();
_FORCE_INLINE_ RID get_shape() const { return shape; }
Shape(RID p_shape);
virtual void _update_shape();
public:
virtual RID get_rid() const { return shape; }
Ref<ArrayMesh> get_debug_mesh();
virtual Vector<Vector3> get_debug_mesh_lines() = 0; // { return Vector<Vector3>(); }
/// Returns the radius of a sphere that fully enclose this shape
virtual real_t get_enclosing_radius() const = 0;
void add_vertices_to_array(PoolVector<Vector3> &array, const Transform &p_xform);
real_t get_margin() const;
void set_margin(real_t p_margin);
Shape();
~Shape();
};
#endif // SHAPE_H

View File

@ -1,87 +0,0 @@
/*************************************************************************/
/* sphere_shape.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "sphere_shape.h"
#include "servers/physics_server.h"
Vector<Vector3> SphereShape::get_debug_mesh_lines() {
float r = get_radius();
Vector<Vector3> points;
for (int i = 0; i <= 360; i++) {
float ra = Math::deg2rad((float)i);
float rb = Math::deg2rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
points.push_back(Vector3(a.x, 0, a.y));
points.push_back(Vector3(b.x, 0, b.y));
points.push_back(Vector3(0, a.x, a.y));
points.push_back(Vector3(0, b.x, b.y));
points.push_back(Vector3(a.x, a.y, 0));
points.push_back(Vector3(b.x, b.y, 0));
}
return points;
}
real_t SphereShape::get_enclosing_radius() const {
return radius;
}
void SphereShape::_update_shape() {
PhysicsServer::get_singleton()->shape_set_data(get_shape(), radius);
Shape::_update_shape();
}
void SphereShape::set_radius(float p_radius) {
radius = p_radius;
_update_shape();
notify_change_to_owners();
_change_notify("radius");
}
float SphereShape::get_radius() const {
return radius;
}
void SphereShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &SphereShape::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &SphereShape::get_radius);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_radius", "get_radius");
}
SphereShape::SphereShape() :
Shape(RID_PRIME(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_SPHERE))) {
set_radius(1.0);
}

View File

@ -1,54 +0,0 @@
#ifndef SPHERE_SHAPE_H
#define SPHERE_SHAPE_H
/*************************************************************************/
/* sphere_shape.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/resources/shapes/shape.h"
class SphereShape : public Shape {
GDCLASS(SphereShape, Shape);
float radius;
protected:
static void _bind_methods();
virtual void _update_shape();
public:
void set_radius(float p_radius);
float get_radius() const;
virtual Vector<Vector3> get_debug_mesh_lines();
virtual real_t get_enclosing_radius() const;
SphereShape();
};
#endif // SPHERE_SHAPE_H

View File

@ -304,10 +304,6 @@ Ref<Environment3D> World3D::get_fallback_environment() const {
return fallback_environment;
}
PhysicsDirectSpaceState *World3D::get_direct_space_state() {
return PhysicsServer::get_singleton()->space_get_direct_state(space);
}
void World3D::get_camera_list(List<Camera *> *r_cameras) {
for (RBMap<Camera *, SpatialIndexer::CameraData>::Element *E = indexer->cameras.front(); E; E = E->next()) {
r_cameras->push_back(E->key());
@ -336,7 +332,7 @@ void World3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_environment"), &World3D::get_environment);
ClassDB::bind_method(D_METHOD("set_fallback_environment", "env"), &World3D::set_fallback_environment);
ClassDB::bind_method(D_METHOD("get_fallback_environment"), &World3D::get_fallback_environment);
ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World3D::get_direct_space_state);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment3D"), "set_environment", "get_environment");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment3D"), "set_fallback_environment", "get_fallback_environment");
ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space");
@ -346,17 +342,8 @@ void World3D::_bind_methods() {
}
World3D::World3D() {
space = RID_PRIME(PhysicsServer::get_singleton()->space_create());
scenario = RID_PRIME(RenderingServer::get_singleton()->scenario_create());
PhysicsServer::get_singleton()->space_set_active(space, true);
PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/3d/default_gravity", 9.8));
PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/3d/default_gravity_vector", Vector3(0, -1, 0)));
PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/3d/default_linear_damp", 0.1));
ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/default_linear_damp", PropertyInfo(Variant::REAL, "physics/3d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/3d/default_angular_damp", 0.1));
ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/default_angular_damp", PropertyInfo(Variant::REAL, "physics/3d/default_angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
// Create default navigation map
navigation_map = NavigationServer::get_singleton()->map_create();
NavigationServer::get_singleton()->map_set_active(navigation_map, true);
@ -375,7 +362,6 @@ World3D::World3D() {
}
World3D::~World3D() {
PhysicsServer::get_singleton()->free(space);
RenderingServer::get_singleton()->free(scenario);
NavigationServer::get_singleton()->free(navigation_map);

View File

@ -33,7 +33,6 @@
#include "core/object/resource.h"
#include "scene/resources/environment_3d.h"
#include "servers/physics_server.h"
#include "servers/rendering_server.h"
class Camera;
@ -82,8 +81,6 @@ public:
void get_camera_list(List<Camera *> *r_cameras);
PhysicsDirectSpaceState *get_direct_space_state();
void move_cameras_into(Ref<World3D> target);
World3D();

View File

@ -1,7 +0,0 @@
#!/usr/bin/env python
Import("env")
env.add_source_files(env.servers_sources, "*.cpp")
SConscript("joints/SCsub")

View File

@ -1,155 +0,0 @@
/*************************************************************************/
/* area_pair_sw.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "area_pair_sw.h"
#include "collision_solver_sw.h"
bool AreaPairSW::setup(real_t p_step) {
bool result = false;
if (area->test_collision_mask(body) && CollisionSolverSW::solve_static(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), nullptr, this)) {
result = true;
}
if (result != colliding) {
if (result) {
if (area->get_space_override_mode() != PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED) {
body->add_area(area);
}
if (area->has_monitor_callback()) {
area->add_body_to_query(body, body_shape, area_shape);
}
} else {
if (area->get_space_override_mode() != PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED) {
body->remove_area(area);
}
if (area->has_monitor_callback()) {
area->remove_body_from_query(body, body_shape, area_shape);
}
}
colliding = result;
}
return false; //never do any post solving
}
void AreaPairSW::solve(real_t p_step) {
}
AreaPairSW::AreaPairSW(BodySW *p_body, int p_body_shape, AreaSW *p_area, int p_area_shape) {
body = p_body;
area = p_area;
body_shape = p_body_shape;
area_shape = p_area_shape;
colliding = false;
body->add_constraint(this, 0);
area->add_constraint(this);
if (p_body->get_mode() == PhysicsServer::BODY_MODE_KINEMATIC) {
p_body->set_active(true);
}
}
AreaPairSW::~AreaPairSW() {
if (colliding) {
if (area->get_space_override_mode() != PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED) {
body->remove_area(area);
}
if (area->has_monitor_callback()) {
area->remove_body_from_query(body, body_shape, area_shape);
}
}
body->remove_constraint(this);
area->remove_constraint(this);
}
////////////////////////////////////////////////////
bool Area2PairSW::setup(real_t p_step) {
bool result = false;
if (area_a->test_collision_mask(area_b) && CollisionSolverSW::solve_static(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), nullptr, this)) {
result = true;
}
if (result != colliding) {
if (result) {
if (area_b->has_area_monitor_callback() && area_a_monitorable) {
area_b->add_area_to_query(area_a, shape_a, shape_b);
}
if (area_a->has_area_monitor_callback() && area_b_monitorable) {
area_a->add_area_to_query(area_b, shape_b, shape_a);
}
} else {
if (area_b->has_area_monitor_callback() && area_a_monitorable) {
area_b->remove_area_from_query(area_a, shape_a, shape_b);
}
if (area_a->has_area_monitor_callback() && area_b_monitorable) {
area_a->remove_area_from_query(area_b, shape_b, shape_a);
}
}
colliding = result;
}
return false; //never do any post solving
}
void Area2PairSW::solve(real_t p_step) {
}
Area2PairSW::Area2PairSW(AreaSW *p_area_a, int p_shape_a, AreaSW *p_area_b, int p_shape_b) {
area_a = p_area_a;
area_b = p_area_b;
shape_a = p_shape_a;
shape_b = p_shape_b;
colliding = false;
area_a_monitorable = area_a->is_monitorable();
area_b_monitorable = area_b->is_monitorable();
area_a->add_constraint(this);
area_b->add_constraint(this);
}
Area2PairSW::~Area2PairSW() {
if (colliding) {
if (area_b->has_area_monitor_callback() && area_a_monitorable) {
area_b->remove_area_from_query(area_a, shape_a, shape_b);
}
if (area_a->has_area_monitor_callback() && area_b_monitorable) {
area_a->remove_area_from_query(area_b, shape_b, shape_a);
}
}
area_a->remove_constraint(this);
area_b->remove_constraint(this);
}

View File

@ -1,69 +0,0 @@
#ifndef AREA_PAIR_SW_H
#define AREA_PAIR_SW_H
/*************************************************************************/
/* area_pair_sw.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "area_sw.h"
#include "body_sw.h"
#include "constraint_sw.h"
class AreaPairSW : public ConstraintSW {
BodySW *body;
AreaSW *area;
int body_shape;
int area_shape;
bool colliding;
public:
bool setup(real_t p_step);
void solve(real_t p_step);
AreaPairSW(BodySW *p_body, int p_body_shape, AreaSW *p_area, int p_area_shape);
~AreaPairSW();
};
class Area2PairSW : public ConstraintSW {
AreaSW *area_a;
AreaSW *area_b;
int shape_a;
int shape_b;
bool colliding;
bool area_a_monitorable;
bool area_b_monitorable;
public:
bool setup(real_t p_step);
void solve(real_t p_step);
Area2PairSW(AreaSW *p_area_a, int p_shape_a, AreaSW *p_area_b, int p_shape_b);
~Area2PairSW();
};
#endif // AREA_PAIR__SW_H

View File

@ -1,296 +0,0 @@
/*************************************************************************/
/* area_sw.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "area_sw.h"
#include "body_sw.h"
#include "space_sw.h"
AreaSW::BodyKey::BodyKey(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
rid = p_body->get_self();
instance_id = p_body->get_instance_id();
body_shape = p_body_shape;
area_shape = p_area_shape;
}
AreaSW::BodyKey::BodyKey(AreaSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
rid = p_body->get_self();
instance_id = p_body->get_instance_id();
body_shape = p_body_shape;
area_shape = p_area_shape;
}
void AreaSW::_shapes_changed() {
if (!moved_list.in_list() && get_space()) {
get_space()->area_add_to_moved_list(&moved_list);
}
}
void AreaSW::set_transform(const Transform &p_transform) {
if (!moved_list.in_list() && get_space()) {
get_space()->area_add_to_moved_list(&moved_list);
}
_set_transform(p_transform);
_set_inv_transform(p_transform.affine_inverse());
}
void AreaSW::set_space(SpaceSW *p_space) {
if (get_space()) {
if (monitor_query_list.in_list()) {
get_space()->area_remove_from_monitor_query_list(&monitor_query_list);
}
if (moved_list.in_list()) {
get_space()->area_remove_from_moved_list(&moved_list);
}
}
monitored_bodies.clear();
monitored_areas.clear();
_set_space(p_space);
}
void AreaSW::set_monitor_callback(ObjectID p_id, const StringName &p_method) {
if (p_id == monitor_callback_id) {
monitor_callback_method = p_method;
return;
}
_unregister_shapes();
monitor_callback_id = p_id;
monitor_callback_method = p_method;
monitored_bodies.clear();
monitored_areas.clear();
_shape_changed();
if (!moved_list.in_list() && get_space()) {
get_space()->area_add_to_moved_list(&moved_list);
}
}
void AreaSW::set_area_monitor_callback(ObjectID p_id, const StringName &p_method) {
if (p_id == area_monitor_callback_id) {
area_monitor_callback_method = p_method;
return;
}
_unregister_shapes();
area_monitor_callback_id = p_id;
area_monitor_callback_method = p_method;
monitored_bodies.clear();
monitored_areas.clear();
_shape_changed();
if (!moved_list.in_list() && get_space()) {
get_space()->area_add_to_moved_list(&moved_list);
}
}
void AreaSW::set_space_override_mode(PhysicsServer::AreaSpaceOverrideMode p_mode) {
bool do_override = p_mode != PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED;
if (do_override == (space_override_mode != PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED)) {
return;
}
_unregister_shapes();
space_override_mode = p_mode;
_shape_changed();
}
void AreaSW::set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value) {
switch (p_param) {
case PhysicsServer::AREA_PARAM_GRAVITY:
gravity = p_value;
break;
case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR:
gravity_vector = p_value;
break;
case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT:
gravity_is_point = p_value;
break;
case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
gravity_distance_scale = p_value;
break;
case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
point_attenuation = p_value;
break;
case PhysicsServer::AREA_PARAM_LINEAR_DAMP:
linear_damp = p_value;
break;
case PhysicsServer::AREA_PARAM_ANGULAR_DAMP:
angular_damp = p_value;
break;
case PhysicsServer::AREA_PARAM_PRIORITY:
priority = p_value;
break;
}
}
Variant AreaSW::get_param(PhysicsServer::AreaParameter p_param) const {
switch (p_param) {
case PhysicsServer::AREA_PARAM_GRAVITY:
return gravity;
case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR:
return gravity_vector;
case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT:
return gravity_is_point;
case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
return gravity_distance_scale;
case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
return point_attenuation;
case PhysicsServer::AREA_PARAM_LINEAR_DAMP:
return linear_damp;
case PhysicsServer::AREA_PARAM_ANGULAR_DAMP:
return angular_damp;
case PhysicsServer::AREA_PARAM_PRIORITY:
return priority;
}
return Variant();
}
void AreaSW::_queue_monitor_update() {
ERR_FAIL_COND(!get_space());
if (!monitor_query_list.in_list()) {
get_space()->area_add_to_monitor_query_list(&monitor_query_list);
}
}
void AreaSW::set_monitorable(bool p_monitorable) {
if (monitorable == p_monitorable) {
return;
}
monitorable = p_monitorable;
_set_static(!monitorable);
_shapes_changed();
}
void AreaSW::call_queries() {
if (monitor_callback_id && !monitored_bodies.empty()) {
Object *obj = ObjectDB::get_instance(monitor_callback_id);
if (obj) {
Variant res[5];
Variant *resptr[5];
for (int i = 0; i < 5; i++) {
resptr[i] = &res[i];
}
for (RBMap<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E;) {
if (E->get().state == 0) { // Nothing happened
RBMap<BodyKey, BodyState>::Element *next = E->next();
monitored_bodies.erase(E);
E = next;
continue;
}
res[0] = E->get().state > 0 ? PhysicsServer::AREA_BODY_ADDED : PhysicsServer::AREA_BODY_REMOVED;
res[1] = E->key().rid;
res[2] = E->key().instance_id;
res[3] = E->key().body_shape;
res[4] = E->key().area_shape;
RBMap<BodyKey, BodyState>::Element *next = E->next();
monitored_bodies.erase(E);
E = next;
Variant::CallError ce;
obj->call(monitor_callback_method, (const Variant **)resptr, 5, ce);
}
} else {
monitored_bodies.clear();
monitor_callback_id = 0;
}
}
if (area_monitor_callback_id && !monitored_areas.empty()) {
Object *obj = ObjectDB::get_instance(area_monitor_callback_id);
if (obj) {
Variant res[5];
Variant *resptr[5];
for (int i = 0; i < 5; i++) {
resptr[i] = &res[i];
}
for (RBMap<BodyKey, BodyState>::Element *E = monitored_areas.front(); E;) {
if (E->get().state == 0) { // Nothing happened
RBMap<BodyKey, BodyState>::Element *next = E->next();
monitored_areas.erase(E);
E = next;
continue;
}
res[0] = E->get().state > 0 ? PhysicsServer::AREA_BODY_ADDED : PhysicsServer::AREA_BODY_REMOVED;
res[1] = E->key().rid;
res[2] = E->key().instance_id;
res[3] = E->key().body_shape;
res[4] = E->key().area_shape;
RBMap<BodyKey, BodyState>::Element *next = E->next();
monitored_areas.erase(E);
E = next;
Variant::CallError ce;
obj->call(area_monitor_callback_method, (const Variant **)resptr, 5, ce);
}
} else {
monitored_areas.clear();
area_monitor_callback_id = 0;
}
}
}
AreaSW::AreaSW() :
CollisionObjectSW(TYPE_AREA),
monitor_query_list(this),
moved_list(this) {
_set_static(true); //areas are never active
space_override_mode = PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED;
gravity = 9.80665;
gravity_vector = Vector3(0, -1, 0);
gravity_is_point = false;
gravity_distance_scale = 0;
point_attenuation = 1;
angular_damp = 0.1;
linear_damp = 0.1;
priority = 0;
set_ray_pickable(false);
monitor_callback_id = 0;
area_monitor_callback_id = 0;
monitorable = false;
}
AreaSW::~AreaSW() {
}

View File

@ -1,198 +0,0 @@
#ifndef AREA_SW_H
#define AREA_SW_H
/*************************************************************************/
/* area_sw.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "collision_object_sw.h"
#include "core/containers/self_list.h"
#include "servers/physics_server.h"
//#include "servers/physics/query_sw.h"
class SpaceSW;
class BodySW;
class ConstraintSW;
class AreaSW : public CollisionObjectSW {
PhysicsServer::AreaSpaceOverrideMode space_override_mode;
real_t gravity;
Vector3 gravity_vector;
bool gravity_is_point;
real_t gravity_distance_scale;
real_t point_attenuation;
real_t linear_damp;
real_t angular_damp;
int priority;
bool monitorable;
ObjectID monitor_callback_id;
StringName monitor_callback_method;
ObjectID area_monitor_callback_id;
StringName area_monitor_callback_method;
SelfList<AreaSW> monitor_query_list;
SelfList<AreaSW> moved_list;
struct BodyKey {
RID rid;
ObjectID instance_id;
uint32_t body_shape;
uint32_t area_shape;
_FORCE_INLINE_ bool operator<(const BodyKey &p_key) const {
if (rid == p_key.rid) {
if (body_shape == p_key.body_shape) {
return area_shape < p_key.area_shape;
} else {
return body_shape < p_key.body_shape;
}
} else {
return rid < p_key.rid;
}
}
_FORCE_INLINE_ BodyKey() {}
BodyKey(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
BodyKey(AreaSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
};
struct BodyState {
int state;
_FORCE_INLINE_ void inc() { state++; }
_FORCE_INLINE_ void dec() { state--; }
_FORCE_INLINE_ BodyState() { state = 0; }
};
RBMap<BodyKey, BodyState> monitored_bodies;
RBMap<BodyKey, BodyState> monitored_areas;
//virtual void shape_changed_notify(ShapeSW *p_shape);
//virtual void shape_deleted_notify(ShapeSW *p_shape);
RBSet<ConstraintSW *> constraints;
virtual void _shapes_changed();
void _queue_monitor_update();
public:
//_FORCE_INLINE_ const Transform& get_inverse_transform() const { return inverse_transform; }
//_FORCE_INLINE_ SpaceSW* get_owner() { return owner; }
void set_monitor_callback(ObjectID p_id, const StringName &p_method);
_FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id; }
void set_area_monitor_callback(ObjectID p_id, const StringName &p_method);
_FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id; }
_FORCE_INLINE_ void add_body_to_query(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
_FORCE_INLINE_ void remove_body_from_query(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
_FORCE_INLINE_ void add_area_to_query(AreaSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
_FORCE_INLINE_ void remove_area_from_query(AreaSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
void set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value);
Variant get_param(PhysicsServer::AreaParameter p_param) const;
void set_space_override_mode(PhysicsServer::AreaSpaceOverrideMode p_mode);
PhysicsServer::AreaSpaceOverrideMode get_space_override_mode() const { return space_override_mode; }
_FORCE_INLINE_ void set_gravity(real_t p_gravity) { gravity = p_gravity; }
_FORCE_INLINE_ real_t get_gravity() const { return gravity; }
_FORCE_INLINE_ void set_gravity_vector(const Vector3 &p_gravity) { gravity_vector = p_gravity; }
_FORCE_INLINE_ Vector3 get_gravity_vector() const { return gravity_vector; }
_FORCE_INLINE_ void set_gravity_as_point(bool p_enable) { gravity_is_point = p_enable; }
_FORCE_INLINE_ bool is_gravity_point() const { return gravity_is_point; }
_FORCE_INLINE_ void set_gravity_distance_scale(real_t scale) { gravity_distance_scale = scale; }
_FORCE_INLINE_ real_t get_gravity_distance_scale() const { return gravity_distance_scale; }
_FORCE_INLINE_ void set_point_attenuation(real_t p_point_attenuation) { point_attenuation = p_point_attenuation; }
_FORCE_INLINE_ real_t get_point_attenuation() const { return point_attenuation; }
_FORCE_INLINE_ void set_linear_damp(real_t p_linear_damp) { linear_damp = p_linear_damp; }
_FORCE_INLINE_ real_t get_linear_damp() const { return linear_damp; }
_FORCE_INLINE_ void set_angular_damp(real_t p_angular_damp) { angular_damp = p_angular_damp; }
_FORCE_INLINE_ real_t get_angular_damp() const { return angular_damp; }
_FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; }
_FORCE_INLINE_ int get_priority() const { return priority; }
_FORCE_INLINE_ void add_constraint(ConstraintSW *p_constraint) { constraints.insert(p_constraint); }
_FORCE_INLINE_ void remove_constraint(ConstraintSW *p_constraint) { constraints.erase(p_constraint); }
_FORCE_INLINE_ const RBSet<ConstraintSW *> &get_constraints() const { return constraints; }
_FORCE_INLINE_ void clear_constraints() { constraints.clear(); }
void set_monitorable(bool p_monitorable);
_FORCE_INLINE_ bool is_monitorable() const { return monitorable; }
void set_transform(const Transform &p_transform);
void set_space(SpaceSW *p_space);
void call_queries();
AreaSW();
~AreaSW();
};
void AreaSW::add_body_to_query(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
BodyKey bk(p_body, p_body_shape, p_area_shape);
monitored_bodies[bk].inc();
if (!monitor_query_list.in_list()) {
_queue_monitor_update();
}
}
void AreaSW::remove_body_from_query(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
BodyKey bk(p_body, p_body_shape, p_area_shape);
monitored_bodies[bk].dec();
if (!monitor_query_list.in_list()) {
_queue_monitor_update();
}
}
void AreaSW::add_area_to_query(AreaSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape) {
BodyKey bk(p_area, p_area_shape, p_self_shape);
monitored_areas[bk].inc();
if (!monitor_query_list.in_list()) {
_queue_monitor_update();
}
}
void AreaSW::remove_area_from_query(AreaSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape) {
BodyKey bk(p_area, p_area_shape, p_self_shape);
monitored_areas[bk].dec();
if (!monitor_query_list.in_list()) {
_queue_monitor_update();
}
}
#endif // AREA__SW_H

View File

@ -1,468 +0,0 @@
/*************************************************************************/
/* body_pair_sw.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "body_pair_sw.h"
#include "collision_solver_sw.h"
#include "core/os/os.h"
#include "space_sw.h"
#define MIN_VELOCITY 0.0001
#define MAX_BIAS_ROTATION (Math_PI / 8)
void BodyPairSW::_contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
BodyPairSW *pair = (BodyPairSW *)p_userdata;
pair->contact_added_callback(p_point_A, p_point_B);
}
void BodyPairSW::contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B) {
// check if we already have the contact
//Vector3 local_A = A->get_inv_transform().xform(p_point_A);
//Vector3 local_B = B->get_inv_transform().xform(p_point_B);
Vector3 local_A = A->get_inv_transform().basis.xform(p_point_A);
Vector3 local_B = B->get_inv_transform().basis.xform(p_point_B - offset_B);
int new_index = contact_count;
ERR_FAIL_COND(new_index >= (MAX_CONTACTS + 1));
Contact contact;
contact.acc_normal_impulse = 0;
contact.acc_bias_impulse = 0;
contact.acc_bias_impulse_center_of_mass = 0;
contact.acc_tangent_impulse = Vector3();
contact.local_A = local_A;
contact.local_B = local_B;
contact.normal = (p_point_A - p_point_B).normalized();
contact.mass_normal = 0; // will be computed in setup()
// attempt to determine if the contact will be reused
real_t contact_recycle_radius = space->get_contact_recycle_radius();
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
if (c.local_A.distance_squared_to(local_A) < (contact_recycle_radius * contact_recycle_radius) &&
c.local_B.distance_squared_to(local_B) < (contact_recycle_radius * contact_recycle_radius)) {
contact.acc_normal_impulse = c.acc_normal_impulse;
contact.acc_bias_impulse = c.acc_bias_impulse;
contact.acc_bias_impulse_center_of_mass = c.acc_bias_impulse_center_of_mass;
contact.acc_tangent_impulse = c.acc_tangent_impulse;
new_index = i;
break;
}
}
// figure out if the contact amount must be reduced to fit the new contact
if (new_index == MAX_CONTACTS) {
// remove the contact with the minimum depth
int least_deep = -1;
real_t min_depth = 1e10;
for (int i = 0; i <= contact_count; i++) {
Contact &c = (i == contact_count) ? contact : contacts[i];
Vector3 global_A = A->get_transform().basis.xform(c.local_A);
Vector3 global_B = B->get_transform().basis.xform(c.local_B) + offset_B;
Vector3 axis = global_A - global_B;
real_t depth = axis.dot(c.normal);
if (depth < min_depth) {
min_depth = depth;
least_deep = i;
}
}
ERR_FAIL_COND(least_deep == -1);
if (least_deep < contact_count) { //replace the last deep contact by the new one
contacts[least_deep] = contact;
}
return;
}
contacts[new_index] = contact;
if (new_index == contact_count) {
contact_count++;
}
}
void BodyPairSW::validate_contacts() {
//make sure to erase contacts that are no longer valid
real_t contact_max_separation = space->get_contact_max_separation();
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
Vector3 global_A = A->get_transform().basis.xform(c.local_A);
Vector3 global_B = B->get_transform().basis.xform(c.local_B) + offset_B;
Vector3 axis = global_A - global_B;
real_t depth = axis.dot(c.normal);
if (depth < -contact_max_separation || (global_B + c.normal * depth - global_A).length() > contact_max_separation) {
// contact no longer needed, remove
if ((i + 1) < contact_count) {
// swap with the last one
SWAP(contacts[i], contacts[contact_count - 1]);
}
i--;
contact_count--;
}
}
}
bool BodyPairSW::_test_ccd(real_t p_step, BodySW *p_A, int p_shape_A, const Transform &p_xform_A, BodySW *p_B, int p_shape_B, const Transform &p_xform_B) {
Vector3 motion = p_A->get_linear_velocity() * p_step;
real_t mlen = motion.length();
if (mlen < CMP_EPSILON) {
return false;
}
Vector3 mnormal = motion / mlen;
real_t min, max;
p_A->get_shape(p_shape_A)->project_range(mnormal, p_xform_A, min, max);
bool fast_object = mlen > (max - min) * 0.3; //going too fast in that direction
if (!fast_object) { //did it move enough in this direction to even attempt raycast? let's say it should move more than 1/3 the size of the object in that axis
return false;
}
//cast a segment from support in motion normal, in the same direction of motion by motion length
//support is the worst case collision point, so real collision happened before
Vector3 s = p_A->get_shape(p_shape_A)->get_support(p_xform_A.basis.xform(mnormal).normalized());
Vector3 from = p_xform_A.xform(s);
Vector3 to = from + motion;
Transform from_inv = p_xform_B.affine_inverse();
Vector3 local_from = from_inv.xform(from - mnormal * mlen * 0.1); //start from a little inside the bounding box
Vector3 local_to = from_inv.xform(to);
Vector3 rpos, rnorm;
if (!p_B->get_shape(p_shape_B)->intersect_segment(local_from, local_to, rpos, rnorm)) {
return false;
}
//shorten the linear velocity so it does not hit, but gets close enough, next frame will hit softly or soft enough
Vector3 hitpos = p_xform_B.xform(rpos);
real_t newlen = hitpos.distance_to(from) - (max - min) * 0.01;
p_A->set_linear_velocity((mnormal * newlen) / p_step);
return true;
}
real_t combine_bounce(BodySW *A, BodySW *B) {
return CLAMP(A->get_bounce() + B->get_bounce(), 0, 1);
}
real_t combine_friction(BodySW *A, BodySW *B) {
return ABS(MIN(A->get_friction(), B->get_friction()));
}
bool BodyPairSW::setup(real_t p_step) {
//cannot collide
if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
collided = false;
return false;
}
bool report_contacts_only = false;
if ((A->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC)) {
if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {
report_contacts_only = true;
} else {
collided = false;
return false;
}
}
offset_B = B->get_transform().get_origin() - A->get_transform().get_origin();
validate_contacts();
Vector3 offset_A = A->get_transform().get_origin();
Transform xform_Au = Transform(A->get_transform().basis, Vector3());
Transform xform_A = xform_Au * A->get_shape_transform(shape_A);
Transform xform_Bu = B->get_transform();
xform_Bu.origin -= offset_A;
Transform xform_B = xform_Bu * B->get_shape_transform(shape_B);
ShapeSW *shape_A_ptr = A->get_shape(shape_A);
ShapeSW *shape_B_ptr = B->get_shape(shape_B);
bool collided = CollisionSolverSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis);
this->collided = collided;
if (!collided) {
//test ccd (currently just a raycast)
if (A->is_continuous_collision_detection_enabled() && A->get_mode() > PhysicsServer::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC) {
_test_ccd(p_step, A, shape_A, xform_A, B, shape_B, xform_B);
}
if (B->is_continuous_collision_detection_enabled() && B->get_mode() > PhysicsServer::BODY_MODE_KINEMATIC && A->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC) {
_test_ccd(p_step, B, shape_B, xform_B, A, shape_A, xform_A);
}
return false;
}
real_t max_penetration = space->get_contact_max_allowed_penetration();
real_t bias = (real_t)0.3;
if (shape_A_ptr->get_custom_bias() || shape_B_ptr->get_custom_bias()) {
if (shape_A_ptr->get_custom_bias() == 0) {
bias = shape_B_ptr->get_custom_bias();
} else if (shape_B_ptr->get_custom_bias() == 0) {
bias = shape_A_ptr->get_custom_bias();
} else {
bias = (shape_B_ptr->get_custom_bias() + shape_A_ptr->get_custom_bias()) * 0.5;
}
}
real_t inv_dt = 1.0 / p_step;
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
c.active = false;
Vector3 global_A = xform_Au.xform(c.local_A);
Vector3 global_B = xform_Bu.xform(c.local_B);
real_t depth = c.normal.dot(global_A - global_B);
if (depth <= 0) {
continue;
}
#ifdef DEBUG_ENABLED
if (space->is_debugging_contacts()) {
space->add_debug_contact(global_A + offset_A);
space->add_debug_contact(global_B + offset_A);
}
#endif
c.rA = global_A - A->get_center_of_mass();
c.rB = global_B - B->get_center_of_mass() - offset_B;
// contact query reporting...
if (A->can_report_contacts()) {
Vector3 crA = A->get_angular_velocity().cross(c.rA) + A->get_linear_velocity();
A->add_contact(global_A, -c.normal, depth, shape_A, global_B, shape_B, B->get_instance_id(), B->get_self(), crA);
}
if (B->can_report_contacts()) {
Vector3 crB = B->get_angular_velocity().cross(c.rB) + B->get_linear_velocity();
B->add_contact(global_B, c.normal, depth, shape_B, global_A, shape_A, A->get_instance_id(), A->get_self(), crB);
}
if (report_contacts_only) {
collided = false;
continue;
}
c.active = true;
// Precompute normal mass, tangent mass, and bias.
Vector3 inertia_A = A->get_inv_inertia_tensor().xform(c.rA.cross(c.normal));
Vector3 inertia_B = B->get_inv_inertia_tensor().xform(c.rB.cross(c.normal));
real_t kNormal = A->get_inv_mass() + B->get_inv_mass();
kNormal += c.normal.dot(inertia_A.cross(c.rA)) + c.normal.dot(inertia_B.cross(c.rB));
c.mass_normal = 1.0f / kNormal;
c.bias = -bias * inv_dt * MIN(0.0f, -depth + max_penetration);
c.depth = depth;
Vector3 j_vec = c.normal * c.acc_normal_impulse + c.acc_tangent_impulse;
A->apply_impulse(c.rA + A->get_center_of_mass(), -j_vec);
B->apply_impulse(c.rB + B->get_center_of_mass(), j_vec);
c.acc_bias_impulse = 0;
c.acc_bias_impulse_center_of_mass = 0;
c.bounce = combine_bounce(A, B);
if (c.bounce) {
Vector3 crA = A->get_prev_angular_velocity().cross(c.rA);
Vector3 crB = B->get_prev_angular_velocity().cross(c.rB);
Vector3 dv = B->get_prev_linear_velocity() + crB - A->get_prev_linear_velocity() - crA;
//normal impule
c.bounce = c.bounce * dv.dot(c.normal);
}
}
return true;
}
void BodyPairSW::solve(real_t p_step) {
if (!collided) {
return;
}
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
if (!c.active) {
continue;
}
c.active = false; //try to deactivate, will activate itself if still needed
//bias impulse
Vector3 crbA = A->get_biased_angular_velocity().cross(c.rA);
Vector3 crbB = B->get_biased_angular_velocity().cross(c.rB);
Vector3 dbv = B->get_biased_linear_velocity() + crbB - A->get_biased_linear_velocity() - crbA;
real_t vbn = dbv.dot(c.normal);
if (Math::abs(-vbn + c.bias) > MIN_VELOCITY) {
real_t jbn = (-vbn + c.bias) * c.mass_normal;
real_t jbnOld = c.acc_bias_impulse;
c.acc_bias_impulse = MAX(jbnOld + jbn, 0.0f);
Vector3 jb = c.normal * (c.acc_bias_impulse - jbnOld);
A->apply_bias_impulse(c.rA + A->get_center_of_mass(), -jb, MAX_BIAS_ROTATION / p_step);
B->apply_bias_impulse(c.rB + B->get_center_of_mass(), jb, MAX_BIAS_ROTATION / p_step);
crbA = A->get_biased_angular_velocity().cross(c.rA);
crbB = B->get_biased_angular_velocity().cross(c.rB);
dbv = B->get_biased_linear_velocity() + crbB - A->get_biased_linear_velocity() - crbA;
vbn = dbv.dot(c.normal);
if (Math::abs(-vbn + c.bias) > MIN_VELOCITY) {
real_t jbn_com = (-vbn + c.bias) / (A->get_inv_mass() + B->get_inv_mass());
real_t jbnOld_com = c.acc_bias_impulse_center_of_mass;
c.acc_bias_impulse_center_of_mass = MAX(jbnOld_com + jbn_com, 0.0f);
Vector3 jb_com = c.normal * (c.acc_bias_impulse_center_of_mass - jbnOld_com);
A->apply_bias_impulse(A->get_center_of_mass(), -jb_com, 0.0f);
B->apply_bias_impulse(B->get_center_of_mass(), jb_com, 0.0f);
}
c.active = true;
}
Vector3 crA = A->get_angular_velocity().cross(c.rA);
Vector3 crB = B->get_angular_velocity().cross(c.rB);
Vector3 dv = B->get_linear_velocity() + crB - A->get_linear_velocity() - crA;
//normal impulse
real_t vn = dv.dot(c.normal);
if (Math::abs(vn) > MIN_VELOCITY) {
real_t jn = -(c.bounce + vn) * c.mass_normal;
real_t jnOld = c.acc_normal_impulse;
c.acc_normal_impulse = MAX(jnOld + jn, 0.0f);
Vector3 j = c.normal * (c.acc_normal_impulse - jnOld);
A->apply_impulse(c.rA + A->get_center_of_mass(), -j);
B->apply_impulse(c.rB + B->get_center_of_mass(), j);
c.active = true;
}
//friction impulse
real_t friction = combine_friction(A, B);
Vector3 lvA = A->get_linear_velocity() + A->get_angular_velocity().cross(c.rA);
Vector3 lvB = B->get_linear_velocity() + B->get_angular_velocity().cross(c.rB);
Vector3 dtv = lvB - lvA;
real_t tn = c.normal.dot(dtv);
// tangential velocity
Vector3 tv = dtv - c.normal * tn;
real_t tvl = tv.length();
if (tvl > MIN_VELOCITY) {
tv /= tvl;
Vector3 temp1 = A->get_inv_inertia_tensor().xform(c.rA.cross(tv));
Vector3 temp2 = B->get_inv_inertia_tensor().xform(c.rB.cross(tv));
real_t t = -tvl / (A->get_inv_mass() + B->get_inv_mass() + tv.dot(temp1.cross(c.rA) + temp2.cross(c.rB)));
Vector3 jt = t * tv;
Vector3 jtOld = c.acc_tangent_impulse;
c.acc_tangent_impulse += jt;
real_t fi_len = c.acc_tangent_impulse.length();
real_t jtMax = c.acc_normal_impulse * friction;
if (fi_len > CMP_EPSILON && fi_len > jtMax) {
c.acc_tangent_impulse *= jtMax / fi_len;
}
jt = c.acc_tangent_impulse - jtOld;
A->apply_impulse(c.rA + A->get_center_of_mass(), -jt);
B->apply_impulse(c.rB + B->get_center_of_mass(), jt);
c.active = true;
}
}
}
BodyPairSW::BodyPairSW(BodySW *p_A, int p_shape_A, BodySW *p_B, int p_shape_B) :
ConstraintSW(_arr, 2) {
A = p_A;
B = p_B;
shape_A = p_shape_A;
shape_B = p_shape_B;
space = A->get_space();
A->add_constraint(this, 0);
B->add_constraint(this, 1);
contact_count = 0;
collided = false;
}
BodyPairSW::~BodyPairSW() {
A->remove_constraint(this);
B->remove_constraint(this);
}

View File

@ -1,95 +0,0 @@
#ifndef BODY_PAIR_SW_H
#define BODY_PAIR_SW_H
/*************************************************************************/
/* body_pair_sw.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "body_sw.h"
#include "constraint_sw.h"
class BodyPairSW : public ConstraintSW {
enum {
MAX_CONTACTS = 4
};
union {
struct {
BodySW *A;
BodySW *B;
};
BodySW *_arr[2];
};
int shape_A;
int shape_B;
struct Contact {
Vector3 position;
Vector3 normal;
Vector3 local_A, local_B;
real_t acc_normal_impulse; // accumulated normal impulse (Pn)
Vector3 acc_tangent_impulse; // accumulated tangent impulse (Pt)
real_t acc_bias_impulse; // accumulated normal impulse for position bias (Pnb)
real_t acc_bias_impulse_center_of_mass; // accumulated normal impulse for position bias applied to com
real_t mass_normal;
real_t bias;
real_t bounce;
real_t depth;
bool active;
Vector3 rA, rB; // Offset in world orientation with respect to center of mass
};
Vector3 offset_B; //use local A coordinates to avoid numerical issues on collision detection
Vector3 sep_axis;
Contact contacts[MAX_CONTACTS];
int contact_count;
bool collided;
static void _contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata);
void contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B);
void validate_contacts();
bool _test_ccd(real_t p_step, BodySW *p_A, int p_shape_A, const Transform &p_xform_A, BodySW *p_B, int p_shape_B, const Transform &p_xform_B);
SpaceSW *space;
public:
bool setup(real_t p_step);
void solve(real_t p_step);
BodyPairSW(BodySW *p_A, int p_shape_A, BodySW *p_B, int p_shape_B);
~BodyPairSW();
};
#endif // BODY_PAIR__SW_H

View File

@ -1,814 +0,0 @@
/*************************************************************************/
/* body_sw.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "body_sw.h"
#include "area_sw.h"
#include "space_sw.h"
void BodySW::_update_inertia() {
if (get_space() && !inertia_update_list.in_list()) {
get_space()->body_add_to_inertia_update_list(&inertia_update_list);
}
}
void BodySW::_update_transform_dependant() {
center_of_mass = get_transform().basis.xform(center_of_mass_local);
principal_inertia_axes = get_transform().basis * principal_inertia_axes_local;
// update inertia tensor
Basis tb = principal_inertia_axes;
Basis tbt = tb.transposed();
Basis diag;
diag.scale(_inv_inertia);
_inv_inertia_tensor = tb * diag * tbt;
}
void BodySW::update_inertias() {
// Update shapes and motions.
switch (mode) {
case PhysicsServer::BODY_MODE_RIGID: {
// Update tensor for all shapes, not the best way but should be somehow OK. (inspired from bullet)
real_t total_area = 0;
for (int i = 0; i < get_shape_count(); i++) {
if (is_shape_disabled(i)) {
continue;
}
total_area += get_shape_area(i);
}
// We have to recompute the center of mass.
center_of_mass_local.zero();
if (total_area != 0.0) {
for (int i = 0; i < get_shape_count(); i++) {
if (is_shape_disabled(i)) {
continue;
}
real_t area = get_shape_area(i);
real_t mass = area * this->mass / total_area;
// NOTE: we assume that the shape origin is also its center of mass.
center_of_mass_local += mass * get_shape_transform(i).origin;
}
center_of_mass_local /= mass;
}
// Recompute the inertia tensor.
Basis inertia_tensor;
inertia_tensor.set_zero();
bool inertia_set = false;
for (int i = 0; i < get_shape_count(); i++) {
if (is_shape_disabled(i)) {
continue;
}
real_t area = get_shape_area(i);
if (area == 0.0) {
continue;
}
inertia_set = true;
const ShapeSW *shape = get_shape(i);
real_t mass = area * this->mass / total_area;
Basis shape_inertia_tensor = shape->get_moment_of_inertia(mass).to_diagonal_matrix();
Transform shape_transform = get_shape_transform(i);
Basis shape_basis = shape_transform.basis.orthonormalized();
// NOTE: we don't take the scale of collision shapes into account when computing the inertia tensor!
shape_inertia_tensor = shape_basis * shape_inertia_tensor * shape_basis.transposed();
Vector3 shape_origin = shape_transform.origin - center_of_mass_local;
inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass;
}
// Set the inertia to a valid value when there are no valid shapes.
if (!inertia_set) {
inertia_tensor.set_diagonal(Vector3(1.0, 1.0, 1.0));
}
// Compute the principal axes of inertia.
principal_inertia_axes_local = inertia_tensor.diagonalize().transposed();
_inv_inertia = inertia_tensor.get_main_diagonal().inverse();
if (mass) {
_inv_mass = 1.0 / mass;
} else {
_inv_mass = 0;
}
} break;
case PhysicsServer::BODY_MODE_KINEMATIC:
case PhysicsServer::BODY_MODE_STATIC: {
_inv_inertia_tensor.set_zero();
_inv_mass = 0;
} break;
case PhysicsServer::BODY_MODE_CHARACTER: {
_inv_inertia_tensor.set_zero();
_inv_mass = 1.0 / mass;
} break;
}
//_update_shapes();
_update_transform_dependant();
}
void BodySW::set_active(bool p_active) {
if (active == p_active) {
return;
}
active = p_active;
if (!p_active) {
if (get_space()) {
get_space()->body_remove_from_active_list(&active_list);
}
} else {
if (mode == PhysicsServer::BODY_MODE_STATIC) {
return; //static bodies can't become active
}
if (get_space()) {
get_space()->body_add_to_active_list(&active_list);
}
//still_time=0;
}
/*
if (!space)
return;
for(int i=0;i<get_shape_count();i++) {
Shape &s=shapes[i];
if (s.bpid>0) {
get_space()->get_broadphase()->set_active(s.bpid,active);
}
}
*/
}
void BodySW::set_param(PhysicsServer::BodyParameter p_param, real_t p_value) {
switch (p_param) {
case PhysicsServer::BODY_PARAM_BOUNCE: {
bounce = p_value;
} break;
case PhysicsServer::BODY_PARAM_FRICTION: {
friction = p_value;
} break;
case PhysicsServer::BODY_PARAM_MASS: {
ERR_FAIL_COND(p_value <= 0);
mass = p_value;
_update_inertia();
} break;
case PhysicsServer::BODY_PARAM_GRAVITY_SCALE: {
gravity_scale = p_value;
} break;
case PhysicsServer::BODY_PARAM_LINEAR_DAMP: {
linear_damp = p_value;
} break;
case PhysicsServer::BODY_PARAM_ANGULAR_DAMP: {
angular_damp = p_value;
} break;
default: {
}
}
}
real_t BodySW::get_param(PhysicsServer::BodyParameter p_param) const {
switch (p_param) {
case PhysicsServer::BODY_PARAM_BOUNCE: {
return bounce;
} break;
case PhysicsServer::BODY_PARAM_FRICTION: {
return friction;
} break;
case PhysicsServer::BODY_PARAM_MASS: {
return mass;
} break;
case PhysicsServer::BODY_PARAM_GRAVITY_SCALE: {
return gravity_scale;
} break;
case PhysicsServer::BODY_PARAM_LINEAR_DAMP: {
return linear_damp;
} break;
case PhysicsServer::BODY_PARAM_ANGULAR_DAMP: {
return angular_damp;
} break;
default: {
}
}
return 0;
}
void BodySW::set_mode(PhysicsServer::BodyMode p_mode) {
PhysicsServer::BodyMode prev = mode;
mode = p_mode;
switch (p_mode) {
//CLEAR UP EVERYTHING IN CASE IT NOT WORKS!
case PhysicsServer::BODY_MODE_STATIC:
case PhysicsServer::BODY_MODE_KINEMATIC: {
_set_inv_transform(get_transform().affine_inverse());
_inv_mass = 0;
_set_static(p_mode == PhysicsServer::BODY_MODE_STATIC);
//set_active(p_mode==PhysicsServer::BODY_MODE_KINEMATIC);
set_active(p_mode == PhysicsServer::BODY_MODE_KINEMATIC && contacts.size());
linear_velocity = Vector3();
angular_velocity = Vector3();
if (mode == PhysicsServer::BODY_MODE_KINEMATIC && prev != mode) {
first_time_kinematic = true;
}
} break;
case PhysicsServer::BODY_MODE_RIGID: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
_set_static(false);
set_active(true);
} break;
case PhysicsServer::BODY_MODE_CHARACTER: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
_set_static(false);
set_active(true);
angular_velocity = Vector3();
} break;
}
_update_inertia();
/*
if (get_space())
_update_queries();
*/
}
PhysicsServer::BodyMode BodySW::get_mode() const {
return mode;
}
void BodySW::_shapes_changed() {
_update_inertia();
wakeup();
wakeup_neighbours();
}
void BodySW::set_state(PhysicsServer::BodyState p_state, const Variant &p_variant) {
switch (p_state) {
case PhysicsServer::BODY_STATE_TRANSFORM: {
if (mode == PhysicsServer::BODY_MODE_KINEMATIC) {
new_transform = p_variant;
//wakeup_neighbours();
set_active(true);
if (first_time_kinematic) {
_set_transform(p_variant);
_set_inv_transform(get_transform().affine_inverse());
first_time_kinematic = false;
}
} else if (mode == PhysicsServer::BODY_MODE_STATIC) {
_set_transform(p_variant);
_set_inv_transform(get_transform().affine_inverse());
wakeup_neighbours();
} else {
Transform t = p_variant;
t.orthonormalize();
new_transform = get_transform(); //used as old to compute motion
if (new_transform == t) {
break;
}
_set_transform(t);
_set_inv_transform(get_transform().inverse());
}
wakeup();
} break;
case PhysicsServer::BODY_STATE_LINEAR_VELOCITY: {
/*
if (mode==PhysicsServer::BODY_MODE_STATIC)
break;
*/
linear_velocity = p_variant;
wakeup();
} break;
case PhysicsServer::BODY_STATE_ANGULAR_VELOCITY: {
/*
if (mode!=PhysicsServer::BODY_MODE_RIGID)
break;
*/
angular_velocity = p_variant;
wakeup();
} break;
case PhysicsServer::BODY_STATE_SLEEPING: {
//?
if (mode == PhysicsServer::BODY_MODE_STATIC || mode == PhysicsServer::BODY_MODE_KINEMATIC) {
break;
}
bool do_sleep = p_variant;
if (do_sleep) {
linear_velocity = Vector3();
//biased_linear_velocity=Vector3();
angular_velocity = Vector3();
//biased_angular_velocity=Vector3();
set_active(false);
} else {
set_active(true);
}
} break;
case PhysicsServer::BODY_STATE_CAN_SLEEP: {
can_sleep = p_variant;
if (mode == PhysicsServer::BODY_MODE_RIGID && !active && !can_sleep) {
set_active(true);
}
} break;
}
}
Variant BodySW::get_state(PhysicsServer::BodyState p_state) const {
switch (p_state) {
case PhysicsServer::BODY_STATE_TRANSFORM: {
return get_transform();
} break;
case PhysicsServer::BODY_STATE_LINEAR_VELOCITY: {
return linear_velocity;
} break;
case PhysicsServer::BODY_STATE_ANGULAR_VELOCITY: {
return angular_velocity;
} break;
case PhysicsServer::BODY_STATE_SLEEPING: {
return !is_active();
} break;
case PhysicsServer::BODY_STATE_CAN_SLEEP: {
return can_sleep;
} break;
}
return Variant();
}
void BodySW::set_space(SpaceSW *p_space) {
if (get_space()) {
if (inertia_update_list.in_list()) {
get_space()->body_remove_from_inertia_update_list(&inertia_update_list);
}
if (active_list.in_list()) {
get_space()->body_remove_from_active_list(&active_list);
}
if (direct_state_query_list.in_list()) {
get_space()->body_remove_from_state_query_list(&direct_state_query_list);
}
}
_set_space(p_space);
if (get_space()) {
_update_inertia();
if (active) {
get_space()->body_add_to_active_list(&active_list);
}
/*
_update_queries();
if (is_active()) {
active=false;
set_active(true);
}
*/
}
first_integration = true;
}
void BodySW::_compute_area_gravity_and_dampenings(const AreaSW *p_area) {
if (p_area->is_gravity_point()) {
if (p_area->get_gravity_distance_scale() > 0) {
Vector3 v = p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin();
gravity += v.normalized() * (p_area->get_gravity() / Math::pow(v.length() * p_area->get_gravity_distance_scale() + 1, 2));
} else {
gravity += (p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin()).normalized() * p_area->get_gravity();
}
} else {
gravity += p_area->get_gravity_vector() * p_area->get_gravity();
}
area_linear_damp += p_area->get_linear_damp();
area_angular_damp += p_area->get_angular_damp();
}
void BodySW::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock) {
if (lock) {
locked_axis |= p_axis;
} else {
locked_axis &= ~p_axis;
}
}
bool BodySW::is_axis_locked(PhysicsServer::BodyAxis p_axis) const {
return locked_axis & p_axis;
}
void BodySW::integrate_forces(real_t p_step) {
if (mode == PhysicsServer::BODY_MODE_STATIC) {
return;
}
AreaSW *def_area = get_space()->get_default_area();
// AreaSW *damp_area = def_area;
ERR_FAIL_COND(!def_area);
int ac = areas.size();
bool stopped = false;
gravity = Vector3(0, 0, 0);
area_linear_damp = 0;
area_angular_damp = 0;
if (ac) {
areas.sort();
const AreaCMP *aa = &areas[0];
// damp_area = aa[ac-1].area;
for (int i = ac - 1; i >= 0 && !stopped; i--) {
PhysicsServer::AreaSpaceOverrideMode mode = aa[i].area->get_space_override_mode();
switch (mode) {
case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE:
case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
_compute_area_gravity_and_dampenings(aa[i].area);
stopped = mode == PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
} break;
case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE:
case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
gravity = Vector3(0, 0, 0);
area_angular_damp = 0;
area_linear_damp = 0;
_compute_area_gravity_and_dampenings(aa[i].area);
stopped = mode == PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE;
} break;
default: {
}
}
}
}
if (!stopped) {
_compute_area_gravity_and_dampenings(def_area);
}
gravity *= gravity_scale;
// If less than 0, override dampenings with that of the Body
if (angular_damp >= 0) {
area_angular_damp = angular_damp;
}
/*
else
area_angular_damp=damp_area->get_angular_damp();
*/
if (linear_damp >= 0) {
area_linear_damp = linear_damp;
}
/*
else
area_linear_damp=damp_area->get_linear_damp();
*/
prev_linear_velocity = linear_velocity;
prev_angular_velocity = angular_velocity;
Vector3 motion;
bool do_motion = false;
if (mode == PhysicsServer::BODY_MODE_KINEMATIC) {
//compute motion, angular and etc. velocities from prev transform
motion = new_transform.origin - get_transform().origin;
do_motion = true;
linear_velocity = motion / p_step;
//compute a FAKE angular velocity, not so easy
Basis rot = new_transform.basis.orthonormalized() * get_transform().basis.orthonormalized().transposed();
Vector3 axis;
real_t angle;
rot.get_axis_angle(axis, angle);
axis.normalize();
angular_velocity = axis * (angle / p_step);
} else {
if (!omit_force_integration && !first_integration) {
//overridden by direct state query
Vector3 force = gravity * mass;
force += applied_force;
Vector3 torque = applied_torque;
real_t damp = 1.0 - p_step * area_linear_damp;
if (damp < 0) { // reached zero in the given time
damp = 0;
}
real_t angular_damp = 1.0 - p_step * area_angular_damp;
if (angular_damp < 0) { // reached zero in the given time
angular_damp = 0;
}
linear_velocity *= damp;
angular_velocity *= angular_damp;
linear_velocity += _inv_mass * force * p_step;
angular_velocity += _inv_inertia_tensor.xform(torque) * p_step;
}
if (continuous_cd) {
motion = linear_velocity * p_step;
do_motion = true;
}
}
applied_force = Vector3();
applied_torque = Vector3();
first_integration = false;
//motion=linear_velocity*p_step;
biased_angular_velocity = Vector3();
biased_linear_velocity = Vector3();
if (do_motion) { //shapes temporarily extend for raycast
_update_shapes_with_motion(motion);
}
def_area = nullptr; // clear the area, so it is set in the next frame
contact_count = 0;
}
void BodySW::integrate_velocities(real_t p_step) {
if (mode == PhysicsServer::BODY_MODE_STATIC) {
return;
}
if (fi_callback) {
get_space()->body_add_to_state_query_list(&direct_state_query_list);
}
//apply axis lock linear
for (int i = 0; i < 3; i++) {
if (is_axis_locked((PhysicsServer::BodyAxis)(1 << i))) {
linear_velocity[i] = 0;
biased_linear_velocity[i] = 0;
new_transform.origin[i] = get_transform().origin[i];
}
}
//apply axis lock angular
for (int i = 0; i < 3; i++) {
if (is_axis_locked((PhysicsServer::BodyAxis)(1 << (i + 3)))) {
angular_velocity[i] = 0;
biased_angular_velocity[i] = 0;
}
}
if (mode == PhysicsServer::BODY_MODE_KINEMATIC) {
_set_transform(new_transform, false);
_set_inv_transform(new_transform.affine_inverse());
if (contacts.size() == 0 && linear_velocity == Vector3() && angular_velocity == Vector3()) {
set_active(false); //stopped moving, deactivate
}
return;
}
Vector3 total_angular_velocity = angular_velocity + biased_angular_velocity;
real_t ang_vel = total_angular_velocity.length();
Transform transform = get_transform();
if (!Math::is_zero_approx(ang_vel)) {
Vector3 ang_vel_axis = total_angular_velocity / ang_vel;
Basis rot(ang_vel_axis, ang_vel * p_step);
Basis identity3(1, 0, 0, 0, 1, 0, 0, 0, 1);
transform.origin += ((identity3 - rot) * transform.basis).xform(center_of_mass_local);
transform.basis = rot * transform.basis;
transform.orthonormalize();
}
Vector3 total_linear_velocity = linear_velocity + biased_linear_velocity;
/*for(int i=0;i<3;i++) {
if (axis_lock&(1<<i)) {
transform.origin[i]=0.0;
}
}*/
transform.origin += total_linear_velocity * p_step;
_set_transform(transform);
_set_inv_transform(get_transform().inverse());
_update_transform_dependant();
/*
if (fi_callback) {
get_space()->body_add_to_state_query_list(&direct_state_query_list);
*/
}
/*
void BodySW::simulate_motion(const Transform& p_xform,real_t p_step) {
Transform inv_xform = p_xform.affine_inverse();
if (!get_space()) {
_set_transform(p_xform);
_set_inv_transform(inv_xform);
return;
}
//compute a FAKE linear velocity - this is easy
linear_velocity=(p_xform.origin - get_transform().origin)/p_step;
//compute a FAKE angular velocity, not so easy
Basis rot=get_transform().basis.orthonormalized().transposed() * p_xform.basis.orthonormalized();
Vector3 axis;
real_t angle;
rot.get_axis_angle(axis,angle);
axis.normalize();
angular_velocity=axis.normalized() * (angle/p_step);
linear_velocity = (p_xform.origin - get_transform().origin)/p_step;
if (!direct_state_query_list.in_list())// - callalways, so lv and av are cleared && (state_query || direct_state_query))
get_space()->body_add_to_state_query_list(&direct_state_query_list);
simulated_motion=true;
_set_transform(p_xform);
}
*/
void BodySW::wakeup_neighbours() {
for (RBMap<ConstraintSW *, int>::Element *E = constraint_map.front(); E; E = E->next()) {
const ConstraintSW *c = E->key();
BodySW **n = c->get_body_ptr();
int bc = c->get_body_count();
for (int i = 0; i < bc; i++) {
if (i == E->get()) {
continue;
}
BodySW *b = n[i];
if (b->mode != PhysicsServer::BODY_MODE_RIGID) {
continue;
}
if (!b->is_active()) {
b->set_active(true);
}
}
}
}
void BodySW::call_queries() {
if (fi_callback) {
Variant v = direct_access;
Object *obj = ObjectDB::get_instance(fi_callback->id);
if (!obj) {
set_force_integration_callback(0, StringName());
} else {
const Variant *vp[2] = { &v, &fi_callback->udata };
Variant::CallError ce;
int argc = (fi_callback->udata.get_type() == Variant::NIL) ? 1 : 2;
obj->call(fi_callback->method, vp, argc, ce);
}
}
}
bool BodySW::sleep_test(real_t p_step) {
if (mode == PhysicsServer::BODY_MODE_STATIC || mode == PhysicsServer::BODY_MODE_KINEMATIC) {
return true; //
} else if (mode == PhysicsServer::BODY_MODE_CHARACTER) {
return !active; // characters don't sleep unless asked to sleep
} else if (!can_sleep) {
return false;
}
if (Math::abs(angular_velocity.length()) < get_space()->get_body_angular_velocity_sleep_threshold() && Math::abs(linear_velocity.length_squared()) < get_space()->get_body_linear_velocity_sleep_threshold() * get_space()->get_body_linear_velocity_sleep_threshold()) {
still_time += p_step;
return still_time > get_space()->get_body_time_to_sleep();
} else {
still_time = 0; //maybe this should be set to 0 on set_active?
return false;
}
}
void BodySW::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
if (fi_callback) {
memdelete(fi_callback);
fi_callback = nullptr;
}
if (p_id != 0) {
fi_callback = memnew(ForceIntegrationCallback);
fi_callback->id = p_id;
fi_callback->method = p_method;
fi_callback->udata = p_udata;
}
}
void BodySW::set_kinematic_margin(real_t p_margin) {
kinematic_safe_margin = p_margin;
}
BodySW::BodySW() :
CollisionObjectSW(TYPE_BODY),
locked_axis(0),
active_list(this),
inertia_update_list(this),
direct_state_query_list(this) {
mode = PhysicsServer::BODY_MODE_RIGID;
active = true;
mass = 1;
kinematic_safe_margin = 0.001;
//_inv_inertia=Transform();
_inv_mass = 1;
bounce = 0;
friction = 1;
omit_force_integration = false;
//applied_torque=0;
island_step = 0;
island_next = nullptr;
island_list_next = nullptr;
first_time_kinematic = false;
first_integration = false;
_set_static(false);
contact_count = 0;
gravity_scale = 1.0;
linear_damp = -1;
angular_damp = -1;
area_angular_damp = 0;
area_linear_damp = 0;
still_time = 0;
continuous_cd = false;
can_sleep = true;
fi_callback = nullptr;
direct_access = memnew(PhysicsDirectBodyStateSW);
direct_access->body = this;
}
BodySW::~BodySW() {
memdelete(direct_access);
if (fi_callback) {
memdelete(fi_callback);
}
}
PhysicsDirectSpaceState *PhysicsDirectBodyStateSW::get_space_state() {
return body->get_space()->get_direct_state();
}
real_t PhysicsDirectBodyStateSW::get_step() const {
return body->get_space()->get_step();
}

View File

@ -1,494 +0,0 @@
#ifndef BODY_SW_H
#define BODY_SW_H
/*************************************************************************/
/* body_sw.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "area_sw.h"
#include "collision_object_sw.h"
#include "core/containers/vset.h"
class ConstraintSW;
class PhysicsDirectBodyStateSW;
class BodySW : public CollisionObjectSW {
PhysicsServer::BodyMode mode;
Vector3 linear_velocity;
Vector3 angular_velocity;
Vector3 prev_linear_velocity;
Vector3 prev_angular_velocity;
Vector3 biased_linear_velocity;
Vector3 biased_angular_velocity;
real_t mass;
real_t bounce;
real_t friction;
real_t linear_damp;
real_t angular_damp;
real_t gravity_scale;
uint16_t locked_axis;
real_t kinematic_safe_margin;
real_t _inv_mass;
Vector3 _inv_inertia; // Relative to the principal axes of inertia
// Relative to the local frame of reference
Basis principal_inertia_axes_local;
Vector3 center_of_mass_local;
// In world orientation with local origin
Basis _inv_inertia_tensor;
Basis principal_inertia_axes;
Vector3 center_of_mass;
Vector3 gravity;
real_t still_time;
Vector3 applied_force;
Vector3 applied_torque;
real_t area_angular_damp;
real_t area_linear_damp;
SelfList<BodySW> active_list;
SelfList<BodySW> inertia_update_list;
SelfList<BodySW> direct_state_query_list;
VSet<RID> exceptions;
bool omit_force_integration;
bool active;
bool first_integration;
bool continuous_cd;
bool can_sleep;
bool first_time_kinematic;
void _update_inertia();
virtual void _shapes_changed();
Transform new_transform;
RBMap<ConstraintSW *, int> constraint_map;
struct AreaCMP {
AreaSW *area;
int refCount;
_FORCE_INLINE_ bool operator==(const AreaCMP &p_cmp) const { return area->get_self() == p_cmp.area->get_self(); }
_FORCE_INLINE_ bool operator<(const AreaCMP &p_cmp) const { return area->get_priority() < p_cmp.area->get_priority(); }
_FORCE_INLINE_ AreaCMP() {}
_FORCE_INLINE_ AreaCMP(AreaSW *p_area) {
area = p_area;
refCount = 1;
}
};
Vector<AreaCMP> areas;
struct Contact {
Vector3 local_pos;
Vector3 local_normal;
real_t depth;
int local_shape;
Vector3 collider_pos;
int collider_shape;
ObjectID collider_instance_id;
RID collider;
Vector3 collider_velocity_at_pos;
};
Vector<Contact> contacts; //no contacts by default
int contact_count;
struct ForceIntegrationCallback {
ObjectID id;
StringName method;
Variant udata;
};
ForceIntegrationCallback *fi_callback;
uint64_t island_step;
BodySW *island_next;
BodySW *island_list_next;
_FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const AreaSW *p_area);
_FORCE_INLINE_ void _update_transform_dependant();
PhysicsDirectBodyStateSW *direct_access = nullptr;
friend class PhysicsDirectBodyStateSW; // i give up, too many functions to expose
public:
void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
void set_kinematic_margin(real_t p_margin);
_FORCE_INLINE_ real_t get_kinematic_margin() { return kinematic_safe_margin; }
_FORCE_INLINE_ void add_area(AreaSW *p_area) {
int index = areas.find(AreaCMP(p_area));
if (index > -1) {
areas.write[index].refCount += 1;
} else {
areas.ordered_insert(AreaCMP(p_area));
}
}
_FORCE_INLINE_ void remove_area(AreaSW *p_area) {
int index = areas.find(AreaCMP(p_area));
if (index > -1) {
areas.write[index].refCount -= 1;
if (areas[index].refCount < 1) {
areas.remove(index);
}
}
}
_FORCE_INLINE_ void set_max_contacts_reported(int p_size) {
contacts.resize(p_size);
contact_count = 0;
if (mode == PhysicsServer::BODY_MODE_KINEMATIC && p_size) {
set_active(true);
}
}
_FORCE_INLINE_ int get_max_contacts_reported() const { return contacts.size(); }
_FORCE_INLINE_ bool can_report_contacts() const { return !contacts.empty(); }
_FORCE_INLINE_ void add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_normal, real_t p_depth, int p_local_shape, const Vector3 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector3 &p_collider_velocity_at_pos);
_FORCE_INLINE_ void add_exception(const RID &p_exception) { exceptions.insert(p_exception); }
_FORCE_INLINE_ void remove_exception(const RID &p_exception) { exceptions.erase(p_exception); }
_FORCE_INLINE_ bool has_exception(const RID &p_exception) const { return exceptions.has(p_exception); }
_FORCE_INLINE_ const VSet<RID> &get_exceptions() const { return exceptions; }
_FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
_FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
_FORCE_INLINE_ BodySW *get_island_next() const { return island_next; }
_FORCE_INLINE_ void set_island_next(BodySW *p_next) { island_next = p_next; }
_FORCE_INLINE_ BodySW *get_island_list_next() const { return island_list_next; }
_FORCE_INLINE_ void set_island_list_next(BodySW *p_next) { island_list_next = p_next; }
_FORCE_INLINE_ void add_constraint(ConstraintSW *p_constraint, int p_pos) { constraint_map[p_constraint] = p_pos; }
_FORCE_INLINE_ void remove_constraint(ConstraintSW *p_constraint) { constraint_map.erase(p_constraint); }
const RBMap<ConstraintSW *, int> &get_constraint_map() const { return constraint_map; }
_FORCE_INLINE_ void clear_constraint_map() { constraint_map.clear(); }
_FORCE_INLINE_ void set_omit_force_integration(bool p_omit_force_integration) { omit_force_integration = p_omit_force_integration; }
_FORCE_INLINE_ bool get_omit_force_integration() const { return omit_force_integration; }
_FORCE_INLINE_ Basis get_principal_inertia_axes() const { return principal_inertia_axes; }
_FORCE_INLINE_ Vector3 get_center_of_mass() const { return center_of_mass; }
_FORCE_INLINE_ Vector3 xform_local_to_principal(const Vector3 &p_pos) const { return principal_inertia_axes_local.xform(p_pos - center_of_mass_local); }
_FORCE_INLINE_ void set_linear_velocity(const Vector3 &p_velocity) { linear_velocity = p_velocity; }
_FORCE_INLINE_ Vector3 get_linear_velocity() const { return linear_velocity; }
_FORCE_INLINE_ void set_angular_velocity(const Vector3 &p_velocity) { angular_velocity = p_velocity; }
_FORCE_INLINE_ Vector3 get_angular_velocity() const { return angular_velocity; }
_FORCE_INLINE_ Vector3 get_prev_linear_velocity() const { return prev_linear_velocity; }
_FORCE_INLINE_ Vector3 get_prev_angular_velocity() const { return prev_angular_velocity; }
_FORCE_INLINE_ const Vector3 &get_biased_linear_velocity() const { return biased_linear_velocity; }
_FORCE_INLINE_ const Vector3 &get_biased_angular_velocity() const { return biased_angular_velocity; }
_FORCE_INLINE_ void apply_central_impulse(const Vector3 &p_j) {
linear_velocity += p_j * _inv_mass;
}
_FORCE_INLINE_ void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) {
linear_velocity += p_j * _inv_mass;
angular_velocity += _inv_inertia_tensor.xform((p_pos - center_of_mass).cross(p_j));
}
_FORCE_INLINE_ void apply_torque_impulse(const Vector3 &p_j) {
angular_velocity += _inv_inertia_tensor.xform(p_j);
}
_FORCE_INLINE_ void apply_bias_impulse(const Vector3 &p_pos, const Vector3 &p_j, real_t p_max_delta_av = -1.0) {
biased_linear_velocity += p_j * _inv_mass;
if (p_max_delta_av != 0.0) {
Vector3 delta_av = _inv_inertia_tensor.xform((p_pos - center_of_mass).cross(p_j));
if (p_max_delta_av > 0 && delta_av.length() > p_max_delta_av) {
delta_av = delta_av.normalized() * p_max_delta_av;
}
biased_angular_velocity += delta_av;
}
}
_FORCE_INLINE_ void apply_bias_torque_impulse(const Vector3 &p_j) {
biased_angular_velocity += _inv_inertia_tensor.xform(p_j);
}
_FORCE_INLINE_ void add_central_force(const Vector3 &p_force) {
applied_force += p_force;
}
_FORCE_INLINE_ void add_force(const Vector3 &p_force, const Vector3 &p_pos) {
applied_force += p_force;
applied_torque += p_pos.cross(p_force);
}
_FORCE_INLINE_ void add_torque(const Vector3 &p_torque) {
applied_torque += p_torque;
}
void set_active(bool p_active);
_FORCE_INLINE_ bool is_active() const { return active; }
_FORCE_INLINE_ void wakeup() {
if ((!get_space()) || mode == PhysicsServer::BODY_MODE_STATIC || mode == PhysicsServer::BODY_MODE_KINEMATIC) {
return;
}
set_active(true);
}
void set_param(PhysicsServer::BodyParameter p_param, real_t);
real_t get_param(PhysicsServer::BodyParameter p_param) const;
void set_mode(PhysicsServer::BodyMode p_mode);
PhysicsServer::BodyMode get_mode() const;
void set_state(PhysicsServer::BodyState p_state, const Variant &p_variant);
Variant get_state(PhysicsServer::BodyState p_state) const;
void set_applied_force(const Vector3 &p_force) { applied_force = p_force; }
Vector3 get_applied_force() const { return applied_force; }
void set_applied_torque(const Vector3 &p_torque) { applied_torque = p_torque; }
Vector3 get_applied_torque() const { return applied_torque; }
_FORCE_INLINE_ void set_continuous_collision_detection(bool p_enable) { continuous_cd = p_enable; }
_FORCE_INLINE_ bool is_continuous_collision_detection_enabled() const { return continuous_cd; }
void set_space(SpaceSW *p_space);
void update_inertias();
_FORCE_INLINE_ real_t get_inv_mass() const { return _inv_mass; }
_FORCE_INLINE_ Vector3 get_inv_inertia() const { return _inv_inertia; }
_FORCE_INLINE_ Basis get_inv_inertia_tensor() const { return _inv_inertia_tensor; }
_FORCE_INLINE_ real_t get_friction() const { return friction; }
_FORCE_INLINE_ Vector3 get_gravity() const { return gravity; }
_FORCE_INLINE_ real_t get_bounce() const { return bounce; }
void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock);
bool is_axis_locked(PhysicsServer::BodyAxis p_axis) const;
void integrate_forces(real_t p_step);
void integrate_velocities(real_t p_step);
_FORCE_INLINE_ Vector3 get_velocity_in_local_point(const Vector3 &rel_pos) const {
return linear_velocity + angular_velocity.cross(rel_pos - center_of_mass);
}
_FORCE_INLINE_ real_t compute_impulse_denominator(const Vector3 &p_pos, const Vector3 &p_normal) const {
Vector3 r0 = p_pos - get_transform().origin - center_of_mass;
Vector3 c0 = (r0).cross(p_normal);
Vector3 vec = (_inv_inertia_tensor.xform_inv(c0)).cross(r0);
return _inv_mass + p_normal.dot(vec);
}
_FORCE_INLINE_ real_t compute_angular_impulse_denominator(const Vector3 &p_axis) const {
return p_axis.dot(_inv_inertia_tensor.xform_inv(p_axis));
}
//void simulate_motion(const Transform& p_xform,real_t p_step);
void call_queries();
void wakeup_neighbours();
bool sleep_test(real_t p_step);
PhysicsDirectBodyStateSW *get_direct_state() const { return direct_access; }
BodySW();
~BodySW();
};
//add contact inline
void BodySW::add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_normal, real_t p_depth, int p_local_shape, const Vector3 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector3 &p_collider_velocity_at_pos) {
int c_max = contacts.size();
if (c_max == 0) {
return;
}
Contact *c = contacts.ptrw();
int idx = -1;
if (contact_count < c_max) {
idx = contact_count++;
} else {
real_t least_depth = 1e20;
int least_deep = -1;
for (int i = 0; i < c_max; i++) {
if (i == 0 || c[i].depth < least_depth) {
least_deep = i;
least_depth = c[i].depth;
}
}
if (least_deep >= 0 && least_depth < p_depth) {
idx = least_deep;
}
if (idx == -1) {
return; //none least deepe than this
}
}
c[idx].local_pos = p_local_pos;
c[idx].local_normal = p_local_normal;
c[idx].depth = p_depth;
c[idx].local_shape = p_local_shape;
c[idx].collider_pos = p_collider_pos;
c[idx].collider_shape = p_collider_shape;
c[idx].collider_instance_id = p_collider_instance_id;
c[idx].collider = p_collider;
c[idx].collider_velocity_at_pos = p_collider_velocity_at_pos;
}
class PhysicsDirectBodyStateSW : public PhysicsDirectBodyState {
GDCLASS(PhysicsDirectBodyStateSW, PhysicsDirectBodyState);
public:
BodySW *body = nullptr;
virtual Vector3 get_total_gravity() const { return body->gravity; } // get gravity vector working on this body space/area
virtual real_t get_total_angular_damp() const { return body->area_angular_damp; } // get density of this body space/area
virtual real_t get_total_linear_damp() const { return body->area_linear_damp; } // get density of this body space/area
virtual Vector3 get_center_of_mass() const { return body->get_center_of_mass(); }
virtual Basis get_principal_inertia_axes() const { return body->get_principal_inertia_axes(); }
virtual real_t get_inverse_mass() const { return body->get_inv_mass(); } // get the mass
virtual Vector3 get_inverse_inertia() const { return body->get_inv_inertia(); } // get density of this body space
virtual Basis get_inverse_inertia_tensor() const { return body->get_inv_inertia_tensor(); } // get density of this body space
virtual void set_linear_velocity(const Vector3 &p_velocity) {
body->wakeup();
body->set_linear_velocity(p_velocity);
}
virtual Vector3 get_linear_velocity() const { return body->get_linear_velocity(); }
virtual void set_angular_velocity(const Vector3 &p_velocity) {
body->wakeup();
body->set_angular_velocity(p_velocity);
}
virtual Vector3 get_angular_velocity() const { return body->get_angular_velocity(); }
virtual void set_transform(const Transform &p_transform) { body->set_state(PhysicsServer::BODY_STATE_TRANSFORM, p_transform); }
virtual Transform get_transform() const { return body->get_transform(); }
virtual Vector3 get_velocity_at_local_position(const Vector3 &p_position) const { return body->get_velocity_in_local_point(p_position); }
virtual void add_central_force(const Vector3 &p_force) {
body->wakeup();
body->add_central_force(p_force);
}
virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos) {
body->wakeup();
body->add_force(p_force, p_pos);
}
virtual void add_torque(const Vector3 &p_torque) {
body->wakeup();
body->add_torque(p_torque);
}
virtual void apply_central_impulse(const Vector3 &p_j) {
body->wakeup();
body->apply_central_impulse(p_j);
}
virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) {
body->wakeup();
body->apply_impulse(p_pos, p_j);
}
virtual void apply_torque_impulse(const Vector3 &p_j) {
body->wakeup();
body->apply_torque_impulse(p_j);
}
virtual void set_sleep_state(bool p_enable) { body->set_active(!p_enable); }
virtual bool is_sleeping() const { return !body->is_active(); }
virtual int get_contact_count() const { return body->contact_count; }
virtual Vector3 get_contact_local_position(int p_contact_idx) const {
ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
return body->contacts[p_contact_idx].local_pos;
}
virtual Vector3 get_contact_local_normal(int p_contact_idx) const {
ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
return body->contacts[p_contact_idx].local_normal;
}
virtual float get_contact_impulse(int p_contact_idx) const {
return 0.0f; // Only implemented for bullet
}
virtual int get_contact_local_shape(int p_contact_idx) const {
ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, -1);
return body->contacts[p_contact_idx].local_shape;
}
virtual RID get_contact_collider(int p_contact_idx) const {
ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, RID());
return body->contacts[p_contact_idx].collider;
}
virtual Vector3 get_contact_collider_position(int p_contact_idx) const {
ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
return body->contacts[p_contact_idx].collider_pos;
}
virtual ObjectID get_contact_collider_id(int p_contact_idx) const {
ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0);
return body->contacts[p_contact_idx].collider_instance_id;
}
virtual int get_contact_collider_shape(int p_contact_idx) const {
ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0);
return body->contacts[p_contact_idx].collider_shape;
}
virtual Vector3 get_contact_collider_velocity_at_position(int p_contact_idx) const {
ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
return body->contacts[p_contact_idx].collider_velocity_at_pos;
}
virtual PhysicsDirectSpaceState *get_space_state();
virtual real_t get_step() const;
PhysicsDirectBodyStateSW() {}
};
#endif // BODY__SW_H

View File

@ -1,212 +0,0 @@
/*************************************************************************/
/* broad_phase_basic.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "broad_phase_basic.h"
#include "core/containers/list.h"
#include "core/string/print_string.h"
BroadPhaseSW::ID BroadPhaseBasic::create(CollisionObjectSW *p_object, int p_subindex, const AABB &p_aabb, bool p_static) {
ERR_FAIL_COND_V(p_object == nullptr, 0);
current++;
Element e;
e.owner = p_object;
e._static = false;
e.subindex = p_subindex;
element_map[current] = e;
return current;
}
void BroadPhaseBasic::move(ID p_id, const AABB &p_aabb) {
RBMap<ID, Element>::Element *E = element_map.find(p_id);
ERR_FAIL_COND(!E);
E->get().aabb = p_aabb;
}
void BroadPhaseBasic::recheck_pairs(ID p_id) {
// Not supported.
}
void BroadPhaseBasic::set_static(ID p_id, bool p_static) {
RBMap<ID, Element>::Element *E = element_map.find(p_id);
ERR_FAIL_COND(!E);
E->get()._static = p_static;
}
void BroadPhaseBasic::remove(ID p_id) {
RBMap<ID, Element>::Element *E = element_map.find(p_id);
ERR_FAIL_COND(!E);
List<PairKey> to_erase;
//unpair must be done immediately on removal to avoid potential invalid pointers
for (RBMap<PairKey, void *>::Element *F = pair_map.front(); F; F = F->next()) {
if (F->key().a == p_id || F->key().b == p_id) {
if (unpair_callback) {
Element *elem_A = &element_map[F->key().a];
Element *elem_B = &element_map[F->key().b];
unpair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, F->get(), unpair_userdata);
}
to_erase.push_back(F->key());
}
}
while (to_erase.size()) {
pair_map.erase(to_erase.front()->get());
to_erase.pop_front();
}
element_map.erase(E);
}
CollisionObjectSW *BroadPhaseBasic::get_object(ID p_id) const {
const RBMap<ID, Element>::Element *E = element_map.find(p_id);
ERR_FAIL_COND_V(!E, nullptr);
return E->get().owner;
}
bool BroadPhaseBasic::is_static(ID p_id) const {
const RBMap<ID, Element>::Element *E = element_map.find(p_id);
ERR_FAIL_COND_V(!E, false);
return E->get()._static;
}
int BroadPhaseBasic::get_subindex(ID p_id) const {
const RBMap<ID, Element>::Element *E = element_map.find(p_id);
ERR_FAIL_COND_V(!E, -1);
return E->get().subindex;
}
int BroadPhaseBasic::cull_point(const Vector3 &p_point, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
int rc = 0;
for (RBMap<ID, Element>::Element *E = element_map.front(); E; E = E->next()) {
const AABB aabb = E->get().aabb;
if (aabb.has_point(p_point)) {
p_results[rc] = E->get().owner;
p_result_indices[rc] = E->get().subindex;
rc++;
if (rc >= p_max_results) {
break;
}
}
}
return rc;
}
int BroadPhaseBasic::cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
int rc = 0;
for (RBMap<ID, Element>::Element *E = element_map.front(); E; E = E->next()) {
const AABB aabb = E->get().aabb;
if (aabb.intersects_segment(p_from, p_to)) {
p_results[rc] = E->get().owner;
p_result_indices[rc] = E->get().subindex;
rc++;
if (rc >= p_max_results) {
break;
}
}
}
return rc;
}
int BroadPhaseBasic::cull_aabb(const AABB &p_aabb, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
int rc = 0;
for (RBMap<ID, Element>::Element *E = element_map.front(); E; E = E->next()) {
const AABB aabb = E->get().aabb;
if (aabb.intersects(p_aabb)) {
p_results[rc] = E->get().owner;
p_result_indices[rc] = E->get().subindex;
rc++;
if (rc >= p_max_results) {
break;
}
}
}
return rc;
}
void BroadPhaseBasic::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) {
pair_userdata = p_userdata;
pair_callback = p_pair_callback;
}
void BroadPhaseBasic::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
unpair_userdata = p_userdata;
unpair_callback = p_unpair_callback;
}
void BroadPhaseBasic::update() {
// recompute pairs
for (RBMap<ID, Element>::Element *I = element_map.front(); I; I = I->next()) {
for (RBMap<ID, Element>::Element *J = I->next(); J; J = J->next()) {
Element *elem_A = &I->get();
Element *elem_B = &J->get();
if (elem_A->owner == elem_B->owner) {
continue;
}
bool pair_ok = elem_A->aabb.intersects(elem_B->aabb) && (!elem_A->_static || !elem_B->_static);
PairKey key(I->key(), J->key());
RBMap<PairKey, void *>::Element *E = pair_map.find(key);
if (!pair_ok && E) {
if (unpair_callback) {
unpair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, E->get(), unpair_userdata);
}
pair_map.erase(key);
}
if (pair_ok && !E) {
void *data = nullptr;
if (pair_callback) {
data = pair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, nullptr, unpair_userdata);
if (data) {
pair_map.insert(key, data);
}
}
}
}
}
}
BroadPhaseSW *BroadPhaseBasic::_create() {
return memnew(BroadPhaseBasic);
}
BroadPhaseBasic::BroadPhaseBasic() {
current = 1;
unpair_callback = nullptr;
unpair_userdata = nullptr;
pair_callback = nullptr;
pair_userdata = nullptr;
}

View File

@ -1,105 +0,0 @@
#ifndef BROAD_PHASE_BASIC_H
#define BROAD_PHASE_BASIC_H
/*************************************************************************/
/* broad_phase_basic.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "broad_phase_sw.h"
#include "core/containers/rb_map.h"
class BroadPhaseBasic : public BroadPhaseSW {
struct Element {
CollisionObjectSW *owner;
bool _static;
AABB aabb;
int subindex;
};
RBMap<ID, Element> element_map;
ID current;
struct PairKey {
union {
struct {
ID a;
ID b;
};
uint64_t key;
};
_FORCE_INLINE_ bool operator<(const PairKey &p_key) const {
return key < p_key.key;
}
PairKey() { key = 0; }
PairKey(ID p_a, ID p_b) {
if (p_a > p_b) {
a = p_b;
b = p_a;
} else {
a = p_a;
b = p_b;
}
}
};
RBMap<PairKey, void *> pair_map;
PairCallback pair_callback;
void *pair_userdata;
UnpairCallback unpair_callback;
void *unpair_userdata;
public:
// 0 is an invalid ID
virtual ID create(CollisionObjectSW *p_object, int p_subindex = 0, const AABB &p_aabb = AABB(), bool p_static = false);
virtual void move(ID p_id, const AABB &p_aabb);
virtual void recheck_pairs(ID p_id);
virtual void set_static(ID p_id, bool p_static);
virtual void remove(ID p_id);
virtual CollisionObjectSW *get_object(ID p_id) const;
virtual bool is_static(ID p_id) const;
virtual int get_subindex(ID p_id) const;
virtual int cull_point(const Vector3 &p_point, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = nullptr);
virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = nullptr);
virtual int cull_aabb(const AABB &p_aabb, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = nullptr);
virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata);
virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata);
virtual void update();
static BroadPhaseSW *_create();
BroadPhaseBasic();
};
#endif // BROAD_PHASE_BASIC_H

View File

@ -1,141 +0,0 @@
/*************************************************************************/
/* broad_phase_bvh.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "broad_phase_bvh.h"
#include "collision_object_sw.h"
#include "core/config/project_settings.h"
BroadPhaseSW::ID BroadPhaseBVH::create(CollisionObjectSW *p_object, int p_subindex, const AABB &p_aabb, bool p_static) {
uint32_t tree_id = p_static ? TREE_STATIC : TREE_DYNAMIC;
uint32_t tree_collision_mask = p_static ? TREE_FLAG_DYNAMIC : (TREE_FLAG_STATIC | TREE_FLAG_DYNAMIC);
ID oid = bvh.create(p_object, true, tree_id, tree_collision_mask, p_aabb, p_subindex); // Pair everything, don't care?
return oid + 1;
}
void BroadPhaseBVH::move(ID p_id, const AABB &p_aabb) {
bvh.move(p_id - 1, p_aabb);
}
void BroadPhaseBVH::recheck_pairs(ID p_id) {
bvh.recheck_pairs(p_id - 1);
}
void BroadPhaseBVH::set_static(ID p_id, bool p_static) {
uint32_t tree_id = p_static ? TREE_STATIC : TREE_DYNAMIC;
uint32_t tree_collision_mask = p_static ? TREE_FLAG_DYNAMIC : (TREE_FLAG_STATIC | TREE_FLAG_DYNAMIC);
bvh.set_tree(p_id - 1, tree_id, tree_collision_mask, false);
}
void BroadPhaseBVH::remove(ID p_id) {
bvh.erase(p_id - 1);
}
CollisionObjectSW *BroadPhaseBVH::get_object(ID p_id) const {
CollisionObjectSW *it = bvh.get(p_id - 1);
ERR_FAIL_COND_V(!it, nullptr);
return it;
}
bool BroadPhaseBVH::is_static(ID p_id) const {
uint32_t tree_id = bvh.get_tree_id(p_id - 1);
return tree_id == 0;
}
int BroadPhaseBVH::get_subindex(ID p_id) const {
return bvh.get_subindex(p_id - 1);
}
int BroadPhaseBVH::cull_point(const Vector3 &p_point, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
return bvh.cull_point(p_point, p_results, p_max_results, nullptr, 0xFFFFFFFF, p_result_indices);
}
int BroadPhaseBVH::cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
return bvh.cull_segment(p_from, p_to, p_results, p_max_results, nullptr, 0xFFFFFFFF, p_result_indices);
}
int BroadPhaseBVH::cull_aabb(const AABB &p_aabb, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
return bvh.cull_aabb(p_aabb, p_results, p_max_results, nullptr, 0xFFFFFFFF, p_result_indices);
}
void *BroadPhaseBVH::_pair_callback(void *p_self, uint32_t p_id_A, CollisionObjectSW *p_object_A, int p_subindex_A, uint32_t p_id_B, CollisionObjectSW *p_object_B, int p_subindex_B) {
BroadPhaseBVH *bpo = (BroadPhaseBVH *)(p_self);
if (!bpo->pair_callback) {
return nullptr;
}
return bpo->pair_callback(p_object_A, p_subindex_A, p_object_B, p_subindex_B, nullptr, bpo->pair_userdata);
}
void BroadPhaseBVH::_unpair_callback(void *p_self, uint32_t p_id_A, CollisionObjectSW *p_object_A, int p_subindex_A, uint32_t p_id_B, CollisionObjectSW *p_object_B, int p_subindex_B, void *p_pair_data) {
BroadPhaseBVH *bpo = (BroadPhaseBVH *)(p_self);
if (!bpo->unpair_callback) {
return;
}
bpo->unpair_callback(p_object_A, p_subindex_A, p_object_B, p_subindex_B, p_pair_data, bpo->unpair_userdata);
}
void *BroadPhaseBVH::_check_pair_callback(void *p_self, uint32_t p_id_A, CollisionObjectSW *p_object_A, int p_subindex_A, uint32_t p_id_B, CollisionObjectSW *p_object_B, int p_subindex_B, void *p_pair_data) {
BroadPhaseBVH *bpo = (BroadPhaseBVH *)(p_self);
if (!bpo->pair_callback) {
return nullptr;
}
return bpo->pair_callback(p_object_A, p_subindex_A, p_object_B, p_subindex_B, p_pair_data, bpo->pair_userdata);
}
void BroadPhaseBVH::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) {
pair_callback = p_pair_callback;
pair_userdata = p_userdata;
}
void BroadPhaseBVH::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
unpair_callback = p_unpair_callback;
unpair_userdata = p_userdata;
}
void BroadPhaseBVH::update() {
bvh.update();
}
BroadPhaseSW *BroadPhaseBVH::_create() {
return memnew(BroadPhaseBVH);
}
BroadPhaseBVH::BroadPhaseBVH() {
bvh.params_set_thread_safe(GLOBAL_GET("rendering/threads/thread_safe_bvh"));
bvh.params_set_pairing_expansion(GLOBAL_GET("physics/3d/pandemonium_physics/bvh_collision_margin"));
bvh.set_pair_callback(_pair_callback, this);
bvh.set_unpair_callback(_unpair_callback, this);
bvh.set_check_pair_callback(_check_pair_callback, this);
pair_callback = nullptr;
pair_userdata = nullptr;
unpair_userdata = nullptr;
}

View File

@ -1,100 +0,0 @@
#ifndef BROAD_PHASE_BVH_H
#define BROAD_PHASE_BVH_H
/*************************************************************************/
/* broad_phase_bvh.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "broad_phase_sw.h"
#include "core/math/bvh.h"
class BroadPhaseBVH : public BroadPhaseSW {
template <class T>
class UserPairTestFunction {
public:
static bool user_pair_check(const T *p_a, const T *p_b) {
// return false if no collision, decided by masks etc
return p_a->test_collision_mask(p_b);
}
};
template <class T>
class UserCullTestFunction {
public:
static bool user_cull_check(const T *p_a, const T *p_b) {
return true;
}
};
enum Tree {
TREE_STATIC = 0,
TREE_DYNAMIC = 1,
};
enum TreeFlag {
TREE_FLAG_STATIC = 1 << TREE_STATIC,
TREE_FLAG_DYNAMIC = 1 << TREE_DYNAMIC,
};
BVH_Manager<CollisionObjectSW, 2, true, 128, UserPairTestFunction<CollisionObjectSW>, UserCullTestFunction<CollisionObjectSW>> bvh;
static void *_pair_callback(void *p_self, uint32_t p_id_A, CollisionObjectSW *p_object_A, int p_subindex_A, uint32_t p_id_B, CollisionObjectSW *p_object_B, int p_subindex_B);
static void _unpair_callback(void *p_self, uint32_t p_id_A, CollisionObjectSW *p_object_A, int p_subindex_A, uint32_t p_id_B, CollisionObjectSW *p_object_B, int p_subindex_B, void *p_pair_data);
static void *_check_pair_callback(void *p_self, uint32_t p_id_A, CollisionObjectSW *p_object_A, int p_subindex_A, uint32_t p_id_B, CollisionObjectSW *p_object_B, int p_subindex_B, void *p_pair_data);
PairCallback pair_callback;
void *pair_userdata;
UnpairCallback unpair_callback;
void *unpair_userdata;
public:
// 0 is an invalid ID
virtual ID create(CollisionObjectSW *p_object, int p_subindex = 0, const AABB &p_aabb = AABB(), bool p_static = false);
virtual void move(ID p_id, const AABB &p_aabb);
virtual void recheck_pairs(ID p_id);
virtual void set_static(ID p_id, bool p_static);
virtual void remove(ID p_id);
virtual CollisionObjectSW *get_object(ID p_id) const;
virtual bool is_static(ID p_id) const;
virtual int get_subindex(ID p_id) const;
virtual int cull_point(const Vector3 &p_point, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = nullptr);
virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = nullptr);
virtual int cull_aabb(const AABB &p_aabb, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = nullptr);
virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata);
virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata);
virtual void update();
static BroadPhaseSW *_create();
BroadPhaseBVH();
};
#endif // BROAD_PHASE_BVH_H

View File

@ -1,128 +0,0 @@
/*************************************************************************/
/* broad_phase_octree.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "broad_phase_octree.h"
#include "collision_object_sw.h"
BroadPhaseSW::ID BroadPhaseOctree::create(CollisionObjectSW *p_object, int p_subindex, const AABB &p_aabb, bool p_static) {
ID oid = octree.create(p_object, AABB(), p_subindex, false, 1 << p_object->get_type(), 0);
return oid;
}
void BroadPhaseOctree::move(ID p_id, const AABB &p_aabb) {
octree.move(p_id, p_aabb);
}
void BroadPhaseOctree::recheck_pairs(ID p_id) {
AABB aabb = octree.get_aabb(p_id);
octree.move(p_id, aabb);
}
void BroadPhaseOctree::set_static(ID p_id, bool p_static) {
CollisionObjectSW *it = octree.get(p_id);
octree.set_pairable(p_id, !p_static, 1 << it->get_type(), p_static ? 0 : 0xFFFFF); //pair everything, don't care 1?
}
void BroadPhaseOctree::remove(ID p_id) {
octree.erase(p_id);
}
CollisionObjectSW *BroadPhaseOctree::get_object(ID p_id) const {
CollisionObjectSW *it = octree.get(p_id);
ERR_FAIL_COND_V(!it, nullptr);
return it;
}
bool BroadPhaseOctree::is_static(ID p_id) const {
return !octree.is_pairable(p_id);
}
int BroadPhaseOctree::get_subindex(ID p_id) const {
return octree.get_subindex(p_id);
}
int BroadPhaseOctree::cull_point(const Vector3 &p_point, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
return octree.cull_point(p_point, p_results, p_max_results, p_result_indices);
}
int BroadPhaseOctree::cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
return octree.cull_segment(p_from, p_to, p_results, p_max_results, p_result_indices);
}
int BroadPhaseOctree::cull_aabb(const AABB &p_aabb, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
return octree.cull_aabb(p_aabb, p_results, p_max_results, p_result_indices);
}
void *BroadPhaseOctree::_pair_callback(void *self, OctreeElementID p_A, CollisionObjectSW *p_object_A, int subindex_A, OctreeElementID p_B, CollisionObjectSW *p_object_B, int subindex_B) {
BroadPhaseOctree *bpo = (BroadPhaseOctree *)(self);
if (!bpo->pair_callback) {
return nullptr;
}
bool valid_collision_pair = p_object_A->test_collision_mask(p_object_B);
if (!valid_collision_pair) {
return nullptr;
}
return bpo->pair_callback(p_object_A, subindex_A, p_object_B, subindex_B, nullptr, bpo->pair_userdata);
}
void BroadPhaseOctree::_unpair_callback(void *self, OctreeElementID p_A, CollisionObjectSW *p_object_A, int subindex_A, OctreeElementID p_B, CollisionObjectSW *p_object_B, int subindex_B, void *pairdata) {
BroadPhaseOctree *bpo = (BroadPhaseOctree *)(self);
if (!bpo->unpair_callback) {
return;
}
bpo->unpair_callback(p_object_A, subindex_A, p_object_B, subindex_B, pairdata, bpo->unpair_userdata);
}
void BroadPhaseOctree::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) {
pair_callback = p_pair_callback;
pair_userdata = p_userdata;
}
void BroadPhaseOctree::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
unpair_callback = p_unpair_callback;
unpair_userdata = p_userdata;
}
void BroadPhaseOctree::update() {
// does.. not?
}
BroadPhaseSW *BroadPhaseOctree::_create() {
return memnew(BroadPhaseOctree);
}
BroadPhaseOctree::BroadPhaseOctree() {
octree.set_pair_callback(_pair_callback, this);
octree.set_unpair_callback(_unpair_callback, this);
pair_callback = nullptr;
pair_userdata = nullptr;
unpair_userdata = nullptr;
}

View File

@ -1,72 +0,0 @@
#ifndef BROAD_PHASE_OCTREE_H
#define BROAD_PHASE_OCTREE_H
/*************************************************************************/
/* broad_phase_octree.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "broad_phase_sw.h"
#include "core/math/octree.h"
class BroadPhaseOctree : public BroadPhaseSW {
Octree<CollisionObjectSW, true> octree;
static void *_pair_callback(void *, OctreeElementID, CollisionObjectSW *, int, OctreeElementID, CollisionObjectSW *, int);
static void _unpair_callback(void *, OctreeElementID, CollisionObjectSW *, int, OctreeElementID, CollisionObjectSW *, int, void *);
PairCallback pair_callback;
void *pair_userdata;
UnpairCallback unpair_callback;
void *unpair_userdata;
public:
// 0 is an invalid ID
virtual ID create(CollisionObjectSW *p_object, int p_subindex = 0, const AABB &p_aabb = AABB(), bool p_static = false);
virtual void move(ID p_id, const AABB &p_aabb);
virtual void recheck_pairs(ID p_id);
virtual void set_static(ID p_id, bool p_static);
virtual void remove(ID p_id);
virtual CollisionObjectSW *get_object(ID p_id) const;
virtual bool is_static(ID p_id) const;
virtual int get_subindex(ID p_id) const;
virtual int cull_point(const Vector3 &p_point, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = nullptr);
virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = nullptr);
virtual int cull_aabb(const AABB &p_aabb, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = nullptr);
virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata);
virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata);
virtual void update();
static BroadPhaseSW *_create();
BroadPhaseOctree();
};
#endif // BROAD_PHASE_OCTREE_H

View File

@ -1,36 +0,0 @@
/*************************************************************************/
/* broad_phase_sw.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "broad_phase_sw.h"
BroadPhaseSW::CreateFunction BroadPhaseSW::create_func = nullptr;
BroadPhaseSW::~BroadPhaseSW() {
}

View File

@ -1,72 +0,0 @@
#ifndef BROAD_PHASE_SW_H
#define BROAD_PHASE_SW_H
/*************************************************************************/
/* broad_phase_sw.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/math/aabb.h"
#include "core/math/math_funcs.h"
class CollisionObjectSW;
class BroadPhaseSW {
public:
typedef BroadPhaseSW *(*CreateFunction)();
static CreateFunction create_func;
typedef uint32_t ID;
typedef void *(*PairCallback)(CollisionObjectSW *p_object_A, int p_subindex_A, CollisionObjectSW *p_object_B, int p_subindex_B, void *p_pair_data, void *p_user_data);
typedef void (*UnpairCallback)(CollisionObjectSW *p_object_A, int p_subindex_A, CollisionObjectSW *p_object_B, int p_subindex_B, void *p_pair_data, void *p_user_data);
// 0 is an invalid ID
virtual ID create(CollisionObjectSW *p_object_, int p_subindex = 0, const AABB &p_aabb = AABB(), bool p_static = false) = 0;
virtual void move(ID p_id, const AABB &p_aabb) = 0;
virtual void recheck_pairs(ID p_id) = 0;
virtual void set_static(ID p_id, bool p_static) = 0;
virtual void remove(ID p_id) = 0;
virtual CollisionObjectSW *get_object(ID p_id) const = 0;
virtual bool is_static(ID p_id) const = 0;
virtual int get_subindex(ID p_id) const = 0;
virtual int cull_point(const Vector3 &p_point, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0;
virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0;
virtual int cull_aabb(const AABB &p_aabb, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0;
virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata) = 0;
virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) = 0;
virtual void update() = 0;
virtual ~BroadPhaseSW();
};
#endif // BROAD_PHASE__SW_H

View File

@ -1,262 +0,0 @@
/*************************************************************************/
/* collision_object_sw.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "collision_object_sw.h"
#include "servers/physics/physics_server_sw.h"
#include "space_sw.h"
void CollisionObjectSW::add_shape(ShapeSW *p_shape, const Transform &p_transform, bool p_disabled) {
Shape s;
s.shape = p_shape;
s.xform = p_transform;
s.xform_inv = s.xform.affine_inverse();
s.bpid = 0; //needs update
s.disabled = p_disabled;
shapes.push_back(s);
p_shape->add_owner(this);
if (!pending_shape_update_list.in_list()) {
PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
}
}
void CollisionObjectSW::set_shape(int p_index, ShapeSW *p_shape) {
ERR_FAIL_INDEX(p_index, shapes.size());
shapes[p_index].shape->remove_owner(this);
shapes.write[p_index].shape = p_shape;
p_shape->add_owner(this);
if (!pending_shape_update_list.in_list()) {
PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
}
}
void CollisionObjectSW::set_shape_transform(int p_index, const Transform &p_transform) {
ERR_FAIL_INDEX(p_index, shapes.size());
shapes.write[p_index].xform = p_transform;
shapes.write[p_index].xform_inv = p_transform.affine_inverse();
if (!pending_shape_update_list.in_list()) {
PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
}
}
void CollisionObjectSW::set_shape_disabled(int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_idx, shapes.size());
CollisionObjectSW::Shape &shape = shapes.write[p_idx];
if (shape.disabled == p_disabled) {
return;
}
shape.disabled = p_disabled;
if (!space) {
return;
}
if (p_disabled && shape.bpid != 0) {
space->get_broadphase()->remove(shape.bpid);
shape.bpid = 0;
if (!pending_shape_update_list.in_list()) {
PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
}
} else if (!p_disabled && shape.bpid == 0) {
if (!pending_shape_update_list.in_list()) {
PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
}
}
}
void CollisionObjectSW::remove_shape(ShapeSW *p_shape) {
//remove a shape, all the times it appears
for (int i = 0; i < shapes.size(); i++) {
if (shapes[i].shape == p_shape) {
remove_shape(i);
i--;
}
}
}
void CollisionObjectSW::remove_shape(int p_index) {
//remove anything from shape to be erased to end, so subindices don't change
ERR_FAIL_INDEX(p_index, shapes.size());
for (int i = p_index; i < shapes.size(); i++) {
if (shapes[i].bpid == 0) {
continue;
}
//should never get here with a null owner
space->get_broadphase()->remove(shapes[i].bpid);
shapes.write[i].bpid = 0;
}
shapes[p_index].shape->remove_owner(this);
shapes.remove(p_index);
if (!pending_shape_update_list.in_list()) {
PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
}
}
void CollisionObjectSW::_set_static(bool p_static) {
if (_static == p_static) {
return;
}
_static = p_static;
if (!space) {
return;
}
for (int i = 0; i < get_shape_count(); i++) {
const Shape &s = shapes[i];
if (s.bpid > 0) {
space->get_broadphase()->set_static(s.bpid, _static);
}
}
}
void CollisionObjectSW::_unregister_shapes() {
for (int i = 0; i < shapes.size(); i++) {
Shape &s = shapes.write[i];
if (s.bpid > 0) {
space->get_broadphase()->remove(s.bpid);
s.bpid = 0;
}
}
}
void CollisionObjectSW::_update_shapes() {
if (!space) {
return;
}
for (int i = 0; i < shapes.size(); i++) {
Shape &s = shapes.write[i];
if (s.disabled) {
continue;
}
//not quite correct, should compute the next matrix..
AABB shape_aabb = s.shape->get_aabb();
Transform xform = transform * s.xform;
shape_aabb = xform.xform(shape_aabb);
shape_aabb.grow_by((s.aabb_cache.size.x + s.aabb_cache.size.y) * 0.5 * 0.05);
s.aabb_cache = shape_aabb;
Vector3 scale = xform.get_basis().get_scale();
s.area_cache = s.shape->get_area() * scale.x * scale.y * scale.z;
if (s.bpid == 0) {
s.bpid = space->get_broadphase()->create(this, i, shape_aabb, _static);
space->get_broadphase()->set_static(s.bpid, _static);
}
space->get_broadphase()->move(s.bpid, shape_aabb);
}
}
void CollisionObjectSW::_recheck_shapes() {
if (!space) {
return;
}
for (int i = 0; i < shapes.size(); i++) {
Shape &s = shapes.write[i];
if (s.disabled) {
continue;
}
if (s.bpid != 0) {
space->get_broadphase()->recheck_pairs(s.bpid);
}
}
}
void CollisionObjectSW::_update_shapes_with_motion(const Vector3 &p_motion) {
if (!space) {
return;
}
for (int i = 0; i < shapes.size(); i++) {
Shape &s = shapes.write[i];
if (s.disabled) {
continue;
}
//not quite correct, should compute the next matrix..
AABB shape_aabb = s.shape->get_aabb();
Transform xform = transform * s.xform;
shape_aabb = xform.xform(shape_aabb);
shape_aabb.merge_with(AABB(shape_aabb.position + p_motion, shape_aabb.size)); //use motion
s.aabb_cache = shape_aabb;
if (s.bpid == 0) {
s.bpid = space->get_broadphase()->create(this, i, shape_aabb, _static);
space->get_broadphase()->set_static(s.bpid, _static);
}
space->get_broadphase()->move(s.bpid, shape_aabb);
}
}
void CollisionObjectSW::_set_space(SpaceSW *p_space) {
if (space) {
space->remove_object(this);
for (int i = 0; i < shapes.size(); i++) {
Shape &s = shapes.write[i];
if (s.bpid) {
space->get_broadphase()->remove(s.bpid);
s.bpid = 0;
}
}
}
space = p_space;
if (space) {
space->add_object(this);
_update_shapes();
}
}
void CollisionObjectSW::_shape_changed() {
_update_shapes();
_shapes_changed();
}
CollisionObjectSW::CollisionObjectSW(Type p_type) :
pending_shape_update_list(this) {
_static = true;
type = p_type;
space = nullptr;
instance_id = 0;
collision_layer = 1;
collision_mask = 1;
ray_pickable = true;
}

View File

@ -1,184 +0,0 @@
#ifndef COLLISION_OBJECT_SW_H
#define COLLISION_OBJECT_SW_H
/*************************************************************************/
/* collision_object_sw.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "broad_phase_sw.h"
#include "core/containers/self_list.h"
#include "servers/physics_server.h"
#include "shape_sw.h"
#ifdef DEBUG_ENABLED
#define MAX_OBJECT_DISTANCE 3.1622776601683791e+18
#define MAX_OBJECT_DISTANCE_X2 (MAX_OBJECT_DISTANCE * MAX_OBJECT_DISTANCE)
#endif
class SpaceSW;
class CollisionObjectSW : public ShapeOwnerSW {
public:
enum Type {
TYPE_AREA,
TYPE_BODY
};
private:
Type type;
RID self;
ObjectID instance_id;
uint32_t collision_layer;
uint32_t collision_mask;
struct Shape {
Transform xform;
Transform xform_inv;
BroadPhaseSW::ID bpid;
AABB aabb_cache; //for rayqueries
real_t area_cache;
ShapeSW *shape;
bool disabled;
Shape() { disabled = false; }
};
Vector<Shape> shapes;
SpaceSW *space;
Transform transform;
Transform inv_transform;
bool _static;
SelfList<CollisionObjectSW> pending_shape_update_list;
void _update_shapes();
void _recheck_shapes();
protected:
void _update_shapes_with_motion(const Vector3 &p_motion);
void _unregister_shapes();
_FORCE_INLINE_ void _set_transform(const Transform &p_transform, bool p_update_shapes = true) {
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(p_transform.origin.length_squared() > MAX_OBJECT_DISTANCE_X2, "Object went too far away (more than '" + itos(MAX_OBJECT_DISTANCE) + "' units from origin).");
#endif
transform = p_transform;
if (p_update_shapes) {
_update_shapes();
}
}
_FORCE_INLINE_ void _set_inv_transform(const Transform &p_transform) { inv_transform = p_transform; }
void _set_static(bool p_static);
virtual void _shapes_changed() = 0;
void _set_space(SpaceSW *p_space);
bool ray_pickable;
CollisionObjectSW(Type p_type);
public:
_FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
_FORCE_INLINE_ RID get_self() const { return self; }
_FORCE_INLINE_ void set_instance_id(const ObjectID &p_instance_id) { instance_id = p_instance_id; }
_FORCE_INLINE_ ObjectID get_instance_id() const { return instance_id; }
void _shape_changed();
_FORCE_INLINE_ Type get_type() const { return type; }
void add_shape(ShapeSW *p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
void set_shape(int p_index, ShapeSW *p_shape);
void set_shape_transform(int p_index, const Transform &p_transform);
_FORCE_INLINE_ int get_shape_count() const { return shapes.size(); }
_FORCE_INLINE_ ShapeSW *get_shape(int p_index) const {
CRASH_BAD_INDEX(p_index, shapes.size());
return shapes[p_index].shape;
}
_FORCE_INLINE_ const Transform &get_shape_transform(int p_index) const {
CRASH_BAD_INDEX(p_index, shapes.size());
return shapes[p_index].xform;
}
_FORCE_INLINE_ const Transform &get_shape_inv_transform(int p_index) const {
CRASH_BAD_INDEX(p_index, shapes.size());
return shapes[p_index].xform_inv;
}
_FORCE_INLINE_ const AABB &get_shape_aabb(int p_index) const {
CRASH_BAD_INDEX(p_index, shapes.size());
return shapes[p_index].aabb_cache;
}
_FORCE_INLINE_ real_t get_shape_area(int p_index) const {
CRASH_BAD_INDEX(p_index, shapes.size());
return shapes[p_index].area_cache;
}
_FORCE_INLINE_ Transform get_transform() const { return transform; }
_FORCE_INLINE_ Transform get_inv_transform() const { return inv_transform; }
_FORCE_INLINE_ SpaceSW *get_space() const { return space; }
_FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; }
_FORCE_INLINE_ bool is_ray_pickable() const { return ray_pickable; }
void set_shape_disabled(int p_idx, bool p_disabled);
_FORCE_INLINE_ bool is_shape_disabled(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, shapes.size(), false);
return shapes[p_idx].disabled;
}
_FORCE_INLINE_ void set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
_recheck_shapes();
_shapes_changed();
}
_FORCE_INLINE_ uint32_t get_collision_layer() const { return collision_layer; }
_FORCE_INLINE_ void set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
_recheck_shapes();
_shapes_changed();
}
_FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; }
_FORCE_INLINE_ bool test_collision_mask(const CollisionObjectSW *p_other) const {
return collision_layer & p_other->collision_mask || p_other->collision_layer & collision_mask;
}
void remove_shape(ShapeSW *p_shape);
void remove_shape(int p_index);
virtual void set_space(SpaceSW *p_space) = 0;
_FORCE_INLINE_ bool is_static() const { return _static; }
virtual ~CollisionObjectSW() {}
};
#endif // COLLISION_OBJECT_SW_H

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +0,0 @@
#ifndef COLLISION_SOLVER_SAT_H
#define COLLISION_SOLVER_SAT_H
/*************************************************************************/
/* collision_solver_sat.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "collision_solver_sw.h"
bool sat_calculate_penetration(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CollisionSolverSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, Vector3 *r_prev_axis = nullptr, real_t p_margin_a = 0, real_t p_margin_b = 0);
#endif // COLLISION_SOLVER_SAT_H

View File

@ -1,405 +0,0 @@
/*************************************************************************/
/* collision_solver_sw.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "collision_solver_sw.h"
#include "collision_solver_sat.h"
#include "gjk_epa.h"
#define collision_solver sat_calculate_penetration
//#define collision_solver gjk_epa_calculate_penetration
bool CollisionSolverSW::solve_static_plane(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
const PlaneShapeSW *plane = static_cast<const PlaneShapeSW *>(p_shape_A);
if (p_shape_B->get_type() == PhysicsServer::SHAPE_PLANE) {
return false;
}
Plane p = p_transform_A.xform(plane->get_plane());
static const int max_supports = 16;
Vector3 supports[max_supports];
int support_count;
ShapeSW::FeatureType support_type;
p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count, support_type);
if (support_type == ShapeSW::FEATURE_CIRCLE) {
ERR_FAIL_COND_V(support_count != 3, false);
Vector3 circle_pos = supports[0];
Vector3 circle_axis_1 = supports[1] - circle_pos;
Vector3 circle_axis_2 = supports[2] - circle_pos;
// Use 3 equidistant points on the circle.
for (int i = 0; i < 3; ++i) {
Vector3 vertex_pos = circle_pos;
vertex_pos += circle_axis_1 * Math::cos(2.0 * Math_PI * i / 3.0);
vertex_pos += circle_axis_2 * Math::sin(2.0 * Math_PI * i / 3.0);
supports[i] = vertex_pos;
}
}
bool found = false;
for (int i = 0; i < support_count; i++) {
supports[i] = p_transform_B.xform(supports[i]);
if (p.distance_to(supports[i]) >= 0) {
continue;
}
found = true;
Vector3 support_A = p.project(supports[i]);
if (p_result_callback) {
if (p_swap_result) {
p_result_callback(supports[i], support_A, p_userdata);
} else {
p_result_callback(support_A, supports[i], p_userdata);
}
}
}
return found;
}
bool CollisionSolverSW::solve_ray(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin) {
const RayShapeSW *ray = static_cast<const RayShapeSW *>(p_shape_A);
Vector3 from = p_transform_A.origin;
Vector3 to = from + p_transform_A.basis.get_axis(2) * (ray->get_length() + p_margin);
Vector3 support_A = to;
Transform ai = p_transform_B.affine_inverse();
from = ai.xform(from);
to = ai.xform(to);
Vector3 p, n;
if (!p_shape_B->intersect_segment(from, to, p, n)) {
return false;
}
Vector3 support_B = p_transform_B.xform(p);
if (ray->get_slips_on_slope()) {
Vector3 global_n = ai.basis.xform_inv(n).normalized();
support_B = support_A + (support_B - support_A).length() * global_n;
}
if (p_result_callback) {
if (p_swap_result) {
p_result_callback(support_B, support_A, p_userdata);
} else {
p_result_callback(support_A, support_B, p_userdata);
}
}
return true;
}
struct _ConcaveCollisionInfo {
const Transform *transform_A;
const ShapeSW *shape_A;
const Transform *transform_B;
CollisionSolverSW::CallbackResult result_callback;
void *userdata;
bool swap_result;
bool collided;
int aabb_tests;
int collisions;
bool tested;
real_t margin_A;
real_t margin_B;
Vector3 close_A, close_B;
};
bool CollisionSolverSW::concave_callback(void *p_userdata, ShapeSW *p_convex) {
_ConcaveCollisionInfo &cinfo = *(_ConcaveCollisionInfo *)(p_userdata);
cinfo.aabb_tests++;
bool collided = collision_solver(cinfo.shape_A, *cinfo.transform_A, p_convex, *cinfo.transform_B, cinfo.result_callback, cinfo.userdata, cinfo.swap_result, nullptr, cinfo.margin_A, cinfo.margin_B);
if (!collided) {
return false;
}
cinfo.collided = true;
cinfo.collisions++;
// Stop at first collision if contacts are not needed.
return !cinfo.result_callback;
}
bool CollisionSolverSW::solve_concave(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A, real_t p_margin_B) {
const ConcaveShapeSW *concave_B = static_cast<const ConcaveShapeSW *>(p_shape_B);
_ConcaveCollisionInfo cinfo;
cinfo.transform_A = &p_transform_A;
cinfo.shape_A = p_shape_A;
cinfo.transform_B = &p_transform_B;
cinfo.result_callback = p_result_callback;
cinfo.userdata = p_userdata;
cinfo.swap_result = p_swap_result;
cinfo.collided = false;
cinfo.collisions = 0;
cinfo.margin_A = p_margin_A;
cinfo.margin_B = p_margin_B;
cinfo.aabb_tests = 0;
Transform rel_transform = p_transform_A;
rel_transform.origin -= p_transform_B.origin;
//quickly compute a local AABB
AABB local_aabb;
for (int i = 0; i < 3; i++) {
Vector3 axis(p_transform_B.basis.get_axis(i));
real_t axis_scale = 1.0 / axis.length();
axis *= axis_scale;
real_t smin, smax;
p_shape_A->project_range(axis, rel_transform, smin, smax);
smin -= p_margin_A;
smax += p_margin_A;
smin *= axis_scale;
smax *= axis_scale;
local_aabb.position[i] = smin;
local_aabb.size[i] = smax - smin;
}
concave_B->cull(local_aabb, concave_callback, &cinfo);
return cinfo.collided;
}
bool CollisionSolverSW::solve_static(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, Vector3 *r_sep_axis, real_t p_margin_A, real_t p_margin_B) {
PhysicsServer::ShapeType type_A = p_shape_A->get_type();
PhysicsServer::ShapeType type_B = p_shape_B->get_type();
bool concave_A = p_shape_A->is_concave();
bool concave_B = p_shape_B->is_concave();
bool swap = false;
if (type_A > type_B) {
SWAP(type_A, type_B);
SWAP(concave_A, concave_B);
swap = true;
}
if (type_A == PhysicsServer::SHAPE_PLANE) {
if (type_B == PhysicsServer::SHAPE_PLANE) {
return false;
}
if (type_B == PhysicsServer::SHAPE_RAY) {
return false;
}
if (swap) {
return solve_static_plane(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
} else {
return solve_static_plane(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
}
} else if (type_A == PhysicsServer::SHAPE_RAY) {
if (type_B == PhysicsServer::SHAPE_RAY) {
return false;
}
if (swap) {
return solve_ray(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true, p_margin_B);
} else {
return solve_ray(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false, p_margin_A);
}
} else if (concave_B) {
if (concave_A) {
return false;
}
if (!swap) {
return solve_concave(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false, p_margin_A, p_margin_B);
} else {
return solve_concave(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true, p_margin_A, p_margin_B);
}
} else {
return collision_solver(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false, r_sep_axis, p_margin_A, p_margin_B);
}
}
bool CollisionSolverSW::concave_distance_callback(void *p_userdata, ShapeSW *p_convex) {
_ConcaveCollisionInfo &cinfo = *(_ConcaveCollisionInfo *)(p_userdata);
cinfo.aabb_tests++;
Vector3 close_A, close_B;
cinfo.collided = !gjk_epa_calculate_distance(cinfo.shape_A, *cinfo.transform_A, p_convex, *cinfo.transform_B, close_A, close_B);
if (cinfo.collided) {
// No need to process any more result.
return true;
}
if (!cinfo.tested || close_A.distance_squared_to(close_B) < cinfo.close_A.distance_squared_to(cinfo.close_B)) {
cinfo.close_A = close_A;
cinfo.close_B = close_B;
cinfo.tested = true;
}
cinfo.collisions++;
return false;
}
bool CollisionSolverSW::solve_distance_plane(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B) {
const PlaneShapeSW *plane = static_cast<const PlaneShapeSW *>(p_shape_A);
if (p_shape_B->get_type() == PhysicsServer::SHAPE_PLANE) {
return false;
}
Plane p = p_transform_A.xform(plane->get_plane());
static const int max_supports = 16;
Vector3 supports[max_supports];
int support_count;
ShapeSW::FeatureType support_type;
p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count, support_type);
if (support_type == ShapeSW::FEATURE_CIRCLE) {
ERR_FAIL_COND_V(support_count != 3, false);
Vector3 circle_pos = supports[0];
Vector3 circle_axis_1 = supports[1] - circle_pos;
Vector3 circle_axis_2 = supports[2] - circle_pos;
// Use 3 equidistant points on the circle.
for (int i = 0; i < 3; ++i) {
Vector3 vertex_pos = circle_pos;
vertex_pos += circle_axis_1 * Math::cos(2.0 * Math_PI * i / 3.0);
vertex_pos += circle_axis_2 * Math::sin(2.0 * Math_PI * i / 3.0);
supports[i] = vertex_pos;
}
}
bool collided = false;
Vector3 closest;
real_t closest_d = 0;
for (int i = 0; i < support_count; i++) {
supports[i] = p_transform_B.xform(supports[i]);
real_t d = p.distance_to(supports[i]);
if (i == 0 || d < closest_d) {
closest = supports[i];
closest_d = d;
if (d <= 0) {
collided = true;
}
}
}
r_point_A = p.project(closest);
r_point_B = closest;
return collided;
}
bool CollisionSolverSW::solve_distance(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis) {
if (p_shape_A->is_concave()) {
return false;
}
if (p_shape_B->get_type() == PhysicsServer::SHAPE_PLANE) {
Vector3 a, b;
bool col = solve_distance_plane(p_shape_B, p_transform_B, p_shape_A, p_transform_A, a, b);
r_point_A = b;
r_point_B = a;
return !col;
} else if (p_shape_B->is_concave()) {
if (p_shape_A->is_concave()) {
return false;
}
const ConcaveShapeSW *concave_B = static_cast<const ConcaveShapeSW *>(p_shape_B);
_ConcaveCollisionInfo cinfo;
cinfo.transform_A = &p_transform_A;
cinfo.shape_A = p_shape_A;
cinfo.transform_B = &p_transform_B;
cinfo.result_callback = nullptr;
cinfo.userdata = nullptr;
cinfo.swap_result = false;
cinfo.collided = false;
cinfo.collisions = 0;
cinfo.aabb_tests = 0;
cinfo.tested = false;
Transform rel_transform = p_transform_A;
rel_transform.origin -= p_transform_B.origin;
//quickly compute a local AABB
bool use_cc_hint = p_concave_hint != AABB();
AABB cc_hint_aabb;
if (use_cc_hint) {
cc_hint_aabb = p_concave_hint;
cc_hint_aabb.position -= p_transform_B.origin;
}
AABB local_aabb;
for (int i = 0; i < 3; i++) {
Vector3 axis(p_transform_B.basis.get_axis(i));
real_t axis_scale = ((real_t)1.0) / axis.length();
axis *= axis_scale;
real_t smin, smax;
if (use_cc_hint) {
cc_hint_aabb.project_range_in_plane(Plane(axis, 0), smin, smax);
} else {
p_shape_A->project_range(axis, rel_transform, smin, smax);
}
smin *= axis_scale;
smax *= axis_scale;
local_aabb.position[i] = smin;
local_aabb.size[i] = smax - smin;
}
concave_B->cull(local_aabb, concave_distance_callback, &cinfo);
if (!cinfo.collided) {
r_point_A = cinfo.close_A;
r_point_B = cinfo.close_B;
}
return !cinfo.collided;
} else {
return gjk_epa_calculate_distance(p_shape_A, p_transform_A, p_shape_B, p_transform_B, r_point_A, r_point_B); //should pass sepaxis..
}
}

View File

@ -1,52 +0,0 @@
#ifndef COLLISION_SOLVER_SW_H
#define COLLISION_SOLVER_SW_H
/*************************************************************************/
/* collision_solver_sw.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "shape_sw.h"
class CollisionSolverSW {
public:
typedef void (*CallbackResult)(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata);
private:
static bool concave_callback(void *p_userdata, ShapeSW *p_convex);
static bool solve_static_plane(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
static bool solve_ray(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin = 0);
static bool solve_concave(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A = 0, real_t p_margin_B = 0);
static bool concave_distance_callback(void *p_userdata, ShapeSW *p_convex);
static bool solve_distance_plane(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B);
public:
static bool solve_static(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, Vector3 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
static bool solve_distance(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis = nullptr);
};
#endif // COLLISION_SOLVER__SW_H

View File

@ -1,83 +0,0 @@
#ifndef CONSTRAINT_SW_H
#define CONSTRAINT_SW_H
/*************************************************************************/
/* constraint_sw.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "body_sw.h"
class ConstraintSW : public RID_Data {
BodySW **_body_ptr;
int _body_count;
uint64_t island_step;
ConstraintSW *island_next;
ConstraintSW *island_list_next;
int priority;
bool disabled_collisions_between_bodies;
RID self;
protected:
ConstraintSW(BodySW **p_body_ptr = nullptr, int p_body_count = 0) {
_body_ptr = p_body_ptr;
_body_count = p_body_count;
island_step = 0;
priority = 1;
disabled_collisions_between_bodies = true;
}
public:
_FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
_FORCE_INLINE_ RID get_self() const { return self; }
_FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
_FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
_FORCE_INLINE_ ConstraintSW *get_island_next() const { return island_next; }
_FORCE_INLINE_ void set_island_next(ConstraintSW *p_next) { island_next = p_next; }
_FORCE_INLINE_ ConstraintSW *get_island_list_next() const { return island_list_next; }
_FORCE_INLINE_ void set_island_list_next(ConstraintSW *p_next) { island_list_next = p_next; }
_FORCE_INLINE_ BodySW **get_body_ptr() const { return _body_ptr; }
_FORCE_INLINE_ int get_body_count() const { return _body_count; }
_FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; }
_FORCE_INLINE_ int get_priority() const { return priority; }
_FORCE_INLINE_ void disable_collisions_between_bodies(const bool p_disabled) { disabled_collisions_between_bodies = p_disabled; }
_FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; }
virtual bool setup(real_t p_step) = 0;
virtual void solve(real_t p_step) = 0;
virtual ~ConstraintSW() {}
};
#endif // CONSTRAINT__SW_H

File diff suppressed because it is too large Load Diff

View File

@ -1,39 +0,0 @@
#ifndef GJK_EPA_H
#define GJK_EPA_H
/*************************************************************************/
/* gjk_epa.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "collision_solver_sw.h"
#include "shape_sw.h"
bool gjk_epa_calculate_penetration(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CollisionSolverSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, real_t p_margin_A = 0.0, real_t p_margin_B = 0.0);
bool gjk_epa_calculate_distance(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B);
#endif

View File

@ -1,5 +0,0 @@
#!/usr/bin/env python
Import("env")
env.add_source_files(env.servers_sources, "*.cpp")

View File

@ -1,356 +0,0 @@
/*************************************************************************/
/* cone_twist_joint_sw.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
/*
Adapted to Pandemonium from the Bullet library.
*/
/*
Bullet Continuous Collision Detection and Physics Library
ConeTwistJointSW is Copyright (c) 2007 Starbreeze Studios
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Written by: Marcus Hennix
*/
#include "cone_twist_joint_sw.h"
static void plane_space(const Vector3 &n, Vector3 &p, Vector3 &q) {
if (Math::abs(n.z) > Math_SQRT12) {
// choose p in y-z plane
real_t a = n[1] * n[1] + n[2] * n[2];
real_t k = 1.0 / Math::sqrt(a);
p = Vector3(0, -n[2] * k, n[1] * k);
// set q = n x p
q = Vector3(a * k, -n[0] * p[2], n[0] * p[1]);
} else {
// choose p in x-y plane
real_t a = n.x * n.x + n.y * n.y;
real_t k = 1.0 / Math::sqrt(a);
p = Vector3(-n.y * k, n.x * k, 0);
// set q = n x p
q = Vector3(-n.z * p.y, n.z * p.x, a * k);
}
}
static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x) {
real_t coeff_1 = Math_PI / 4.0f;
real_t coeff_2 = 3.0f * coeff_1;
real_t abs_y = Math::abs(y);
real_t angle;
if (x >= 0.0f) {
real_t r = (x - abs_y) / (x + abs_y);
angle = coeff_1 - coeff_1 * r;
} else {
real_t r = (x + abs_y) / (abs_y - x);
angle = coeff_2 - coeff_1 * r;
}
return (y < 0.0f) ? -angle : angle;
}
ConeTwistJointSW::ConeTwistJointSW(BodySW *rbA, BodySW *rbB, const Transform &rbAFrame, const Transform &rbBFrame) :
JointSW(_arr, 2) {
A = rbA;
B = rbB;
m_rbAFrame = rbAFrame;
m_rbBFrame = rbBFrame;
m_swingSpan1 = Math_PI / 4.0;
m_swingSpan2 = Math_PI / 4.0;
m_twistSpan = Math_PI * 2;
m_biasFactor = 0.3f;
m_relaxationFactor = 1.0f;
m_angularOnly = false;
m_solveTwistLimit = false;
m_solveSwingLimit = false;
A->add_constraint(this, 0);
B->add_constraint(this, 1);
m_appliedImpulse = 0;
}
bool ConeTwistJointSW::setup(real_t p_timestep) {
if ((A->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC)) {
return false;
}
m_appliedImpulse = real_t(0.);
//set bias, sign, clear accumulator
m_swingCorrection = real_t(0.);
m_twistLimitSign = real_t(0.);
m_solveTwistLimit = false;
m_solveSwingLimit = false;
m_accTwistLimitImpulse = real_t(0.);
m_accSwingLimitImpulse = real_t(0.);
if (!m_angularOnly) {
Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
Vector3 relPos = pivotBInW - pivotAInW;
Vector3 normal[3];
if (Math::is_zero_approx(relPos.length_squared())) {
normal[0] = Vector3(real_t(1.0), 0, 0);
} else {
normal[0] = relPos.normalized();
}
plane_space(normal[0], normal[1], normal[2]);
for (int i = 0; i < 3; i++) {
memnew_placement(
&m_jac[i],
JacobianEntrySW(
A->get_principal_inertia_axes().transposed(),
B->get_principal_inertia_axes().transposed(),
pivotAInW - A->get_transform().origin - A->get_center_of_mass(),
pivotBInW - B->get_transform().origin - B->get_center_of_mass(),
normal[i],
A->get_inv_inertia(),
A->get_inv_mass(),
B->get_inv_inertia(),
B->get_inv_mass()));
}
}
Vector3 b1Axis1, b1Axis2, b1Axis3;
Vector3 b2Axis1, b2Axis2;
b1Axis1 = A->get_transform().basis.xform(this->m_rbAFrame.basis.get_axis(0));
b2Axis1 = B->get_transform().basis.xform(this->m_rbBFrame.basis.get_axis(0));
real_t swing1 = real_t(0.), swing2 = real_t(0.);
real_t swx = real_t(0.), swy = real_t(0.);
real_t thresh = real_t(10.);
real_t fact;
// Get Frame into world space
if (m_swingSpan1 >= real_t(0.05f)) {
b1Axis2 = A->get_transform().basis.xform(this->m_rbAFrame.basis.get_axis(1));
//swing1 = btAtan2Fast( b2Axis1.dot(b1Axis2),b2Axis1.dot(b1Axis1) );
swx = b2Axis1.dot(b1Axis1);
swy = b2Axis1.dot(b1Axis2);
swing1 = atan2fast(swy, swx);
fact = (swy * swy + swx * swx) * thresh * thresh;
fact = fact / (fact + real_t(1.0));
swing1 *= fact;
}
if (m_swingSpan2 >= real_t(0.05f)) {
b1Axis3 = A->get_transform().basis.xform(this->m_rbAFrame.basis.get_axis(2));
//swing2 = btAtan2Fast( b2Axis1.dot(b1Axis3),b2Axis1.dot(b1Axis1) );
swx = b2Axis1.dot(b1Axis1);
swy = b2Axis1.dot(b1Axis3);
swing2 = atan2fast(swy, swx);
fact = (swy * swy + swx * swx) * thresh * thresh;
fact = fact / (fact + real_t(1.0));
swing2 *= fact;
}
real_t RMaxAngle1Sq = 1.0f / (m_swingSpan1 * m_swingSpan1);
real_t RMaxAngle2Sq = 1.0f / (m_swingSpan2 * m_swingSpan2);
real_t EllipseAngle = Math::abs(swing1 * swing1) * RMaxAngle1Sq + Math::abs(swing2 * swing2) * RMaxAngle2Sq;
if (EllipseAngle > 1.0f) {
m_swingCorrection = EllipseAngle - 1.0f;
m_solveSwingLimit = true;
// Calculate necessary axis & factors
m_swingAxis = b2Axis1.cross(b1Axis2 * b2Axis1.dot(b1Axis2) + b1Axis3 * b2Axis1.dot(b1Axis3));
m_swingAxis.normalize();
real_t swingAxisSign = (b2Axis1.dot(b1Axis1) >= 0.0f) ? 1.0f : -1.0f;
m_swingAxis *= swingAxisSign;
m_kSwing = real_t(1.) / (A->compute_angular_impulse_denominator(m_swingAxis) + B->compute_angular_impulse_denominator(m_swingAxis));
}
// Twist limits
if (m_twistSpan >= real_t(0.)) {
Vector3 b2Axis22 = B->get_transform().basis.xform(this->m_rbBFrame.basis.get_axis(1));
Quaternion rotationArc = Quaternion(b2Axis1, b1Axis1);
Vector3 TwistRef = rotationArc.xform(b2Axis22);
real_t twist = atan2fast(TwistRef.dot(b1Axis3), TwistRef.dot(b1Axis2));
real_t lockedFreeFactor = (m_twistSpan > real_t(0.05f)) ? m_limitSoftness : real_t(0.);
if (twist <= -m_twistSpan * lockedFreeFactor) {
m_twistCorrection = -(twist + m_twistSpan);
m_solveTwistLimit = true;
m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f;
m_twistAxis.normalize();
m_twistAxis *= -1.0f;
m_kTwist = real_t(1.) / (A->compute_angular_impulse_denominator(m_twistAxis) + B->compute_angular_impulse_denominator(m_twistAxis));
} else if (twist > m_twistSpan * lockedFreeFactor) {
m_twistCorrection = (twist - m_twistSpan);
m_solveTwistLimit = true;
m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f;
m_twistAxis.normalize();
m_kTwist = real_t(1.) / (A->compute_angular_impulse_denominator(m_twistAxis) + B->compute_angular_impulse_denominator(m_twistAxis));
}
}
return true;
}
void ConeTwistJointSW::solve(real_t p_timestep) {
Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
real_t tau = real_t(0.3);
//linear part
if (!m_angularOnly) {
Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
Vector3 vel1 = A->get_velocity_in_local_point(rel_pos1);
Vector3 vel2 = B->get_velocity_in_local_point(rel_pos2);
Vector3 vel = vel1 - vel2;
for (int i = 0; i < 3; i++) {
const Vector3 &normal = m_jac[i].m_linearJointAxis;
real_t jacDiagABInv = real_t(1.) / m_jac[i].getDiagonal();
real_t rel_vel;
rel_vel = normal.dot(vel);
//positional error (zeroth order error)
real_t depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
real_t impulse = depth * tau / p_timestep * jacDiagABInv - rel_vel * jacDiagABInv;
m_appliedImpulse += impulse;
Vector3 impulse_vector = normal * impulse;
A->apply_impulse(pivotAInW - A->get_transform().origin, impulse_vector);
B->apply_impulse(pivotBInW - B->get_transform().origin, -impulse_vector);
}
}
{
///solve angular part
const Vector3 &angVelA = A->get_angular_velocity();
const Vector3 &angVelB = B->get_angular_velocity();
// solve swing limit
if (m_solveSwingLimit) {
real_t amplitude = ((angVelB - angVelA).dot(m_swingAxis) * m_relaxationFactor * m_relaxationFactor + m_swingCorrection * (real_t(1.) / p_timestep) * m_biasFactor);
real_t impulseMag = amplitude * m_kSwing;
// Clamp the accumulated impulse
real_t temp = m_accSwingLimitImpulse;
m_accSwingLimitImpulse = MAX(m_accSwingLimitImpulse + impulseMag, real_t(0.0));
impulseMag = m_accSwingLimitImpulse - temp;
Vector3 impulse = m_swingAxis * impulseMag;
A->apply_torque_impulse(impulse);
B->apply_torque_impulse(-impulse);
}
// solve twist limit
if (m_solveTwistLimit) {
real_t amplitude = ((angVelB - angVelA).dot(m_twistAxis) * m_relaxationFactor * m_relaxationFactor + m_twistCorrection * (real_t(1.) / p_timestep) * m_biasFactor);
real_t impulseMag = amplitude * m_kTwist;
// Clamp the accumulated impulse
real_t temp = m_accTwistLimitImpulse;
m_accTwistLimitImpulse = MAX(m_accTwistLimitImpulse + impulseMag, real_t(0.0));
impulseMag = m_accTwistLimitImpulse - temp;
Vector3 impulse = m_twistAxis * impulseMag;
A->apply_torque_impulse(impulse);
B->apply_torque_impulse(-impulse);
}
}
}
void ConeTwistJointSW::set_param(PhysicsServer::ConeTwistJointParam p_param, real_t p_value) {
switch (p_param) {
case PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN: {
m_swingSpan1 = p_value;
m_swingSpan2 = p_value;
} break;
case PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN: {
m_twistSpan = p_value;
} break;
case PhysicsServer::CONE_TWIST_JOINT_BIAS: {
m_biasFactor = p_value;
} break;
case PhysicsServer::CONE_TWIST_JOINT_SOFTNESS: {
m_limitSoftness = p_value;
} break;
case PhysicsServer::CONE_TWIST_JOINT_RELAXATION: {
m_relaxationFactor = p_value;
} break;
case PhysicsServer::CONE_TWIST_MAX:
break; // Can't happen, but silences warning
}
}
real_t ConeTwistJointSW::get_param(PhysicsServer::ConeTwistJointParam p_param) const {
switch (p_param) {
case PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN: {
return m_swingSpan1;
} break;
case PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN: {
return m_twistSpan;
} break;
case PhysicsServer::CONE_TWIST_JOINT_BIAS: {
return m_biasFactor;
} break;
case PhysicsServer::CONE_TWIST_JOINT_SOFTNESS: {
return m_limitSoftness;
} break;
case PhysicsServer::CONE_TWIST_JOINT_RELAXATION: {
return m_relaxationFactor;
} break;
case PhysicsServer::CONE_TWIST_MAX:
break; // Can't happen, but silences warning
}
return 0;
}

View File

@ -1,141 +0,0 @@
#ifndef CONE_TWIST_JOINT_SW_H
#define CONE_TWIST_JOINT_SW_H
/*************************************************************************/
/* cone_twist_joint_sw.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
/*
Adapted to Pandemonium from the Bullet library.
*/
/*
Bullet Continuous Collision Detection and Physics Library
ConeTwistJointSW is Copyright (c) 2007 Starbreeze Studios
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Written by: Marcus Hennix
*/
#include "servers/physics/joints/jacobian_entry_sw.h"
#include "servers/physics/joints_sw.h"
///ConeTwistJointSW can be used to simulate ragdoll joints (upper arm, leg etc)
class ConeTwistJointSW : public JointSW {
#ifdef IN_PARALLELL_SOLVER
public:
#endif
union {
struct {
BodySW *A;
BodySW *B;
};
BodySW *_arr[2];
};
JacobianEntrySW m_jac[3]; //3 orthogonal linear constraints
real_t m_appliedImpulse;
Transform m_rbAFrame;
Transform m_rbBFrame;
real_t m_limitSoftness;
real_t m_biasFactor;
real_t m_relaxationFactor;
real_t m_swingSpan1;
real_t m_swingSpan2;
real_t m_twistSpan;
Vector3 m_swingAxis;
Vector3 m_twistAxis;
real_t m_kSwing;
real_t m_kTwist;
real_t m_twistLimitSign;
real_t m_swingCorrection;
real_t m_twistCorrection;
real_t m_accSwingLimitImpulse;
real_t m_accTwistLimitImpulse;
bool m_angularOnly;
bool m_solveTwistLimit;
bool m_solveSwingLimit;
public:
virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_CONE_TWIST; }
virtual bool setup(real_t p_timestep);
virtual void solve(real_t p_timestep);
ConeTwistJointSW(BodySW *rbA, BodySW *rbB, const Transform &rbAFrame, const Transform &rbBFrame);
void setAngularOnly(bool angularOnly) {
m_angularOnly = angularOnly;
}
void setLimit(real_t _swingSpan1, real_t _swingSpan2, real_t _twistSpan, real_t _softness = 0.8f, real_t _biasFactor = 0.3f, real_t _relaxationFactor = 1.0f) {
m_swingSpan1 = _swingSpan1;
m_swingSpan2 = _swingSpan2;
m_twistSpan = _twistSpan;
m_limitSoftness = _softness;
m_biasFactor = _biasFactor;
m_relaxationFactor = _relaxationFactor;
}
inline int getSolveTwistLimit() {
return m_solveTwistLimit;
}
inline int getSolveSwingLimit() {
return m_solveTwistLimit;
}
inline real_t getTwistLimitSign() {
return m_twistLimitSign;
}
void set_param(PhysicsServer::ConeTwistJointParam p_param, real_t p_value);
real_t get_param(PhysicsServer::ConeTwistJointParam p_param) const;
};
#endif // CONE_TWIST_JOINT_SW_H

View File

@ -1,663 +0,0 @@
/*************************************************************************/
/* generic_6dof_joint_sw.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
/*
Adapted to Pandemonium from the Bullet library.
*/
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
2007-09-09
Generic6DOFJointSW Refactored by Francisco Le?n
email: projectileman@yahoo.com
http://gimpact.sf.net
*/
#include "generic_6dof_joint_sw.h"
#define GENERIC_D6_DISABLE_WARMSTARTING 1
//////////////////////////// G6DOFRotationalLimitMotorSW ////////////////////////////////////
int G6DOFRotationalLimitMotorSW::testLimitValue(real_t test_value) {
if (m_loLimit > m_hiLimit) {
m_currentLimit = 0; //Free from violation
return 0;
}
if (test_value < m_loLimit) {
m_currentLimit = 1; //low limit violation
m_currentLimitError = test_value - m_loLimit;
return 1;
} else if (test_value > m_hiLimit) {
m_currentLimit = 2; //High limit violation
m_currentLimitError = test_value - m_hiLimit;
return 2;
};
m_currentLimit = 0; //Free from violation
return 0;
}
real_t G6DOFRotationalLimitMotorSW::solveAngularLimits(
real_t timeStep, Vector3 &axis, real_t jacDiagABInv,
BodySW *body0, BodySW *body1) {
if (!needApplyTorques()) {
return 0.0f;
}
real_t target_velocity = m_targetVelocity;
real_t maxMotorForce = m_maxMotorForce;
//current error correction
if (m_currentLimit != 0) {
target_velocity = -m_ERP * m_currentLimitError / (timeStep);
maxMotorForce = m_maxLimitForce;
}
maxMotorForce *= timeStep;
// current velocity difference
Vector3 vel_diff = body0->get_angular_velocity();
if (body1) {
vel_diff -= body1->get_angular_velocity();
}
real_t rel_vel = axis.dot(vel_diff);
// correction velocity
real_t motor_relvel = m_limitSoftness * (target_velocity - m_damping * rel_vel);
if (Math::is_zero_approx(motor_relvel)) {
return 0.0f; //no need for applying force
}
// correction impulse
real_t unclippedMotorImpulse = (1 + m_bounce) * motor_relvel * jacDiagABInv;
// clip correction impulse
real_t clippedMotorImpulse;
///@todo: should clip against accumulated impulse
if (unclippedMotorImpulse > 0.0f) {
clippedMotorImpulse = unclippedMotorImpulse > maxMotorForce ? maxMotorForce : unclippedMotorImpulse;
} else {
clippedMotorImpulse = unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce : unclippedMotorImpulse;
}
// sort with accumulated impulses
real_t lo = real_t(-1e30);
real_t hi = real_t(1e30);
real_t oldaccumImpulse = m_accumulatedImpulse;
real_t sum = oldaccumImpulse + clippedMotorImpulse;
m_accumulatedImpulse = sum > hi ? real_t(0.) : (sum < lo ? real_t(0.) : sum);
clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse;
Vector3 motorImp = clippedMotorImpulse * axis;
body0->apply_torque_impulse(motorImp);
if (body1) {
body1->apply_torque_impulse(-motorImp);
}
return clippedMotorImpulse;
}
//////////////////////////// End G6DOFRotationalLimitMotorSW ////////////////////////////////////
//////////////////////////// G6DOFTranslationalLimitMotorSW ////////////////////////////////////
real_t G6DOFTranslationalLimitMotorSW::solveLinearAxis(
real_t timeStep,
real_t jacDiagABInv,
BodySW *body1, const Vector3 &pointInA,
BodySW *body2, const Vector3 &pointInB,
int limit_index,
const Vector3 &axis_normal_on_a,
const Vector3 &anchorPos) {
///find relative velocity
// Vector3 rel_pos1 = pointInA - body1->get_transform().origin;
// Vector3 rel_pos2 = pointInB - body2->get_transform().origin;
Vector3 rel_pos1 = anchorPos - body1->get_transform().origin;
Vector3 rel_pos2 = anchorPos - body2->get_transform().origin;
Vector3 vel1 = body1->get_velocity_in_local_point(rel_pos1);
Vector3 vel2 = body2->get_velocity_in_local_point(rel_pos2);
Vector3 vel = vel1 - vel2;
real_t rel_vel = axis_normal_on_a.dot(vel);
/// apply displacement correction
//positional error (zeroth order error)
real_t depth = -(pointInA - pointInB).dot(axis_normal_on_a);
real_t lo = real_t(-1e30);
real_t hi = real_t(1e30);
real_t minLimit = m_lowerLimit[limit_index];
real_t maxLimit = m_upperLimit[limit_index];
//handle the limits
if (minLimit < maxLimit) {
if (depth > maxLimit) {
depth -= maxLimit;
lo = real_t(0.);
} else {
if (depth < minLimit) {
depth -= minLimit;
hi = real_t(0.);
} else {
return 0.0f;
}
}
}
real_t normalImpulse = m_limitSoftness[limit_index] * (m_restitution[limit_index] * depth / timeStep - m_damping[limit_index] * rel_vel) * jacDiagABInv;
real_t oldNormalImpulse = m_accumulatedImpulse[limit_index];
real_t sum = oldNormalImpulse + normalImpulse;
m_accumulatedImpulse[limit_index] = sum > hi ? real_t(0.) : (sum < lo ? real_t(0.) : sum);
normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
Vector3 impulse_vector = axis_normal_on_a * normalImpulse;
body1->apply_impulse(rel_pos1, impulse_vector);
body2->apply_impulse(rel_pos2, -impulse_vector);
return normalImpulse;
}
//////////////////////////// G6DOFTranslationalLimitMotorSW ////////////////////////////////////
Generic6DOFJointSW::Generic6DOFJointSW(BodySW *rbA, BodySW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA) :
JointSW(_arr, 2),
m_frameInA(frameInA),
m_frameInB(frameInB),
m_useLinearReferenceFrameA(useLinearReferenceFrameA) {
A = rbA;
B = rbB;
A->add_constraint(this, 0);
B->add_constraint(this, 1);
}
void Generic6DOFJointSW::calculateAngleInfo() {
Basis relative_frame = m_calculatedTransformB.basis.inverse() * m_calculatedTransformA.basis;
m_calculatedAxisAngleDiff = relative_frame.get_euler_xyz();
// in euler angle mode we do not actually constrain the angular velocity
// along the axes axis[0] and axis[2] (although we do use axis[1]) :
//
// to get constrain w2-w1 along ...not
// ------ --------------------- ------
// d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
// d(angle[1])/dt = 0 ax[1]
// d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
//
// constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
// to prove the result for angle[0], write the expression for angle[0] from
// GetInfo1 then take the derivative. to prove this for angle[2] it is
// easier to take the euler rate expression for d(angle[2])/dt with respect
// to the components of w and set that to 0.
Vector3 axis0 = m_calculatedTransformB.basis.get_axis(0);
Vector3 axis2 = m_calculatedTransformA.basis.get_axis(2);
m_calculatedAxis[1] = axis2.cross(axis0);
m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
/*
if(m_debugDrawer)
{
char buff[300];
sprintf(buff,"\n X: %.2f ; Y: %.2f ; Z: %.2f ",
m_calculatedAxisAngleDiff[0],
m_calculatedAxisAngleDiff[1],
m_calculatedAxisAngleDiff[2]);
m_debugDrawer->reportErrorWarning(buff);
}
*/
}
void Generic6DOFJointSW::calculateTransforms() {
m_calculatedTransformA = A->get_transform() * m_frameInA;
m_calculatedTransformB = B->get_transform() * m_frameInB;
calculateAngleInfo();
}
void Generic6DOFJointSW::buildLinearJacobian(
JacobianEntrySW &jacLinear, const Vector3 &normalWorld,
const Vector3 &pivotAInW, const Vector3 &pivotBInW) {
memnew_placement(
&jacLinear,
JacobianEntrySW(
A->get_principal_inertia_axes().transposed(),
B->get_principal_inertia_axes().transposed(),
pivotAInW - A->get_transform().origin - A->get_center_of_mass(),
pivotBInW - B->get_transform().origin - B->get_center_of_mass(),
normalWorld,
A->get_inv_inertia(),
A->get_inv_mass(),
B->get_inv_inertia(),
B->get_inv_mass()));
}
void Generic6DOFJointSW::buildAngularJacobian(
JacobianEntrySW &jacAngular, const Vector3 &jointAxisW) {
memnew_placement(
&jacAngular,
JacobianEntrySW(
jointAxisW,
A->get_principal_inertia_axes().transposed(),
B->get_principal_inertia_axes().transposed(),
A->get_inv_inertia(),
B->get_inv_inertia()));
}
bool Generic6DOFJointSW::testAngularLimitMotor(int axis_index) {
real_t angle = m_calculatedAxisAngleDiff[axis_index];
//test limits
m_angularLimits[axis_index].testLimitValue(angle);
return m_angularLimits[axis_index].needApplyTorques();
}
bool Generic6DOFJointSW::setup(real_t p_timestep) {
if ((A->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC)) {
return false;
}
// Clear accumulated impulses for the next simulation step
m_linearLimits.m_accumulatedImpulse = Vector3(real_t(0.), real_t(0.), real_t(0.));
int i;
for (i = 0; i < 3; i++) {
m_angularLimits[i].m_accumulatedImpulse = real_t(0.);
}
//calculates transform
calculateTransforms();
// const Vector3& pivotAInW = m_calculatedTransformA.origin;
// const Vector3& pivotBInW = m_calculatedTransformB.origin;
calcAnchorPos();
Vector3 pivotAInW = m_AnchorPos;
Vector3 pivotBInW = m_AnchorPos;
// not used here
// Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
// Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
Vector3 normalWorld;
//linear part
for (i = 0; i < 3; i++) {
if (m_linearLimits.enable_limit[i] && m_linearLimits.isLimited(i)) {
if (m_useLinearReferenceFrameA) {
normalWorld = m_calculatedTransformA.basis.get_axis(i);
} else {
normalWorld = m_calculatedTransformB.basis.get_axis(i);
}
buildLinearJacobian(
m_jacLinear[i], normalWorld,
pivotAInW, pivotBInW);
}
}
// angular part
for (i = 0; i < 3; i++) {
//calculates error angle
if (m_angularLimits[i].m_enableLimit && testAngularLimitMotor(i)) {
normalWorld = this->getAxis(i);
// Create angular atom
buildAngularJacobian(m_jacAng[i], normalWorld);
}
}
return true;
}
void Generic6DOFJointSW::solve(real_t p_timestep) {
m_timeStep = p_timestep;
//calculateTransforms();
int i;
// linear
Vector3 pointInA = m_calculatedTransformA.origin;
Vector3 pointInB = m_calculatedTransformB.origin;
real_t jacDiagABInv;
Vector3 linear_axis;
for (i = 0; i < 3; i++) {
if (m_linearLimits.enable_limit[i] && m_linearLimits.isLimited(i)) {
jacDiagABInv = real_t(1.) / m_jacLinear[i].getDiagonal();
if (m_useLinearReferenceFrameA) {
linear_axis = m_calculatedTransformA.basis.get_axis(i);
} else {
linear_axis = m_calculatedTransformB.basis.get_axis(i);
}
m_linearLimits.solveLinearAxis(
m_timeStep,
jacDiagABInv,
A, pointInA,
B, pointInB,
i, linear_axis, m_AnchorPos);
}
}
// angular
Vector3 angular_axis;
real_t angularJacDiagABInv;
for (i = 0; i < 3; i++) {
if (m_angularLimits[i].m_enableLimit && m_angularLimits[i].needApplyTorques()) {
// get axis
angular_axis = getAxis(i);
angularJacDiagABInv = real_t(1.) / m_jacAng[i].getDiagonal();
m_angularLimits[i].solveAngularLimits(m_timeStep, angular_axis, angularJacDiagABInv, A, B);
}
}
}
void Generic6DOFJointSW::updateRHS(real_t timeStep) {
(void)timeStep;
}
Vector3 Generic6DOFJointSW::getAxis(int axis_index) const {
return m_calculatedAxis[axis_index];
}
real_t Generic6DOFJointSW::getAngle(int axis_index) const {
return m_calculatedAxisAngleDiff[axis_index];
}
void Generic6DOFJointSW::calcAnchorPos() {
real_t imA = A->get_inv_mass();
real_t imB = B->get_inv_mass();
real_t weight;
if (imB == real_t(0.0)) {
weight = real_t(1.0);
} else {
weight = imA / (imA + imB);
}
const Vector3 &pA = m_calculatedTransformA.origin;
const Vector3 &pB = m_calculatedTransformB.origin;
m_AnchorPos = pA * weight + pB * (real_t(1.0) - weight);
} // Generic6DOFJointSW::calcAnchorPos()
void Generic6DOFJointSW::set_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param, real_t p_value) {
ERR_FAIL_INDEX(p_axis, 3);
switch (p_param) {
case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT: {
m_linearLimits.m_lowerLimit[p_axis] = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT: {
m_linearLimits.m_upperLimit[p_axis] = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: {
m_linearLimits.m_limitSoftness[p_axis] = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION: {
m_linearLimits.m_restitution[p_axis] = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING: {
m_linearLimits.m_damping[p_axis] = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: {
m_angularLimits[p_axis].m_loLimit = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: {
m_angularLimits[p_axis].m_hiLimit = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: {
m_angularLimits[p_axis].m_limitSoftness = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING: {
m_angularLimits[p_axis].m_damping = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION: {
m_angularLimits[p_axis].m_bounce = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: {
m_angularLimits[p_axis].m_maxLimitForce = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP: {
m_angularLimits[p_axis].m_ERP = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: {
m_angularLimits[p_axis].m_targetVelocity = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: {
m_angularLimits[p_axis].m_maxLimitForce = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_MAX:
break; // Can't happen, but silences warning
}
}
real_t Generic6DOFJointSW::get_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param) const {
ERR_FAIL_INDEX_V(p_axis, 3, 0);
switch (p_param) {
case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT: {
return m_linearLimits.m_lowerLimit[p_axis];
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT: {
return m_linearLimits.m_upperLimit[p_axis];
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: {
return m_linearLimits.m_limitSoftness[p_axis];
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION: {
return m_linearLimits.m_restitution[p_axis];
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING: {
return m_linearLimits.m_damping[p_axis];
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: {
return m_angularLimits[p_axis].m_loLimit;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: {
return m_angularLimits[p_axis].m_hiLimit;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: {
return m_angularLimits[p_axis].m_limitSoftness;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING: {
return m_angularLimits[p_axis].m_damping;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION: {
return m_angularLimits[p_axis].m_bounce;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: {
return m_angularLimits[p_axis].m_maxLimitForce;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP: {
return m_angularLimits[p_axis].m_ERP;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: {
return m_angularLimits[p_axis].m_targetVelocity;
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: {
return m_angularLimits[p_axis].m_maxMotorForce;
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_MAX:
break; // Can't happen, but silences warning
}
return 0;
}
void Generic6DOFJointSW::set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value) {
ERR_FAIL_INDEX(p_axis, 3);
switch (p_flag) {
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: {
m_linearLimits.enable_limit[p_axis] = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: {
m_angularLimits[p_axis].m_enableLimit = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR: {
m_angularLimits[p_axis].m_enableMotor = p_value;
} break;
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_FLAG_MAX:
break; // Can't happen, but silences warning
}
}
bool Generic6DOFJointSW::get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const {
ERR_FAIL_INDEX_V(p_axis, 3, 0);
switch (p_flag) {
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: {
return m_linearLimits.enable_limit[p_axis];
} break;
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: {
return m_angularLimits[p_axis].m_enableLimit;
} break;
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR: {
return m_angularLimits[p_axis].m_enableMotor;
} break;
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: {
// Not implemented in PandemoniumPhysics backend
} break;
case PhysicsServer::G6DOF_JOINT_FLAG_MAX:
break; // Can't happen, but silences warning
}
return false;
}

View File

@ -1,364 +0,0 @@
#ifndef GENERIC_6DOF_JOINT_SW_H
#define GENERIC_6DOF_JOINT_SW_H
/*************************************************************************/
/* generic_6dof_joint_sw.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
/*
Adapted to Pandemonium from the Bullet library.
*/
#include "servers/physics/joints/jacobian_entry_sw.h"
#include "servers/physics/joints_sw.h"
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
2007-09-09
Generic6DOFJointSW Refactored by Francisco Le?n
email: projectileman@yahoo.com
http://gimpact.sf.net
*/
//! Rotation Limit structure for generic joints
class G6DOFRotationalLimitMotorSW {
public:
//! limit_parameters
//!@{
real_t m_loLimit; //!< joint limit
real_t m_hiLimit; //!< joint limit
real_t m_targetVelocity; //!< target motor velocity
real_t m_maxMotorForce; //!< max force on motor
real_t m_maxLimitForce; //!< max force on limit
real_t m_damping; //!< Damping.
real_t m_limitSoftness; //! Relaxation factor
real_t m_ERP; //!< Error tolerance factor when joint is at limit
real_t m_bounce; //!< restitution factor
bool m_enableMotor;
bool m_enableLimit;
//!@}
//! temp_variables
//!@{
real_t m_currentLimitError; //!< How much is violated this limit
int m_currentLimit; //!< 0=free, 1=at lo limit, 2=at hi limit
real_t m_accumulatedImpulse;
//!@}
G6DOFRotationalLimitMotorSW() {
m_accumulatedImpulse = 0.f;
m_targetVelocity = 0;
m_maxMotorForce = 0.1f;
m_maxLimitForce = 300.0f;
m_loLimit = -1e30;
m_hiLimit = 1e30;
m_ERP = 0.5f;
m_bounce = 0.0f;
m_damping = 1.0f;
m_limitSoftness = 0.5f;
m_currentLimit = 0;
m_currentLimitError = 0;
m_enableMotor = false;
m_enableLimit = false;
}
//! Is limited
bool isLimited() {
return (m_loLimit < m_hiLimit);
}
//! Need apply correction
bool needApplyTorques() {
return (m_enableMotor || m_currentLimit != 0);
}
//! calculates error
/*!
calculates m_currentLimit and m_currentLimitError.
*/
int testLimitValue(real_t test_value);
//! apply the correction impulses for two bodies
real_t solveAngularLimits(real_t timeStep, Vector3 &axis, real_t jacDiagABInv, BodySW *body0, BodySW *body1);
};
class G6DOFTranslationalLimitMotorSW {
public:
Vector3 m_lowerLimit; //!< the constraint lower limits
Vector3 m_upperLimit; //!< the constraint upper limits
Vector3 m_accumulatedImpulse;
//! Linear_Limit_parameters
//!@{
Vector3 m_limitSoftness; //!< Softness for linear limit
Vector3 m_damping; //!< Damping for linear limit
Vector3 m_restitution; //! Bounce parameter for linear limit
//!@}
bool enable_limit[3];
G6DOFTranslationalLimitMotorSW() {
m_lowerLimit = Vector3(0.f, 0.f, 0.f);
m_upperLimit = Vector3(0.f, 0.f, 0.f);
m_accumulatedImpulse = Vector3(0.f, 0.f, 0.f);
m_limitSoftness = Vector3(1, 1, 1) * 0.7f;
m_damping = Vector3(1, 1, 1) * real_t(1.0f);
m_restitution = Vector3(1, 1, 1) * real_t(0.5f);
enable_limit[0] = true;
enable_limit[1] = true;
enable_limit[2] = true;
}
//! Test limit
/*!
* - free means upper < lower,
* - locked means upper == lower
* - limited means upper > lower
* - limitIndex: first 3 are linear, next 3 are angular
*/
inline bool isLimited(int limitIndex) {
return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]);
}
real_t solveLinearAxis(
real_t timeStep,
real_t jacDiagABInv,
BodySW *body1, const Vector3 &pointInA,
BodySW *body2, const Vector3 &pointInB,
int limit_index,
const Vector3 &axis_normal_on_a,
const Vector3 &anchorPos);
};
class Generic6DOFJointSW : public JointSW {
protected:
union {
struct {
BodySW *A;
BodySW *B;
};
BodySW *_arr[2];
};
//! relative_frames
//!@{
Transform m_frameInA; //!< the constraint space w.r.t body A
Transform m_frameInB; //!< the constraint space w.r.t body B
//!@}
//! Jacobians
//!@{
JacobianEntrySW m_jacLinear[3]; //!< 3 orthogonal linear constraints
JacobianEntrySW m_jacAng[3]; //!< 3 orthogonal angular constraints
//!@}
//! Linear_Limit_parameters
//!@{
G6DOFTranslationalLimitMotorSW m_linearLimits;
//!@}
//! hinge_parameters
//!@{
G6DOFRotationalLimitMotorSW m_angularLimits[3];
//!@}
protected:
//! temporal variables
//!@{
real_t m_timeStep;
Transform m_calculatedTransformA;
Transform m_calculatedTransformB;
Vector3 m_calculatedAxisAngleDiff;
Vector3 m_calculatedAxis[3];
Vector3 m_AnchorPos; // point between pivots of bodies A and B to solve linear axes
bool m_useLinearReferenceFrameA;
//!@}
Generic6DOFJointSW(Generic6DOFJointSW const &) = delete;
void operator=(Generic6DOFJointSW const &) = delete;
void buildLinearJacobian(
JacobianEntrySW &jacLinear, const Vector3 &normalWorld,
const Vector3 &pivotAInW, const Vector3 &pivotBInW);
void buildAngularJacobian(JacobianEntrySW &jacAngular, const Vector3 &jointAxisW);
//! calcs the euler angles between the two bodies.
void calculateAngleInfo();
public:
Generic6DOFJointSW(BodySW *rbA, BodySW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA);
virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_6DOF; }
virtual bool setup(real_t p_timestep);
virtual void solve(real_t p_timestep);
// Calcs the global transform for the joint offset for body A an B, and also calcs the angle differences between the bodies.
void calculateTransforms();
// Gets the global transform of the offset for body A. */
const Transform &getCalculatedTransformA() const {
return m_calculatedTransformA;
}
// Gets the global transform of the offset for body B.
const Transform &getCalculatedTransformB() const {
return m_calculatedTransformB;
}
const Transform &getFrameOffsetA() const {
return m_frameInA;
}
const Transform &getFrameOffsetB() const {
return m_frameInB;
}
Transform &getFrameOffsetA() {
return m_frameInA;
}
Transform &getFrameOffsetB() {
return m_frameInB;
}
//! performs Jacobian calculation, and also calculates angle differences and axis
void updateRHS(real_t timeStep);
//! Get the rotation axis in global coordinates
/*!
\pre Generic6DOFJointSW.buildJacobian must be called previously.
*/
Vector3 getAxis(int axis_index) const;
//! Get the relative Euler angle
/*!
\pre Generic6DOFJointSW.buildJacobian must be called previously.
*/
real_t getAngle(int axis_index) const;
//! Test angular limit.
/*!
Calculates angular correction and returns true if limit needs to be corrected.
\pre Generic6DOFJointSW.buildJacobian must be called previously.
*/
bool testAngularLimitMotor(int axis_index);
void setLinearLowerLimit(const Vector3 &linearLower) {
m_linearLimits.m_lowerLimit = linearLower;
}
void setLinearUpperLimit(const Vector3 &linearUpper) {
m_linearLimits.m_upperLimit = linearUpper;
}
void setAngularLowerLimit(const Vector3 &angularLower) {
m_angularLimits[0].m_loLimit = angularLower.x;
m_angularLimits[1].m_loLimit = angularLower.y;
m_angularLimits[2].m_loLimit = angularLower.z;
}
void setAngularUpperLimit(const Vector3 &angularUpper) {
m_angularLimits[0].m_hiLimit = angularUpper.x;
m_angularLimits[1].m_hiLimit = angularUpper.y;
m_angularLimits[2].m_hiLimit = angularUpper.z;
}
//! Retrieves the angular limit information
G6DOFRotationalLimitMotorSW *getRotationalLimitMotor(int index) {
return &m_angularLimits[index];
}
//! Retrieves the limit information
G6DOFTranslationalLimitMotorSW *getTranslationalLimitMotor() {
return &m_linearLimits;
}
//first 3 are linear, next 3 are angular
void setLimit(int axis, real_t lo, real_t hi) {
if (axis < 3) {
m_linearLimits.m_lowerLimit[axis] = lo;
m_linearLimits.m_upperLimit[axis] = hi;
} else {
m_angularLimits[axis - 3].m_loLimit = lo;
m_angularLimits[axis - 3].m_hiLimit = hi;
}
}
//! Test limit
/*!
* - free means upper < lower,
* - locked means upper == lower
* - limited means upper > lower
* - limitIndex: first 3 are linear, next 3 are angular
*/
bool isLimited(int limitIndex) {
if (limitIndex < 3) {
return m_linearLimits.isLimited(limitIndex);
}
return m_angularLimits[limitIndex - 3].isLimited();
}
const BodySW *getRigidBodyA() const {
return A;
}
const BodySW *getRigidBodyB() const {
return B;
}
virtual void calcAnchorPos(); // overridable
void set_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param, real_t p_value);
real_t get_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param) const;
void set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value);
bool get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const;
};
#endif // GENERIC_6DOF_JOINT_SW_H

View File

@ -1,487 +0,0 @@
/*************************************************************************/
/* hinge_joint_sw.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
/*
Adapted to Pandemonium from the Bullet library.
*/
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "hinge_joint_sw.h"
void HingeJointSW::plane_space(const Vector3 &n, Vector3 &p, Vector3 &q) {
if (Math::abs(n.z) > Math_SQRT12) {
// choose p in y-z plane
real_t a = n[1] * n[1] + n[2] * n[2];
real_t k = 1.0 / Math::sqrt(a);
p = Vector3(0, -n[2] * k, n[1] * k);
// set q = n x p
q = Vector3(a * k, -n[0] * p[2], n[0] * p[1]);
} else {
// choose p in x-y plane
real_t a = n.x * n.x + n.y * n.y;
real_t k = 1.0 / Math::sqrt(a);
p = Vector3(-n.y * k, n.x * k, 0);
// set q = n x p
q = Vector3(-n.z * p.y, n.z * p.x, a * k);
}
}
HingeJointSW::HingeJointSW(BodySW *rbA, BodySW *rbB, const Transform &frameA, const Transform &frameB) :
JointSW(_arr, 2) {
A = rbA;
B = rbB;
m_rbAFrame = frameA;
m_rbBFrame = frameB;
// flip axis
m_rbBFrame.basis[0][2] *= real_t(-1.);
m_rbBFrame.basis[1][2] *= real_t(-1.);
m_rbBFrame.basis[2][2] *= real_t(-1.);
//start with free
m_lowerLimit = Math_PI;
m_upperLimit = -Math_PI;
m_useLimit = false;
m_biasFactor = 0.3f;
m_relaxationFactor = 1.0f;
m_limitSoftness = 0.9f;
m_solveLimit = false;
tau = 0.3;
m_angularOnly = false;
m_enableAngularMotor = false;
A->add_constraint(this, 0);
B->add_constraint(this, 1);
}
HingeJointSW::HingeJointSW(BodySW *rbA, BodySW *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB,
const Vector3 &axisInA, const Vector3 &axisInB) :
JointSW(_arr, 2) {
A = rbA;
B = rbB;
m_rbAFrame.origin = pivotInA;
// since no frame is given, assume this to be zero angle and just pick rb transform axis
Vector3 rbAxisA1 = rbA->get_transform().basis.get_axis(0);
Vector3 rbAxisA2;
real_t projection = axisInA.dot(rbAxisA1);
if (projection >= 1.0f - CMP_EPSILON) {
rbAxisA1 = -rbA->get_transform().basis.get_axis(2);
rbAxisA2 = rbA->get_transform().basis.get_axis(1);
} else if (projection <= -1.0f + CMP_EPSILON) {
rbAxisA1 = rbA->get_transform().basis.get_axis(2);
rbAxisA2 = rbA->get_transform().basis.get_axis(1);
} else {
rbAxisA2 = axisInA.cross(rbAxisA1);
rbAxisA1 = rbAxisA2.cross(axisInA);
}
m_rbAFrame.basis = Basis(rbAxisA1.x, rbAxisA2.x, axisInA.x,
rbAxisA1.y, rbAxisA2.y, axisInA.y,
rbAxisA1.z, rbAxisA2.z, axisInA.z);
Quaternion rotationArc = Quaternion(axisInA, axisInB);
Vector3 rbAxisB1 = rotationArc.xform(rbAxisA1);
Vector3 rbAxisB2 = axisInB.cross(rbAxisB1);
m_rbBFrame.origin = pivotInB;
m_rbBFrame.basis = Basis(rbAxisB1.x, rbAxisB2.x, -axisInB.x,
rbAxisB1.y, rbAxisB2.y, -axisInB.y,
rbAxisB1.z, rbAxisB2.z, -axisInB.z);
//start with free
m_lowerLimit = Math_PI;
m_upperLimit = -Math_PI;
m_useLimit = false;
m_biasFactor = 0.3f;
m_relaxationFactor = 1.0f;
m_limitSoftness = 0.9f;
m_solveLimit = false;
tau = 0.3;
m_angularOnly = false;
m_enableAngularMotor = false;
A->add_constraint(this, 0);
B->add_constraint(this, 1);
}
bool HingeJointSW::setup(real_t p_step) {
if ((A->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC)) {
return false;
}
m_appliedImpulse = real_t(0.);
if (!m_angularOnly) {
Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
Vector3 relPos = pivotBInW - pivotAInW;
Vector3 normal[3];
if (Math::is_zero_approx(relPos.length_squared())) {
normal[0] = Vector3(real_t(1.0), 0, 0);
} else {
normal[0] = relPos.normalized();
}
plane_space(normal[0], normal[1], normal[2]);
for (int i = 0; i < 3; i++) {
memnew_placement(
&m_jac[i],
JacobianEntrySW(
A->get_principal_inertia_axes().transposed(),
B->get_principal_inertia_axes().transposed(),
pivotAInW - A->get_transform().origin - A->get_center_of_mass(),
pivotBInW - B->get_transform().origin - B->get_center_of_mass(),
normal[i],
A->get_inv_inertia(),
A->get_inv_mass(),
B->get_inv_inertia(),
B->get_inv_mass()));
}
}
//calculate two perpendicular jointAxis, orthogonal to hingeAxis
//these two jointAxis require equal angular velocities for both bodies
//this is unused for now, it's a todo
Vector3 jointAxis0local;
Vector3 jointAxis1local;
plane_space(m_rbAFrame.basis.get_axis(2), jointAxis0local, jointAxis1local);
Vector3 jointAxis0 = A->get_transform().basis.xform(jointAxis0local);
Vector3 jointAxis1 = A->get_transform().basis.xform(jointAxis1local);
Vector3 hingeAxisWorld = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(2));
memnew_placement(
&m_jacAng[0],
JacobianEntrySW(
jointAxis0,
A->get_principal_inertia_axes().transposed(),
B->get_principal_inertia_axes().transposed(),
A->get_inv_inertia(),
B->get_inv_inertia()));
memnew_placement(
&m_jacAng[1],
JacobianEntrySW(
jointAxis1,
A->get_principal_inertia_axes().transposed(),
B->get_principal_inertia_axes().transposed(),
A->get_inv_inertia(),
B->get_inv_inertia()));
memnew_placement(
&m_jacAng[2],
JacobianEntrySW(
hingeAxisWorld,
A->get_principal_inertia_axes().transposed(),
B->get_principal_inertia_axes().transposed(),
A->get_inv_inertia(),
B->get_inv_inertia()));
// Compute limit information
real_t hingeAngle = get_hinge_angle();
//set bias, sign, clear accumulator
m_correction = real_t(0.);
m_limitSign = real_t(0.);
m_solveLimit = false;
m_accLimitImpulse = real_t(0.);
//if (m_lowerLimit < m_upperLimit)
if (m_useLimit && m_lowerLimit <= m_upperLimit) {
//if (hingeAngle <= m_lowerLimit*m_limitSoftness)
if (hingeAngle <= m_lowerLimit) {
m_correction = (m_lowerLimit - hingeAngle);
m_limitSign = 1.0f;
m_solveLimit = true;
}
//else if (hingeAngle >= m_upperLimit*m_limitSoftness)
else if (hingeAngle >= m_upperLimit) {
m_correction = m_upperLimit - hingeAngle;
m_limitSign = -1.0f;
m_solveLimit = true;
}
}
//Compute K = J*W*J' for hinge axis
Vector3 axisA = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(2));
m_kHinge = 1.0f / (A->compute_angular_impulse_denominator(axisA) + B->compute_angular_impulse_denominator(axisA));
return true;
}
void HingeJointSW::solve(real_t p_step) {
Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
//real_t tau = real_t(0.3);
//linear part
if (!m_angularOnly) {
Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
Vector3 vel1 = A->get_velocity_in_local_point(rel_pos1);
Vector3 vel2 = B->get_velocity_in_local_point(rel_pos2);
Vector3 vel = vel1 - vel2;
for (int i = 0; i < 3; i++) {
const Vector3 &normal = m_jac[i].m_linearJointAxis;
real_t jacDiagABInv = real_t(1.) / m_jac[i].getDiagonal();
real_t rel_vel;
rel_vel = normal.dot(vel);
//positional error (zeroth order error)
real_t depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
real_t impulse = depth * tau / p_step * jacDiagABInv - rel_vel * jacDiagABInv;
m_appliedImpulse += impulse;
Vector3 impulse_vector = normal * impulse;
A->apply_impulse(pivotAInW - A->get_transform().origin, impulse_vector);
B->apply_impulse(pivotBInW - B->get_transform().origin, -impulse_vector);
}
}
{
///solve angular part
// get axes in world space
Vector3 axisA = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(2));
Vector3 axisB = B->get_transform().basis.xform(m_rbBFrame.basis.get_axis(2));
const Vector3 &angVelA = A->get_angular_velocity();
const Vector3 &angVelB = B->get_angular_velocity();
Vector3 angVelAroundHingeAxisA = axisA * axisA.dot(angVelA);
Vector3 angVelAroundHingeAxisB = axisB * axisB.dot(angVelB);
Vector3 angAorthog = angVelA - angVelAroundHingeAxisA;
Vector3 angBorthog = angVelB - angVelAroundHingeAxisB;
Vector3 velrelOrthog = angAorthog - angBorthog;
{
//solve orthogonal angular velocity correction
real_t relaxation = real_t(1.);
real_t len = velrelOrthog.length();
if (len > real_t(0.00001)) {
Vector3 normal = velrelOrthog.normalized();
real_t denom = A->compute_angular_impulse_denominator(normal) +
B->compute_angular_impulse_denominator(normal);
// scale for mass and relaxation
velrelOrthog *= (real_t(1.) / denom) * m_relaxationFactor;
}
//solve angular positional correction
Vector3 angularError = -axisA.cross(axisB) * (real_t(1.) / p_step);
real_t len2 = angularError.length();
if (len2 > real_t(0.00001)) {
Vector3 normal2 = angularError.normalized();
real_t denom2 = A->compute_angular_impulse_denominator(normal2) +
B->compute_angular_impulse_denominator(normal2);
angularError *= (real_t(1.) / denom2) * relaxation;
}
A->apply_torque_impulse(-velrelOrthog + angularError);
B->apply_torque_impulse(velrelOrthog - angularError);
// solve limit
if (m_solveLimit) {
real_t amplitude = ((angVelB - angVelA).dot(axisA) * m_relaxationFactor + m_correction * (real_t(1.) / p_step) * m_biasFactor) * m_limitSign;
real_t impulseMag = amplitude * m_kHinge;
// Clamp the accumulated impulse
real_t temp = m_accLimitImpulse;
m_accLimitImpulse = MAX(m_accLimitImpulse + impulseMag, real_t(0));
impulseMag = m_accLimitImpulse - temp;
Vector3 impulse = axisA * impulseMag * m_limitSign;
A->apply_torque_impulse(impulse);
B->apply_torque_impulse(-impulse);
}
}
//apply motor
if (m_enableAngularMotor) {
//todo: add limits too
Vector3 angularLimit(0, 0, 0);
Vector3 velrel = angVelAroundHingeAxisA - angVelAroundHingeAxisB;
real_t projRelVel = velrel.dot(axisA);
real_t desiredMotorVel = m_motorTargetVelocity;
real_t motor_relvel = desiredMotorVel - projRelVel;
real_t unclippedMotorImpulse = m_kHinge * motor_relvel;
//todo: should clip against accumulated impulse
real_t clippedMotorImpulse = unclippedMotorImpulse > m_maxMotorImpulse ? m_maxMotorImpulse : unclippedMotorImpulse;
clippedMotorImpulse = clippedMotorImpulse < -m_maxMotorImpulse ? -m_maxMotorImpulse : clippedMotorImpulse;
Vector3 motorImp = clippedMotorImpulse * axisA;
A->apply_torque_impulse(motorImp + angularLimit);
B->apply_torque_impulse(-motorImp - angularLimit);
}
}
}
/*
void HingeJointSW::updateRHS(real_t timeStep)
{
(void)timeStep;
}
*/
real_t HingeJointSW::atan2fast(real_t y, real_t x) {
real_t coeff_1 = Math_PI / 4.0f;
real_t coeff_2 = 3.0f * coeff_1;
real_t abs_y = Math::abs(y);
real_t angle;
if (x >= 0.0f) {
real_t r = (x - abs_y) / (x + abs_y);
angle = coeff_1 - coeff_1 * r;
} else {
real_t r = (x + abs_y) / (abs_y - x);
angle = coeff_2 - coeff_1 * r;
}
return (y < 0.0f) ? -angle : angle;
}
real_t HingeJointSW::get_hinge_angle() {
const Vector3 refAxis0 = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(0));
const Vector3 refAxis1 = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(1));
const Vector3 swingAxis = B->get_transform().basis.xform(m_rbBFrame.basis.get_axis(1));
return atan2fast(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1));
}
void HingeJointSW::set_param(PhysicsServer::HingeJointParam p_param, real_t p_value) {
switch (p_param) {
case PhysicsServer::HINGE_JOINT_BIAS:
tau = p_value;
break;
case PhysicsServer::HINGE_JOINT_LIMIT_UPPER:
m_upperLimit = p_value;
break;
case PhysicsServer::HINGE_JOINT_LIMIT_LOWER:
m_lowerLimit = p_value;
break;
case PhysicsServer::HINGE_JOINT_LIMIT_BIAS:
m_biasFactor = p_value;
break;
case PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS:
m_limitSoftness = p_value;
break;
case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION:
m_relaxationFactor = p_value;
break;
case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY:
m_motorTargetVelocity = p_value;
break;
case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE:
m_maxMotorImpulse = p_value;
break;
case PhysicsServer::HINGE_JOINT_MAX:
break; // Can't happen, but silences warning
}
}
real_t HingeJointSW::get_param(PhysicsServer::HingeJointParam p_param) const {
switch (p_param) {
case PhysicsServer::HINGE_JOINT_BIAS:
return tau;
case PhysicsServer::HINGE_JOINT_LIMIT_UPPER:
return m_upperLimit;
case PhysicsServer::HINGE_JOINT_LIMIT_LOWER:
return m_lowerLimit;
case PhysicsServer::HINGE_JOINT_LIMIT_BIAS:
return m_biasFactor;
case PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS:
return m_limitSoftness;
case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION:
return m_relaxationFactor;
case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY:
return m_motorTargetVelocity;
case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE:
return m_maxMotorImpulse;
case PhysicsServer::HINGE_JOINT_MAX:
break; // Can't happen, but silences warning
}
return 0;
}
void HingeJointSW::set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_value) {
switch (p_flag) {
case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT:
m_useLimit = p_value;
break;
case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR:
m_enableAngularMotor = p_value;
break;
case PhysicsServer::HINGE_JOINT_FLAG_MAX:
break; // Can't happen, but silences warning
}
}
bool HingeJointSW::get_flag(PhysicsServer::HingeJointFlag p_flag) const {
switch (p_flag) {
case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT:
return m_useLimit;
case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR:
return m_enableAngularMotor;
case PhysicsServer::HINGE_JOINT_FLAG_MAX:
break; // Can't happen, but silences warning
}
return false;
}

View File

@ -1,118 +0,0 @@
#ifndef HINGE_JOINT_SW_H
#define HINGE_JOINT_SW_H
/*************************************************************************/
/* hinge_joint_sw.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
/*
Adapted to Pandemonium from the Bullet library.
*/
#include "servers/physics/joints/jacobian_entry_sw.h"
#include "servers/physics/joints_sw.h"
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
class HingeJointSW : public JointSW {
union {
struct {
BodySW *A;
BodySW *B;
};
BodySW *_arr[2];
};
JacobianEntrySW m_jac[3]; //3 orthogonal linear constraints
JacobianEntrySW m_jacAng[3]; //2 orthogonal angular constraints+ 1 for limit/motor
Transform m_rbAFrame; // constraint axii. Assumes z is hinge axis.
Transform m_rbBFrame;
real_t m_motorTargetVelocity;
real_t m_maxMotorImpulse;
real_t m_limitSoftness;
real_t m_biasFactor;
real_t m_relaxationFactor;
real_t m_lowerLimit;
real_t m_upperLimit;
real_t m_kHinge;
real_t m_limitSign;
real_t m_correction;
real_t m_accLimitImpulse;
real_t tau;
bool m_useLimit;
bool m_angularOnly;
bool m_enableAngularMotor;
bool m_solveLimit;
real_t m_appliedImpulse;
void plane_space(const Vector3 &n, Vector3 &p, Vector3 &q);
_FORCE_INLINE_ real_t atan2fast(real_t y, real_t x);
public:
virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_HINGE; }
virtual bool setup(real_t p_step);
virtual void solve(real_t p_step);
real_t get_hinge_angle();
void set_param(PhysicsServer::HingeJointParam p_param, real_t p_value);
real_t get_param(PhysicsServer::HingeJointParam p_param) const;
void set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_value);
bool get_flag(PhysicsServer::HingeJointFlag p_flag) const;
HingeJointSW(BodySW *rbA, BodySW *rbB, const Transform &frameA, const Transform &frameB);
HingeJointSW(BodySW *rbA, BodySW *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB);
};
#endif // HINGE_JOINT_SW_H

Some files were not shown because too many files have changed in this diff Show More