Path: blob/master/modules/godot_physics_3d/godot_shape_3d.h
10277 views
/**************************************************************************/1/* godot_shape_3d.h */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#pragma once3132#include "core/math/geometry_3d.h"33#include "core/templates/local_vector.h"34#include "servers/physics_server_3d.h"3536class GodotShape3D;3738class GodotShapeOwner3D {39public:40virtual void _shape_changed() = 0;41virtual void remove_shape(GodotShape3D *p_shape) = 0;4243virtual ~GodotShapeOwner3D() {}44};4546class GodotShape3D {47RID self;48AABB aabb;49bool configured = false;50real_t custom_bias = 0.0;5152HashMap<GodotShapeOwner3D *, int> owners;5354protected:55void configure(const AABB &p_aabb);5657public:58enum FeatureType {59FEATURE_POINT,60FEATURE_EDGE,61FEATURE_FACE,62FEATURE_CIRCLE,63};6465virtual real_t get_volume() const { return aabb.get_volume(); }6667_FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }68_FORCE_INLINE_ RID get_self() const { return self; }6970virtual PhysicsServer3D::ShapeType get_type() const = 0;7172_FORCE_INLINE_ const AABB &get_aabb() const { return aabb; }73_FORCE_INLINE_ bool is_configured() const { return configured; }7475virtual bool is_concave() const { return false; }7677virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const = 0;78virtual Vector3 get_support(const Vector3 &p_normal) const;79virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const = 0;80virtual Vector3 get_closest_point_to(const Vector3 &p_point) const = 0;81virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const = 0;82virtual bool intersect_point(const Vector3 &p_point) const = 0;83virtual Vector3 get_moment_of_inertia(real_t p_mass) const = 0;8485virtual void set_data(const Variant &p_data) = 0;86virtual Variant get_data() const = 0;8788_FORCE_INLINE_ void set_custom_bias(real_t p_bias) { custom_bias = p_bias; }89_FORCE_INLINE_ real_t get_custom_bias() const { return custom_bias; }9091void add_owner(GodotShapeOwner3D *p_owner);92void remove_owner(GodotShapeOwner3D *p_owner);93bool is_owner(GodotShapeOwner3D *p_owner) const;94const HashMap<GodotShapeOwner3D *, int> &get_owners() const;9596GodotShape3D() {}97virtual ~GodotShape3D();98};99100class GodotConcaveShape3D : public GodotShape3D {101public:102virtual bool is_concave() const override { return true; }103virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; }104105// Returns true to stop the query.106typedef bool (*QueryCallback)(void *p_userdata, GodotShape3D *p_convex);107108virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const = 0;109110GodotConcaveShape3D() {}111};112113class GodotWorldBoundaryShape3D : public GodotShape3D {114Plane plane;115116void _setup(const Plane &p_plane);117118public:119Plane get_plane() const;120121virtual real_t get_volume() const override { return Math::INF; }122virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_WORLD_BOUNDARY; }123virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;124virtual Vector3 get_support(const Vector3 &p_normal) const override;125virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; }126127virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const override;128virtual bool intersect_point(const Vector3 &p_point) const override;129virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;130virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;131132virtual void set_data(const Variant &p_data) override;133virtual Variant get_data() const override;134135GodotWorldBoundaryShape3D();136};137138class GodotSeparationRayShape3D : public GodotShape3D {139real_t length = 1.0;140bool slide_on_slope = false;141142void _setup(real_t p_length, bool p_slide_on_slope);143144public:145real_t get_length() const;146bool get_slide_on_slope() const;147148virtual real_t get_volume() const override { return 0.0; }149virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_SEPARATION_RAY; }150virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;151virtual Vector3 get_support(const Vector3 &p_normal) const override;152virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;153154virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const override;155virtual bool intersect_point(const Vector3 &p_point) const override;156virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;157158virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;159160virtual void set_data(const Variant &p_data) override;161virtual Variant get_data() const override;162163GodotSeparationRayShape3D();164};165166class GodotSphereShape3D : public GodotShape3D {167real_t radius = 0.0;168169void _setup(real_t p_radius);170171public:172real_t get_radius() const;173174virtual real_t get_volume() const override { return 4.0 / 3.0 * Math::PI * radius * radius * radius; }175176virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_SPHERE; }177178virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;179virtual Vector3 get_support(const Vector3 &p_normal) const override;180virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;181virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const override;182virtual bool intersect_point(const Vector3 &p_point) const override;183virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;184185virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;186187virtual void set_data(const Variant &p_data) override;188virtual Variant get_data() const override;189190GodotSphereShape3D();191};192193class GodotBoxShape3D : public GodotShape3D {194Vector3 half_extents;195void _setup(const Vector3 &p_half_extents);196197public:198_FORCE_INLINE_ Vector3 get_half_extents() const { return half_extents; }199virtual real_t get_volume() const override { return 8 * half_extents.x * half_extents.y * half_extents.z; }200201virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_BOX; }202203virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;204virtual Vector3 get_support(const Vector3 &p_normal) const override;205virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;206virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const override;207virtual bool intersect_point(const Vector3 &p_point) const override;208virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;209210virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;211212virtual void set_data(const Variant &p_data) override;213virtual Variant get_data() const override;214215GodotBoxShape3D();216};217218class GodotCapsuleShape3D : public GodotShape3D {219real_t height = 0.0;220real_t radius = 0.0;221222void _setup(real_t p_height, real_t p_radius);223224public:225_FORCE_INLINE_ real_t get_height() const { return height; }226_FORCE_INLINE_ real_t get_radius() const { return radius; }227228virtual real_t get_volume() const override { return 4.0 / 3.0 * Math::PI * radius * radius * radius + (height - radius * 2.0) * Math::PI * radius * radius; }229230virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CAPSULE; }231232virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;233virtual Vector3 get_support(const Vector3 &p_normal) const override;234virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;235virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const override;236virtual bool intersect_point(const Vector3 &p_point) const override;237virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;238239virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;240241virtual void set_data(const Variant &p_data) override;242virtual Variant get_data() const override;243244GodotCapsuleShape3D();245};246247class GodotCylinderShape3D : public GodotShape3D {248real_t height = 0.0;249real_t radius = 0.0;250251void _setup(real_t p_height, real_t p_radius);252253public:254_FORCE_INLINE_ real_t get_height() const { return height; }255_FORCE_INLINE_ real_t get_radius() const { return radius; }256257virtual real_t get_volume() const override { return height * Math::PI * radius * radius; }258259virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CYLINDER; }260261virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;262virtual Vector3 get_support(const Vector3 &p_normal) const override;263virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;264virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const override;265virtual bool intersect_point(const Vector3 &p_point) const override;266virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;267268virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;269270virtual void set_data(const Variant &p_data) override;271virtual Variant get_data() const override;272273GodotCylinderShape3D();274};275276struct GodotConvexPolygonShape3D : public GodotShape3D {277Geometry3D::MeshData mesh;278LocalVector<int> extreme_vertices;279LocalVector<LocalVector<int>> vertex_neighbors;280281void _setup(const Vector<Vector3> &p_vertices);282283public:284const Geometry3D::MeshData &get_mesh() const { return mesh; }285286virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CONVEX_POLYGON; }287288virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;289virtual Vector3 get_support(const Vector3 &p_normal) const override;290virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;291virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const override;292virtual bool intersect_point(const Vector3 &p_point) const override;293virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;294295virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;296297virtual void set_data(const Variant &p_data) override;298virtual Variant get_data() const override;299300GodotConvexPolygonShape3D();301};302303struct _Volume_BVH;304struct GodotFaceShape3D;305306struct GodotConcavePolygonShape3D : public GodotConcaveShape3D {307// always a trimesh308309struct Face {310Vector3 normal;311int indices[3] = {};312};313314Vector<Face> faces;315Vector<Vector3> vertices;316317struct BVH {318AABB aabb;319int left = 0;320int right = 0;321322int face_index = 0;323};324325Vector<BVH> bvh;326327struct _CullParams {328AABB aabb;329QueryCallback callback = nullptr;330void *userdata = nullptr;331const Face *faces = nullptr;332const Vector3 *vertices = nullptr;333const BVH *bvh = nullptr;334GodotFaceShape3D *face = nullptr;335};336337struct _SegmentCullParams {338Vector3 from;339Vector3 to;340Vector3 dir;341const Face *faces = nullptr;342const Vector3 *vertices = nullptr;343const BVH *bvh = nullptr;344GodotFaceShape3D *face = nullptr;345346Vector3 result;347Vector3 normal;348int face_index = -1;349real_t min_d = 1e20;350int collisions = 0;351};352353bool backface_collision = false;354355void _cull_segment(int p_idx, _SegmentCullParams *p_params) const;356bool _cull(int p_idx, _CullParams *p_params) const;357358void _fill_bvh(_Volume_BVH *p_bvh_tree, BVH *p_bvh_array, int &p_idx);359360void _setup(const Vector<Vector3> &p_faces, bool p_backface_collision);361362public:363Vector<Vector3> get_faces() const;364365virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; }366367virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;368virtual Vector3 get_support(const Vector3 &p_normal) const override;369370virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const override;371virtual bool intersect_point(const Vector3 &p_point) const override;372virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;373374virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const override;375376virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;377378virtual void set_data(const Variant &p_data) override;379virtual Variant get_data() const override;380381GodotConcavePolygonShape3D();382};383384struct GodotHeightMapShape3D : public GodotConcaveShape3D {385Vector<real_t> heights;386int width = 0;387int depth = 0;388Vector3 local_origin;389390// Accelerator.391struct Range {392real_t min = 0.0;393real_t max = 0.0;394};395LocalVector<Range> bounds_grid;396int bounds_grid_width = 0;397int bounds_grid_depth = 0;398399static const int BOUNDS_CHUNK_SIZE = 16;400401_FORCE_INLINE_ const Range &_get_bounds_chunk(int p_x, int p_z) const {402return bounds_grid[(p_z * bounds_grid_width) + p_x];403}404405_FORCE_INLINE_ real_t _get_height(int p_x, int p_z) const {406return heights[(p_z * width) + p_x];407}408409_FORCE_INLINE_ void _get_point(int p_x, int p_z, Vector3 &r_point) const {410r_point.x = p_x - 0.5 * (width - 1.0);411r_point.y = _get_height(p_x, p_z);412r_point.z = p_z - 0.5 * (depth - 1.0);413}414415void _get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const;416417void _build_accelerator();418419template <typename ProcessFunction>420bool _intersect_grid_segment(ProcessFunction &p_process, const Vector3 &p_begin, const Vector3 &p_end, int p_width, int p_depth, const Vector3 &offset, Vector3 &r_point, Vector3 &r_normal) const;421422void _setup(const Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);423424public:425Vector<real_t> get_heights() const;426int get_width() const;427int get_depth() const;428429virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_HEIGHTMAP; }430431virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;432virtual Vector3 get_support(const Vector3 &p_normal) const override;433virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const override;434virtual bool intersect_point(const Vector3 &p_point) const override;435436virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;437virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const override;438439virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;440441virtual void set_data(const Variant &p_data) override;442virtual Variant get_data() const override;443444GodotHeightMapShape3D();445};446447//used internally448struct GodotFaceShape3D : public GodotShape3D {449Vector3 normal; //cache450Vector3 vertex[3];451bool backface_collision = false;452bool invert_backface_collision = false;453454virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; }455456const Vector3 &get_vertex(int p_idx) const { return vertex[p_idx]; }457458virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override;459virtual Vector3 get_support(const Vector3 &p_normal) const override;460virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override;461virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const override;462virtual bool intersect_point(const Vector3 &p_point) const override;463virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override;464465virtual Vector3 get_moment_of_inertia(real_t p_mass) const override;466467virtual void set_data(const Variant &p_data) override {}468virtual Variant get_data() const override { return Variant(); }469470GodotFaceShape3D();471};472473struct GodotMotionShape3D : public GodotShape3D {474GodotShape3D *shape = nullptr;475Vector3 motion;476477virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CONVEX_POLYGON; }478479virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override {480Vector3 cast = p_transform.basis.xform(motion);481real_t mina, maxa;482real_t minb, maxb;483Transform3D ofsb = p_transform;484ofsb.origin += cast;485shape->project_range(p_normal, p_transform, mina, maxa);486shape->project_range(p_normal, ofsb, minb, maxb);487r_min = MIN(mina, minb);488r_max = MAX(maxa, maxb);489}490491virtual Vector3 get_support(const Vector3 &p_normal) const override {492Vector3 support = shape->get_support(p_normal);493if (p_normal.dot(motion) > 0) {494support += motion;495}496return support;497}498499virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; }500virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const override { return false; }501virtual bool intersect_point(const Vector3 &p_point) const override { return false; }502virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override { return p_point; }503504virtual Vector3 get_moment_of_inertia(real_t p_mass) const override { return Vector3(); }505506virtual void set_data(const Variant &p_data) override {}507virtual Variant get_data() const override { return Variant(); }508509GodotMotionShape3D() { configure(AABB()); }510};511512513