| 1 | /**************************************************************************/ |
| 2 | /* joint_3d_gizmo_plugin.cpp */ |
| 3 | /**************************************************************************/ |
| 4 | /* This file is part of: */ |
| 5 | /* GODOT ENGINE */ |
| 6 | /* https://godotengine.org */ |
| 7 | /**************************************************************************/ |
| 8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
| 9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
| 10 | /* */ |
| 11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
| 12 | /* a copy of this software and associated documentation files (the */ |
| 13 | /* "Software"), to deal in the Software without restriction, including */ |
| 14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
| 15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
| 16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
| 17 | /* the following conditions: */ |
| 18 | /* */ |
| 19 | /* The above copyright notice and this permission notice shall be */ |
| 20 | /* included in all copies or substantial portions of the Software. */ |
| 21 | /* */ |
| 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
| 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
| 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
| 25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
| 26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
| 27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
| 28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
| 29 | /**************************************************************************/ |
| 30 | |
| 31 | #include "joint_3d_gizmo_plugin.h" |
| 32 | |
| 33 | #include "editor/editor_node.h" |
| 34 | #include "editor/editor_settings.h" |
| 35 | #include "editor/plugins/node_3d_editor_plugin.h" |
| 36 | #include "scene/3d/joint_3d.h" |
| 37 | |
| 38 | #define BODY_A_RADIUS 0.25 |
| 39 | #define BODY_B_RADIUS 0.27 |
| 40 | |
| 41 | Basis JointGizmosDrawer::look_body(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { |
| 42 | const Vector3 &p_eye(p_joint_transform.origin); |
| 43 | const Vector3 &p_target(p_body_transform.origin); |
| 44 | |
| 45 | Vector3 v_x, v_y, v_z; |
| 46 | |
| 47 | // Look the body with X |
| 48 | v_x = p_target - p_eye; |
| 49 | v_x.normalize(); |
| 50 | |
| 51 | v_z = v_x.cross(Vector3(0, 1, 0)); |
| 52 | v_z.normalize(); |
| 53 | |
| 54 | v_y = v_z.cross(v_x); |
| 55 | v_y.normalize(); |
| 56 | |
| 57 | Basis base; |
| 58 | base.set_columns(v_x, v_y, v_z); |
| 59 | |
| 60 | // Absorb current joint transform |
| 61 | base = p_joint_transform.basis.inverse() * base; |
| 62 | |
| 63 | return base; |
| 64 | } |
| 65 | |
| 66 | Basis JointGizmosDrawer::look_body_toward(Vector3::Axis p_axis, const Transform3D &joint_transform, const Transform3D &body_transform) { |
| 67 | switch (p_axis) { |
| 68 | case Vector3::AXIS_X: |
| 69 | return look_body_toward_x(joint_transform, body_transform); |
| 70 | case Vector3::AXIS_Y: |
| 71 | return look_body_toward_y(joint_transform, body_transform); |
| 72 | case Vector3::AXIS_Z: |
| 73 | return look_body_toward_z(joint_transform, body_transform); |
| 74 | default: |
| 75 | return Basis(); |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | Basis JointGizmosDrawer::look_body_toward_x(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { |
| 80 | const Vector3 &p_eye(p_joint_transform.origin); |
| 81 | const Vector3 &p_target(p_body_transform.origin); |
| 82 | |
| 83 | const Vector3 p_front(p_joint_transform.basis.get_column(0)); |
| 84 | |
| 85 | Vector3 v_x, v_y, v_z; |
| 86 | |
| 87 | // Look the body with X |
| 88 | v_x = p_target - p_eye; |
| 89 | v_x.normalize(); |
| 90 | |
| 91 | v_y = p_front.cross(v_x); |
| 92 | v_y.normalize(); |
| 93 | |
| 94 | v_z = v_y.cross(p_front); |
| 95 | v_z.normalize(); |
| 96 | |
| 97 | // Clamp X to FRONT axis |
| 98 | v_x = p_front; |
| 99 | v_x.normalize(); |
| 100 | |
| 101 | Basis base; |
| 102 | base.set_columns(v_x, v_y, v_z); |
| 103 | |
| 104 | // Absorb current joint transform |
| 105 | base = p_joint_transform.basis.inverse() * base; |
| 106 | |
| 107 | return base; |
| 108 | } |
| 109 | |
| 110 | Basis JointGizmosDrawer::look_body_toward_y(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { |
| 111 | const Vector3 &p_eye(p_joint_transform.origin); |
| 112 | const Vector3 &p_target(p_body_transform.origin); |
| 113 | |
| 114 | const Vector3 p_up(p_joint_transform.basis.get_column(1)); |
| 115 | |
| 116 | Vector3 v_x, v_y, v_z; |
| 117 | |
| 118 | // Look the body with X |
| 119 | v_x = p_target - p_eye; |
| 120 | v_x.normalize(); |
| 121 | |
| 122 | v_z = v_x.cross(p_up); |
| 123 | v_z.normalize(); |
| 124 | |
| 125 | v_x = p_up.cross(v_z); |
| 126 | v_x.normalize(); |
| 127 | |
| 128 | // Clamp Y to UP axis |
| 129 | v_y = p_up; |
| 130 | v_y.normalize(); |
| 131 | |
| 132 | Basis base; |
| 133 | base.set_columns(v_x, v_y, v_z); |
| 134 | |
| 135 | // Absorb current joint transform |
| 136 | base = p_joint_transform.basis.inverse() * base; |
| 137 | |
| 138 | return base; |
| 139 | } |
| 140 | |
| 141 | Basis JointGizmosDrawer::look_body_toward_z(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { |
| 142 | const Vector3 &p_eye(p_joint_transform.origin); |
| 143 | const Vector3 &p_target(p_body_transform.origin); |
| 144 | |
| 145 | const Vector3 p_lateral(p_joint_transform.basis.get_column(2)); |
| 146 | |
| 147 | Vector3 v_x, v_y, v_z; |
| 148 | |
| 149 | // Look the body with X |
| 150 | v_x = p_target - p_eye; |
| 151 | v_x.normalize(); |
| 152 | |
| 153 | v_z = p_lateral; |
| 154 | v_z.normalize(); |
| 155 | |
| 156 | v_y = v_z.cross(v_x); |
| 157 | v_y.normalize(); |
| 158 | |
| 159 | // Clamp X to Z axis |
| 160 | v_x = v_y.cross(v_z); |
| 161 | v_x.normalize(); |
| 162 | |
| 163 | Basis base; |
| 164 | base.set_columns(v_x, v_y, v_z); |
| 165 | |
| 166 | // Absorb current joint transform |
| 167 | base = p_joint_transform.basis.inverse() * base; |
| 168 | |
| 169 | return base; |
| 170 | } |
| 171 | |
| 172 | void JointGizmosDrawer::draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform3D &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector<Vector3> &r_points, bool p_inverse) { |
| 173 | if (p_limit_lower == p_limit_upper) { |
| 174 | r_points.push_back(p_offset.translated_local(Vector3()).origin); |
| 175 | r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(0.5, 0, 0))).origin); |
| 176 | |
| 177 | } else { |
| 178 | if (p_limit_lower > p_limit_upper) { |
| 179 | p_limit_lower = -Math_PI; |
| 180 | p_limit_upper = Math_PI; |
| 181 | } |
| 182 | |
| 183 | const int points = 32; |
| 184 | |
| 185 | for (int i = 0; i < points; i++) { |
| 186 | real_t s = p_limit_lower + i * (p_limit_upper - p_limit_lower) / points; |
| 187 | real_t n = p_limit_lower + (i + 1) * (p_limit_upper - p_limit_lower) / points; |
| 188 | |
| 189 | Vector3 from; |
| 190 | Vector3 to; |
| 191 | switch (p_axis) { |
| 192 | case Vector3::AXIS_X: |
| 193 | if (p_inverse) { |
| 194 | from = p_base.xform(Vector3(0, Math::sin(s), Math::cos(s))) * p_radius; |
| 195 | to = p_base.xform(Vector3(0, Math::sin(n), Math::cos(n))) * p_radius; |
| 196 | } else { |
| 197 | from = p_base.xform(Vector3(0, -Math::sin(s), Math::cos(s))) * p_radius; |
| 198 | to = p_base.xform(Vector3(0, -Math::sin(n), Math::cos(n))) * p_radius; |
| 199 | } |
| 200 | break; |
| 201 | case Vector3::AXIS_Y: |
| 202 | if (p_inverse) { |
| 203 | from = p_base.xform(Vector3(Math::cos(s), 0, -Math::sin(s))) * p_radius; |
| 204 | to = p_base.xform(Vector3(Math::cos(n), 0, -Math::sin(n))) * p_radius; |
| 205 | } else { |
| 206 | from = p_base.xform(Vector3(Math::cos(s), 0, Math::sin(s))) * p_radius; |
| 207 | to = p_base.xform(Vector3(Math::cos(n), 0, Math::sin(n))) * p_radius; |
| 208 | } |
| 209 | break; |
| 210 | case Vector3::AXIS_Z: |
| 211 | from = p_base.xform(Vector3(Math::cos(s), Math::sin(s), 0)) * p_radius; |
| 212 | to = p_base.xform(Vector3(Math::cos(n), Math::sin(n), 0)) * p_radius; |
| 213 | break; |
| 214 | } |
| 215 | |
| 216 | if (i == points - 1) { |
| 217 | r_points.push_back(p_offset.translated_local(to).origin); |
| 218 | r_points.push_back(p_offset.translated_local(Vector3()).origin); |
| 219 | } |
| 220 | if (i == 0) { |
| 221 | r_points.push_back(p_offset.translated_local(from).origin); |
| 222 | r_points.push_back(p_offset.translated_local(Vector3()).origin); |
| 223 | } |
| 224 | |
| 225 | r_points.push_back(p_offset.translated_local(from).origin); |
| 226 | r_points.push_back(p_offset.translated_local(to).origin); |
| 227 | } |
| 228 | |
| 229 | r_points.push_back(p_offset.translated_local(Vector3(0, p_radius * 1.5, 0)).origin); |
| 230 | r_points.push_back(p_offset.translated_local(Vector3()).origin); |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | void JointGizmosDrawer::draw_cone(const Transform3D &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points) { |
| 235 | float r = 1.0; |
| 236 | float w = r * Math::sin(p_swing); |
| 237 | float d = r * Math::cos(p_swing); |
| 238 | |
| 239 | //swing |
| 240 | for (int i = 0; i < 360; i += 10) { |
| 241 | float ra = Math::deg_to_rad((float)i); |
| 242 | float rb = Math::deg_to_rad((float)i + 10); |
| 243 | Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w; |
| 244 | Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w; |
| 245 | |
| 246 | r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(d, a.x, a.y))).origin); |
| 247 | r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(d, b.x, b.y))).origin); |
| 248 | |
| 249 | if (i % 90 == 0) { |
| 250 | r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(d, a.x, a.y))).origin); |
| 251 | r_points.push_back(p_offset.translated_local(p_base.xform(Vector3())).origin); |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | r_points.push_back(p_offset.translated_local(p_base.xform(Vector3())).origin); |
| 256 | r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(1, 0, 0))).origin); |
| 257 | |
| 258 | /// Twist |
| 259 | float ts = Math::rad_to_deg(p_twist); |
| 260 | ts = MIN(ts, 720); |
| 261 | |
| 262 | for (int i = 0; i < int(ts); i += 5) { |
| 263 | float ra = Math::deg_to_rad((float)i); |
| 264 | float rb = Math::deg_to_rad((float)i + 5); |
| 265 | float c = i / 720.0; |
| 266 | float cn = (i + 5) / 720.0; |
| 267 | Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w * c; |
| 268 | Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w * cn; |
| 269 | |
| 270 | r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(c, a.x, a.y))).origin); |
| 271 | r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(cn, b.x, b.y))).origin); |
| 272 | } |
| 273 | } |
| 274 | |
| 275 | //// |
| 276 | |
| 277 | Joint3DGizmoPlugin::Joint3DGizmoPlugin() { |
| 278 | create_material("joint_material" , EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint" )); |
| 279 | create_material("joint_body_a_material" , EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a" , Color(0.6, 0.8, 1))); |
| 280 | create_material("joint_body_b_material" , EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b" , Color(0.6, 0.9, 1))); |
| 281 | |
| 282 | update_timer = memnew(Timer); |
| 283 | update_timer->set_name("JointGizmoUpdateTimer" ); |
| 284 | update_timer->set_wait_time(1.0 / 120.0); |
| 285 | update_timer->connect("timeout" , callable_mp(this, &Joint3DGizmoPlugin::incremental_update_gizmos)); |
| 286 | update_timer->set_autostart(true); |
| 287 | EditorNode::get_singleton()->call_deferred(SNAME("add_child" ), update_timer); |
| 288 | } |
| 289 | |
| 290 | void Joint3DGizmoPlugin::incremental_update_gizmos() { |
| 291 | if (!current_gizmos.is_empty()) { |
| 292 | update_idx++; |
| 293 | update_idx = update_idx % current_gizmos.size(); |
| 294 | redraw(current_gizmos[update_idx]); |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | bool Joint3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { |
| 299 | return Object::cast_to<Joint3D>(p_spatial) != nullptr; |
| 300 | } |
| 301 | |
| 302 | String Joint3DGizmoPlugin::get_gizmo_name() const { |
| 303 | return "Joint3D" ; |
| 304 | } |
| 305 | |
| 306 | int Joint3DGizmoPlugin::get_priority() const { |
| 307 | return -1; |
| 308 | } |
| 309 | |
| 310 | void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { |
| 311 | Joint3D *joint = Object::cast_to<Joint3D>(p_gizmo->get_node_3d()); |
| 312 | |
| 313 | p_gizmo->clear(); |
| 314 | |
| 315 | Node3D *node_body_a = nullptr; |
| 316 | if (!joint->get_node_a().is_empty()) { |
| 317 | node_body_a = Object::cast_to<Node3D>(joint->get_node(joint->get_node_a())); |
| 318 | } |
| 319 | |
| 320 | Node3D *node_body_b = nullptr; |
| 321 | if (!joint->get_node_b().is_empty()) { |
| 322 | node_body_b = Object::cast_to<Node3D>(joint->get_node(joint->get_node_b())); |
| 323 | } |
| 324 | |
| 325 | if (!node_body_a && !node_body_b) { |
| 326 | return; |
| 327 | } |
| 328 | |
| 329 | Ref<Material> common_material = get_material("joint_material" , p_gizmo); |
| 330 | Ref<Material> body_a_material = get_material("joint_body_a_material" , p_gizmo); |
| 331 | Ref<Material> body_b_material = get_material("joint_body_b_material" , p_gizmo); |
| 332 | |
| 333 | Vector<Vector3> points; |
| 334 | Vector<Vector3> body_a_points; |
| 335 | Vector<Vector3> body_b_points; |
| 336 | |
| 337 | if (Object::cast_to<PinJoint3D>(joint)) { |
| 338 | CreatePinJointGizmo(Transform3D(), points); |
| 339 | p_gizmo->add_collision_segments(points); |
| 340 | p_gizmo->add_lines(points, common_material); |
| 341 | } |
| 342 | |
| 343 | HingeJoint3D *hinge = Object::cast_to<HingeJoint3D>(joint); |
| 344 | if (hinge) { |
| 345 | CreateHingeJointGizmo( |
| 346 | Transform3D(), |
| 347 | hinge->get_global_transform(), |
| 348 | node_body_a ? node_body_a->get_global_transform() : Transform3D(), |
| 349 | node_body_b ? node_body_b->get_global_transform() : Transform3D(), |
| 350 | hinge->get_param(HingeJoint3D::PARAM_LIMIT_LOWER), |
| 351 | hinge->get_param(HingeJoint3D::PARAM_LIMIT_UPPER), |
| 352 | hinge->get_flag(HingeJoint3D::FLAG_USE_LIMIT), |
| 353 | points, |
| 354 | node_body_a ? &body_a_points : nullptr, |
| 355 | node_body_b ? &body_b_points : nullptr); |
| 356 | |
| 357 | p_gizmo->add_collision_segments(points); |
| 358 | p_gizmo->add_collision_segments(body_a_points); |
| 359 | p_gizmo->add_collision_segments(body_b_points); |
| 360 | |
| 361 | p_gizmo->add_lines(points, common_material); |
| 362 | p_gizmo->add_lines(body_a_points, body_a_material); |
| 363 | p_gizmo->add_lines(body_b_points, body_b_material); |
| 364 | } |
| 365 | |
| 366 | SliderJoint3D *slider = Object::cast_to<SliderJoint3D>(joint); |
| 367 | if (slider) { |
| 368 | CreateSliderJointGizmo( |
| 369 | Transform3D(), |
| 370 | slider->get_global_transform(), |
| 371 | node_body_a ? node_body_a->get_global_transform() : Transform3D(), |
| 372 | node_body_b ? node_body_b->get_global_transform() : Transform3D(), |
| 373 | slider->get_param(SliderJoint3D::PARAM_ANGULAR_LIMIT_LOWER), |
| 374 | slider->get_param(SliderJoint3D::PARAM_ANGULAR_LIMIT_UPPER), |
| 375 | slider->get_param(SliderJoint3D::PARAM_LINEAR_LIMIT_LOWER), |
| 376 | slider->get_param(SliderJoint3D::PARAM_LINEAR_LIMIT_UPPER), |
| 377 | points, |
| 378 | node_body_a ? &body_a_points : nullptr, |
| 379 | node_body_b ? &body_b_points : nullptr); |
| 380 | |
| 381 | p_gizmo->add_collision_segments(points); |
| 382 | p_gizmo->add_collision_segments(body_a_points); |
| 383 | p_gizmo->add_collision_segments(body_b_points); |
| 384 | |
| 385 | p_gizmo->add_lines(points, common_material); |
| 386 | p_gizmo->add_lines(body_a_points, body_a_material); |
| 387 | p_gizmo->add_lines(body_b_points, body_b_material); |
| 388 | } |
| 389 | |
| 390 | ConeTwistJoint3D *cone = Object::cast_to<ConeTwistJoint3D>(joint); |
| 391 | if (cone) { |
| 392 | CreateConeTwistJointGizmo( |
| 393 | Transform3D(), |
| 394 | cone->get_global_transform(), |
| 395 | node_body_a ? node_body_a->get_global_transform() : Transform3D(), |
| 396 | node_body_b ? node_body_b->get_global_transform() : Transform3D(), |
| 397 | cone->get_param(ConeTwistJoint3D::PARAM_SWING_SPAN), |
| 398 | cone->get_param(ConeTwistJoint3D::PARAM_TWIST_SPAN), |
| 399 | node_body_a ? &body_a_points : nullptr, |
| 400 | node_body_b ? &body_b_points : nullptr); |
| 401 | |
| 402 | p_gizmo->add_collision_segments(body_a_points); |
| 403 | p_gizmo->add_collision_segments(body_b_points); |
| 404 | |
| 405 | p_gizmo->add_lines(body_a_points, body_a_material); |
| 406 | p_gizmo->add_lines(body_b_points, body_b_material); |
| 407 | } |
| 408 | |
| 409 | Generic6DOFJoint3D *gen = Object::cast_to<Generic6DOFJoint3D>(joint); |
| 410 | if (gen) { |
| 411 | CreateGeneric6DOFJointGizmo( |
| 412 | Transform3D(), |
| 413 | gen->get_global_transform(), |
| 414 | node_body_a ? node_body_a->get_global_transform() : Transform3D(), |
| 415 | node_body_b ? node_body_b->get_global_transform() : Transform3D(), |
| 416 | |
| 417 | gen->get_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT), |
| 418 | gen->get_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT), |
| 419 | gen->get_param_x(Generic6DOFJoint3D::PARAM_LINEAR_LOWER_LIMIT), |
| 420 | gen->get_param_x(Generic6DOFJoint3D::PARAM_LINEAR_UPPER_LIMIT), |
| 421 | gen->get_flag_x(Generic6DOFJoint3D::FLAG_ENABLE_ANGULAR_LIMIT), |
| 422 | gen->get_flag_x(Generic6DOFJoint3D::FLAG_ENABLE_LINEAR_LIMIT), |
| 423 | |
| 424 | gen->get_param_y(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT), |
| 425 | gen->get_param_y(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT), |
| 426 | gen->get_param_y(Generic6DOFJoint3D::PARAM_LINEAR_LOWER_LIMIT), |
| 427 | gen->get_param_y(Generic6DOFJoint3D::PARAM_LINEAR_UPPER_LIMIT), |
| 428 | gen->get_flag_y(Generic6DOFJoint3D::FLAG_ENABLE_ANGULAR_LIMIT), |
| 429 | gen->get_flag_y(Generic6DOFJoint3D::FLAG_ENABLE_LINEAR_LIMIT), |
| 430 | |
| 431 | gen->get_param_z(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT), |
| 432 | gen->get_param_z(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT), |
| 433 | gen->get_param_z(Generic6DOFJoint3D::PARAM_LINEAR_LOWER_LIMIT), |
| 434 | gen->get_param_z(Generic6DOFJoint3D::PARAM_LINEAR_UPPER_LIMIT), |
| 435 | gen->get_flag_z(Generic6DOFJoint3D::FLAG_ENABLE_ANGULAR_LIMIT), |
| 436 | gen->get_flag_z(Generic6DOFJoint3D::FLAG_ENABLE_LINEAR_LIMIT), |
| 437 | |
| 438 | points, |
| 439 | node_body_a ? &body_a_points : nullptr, |
| 440 | node_body_a ? &body_b_points : nullptr); |
| 441 | |
| 442 | p_gizmo->add_collision_segments(points); |
| 443 | p_gizmo->add_collision_segments(body_a_points); |
| 444 | p_gizmo->add_collision_segments(body_b_points); |
| 445 | |
| 446 | p_gizmo->add_lines(points, common_material); |
| 447 | p_gizmo->add_lines(body_a_points, body_a_material); |
| 448 | p_gizmo->add_lines(body_b_points, body_b_material); |
| 449 | } |
| 450 | } |
| 451 | |
| 452 | void Joint3DGizmoPlugin::CreatePinJointGizmo(const Transform3D &p_offset, Vector<Vector3> &r_cursor_points) { |
| 453 | float cs = 0.25; |
| 454 | |
| 455 | r_cursor_points.push_back(p_offset.translated_local(Vector3(+cs, 0, 0)).origin); |
| 456 | r_cursor_points.push_back(p_offset.translated_local(Vector3(-cs, 0, 0)).origin); |
| 457 | r_cursor_points.push_back(p_offset.translated_local(Vector3(0, +cs, 0)).origin); |
| 458 | r_cursor_points.push_back(p_offset.translated_local(Vector3(0, -cs, 0)).origin); |
| 459 | r_cursor_points.push_back(p_offset.translated_local(Vector3(0, 0, +cs)).origin); |
| 460 | r_cursor_points.push_back(p_offset.translated_local(Vector3(0, 0, -cs)).origin); |
| 461 | } |
| 462 | |
| 463 | void Joint3DGizmoPlugin::CreateHingeJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { |
| 464 | r_common_points.push_back(p_offset.translated_local(Vector3(0, 0, 0.5)).origin); |
| 465 | r_common_points.push_back(p_offset.translated_local(Vector3(0, 0, -0.5)).origin); |
| 466 | |
| 467 | if (!p_use_limit) { |
| 468 | p_limit_upper = -1; |
| 469 | p_limit_lower = 0; |
| 470 | } |
| 471 | |
| 472 | if (r_body_a_points) { |
| 473 | JointGizmosDrawer::draw_circle(Vector3::AXIS_Z, |
| 474 | BODY_A_RADIUS, |
| 475 | p_offset, |
| 476 | JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_a), |
| 477 | p_limit_lower, |
| 478 | p_limit_upper, |
| 479 | *r_body_a_points); |
| 480 | } |
| 481 | |
| 482 | if (r_body_b_points) { |
| 483 | JointGizmosDrawer::draw_circle(Vector3::AXIS_Z, |
| 484 | BODY_B_RADIUS, |
| 485 | p_offset, |
| 486 | JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_b), |
| 487 | p_limit_lower, |
| 488 | p_limit_upper, |
| 489 | *r_body_b_points); |
| 490 | } |
| 491 | } |
| 492 | |
| 493 | void Joint3DGizmoPlugin::CreateSliderJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { |
| 494 | p_linear_limit_lower = -p_linear_limit_lower; |
| 495 | p_linear_limit_upper = -p_linear_limit_upper; |
| 496 | |
| 497 | float cs = 0.25; |
| 498 | r_points.push_back(p_offset.translated_local(Vector3(0, 0, 0.5)).origin); |
| 499 | r_points.push_back(p_offset.translated_local(Vector3(0, 0, -0.5)).origin); |
| 500 | |
| 501 | if (p_linear_limit_lower >= p_linear_limit_upper) { |
| 502 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, 0, 0)).origin); |
| 503 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, 0, 0)).origin); |
| 504 | |
| 505 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, -cs, -cs)).origin); |
| 506 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, -cs, cs)).origin); |
| 507 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, -cs, cs)).origin); |
| 508 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, cs, cs)).origin); |
| 509 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, cs, cs)).origin); |
| 510 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, cs, -cs)).origin); |
| 511 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, cs, -cs)).origin); |
| 512 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_upper, -cs, -cs)).origin); |
| 513 | |
| 514 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, -cs, -cs)).origin); |
| 515 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, -cs, cs)).origin); |
| 516 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, -cs, cs)).origin); |
| 517 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, cs, cs)).origin); |
| 518 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, cs, cs)).origin); |
| 519 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, cs, -cs)).origin); |
| 520 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, cs, -cs)).origin); |
| 521 | r_points.push_back(p_offset.translated_local(Vector3(p_linear_limit_lower, -cs, -cs)).origin); |
| 522 | |
| 523 | } else { |
| 524 | r_points.push_back(p_offset.translated_local(Vector3(+cs * 2, 0, 0)).origin); |
| 525 | r_points.push_back(p_offset.translated_local(Vector3(-cs * 2, 0, 0)).origin); |
| 526 | } |
| 527 | |
| 528 | if (r_body_a_points) { |
| 529 | JointGizmosDrawer::draw_circle( |
| 530 | Vector3::AXIS_X, |
| 531 | BODY_A_RADIUS, |
| 532 | p_offset, |
| 533 | JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_a), |
| 534 | p_angular_limit_lower, |
| 535 | p_angular_limit_upper, |
| 536 | *r_body_a_points); |
| 537 | } |
| 538 | |
| 539 | if (r_body_b_points) { |
| 540 | JointGizmosDrawer::draw_circle( |
| 541 | Vector3::AXIS_X, |
| 542 | BODY_B_RADIUS, |
| 543 | p_offset, |
| 544 | JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_b), |
| 545 | p_angular_limit_lower, |
| 546 | p_angular_limit_upper, |
| 547 | *r_body_b_points, |
| 548 | true); |
| 549 | } |
| 550 | } |
| 551 | |
| 552 | void Joint3DGizmoPlugin::CreateConeTwistJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { |
| 553 | if (r_body_a_points) { |
| 554 | JointGizmosDrawer::draw_cone( |
| 555 | p_offset, |
| 556 | JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_a), |
| 557 | p_swing, |
| 558 | p_twist, |
| 559 | *r_body_a_points); |
| 560 | } |
| 561 | |
| 562 | if (r_body_b_points) { |
| 563 | JointGizmosDrawer::draw_cone( |
| 564 | p_offset, |
| 565 | JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_b), |
| 566 | p_swing, |
| 567 | p_twist, |
| 568 | *r_body_b_points); |
| 569 | } |
| 570 | } |
| 571 | |
| 572 | void Joint3DGizmoPlugin::CreateGeneric6DOFJointGizmo( |
| 573 | const Transform3D &p_offset, |
| 574 | const Transform3D &p_trs_joint, |
| 575 | const Transform3D &p_trs_body_a, |
| 576 | const Transform3D &p_trs_body_b, |
| 577 | real_t p_angular_limit_lower_x, |
| 578 | real_t p_angular_limit_upper_x, |
| 579 | real_t p_linear_limit_lower_x, |
| 580 | real_t p_linear_limit_upper_x, |
| 581 | bool p_enable_angular_limit_x, |
| 582 | bool p_enable_linear_limit_x, |
| 583 | real_t p_angular_limit_lower_y, |
| 584 | real_t p_angular_limit_upper_y, |
| 585 | real_t p_linear_limit_lower_y, |
| 586 | real_t p_linear_limit_upper_y, |
| 587 | bool p_enable_angular_limit_y, |
| 588 | bool p_enable_linear_limit_y, |
| 589 | real_t p_angular_limit_lower_z, |
| 590 | real_t p_angular_limit_upper_z, |
| 591 | real_t p_linear_limit_lower_z, |
| 592 | real_t p_linear_limit_upper_z, |
| 593 | bool p_enable_angular_limit_z, |
| 594 | bool p_enable_linear_limit_z, |
| 595 | Vector<Vector3> &r_points, |
| 596 | Vector<Vector3> *r_body_a_points, |
| 597 | Vector<Vector3> *r_body_b_points) { |
| 598 | float cs = 0.25; |
| 599 | |
| 600 | for (int ax = 0; ax < 3; ax++) { |
| 601 | float ll = 0; |
| 602 | float ul = 0; |
| 603 | float lll = 0; |
| 604 | float lul = 0; |
| 605 | |
| 606 | int a1 = 0; |
| 607 | int a2 = 0; |
| 608 | int a3 = 0; |
| 609 | bool enable_ang = false; |
| 610 | bool enable_lin = false; |
| 611 | |
| 612 | switch (ax) { |
| 613 | case 0: |
| 614 | ll = p_angular_limit_lower_x; |
| 615 | ul = p_angular_limit_upper_x; |
| 616 | lll = -p_linear_limit_lower_x; |
| 617 | lul = -p_linear_limit_upper_x; |
| 618 | enable_ang = p_enable_angular_limit_x; |
| 619 | enable_lin = p_enable_linear_limit_x; |
| 620 | a1 = 0; |
| 621 | a2 = 1; |
| 622 | a3 = 2; |
| 623 | break; |
| 624 | case 1: |
| 625 | ll = p_angular_limit_lower_y; |
| 626 | ul = p_angular_limit_upper_y; |
| 627 | lll = -p_linear_limit_lower_y; |
| 628 | lul = -p_linear_limit_upper_y; |
| 629 | enable_ang = p_enable_angular_limit_y; |
| 630 | enable_lin = p_enable_linear_limit_y; |
| 631 | a1 = 1; |
| 632 | a2 = 2; |
| 633 | a3 = 0; |
| 634 | break; |
| 635 | case 2: |
| 636 | ll = p_angular_limit_lower_z; |
| 637 | ul = p_angular_limit_upper_z; |
| 638 | lll = -p_linear_limit_lower_z; |
| 639 | lul = -p_linear_limit_upper_z; |
| 640 | enable_ang = p_enable_angular_limit_z; |
| 641 | enable_lin = p_enable_linear_limit_z; |
| 642 | a1 = 2; |
| 643 | a2 = 0; |
| 644 | a3 = 1; |
| 645 | break; |
| 646 | } |
| 647 | |
| 648 | #define ADD_VTX(x, y, z) \ |
| 649 | { \ |
| 650 | Vector3 v; \ |
| 651 | v[a1] = (x); \ |
| 652 | v[a2] = (y); \ |
| 653 | v[a3] = (z); \ |
| 654 | r_points.push_back(p_offset.translated_local(v).origin); \ |
| 655 | } |
| 656 | |
| 657 | if (enable_lin && lll >= lul) { |
| 658 | ADD_VTX(lul, 0, 0); |
| 659 | ADD_VTX(lll, 0, 0); |
| 660 | |
| 661 | ADD_VTX(lul, -cs, -cs); |
| 662 | ADD_VTX(lul, -cs, cs); |
| 663 | ADD_VTX(lul, -cs, cs); |
| 664 | ADD_VTX(lul, cs, cs); |
| 665 | ADD_VTX(lul, cs, cs); |
| 666 | ADD_VTX(lul, cs, -cs); |
| 667 | ADD_VTX(lul, cs, -cs); |
| 668 | ADD_VTX(lul, -cs, -cs); |
| 669 | |
| 670 | ADD_VTX(lll, -cs, -cs); |
| 671 | ADD_VTX(lll, -cs, cs); |
| 672 | ADD_VTX(lll, -cs, cs); |
| 673 | ADD_VTX(lll, cs, cs); |
| 674 | ADD_VTX(lll, cs, cs); |
| 675 | ADD_VTX(lll, cs, -cs); |
| 676 | ADD_VTX(lll, cs, -cs); |
| 677 | ADD_VTX(lll, -cs, -cs); |
| 678 | |
| 679 | } else { |
| 680 | ADD_VTX(+cs * 2, 0, 0); |
| 681 | ADD_VTX(-cs * 2, 0, 0); |
| 682 | } |
| 683 | |
| 684 | if (!enable_ang) { |
| 685 | ll = 0; |
| 686 | ul = -1; |
| 687 | } |
| 688 | |
| 689 | if (r_body_a_points) { |
| 690 | JointGizmosDrawer::draw_circle( |
| 691 | static_cast<Vector3::Axis>(ax), |
| 692 | BODY_A_RADIUS, |
| 693 | p_offset, |
| 694 | JointGizmosDrawer::look_body_toward(static_cast<Vector3::Axis>(ax), p_trs_joint, p_trs_body_a), |
| 695 | ll, |
| 696 | ul, |
| 697 | *r_body_a_points, |
| 698 | true); |
| 699 | } |
| 700 | |
| 701 | if (r_body_b_points) { |
| 702 | JointGizmosDrawer::draw_circle( |
| 703 | static_cast<Vector3::Axis>(ax), |
| 704 | BODY_B_RADIUS, |
| 705 | p_offset, |
| 706 | JointGizmosDrawer::look_body_toward(static_cast<Vector3::Axis>(ax), p_trs_joint, p_trs_body_b), |
| 707 | ll, |
| 708 | ul, |
| 709 | *r_body_b_points); |
| 710 | } |
| 711 | } |
| 712 | |
| 713 | #undef ADD_VTX |
| 714 | } |
| 715 | |