Polished 3D selection
This commit is contained in:
parent
e949230837
commit
9cd1c20f6a
10 changed files with 486 additions and 86 deletions
|
@ -76,6 +76,7 @@ public:
|
||||||
_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const;
|
_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const;
|
||||||
|
|
||||||
_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count) const;
|
_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count) const;
|
||||||
|
_FORCE_INLINE_ bool inside_convex_shape(const Plane *p_planes, int p_plane_count) const;
|
||||||
bool intersects_plane(const Plane &p_plane) const;
|
bool intersects_plane(const Plane &p_plane) const;
|
||||||
|
|
||||||
_FORCE_INLINE_ bool has_point(const Vector3 &p_point) const;
|
_FORCE_INLINE_ bool has_point(const Vector3 &p_point) const;
|
||||||
|
@ -207,6 +208,25 @@ bool AABB::intersects_convex_shape(const Plane *p_planes, int p_plane_count) con
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AABB::inside_convex_shape(const Plane *p_planes, int p_plane_count) const {
|
||||||
|
|
||||||
|
Vector3 half_extents = size * 0.5;
|
||||||
|
Vector3 ofs = position + half_extents;
|
||||||
|
|
||||||
|
for (int i = 0; i < p_plane_count; i++) {
|
||||||
|
const Plane &p = p_planes[i];
|
||||||
|
Vector3 point(
|
||||||
|
(p.normal.x < 0) ? -half_extents.x : half_extents.x,
|
||||||
|
(p.normal.y < 0) ? -half_extents.y : half_extents.y,
|
||||||
|
(p.normal.z < 0) ? -half_extents.z : half_extents.z);
|
||||||
|
point += ofs;
|
||||||
|
if (p.is_point_over(point))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool AABB::has_point(const Vector3 &p_point) const {
|
bool AABB::has_point(const Vector3 &p_point) const {
|
||||||
|
|
||||||
if (p_point.x < position.x)
|
if (p_point.x < position.x)
|
||||||
|
|
|
@ -510,6 +510,222 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V
|
||||||
return inters;
|
return inters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TriangleMesh::intersect_convex_shape(const Plane *p_planes, int p_plane_count) const {
|
||||||
|
uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
|
||||||
|
|
||||||
|
//p_fully_inside = true;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TEST_AABB_BIT = 0,
|
||||||
|
VISIT_LEFT_BIT = 1,
|
||||||
|
VISIT_RIGHT_BIT = 2,
|
||||||
|
VISIT_DONE_BIT = 3,
|
||||||
|
VISITED_BIT_SHIFT = 29,
|
||||||
|
NODE_IDX_MASK = (1 << VISITED_BIT_SHIFT) - 1,
|
||||||
|
VISITED_BIT_MASK = ~NODE_IDX_MASK,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
int level = 0;
|
||||||
|
|
||||||
|
PoolVector<Triangle>::Read trianglesr = triangles.read();
|
||||||
|
PoolVector<Vector3>::Read verticesr = vertices.read();
|
||||||
|
PoolVector<BVH>::Read bvhr = bvh.read();
|
||||||
|
|
||||||
|
const Triangle *triangleptr = trianglesr.ptr();
|
||||||
|
const Vector3 *vertexptr = verticesr.ptr();
|
||||||
|
int pos = bvh.size() - 1;
|
||||||
|
const BVH *bvhptr = bvhr.ptr();
|
||||||
|
|
||||||
|
stack[0] = pos;
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
uint32_t node = stack[level] & NODE_IDX_MASK;
|
||||||
|
const BVH &b = bvhptr[node];
|
||||||
|
bool done = false;
|
||||||
|
|
||||||
|
switch (stack[level] >> VISITED_BIT_SHIFT) {
|
||||||
|
case TEST_AABB_BIT: {
|
||||||
|
|
||||||
|
bool valid = b.aabb.intersects_convex_shape(p_planes, p_plane_count);
|
||||||
|
if (!valid) {
|
||||||
|
|
||||||
|
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (b.face_index >= 0) {
|
||||||
|
|
||||||
|
const Triangle &s = triangleptr[b.face_index];
|
||||||
|
|
||||||
|
for (int j = 0; j < 3; ++j) {
|
||||||
|
const Vector3 &point = vertexptr[s.indices[j]];
|
||||||
|
const Vector3 &next_point = vertexptr[s.indices[(j + 1) % 3]];
|
||||||
|
Vector3 res;
|
||||||
|
bool over = true;
|
||||||
|
for (int i = 0; i < p_plane_count; i++) {
|
||||||
|
const Plane &p = p_planes[i];
|
||||||
|
|
||||||
|
if (p.intersects_segment(point, next_point, &res)) {
|
||||||
|
bool inisde = true;
|
||||||
|
for (int k = 0; k < p_plane_count; k++) {
|
||||||
|
if (k == i) continue;
|
||||||
|
const Plane &pp = p_planes[k];
|
||||||
|
if (pp.is_point_over(res)) {
|
||||||
|
inisde = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inisde) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.is_point_over(point)) {
|
||||||
|
over = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (over) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
stack[level] = (VISIT_LEFT_BIT << VISITED_BIT_SHIFT) | node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case VISIT_LEFT_BIT: {
|
||||||
|
|
||||||
|
stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;
|
||||||
|
stack[level + 1] = b.left | TEST_AABB_BIT;
|
||||||
|
level++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case VISIT_RIGHT_BIT: {
|
||||||
|
|
||||||
|
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
|
||||||
|
stack[level + 1] = b.right | TEST_AABB_BIT;
|
||||||
|
level++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case VISIT_DONE_BIT: {
|
||||||
|
|
||||||
|
if (level == 0) {
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
level--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count, Vector3 p_scale) const {
|
||||||
|
uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TEST_AABB_BIT = 0,
|
||||||
|
VISIT_LEFT_BIT = 1,
|
||||||
|
VISIT_RIGHT_BIT = 2,
|
||||||
|
VISIT_DONE_BIT = 3,
|
||||||
|
VISITED_BIT_SHIFT = 29,
|
||||||
|
NODE_IDX_MASK = (1 << VISITED_BIT_SHIFT) - 1,
|
||||||
|
VISITED_BIT_MASK = ~NODE_IDX_MASK,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
int level = 0;
|
||||||
|
|
||||||
|
PoolVector<Triangle>::Read trianglesr = triangles.read();
|
||||||
|
PoolVector<Vector3>::Read verticesr = vertices.read();
|
||||||
|
PoolVector<BVH>::Read bvhr = bvh.read();
|
||||||
|
|
||||||
|
Transform scale(Basis().scaled(p_scale));
|
||||||
|
|
||||||
|
const Triangle *triangleptr = trianglesr.ptr();
|
||||||
|
const Vector3 *vertexptr = verticesr.ptr();
|
||||||
|
int pos = bvh.size() - 1;
|
||||||
|
const BVH *bvhptr = bvhr.ptr();
|
||||||
|
|
||||||
|
stack[0] = pos;
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
uint32_t node = stack[level] & NODE_IDX_MASK;
|
||||||
|
const BVH &b = bvhptr[node];
|
||||||
|
bool done = false;
|
||||||
|
|
||||||
|
switch (stack[level] >> VISITED_BIT_SHIFT) {
|
||||||
|
case TEST_AABB_BIT: {
|
||||||
|
|
||||||
|
bool intersects = scale.xform(b.aabb).intersects_convex_shape(p_planes, p_plane_count);
|
||||||
|
if (!intersects) return false;
|
||||||
|
|
||||||
|
bool inside = scale.xform(b.aabb).inside_convex_shape(p_planes, p_plane_count);
|
||||||
|
if (inside) {
|
||||||
|
|
||||||
|
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (b.face_index >= 0) {
|
||||||
|
const Triangle &s = triangleptr[b.face_index];
|
||||||
|
for (int j = 0; j < 3; ++j) {
|
||||||
|
Vector3 point = scale.xform(vertexptr[s.indices[j]]);
|
||||||
|
for (int i = 0; i < p_plane_count; i++) {
|
||||||
|
const Plane &p = p_planes[i];
|
||||||
|
if (p.is_point_over(point)) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
stack[level] = (VISIT_LEFT_BIT << VISITED_BIT_SHIFT) | node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case VISIT_LEFT_BIT: {
|
||||||
|
|
||||||
|
stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;
|
||||||
|
stack[level + 1] = b.left | TEST_AABB_BIT;
|
||||||
|
level++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case VISIT_RIGHT_BIT: {
|
||||||
|
|
||||||
|
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
|
||||||
|
stack[level + 1] = b.right | TEST_AABB_BIT;
|
||||||
|
level++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case VISIT_DONE_BIT: {
|
||||||
|
|
||||||
|
if (level == 0) {
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
level--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool TriangleMesh::is_valid() const {
|
bool TriangleMesh::is_valid() const {
|
||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
|
|
|
@ -89,6 +89,8 @@ public:
|
||||||
bool is_valid() const;
|
bool is_valid() const;
|
||||||
bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const;
|
bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const;
|
||||||
bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal) const;
|
bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal) const;
|
||||||
|
bool intersect_convex_shape(const Plane *p_planes, int p_plane_count) const;
|
||||||
|
bool inside_convex_shape(const Plane *p_planes, int p_plane_count, Vector3 p_scale = Vector3(1, 1, 1)) const;
|
||||||
Vector3 get_area_normal(const AABB &p_aabb) const;
|
Vector3 get_area_normal(const AABB &p_aabb) const;
|
||||||
PoolVector<Face3> get_faces() const;
|
PoolVector<Face3> get_faces() const;
|
||||||
|
|
||||||
|
|
|
@ -217,7 +217,7 @@ bool SpatialEditorGizmo::intersect_frustum(const Camera *p_camera, const Vector<
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpatialEditorGizmo::intersect_ray(const Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) {
|
bool SpatialEditorGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -320,24 +320,20 @@ void SpatialEditorViewport::_select_clicked(bool p_append, bool p_single) {
|
||||||
void SpatialEditorViewport::_select(Spatial *p_node, bool p_append, bool p_single) {
|
void SpatialEditorViewport::_select(Spatial *p_node, bool p_append, bool p_single) {
|
||||||
|
|
||||||
if (!p_append) {
|
if (!p_append) {
|
||||||
|
|
||||||
// should not modify the selection..
|
|
||||||
|
|
||||||
editor_selection->clear();
|
editor_selection->clear();
|
||||||
editor_selection->add_node(p_node);
|
}
|
||||||
|
|
||||||
if (Engine::get_singleton()->is_editor_hint())
|
|
||||||
editor->call("edit_node", p_node);
|
|
||||||
|
|
||||||
|
if (editor_selection->is_selected(p_node)) {
|
||||||
|
//erase
|
||||||
|
editor_selection->remove_node(p_node);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (editor_selection->is_selected(p_node) && p_single) {
|
editor_selection->add_node(p_node);
|
||||||
//erase
|
}
|
||||||
editor_selection->remove_node(p_node);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
editor_selection->add_node(p_node);
|
if (p_single) {
|
||||||
}
|
if (Engine::get_singleton()->is_editor_hint())
|
||||||
|
editor->call("edit_node", p_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,7 +372,7 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append,
|
||||||
Vector3 normal;
|
Vector3 normal;
|
||||||
|
|
||||||
int handle = -1;
|
int handle = -1;
|
||||||
bool inters = seg->intersect_ray(camera, p_pos, point, normal, NULL, p_alt_select);
|
bool inters = seg->intersect_ray(camera, p_pos, point, normal, &handle, p_alt_select);
|
||||||
|
|
||||||
if (!inters)
|
if (!inters)
|
||||||
continue;
|
continue;
|
||||||
|
@ -475,7 +471,7 @@ void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_incl
|
||||||
Vector3 SpatialEditorViewport::_get_screen_to_space(const Vector3 &p_vector3) {
|
Vector3 SpatialEditorViewport::_get_screen_to_space(const Vector3 &p_vector3) {
|
||||||
|
|
||||||
CameraMatrix cm;
|
CameraMatrix cm;
|
||||||
cm.set_perspective(get_fov(), get_size().aspect(), get_znear(), get_zfar());
|
cm.set_perspective(get_fov(), get_size().aspect(), get_znear() + p_vector3.z, get_zfar());
|
||||||
float screen_w, screen_h;
|
float screen_w, screen_h;
|
||||||
cm.get_viewport_size(screen_w, screen_h);
|
cm.get_viewport_size(screen_w, screen_h);
|
||||||
|
|
||||||
|
@ -485,7 +481,7 @@ Vector3 SpatialEditorViewport::_get_screen_to_space(const Vector3 &p_vector3) {
|
||||||
camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
|
camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
|
||||||
camera_transform.translate(0, 0, cursor.distance);
|
camera_transform.translate(0, 0, cursor.distance);
|
||||||
|
|
||||||
return camera_transform.xform(Vector3(((p_vector3.x / get_size().width) * 2.0 - 1.0) * screen_w, ((1.0 - (p_vector3.y / get_size().height)) * 2.0 - 1.0) * screen_h, -get_znear()));
|
return camera_transform.xform(Vector3(((p_vector3.x / get_size().width) * 2.0 - 1.0) * screen_w, ((1.0 - (p_vector3.y / get_size().height)) * 2.0 - 1.0) * screen_h, -(get_znear() + p_vector3.z)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpatialEditorViewport::_select_region() {
|
void SpatialEditorViewport::_select_region() {
|
||||||
|
@ -493,23 +489,25 @@ void SpatialEditorViewport::_select_region() {
|
||||||
if (cursor.region_begin == cursor.region_end)
|
if (cursor.region_begin == cursor.region_end)
|
||||||
return; //nothing really
|
return; //nothing really
|
||||||
|
|
||||||
|
float z_offset = MAX(0.0, 5.0 - get_znear());
|
||||||
|
|
||||||
Vector3 box[4] = {
|
Vector3 box[4] = {
|
||||||
Vector3(
|
Vector3(
|
||||||
MIN(cursor.region_begin.x, cursor.region_end.x),
|
MIN(cursor.region_begin.x, cursor.region_end.x),
|
||||||
MIN(cursor.region_begin.y, cursor.region_end.y),
|
MIN(cursor.region_begin.y, cursor.region_end.y),
|
||||||
0),
|
z_offset),
|
||||||
Vector3(
|
Vector3(
|
||||||
MAX(cursor.region_begin.x, cursor.region_end.x),
|
MAX(cursor.region_begin.x, cursor.region_end.x),
|
||||||
MIN(cursor.region_begin.y, cursor.region_end.y),
|
MIN(cursor.region_begin.y, cursor.region_end.y),
|
||||||
0),
|
z_offset),
|
||||||
Vector3(
|
Vector3(
|
||||||
MAX(cursor.region_begin.x, cursor.region_end.x),
|
MAX(cursor.region_begin.x, cursor.region_end.x),
|
||||||
MAX(cursor.region_begin.y, cursor.region_end.y),
|
MAX(cursor.region_begin.y, cursor.region_end.y),
|
||||||
0),
|
z_offset),
|
||||||
Vector3(
|
Vector3(
|
||||||
MIN(cursor.region_begin.x, cursor.region_end.x),
|
MIN(cursor.region_begin.x, cursor.region_end.x),
|
||||||
MAX(cursor.region_begin.y, cursor.region_end.y),
|
MAX(cursor.region_begin.y, cursor.region_end.y),
|
||||||
0)
|
z_offset)
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector<Plane> frustum;
|
Vector<Plane> frustum;
|
||||||
|
@ -529,7 +527,7 @@ void SpatialEditorViewport::_select_region() {
|
||||||
frustum.push_back(near);
|
frustum.push_back(near);
|
||||||
|
|
||||||
Plane far = -near;
|
Plane far = -near;
|
||||||
far.d += 500.0;
|
far.d += get_zfar();
|
||||||
|
|
||||||
frustum.push_back(far);
|
frustum.push_back(far);
|
||||||
|
|
||||||
|
@ -544,19 +542,26 @@ void SpatialEditorViewport::_select_region() {
|
||||||
if (!sp)
|
if (!sp)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Ref<SpatialEditorGizmo> seg = sp->get_gizmo();
|
|
||||||
|
|
||||||
if (!seg.is_valid())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Spatial *root_sp = sp;
|
Spatial *root_sp = sp;
|
||||||
while (root_sp && root_sp != edited_scene && root_sp->get_owner() != edited_scene && !edited_scene->is_editable_instance(root_sp->get_owner())) {
|
while (root_sp && root_sp != edited_scene && root_sp->get_owner() != edited_scene && !edited_scene->is_editable_instance(root_sp->get_owner())) {
|
||||||
root_sp = Object::cast_to<Spatial>(root_sp->get_owner());
|
root_sp = Object::cast_to<Spatial>(root_sp->get_owner());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected.find(root_sp) == -1)
|
if (selected.find(root_sp) != -1) continue;
|
||||||
if (seg->intersect_frustum(camera, frustum))
|
|
||||||
_select(root_sp, true, false);
|
Ref<SpatialEditorGizmo> seg = sp->get_gizmo();
|
||||||
|
|
||||||
|
if (!seg.is_valid())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (seg->intersect_frustum(camera, frustum)) {
|
||||||
|
selected.push_back(root_sp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool single = selected.size() == 1;
|
||||||
|
for (int i = 0; i < selected.size(); i++) {
|
||||||
|
_select(selected[i], true, single);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1170,6 +1175,9 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor.region_select) {
|
if (cursor.region_select) {
|
||||||
|
|
||||||
|
if (!clicked_wants_append) _clear_selected();
|
||||||
|
|
||||||
_select_region();
|
_select_region();
|
||||||
cursor.region_select = false;
|
cursor.region_select = false;
|
||||||
surface->update();
|
surface->update();
|
||||||
|
@ -1279,7 +1287,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor.region_select && nav_mode == NAVIGATION_NONE) {
|
if (cursor.region_select && nav_mode == NAVIGATION_NONE) {
|
||||||
|
|
||||||
cursor.region_end = m->get_position();
|
cursor.region_end = m->get_position();
|
||||||
surface->update();
|
surface->update();
|
||||||
return;
|
return;
|
||||||
|
@ -2153,10 +2160,7 @@ void SpatialEditorViewport::_notification(int p_what) {
|
||||||
|
|
||||||
VisualInstance *vi = Object::cast_to<VisualInstance>(sp);
|
VisualInstance *vi = Object::cast_to<VisualInstance>(sp);
|
||||||
|
|
||||||
if (se->aabb.has_no_surface()) {
|
se->aabb = vi ? vi->get_aabb() : AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
|
||||||
|
|
||||||
se->aabb = vi ? vi->get_aabb() : AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
|
|
||||||
}
|
|
||||||
|
|
||||||
Transform t = sp->get_global_gizmo_transform();
|
Transform t = sp->get_global_gizmo_transform();
|
||||||
t.translate(se->aabb.position);
|
t.translate(se->aabb.position);
|
||||||
|
|
|
@ -62,7 +62,7 @@ public:
|
||||||
virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
|
virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
|
||||||
|
|
||||||
virtual bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum);
|
virtual bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum);
|
||||||
virtual bool intersect_ray(const Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false);
|
virtual bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false);
|
||||||
SpatialEditorGizmo();
|
SpatialEditorGizmo();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -201,6 +201,9 @@ void EditorSpatialGizmo::add_unscaled_billboard(const Ref<Material> &p_material,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectable_icon_size = p_scale;
|
||||||
|
mesh->set_custom_aabb(AABB(Vector3(-selectable_icon_size, -selectable_icon_size, -selectable_icon_size) * 40.0f, Vector3(selectable_icon_size, selectable_icon_size, selectable_icon_size) * 80.0f));
|
||||||
|
|
||||||
ins.mesh = mesh;
|
ins.mesh = mesh;
|
||||||
ins.unscaled = true;
|
ins.unscaled = true;
|
||||||
ins.billboard = true;
|
ins.billboard = true;
|
||||||
|
@ -209,13 +212,13 @@ void EditorSpatialGizmo::add_unscaled_billboard(const Ref<Material> &p_material,
|
||||||
VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
|
VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectable_icon_size = p_scale * 2.0;
|
||||||
|
|
||||||
instances.push_back(ins);
|
instances.push_back(ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorSpatialGizmo::add_collision_triangles(const Ref<TriangleMesh> &p_tmesh, const AABB &p_bounds) {
|
void EditorSpatialGizmo::add_collision_triangles(const Ref<TriangleMesh> &p_tmesh) {
|
||||||
|
|
||||||
collision_mesh = p_tmesh;
|
collision_mesh = p_tmesh;
|
||||||
collision_mesh_bounds = p_bounds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorSpatialGizmo::add_collision_segments(const Vector<Vector3> &p_lines) {
|
void EditorSpatialGizmo::add_collision_segments(const Vector<Vector3> &p_lines) {
|
||||||
|
@ -332,6 +335,27 @@ bool EditorSpatialGizmo::intersect_frustum(const Camera *p_camera, const Vector<
|
||||||
ERR_FAIL_COND_V(!spatial_node, false);
|
ERR_FAIL_COND_V(!spatial_node, false);
|
||||||
ERR_FAIL_COND_V(!valid, false);
|
ERR_FAIL_COND_V(!valid, false);
|
||||||
|
|
||||||
|
if (selectable_icon_size > 0.0f) {
|
||||||
|
Vector3 origin = spatial_node->get_global_transform().get_origin();
|
||||||
|
|
||||||
|
const Plane *p = p_frustum.ptr();
|
||||||
|
int fc = p_frustum.size();
|
||||||
|
|
||||||
|
bool any_out = false;
|
||||||
|
|
||||||
|
for (int j = 0; j < fc; j++) {
|
||||||
|
|
||||||
|
if (p[j].is_point_over(origin)) {
|
||||||
|
any_out = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!any_out)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (collision_segments.size()) {
|
if (collision_segments.size()) {
|
||||||
|
|
||||||
const Plane *p = p_frustum.ptr();
|
const Plane *p = p_frustum.ptr();
|
||||||
|
@ -341,55 +365,44 @@ bool EditorSpatialGizmo::intersect_frustum(const Camera *p_camera, const Vector<
|
||||||
const Vector3 *vptr = collision_segments.ptr();
|
const Vector3 *vptr = collision_segments.ptr();
|
||||||
Transform t = spatial_node->get_global_transform();
|
Transform t = spatial_node->get_global_transform();
|
||||||
|
|
||||||
for (int i = 0; i < vc / 2; i++) {
|
bool any_out = false;
|
||||||
|
for (int j = 0; j < fc; j++) {
|
||||||
Vector3 a = t.xform(vptr[i * 2 + 0]);
|
for (int i = 0; i < vc; i++) {
|
||||||
Vector3 b = t.xform(vptr[i * 2 + 1]);
|
Vector3 v = t.xform(vptr[i]);
|
||||||
|
if (p[j].is_point_over(v)) {
|
||||||
bool any_out = false;
|
|
||||||
for (int j = 0; j < fc; j++) {
|
|
||||||
|
|
||||||
if (p[j].distance_to(a) > 0 && p[j].distance_to(b) > 0) {
|
|
||||||
|
|
||||||
any_out = true;
|
any_out = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (any_out) break;
|
||||||
if (!any_out)
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
if (!any_out) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collision_mesh_bounds.size != Vector3(0.0, 0.0, 0.0)) {
|
if (collision_mesh.is_valid()) {
|
||||||
Transform t = spatial_node->get_global_transform();
|
Transform t = spatial_node->get_global_transform();
|
||||||
const Plane *p = p_frustum.ptr();
|
|
||||||
int fc = p_frustum.size();
|
|
||||||
|
|
||||||
Vector3 mins = t.xform(collision_mesh_bounds.get_position());
|
Vector3 mesh_scale = t.get_basis().get_scale();
|
||||||
Vector3 max = t.xform(collision_mesh_bounds.get_position() + collision_mesh_bounds.get_size());
|
t.orthonormalize();
|
||||||
|
|
||||||
bool any_out = false;
|
Transform it = t.affine_inverse();
|
||||||
|
|
||||||
for (int j = 0; j < fc; j++) {
|
Vector<Plane> transformed_frustum;
|
||||||
|
|
||||||
if (p[j].distance_to(mins) > 0 || p[j].distance_to(max) > 0) {
|
for (int i = 0; i < 4; i++) {
|
||||||
|
transformed_frustum.push_back(it.xform(p_frustum[i]));
|
||||||
any_out = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!any_out)
|
if (collision_mesh->inside_convex_shape(transformed_frustum.ptr(), transformed_frustum.size(), mesh_scale)) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditorSpatialGizmo::intersect_ray(const Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) {
|
bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) {
|
||||||
|
|
||||||
ERR_FAIL_COND_V(!spatial_node, false);
|
ERR_FAIL_COND_V(!spatial_node, false);
|
||||||
ERR_FAIL_COND_V(!valid, false);
|
ERR_FAIL_COND_V(!valid, false);
|
||||||
|
@ -453,6 +466,43 @@ bool EditorSpatialGizmo::intersect_ray(const Camera *p_camera, const Point2 &p_p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selectable_icon_size > 0.0f) {
|
||||||
|
|
||||||
|
Transform t = spatial_node->get_global_transform();
|
||||||
|
t.orthonormalize();
|
||||||
|
t.set_look_at(t.origin, p_camera->get_camera_transform().origin, Vector3(0, 1, 0));
|
||||||
|
|
||||||
|
float scale = t.origin.distance_to(p_camera->get_camera_transform().origin);
|
||||||
|
|
||||||
|
if (p_camera->get_projection() == Camera::PROJECTION_ORTHOGONAL) {
|
||||||
|
float h = Math::abs(p_camera->get_size());
|
||||||
|
scale = (h * 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point2 center = p_camera->unproject_position(t.origin);
|
||||||
|
|
||||||
|
Transform oct = p_camera->get_camera_transform();
|
||||||
|
|
||||||
|
p_camera->look_at(t.origin, Vector3(0, 1, 0));
|
||||||
|
Vector3 c0 = t.xform(Vector3(selectable_icon_size, selectable_icon_size, 0) * scale);
|
||||||
|
Vector3 c1 = t.xform(Vector3(-selectable_icon_size, -selectable_icon_size, 0) * scale);
|
||||||
|
|
||||||
|
Point2 p0 = p_camera->unproject_position(c0);
|
||||||
|
Point2 p1 = p_camera->unproject_position(c1);
|
||||||
|
|
||||||
|
p_camera->set_global_transform(oct);
|
||||||
|
|
||||||
|
Rect2 rect(p0, p1 - p0);
|
||||||
|
|
||||||
|
rect.set_position(center - rect.get_size() / 2.0);
|
||||||
|
|
||||||
|
if (rect.has_point(p_point)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (collision_segments.size()) {
|
if (collision_segments.size()) {
|
||||||
|
|
||||||
Plane camp(p_camera->get_transform().origin, (-p_camera->get_transform().basis.get_axis(2)).normalized());
|
Plane camp(p_camera->get_transform().origin, (-p_camera->get_transform().basis.get_axis(2)).normalized());
|
||||||
|
@ -664,8 +714,8 @@ void EditorSpatialGizmo::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("add_lines", "lines", "material", "billboard"), &EditorSpatialGizmo::add_lines, DEFVAL(false));
|
ClassDB::bind_method(D_METHOD("add_lines", "lines", "material", "billboard"), &EditorSpatialGizmo::add_lines, DEFVAL(false));
|
||||||
ClassDB::bind_method(D_METHOD("add_mesh", "mesh", "billboard", "skeleton"), &EditorSpatialGizmo::add_mesh, DEFVAL(false), DEFVAL(RID()));
|
ClassDB::bind_method(D_METHOD("add_mesh", "mesh", "billboard", "skeleton"), &EditorSpatialGizmo::add_mesh, DEFVAL(false), DEFVAL(RID()));
|
||||||
ClassDB::bind_method(D_METHOD("add_collision_segments", "segments"), &EditorSpatialGizmo::add_collision_segments);
|
ClassDB::bind_method(D_METHOD("add_collision_segments", "segments"), &EditorSpatialGizmo::add_collision_segments);
|
||||||
ClassDB::bind_method(D_METHOD("add_collision_triangles", "triangles", "bounds"), &EditorSpatialGizmo::add_collision_triangles);
|
ClassDB::bind_method(D_METHOD("add_collision_triangles", "triangles"), &EditorSpatialGizmo::add_collision_triangles);
|
||||||
ClassDB::bind_method(D_METHOD("add_unscaled_billboard", "material", "default_scale"), &EditorSpatialGizmo::add_unscaled_billboard, DEFVAL(1));
|
ClassDB::bind_method(D_METHOD("add_unscaled_billboard", "material", "default_scale"), &EditorSpatialGizmo::add_unscaled_billboard, DEFVAL(1), DEFVAL(true));
|
||||||
ClassDB::bind_method(D_METHOD("add_handles", "handles", "billboard", "secondary"), &EditorSpatialGizmo::add_handles, DEFVAL(false), DEFVAL(false));
|
ClassDB::bind_method(D_METHOD("add_handles", "handles", "billboard", "secondary"), &EditorSpatialGizmo::add_handles, DEFVAL(false), DEFVAL(false));
|
||||||
ClassDB::bind_method(D_METHOD("set_spatial_node", "node"), &EditorSpatialGizmo::_set_spatial_node);
|
ClassDB::bind_method(D_METHOD("set_spatial_node", "node"), &EditorSpatialGizmo::_set_spatial_node);
|
||||||
ClassDB::bind_method(D_METHOD("clear"), &EditorSpatialGizmo::clear);
|
ClassDB::bind_method(D_METHOD("clear"), &EditorSpatialGizmo::clear);
|
||||||
|
@ -1272,14 +1322,15 @@ bool MeshInstanceSpatialGizmo::can_draw() const {
|
||||||
}
|
}
|
||||||
void MeshInstanceSpatialGizmo::redraw() {
|
void MeshInstanceSpatialGizmo::redraw() {
|
||||||
|
|
||||||
|
clear();
|
||||||
|
|
||||||
Ref<Mesh> m = mesh->get_mesh();
|
Ref<Mesh> m = mesh->get_mesh();
|
||||||
if (!m.is_valid())
|
if (!m.is_valid())
|
||||||
return; //none
|
return; //none
|
||||||
|
|
||||||
Ref<TriangleMesh> tm = m->generate_triangle_mesh();
|
Ref<TriangleMesh> tm = m->generate_triangle_mesh();
|
||||||
if (tm.is_valid()) {
|
if (tm.is_valid()) {
|
||||||
AABB aabb;
|
add_collision_triangles(tm);
|
||||||
add_collision_triangles(tm, aabb);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1291,6 +1342,27 @@ MeshInstanceSpatialGizmo::MeshInstanceSpatialGizmo(MeshInstance *p_mesh) {
|
||||||
|
|
||||||
/////
|
/////
|
||||||
|
|
||||||
|
bool Sprite3DSpatialGizmo::can_draw() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void Sprite3DSpatialGizmo::redraw() {
|
||||||
|
|
||||||
|
clear();
|
||||||
|
|
||||||
|
Ref<TriangleMesh> tm = sprite->generate_triangle_mesh();
|
||||||
|
if (tm.is_valid()) {
|
||||||
|
add_collision_triangles(tm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Sprite3DSpatialGizmo::Sprite3DSpatialGizmo(SpriteBase3D *p_sprite) {
|
||||||
|
|
||||||
|
sprite = p_sprite;
|
||||||
|
set_spatial_node(p_sprite);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
void Position3DSpatialGizmo::redraw() {
|
void Position3DSpatialGizmo::redraw() {
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
@ -2540,8 +2612,9 @@ void ParticlesGizmo::redraw() {
|
||||||
}
|
}
|
||||||
|
|
||||||
//add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05);
|
//add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05);
|
||||||
add_unscaled_billboard(icon, 0.05);
|
|
||||||
add_handles(handles);
|
add_handles(handles);
|
||||||
|
add_unscaled_billboard(icon, 0.05);
|
||||||
}
|
}
|
||||||
ParticlesGizmo::ParticlesGizmo(Particles *p_particles) {
|
ParticlesGizmo::ParticlesGizmo(Particles *p_particles) {
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "scene/3d/ray_cast.h"
|
#include "scene/3d/ray_cast.h"
|
||||||
#include "scene/3d/reflection_probe.h"
|
#include "scene/3d/reflection_probe.h"
|
||||||
#include "scene/3d/room_instance.h"
|
#include "scene/3d/room_instance.h"
|
||||||
|
#include "scene/3d/sprite_3d.h"
|
||||||
#include "scene/3d/vehicle_body.h"
|
#include "scene/3d/vehicle_body.h"
|
||||||
#include "scene/3d/visibility_notifier.h"
|
#include "scene/3d/visibility_notifier.h"
|
||||||
|
|
||||||
|
@ -80,7 +81,6 @@ class EditorSpatialGizmo : public SpatialEditorGizmo {
|
||||||
|
|
||||||
Vector<Vector3> collision_segments;
|
Vector<Vector3> collision_segments;
|
||||||
Ref<TriangleMesh> collision_mesh;
|
Ref<TriangleMesh> collision_mesh;
|
||||||
AABB collision_mesh_bounds;
|
|
||||||
|
|
||||||
struct Handle {
|
struct Handle {
|
||||||
Vector3 pos;
|
Vector3 pos;
|
||||||
|
@ -89,6 +89,7 @@ class EditorSpatialGizmo : public SpatialEditorGizmo {
|
||||||
|
|
||||||
Vector<Vector3> handles;
|
Vector<Vector3> handles;
|
||||||
Vector<Vector3> secondary_handles;
|
Vector<Vector3> secondary_handles;
|
||||||
|
float selectable_icon_size = -1.0f;
|
||||||
bool billboard_handle;
|
bool billboard_handle;
|
||||||
|
|
||||||
bool valid;
|
bool valid;
|
||||||
|
@ -102,7 +103,7 @@ protected:
|
||||||
void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false);
|
void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false);
|
||||||
void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const RID &p_skeleton = RID());
|
void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const RID &p_skeleton = RID());
|
||||||
void add_collision_segments(const Vector<Vector3> &p_lines);
|
void add_collision_segments(const Vector<Vector3> &p_lines);
|
||||||
void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh, const AABB &p_bounds = AABB());
|
void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh);
|
||||||
void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1);
|
void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1);
|
||||||
void add_handles(const Vector<Vector3> &p_handles, bool p_billboard = false, bool p_secondary = false);
|
void add_handles(const Vector<Vector3> &p_handles, bool p_billboard = false, bool p_secondary = false);
|
||||||
void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3());
|
void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3());
|
||||||
|
@ -118,7 +119,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
virtual Vector3 get_handle_pos(int p_idx) const;
|
virtual Vector3 get_handle_pos(int p_idx) const;
|
||||||
virtual bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum);
|
virtual bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum);
|
||||||
virtual bool intersect_ray(const Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false);
|
virtual bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
void create();
|
void create();
|
||||||
|
@ -192,6 +193,18 @@ public:
|
||||||
MeshInstanceSpatialGizmo(MeshInstance *p_mesh = NULL);
|
MeshInstanceSpatialGizmo(MeshInstance *p_mesh = NULL);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Sprite3DSpatialGizmo : public EditorSpatialGizmo {
|
||||||
|
|
||||||
|
GDCLASS(Sprite3DSpatialGizmo, EditorSpatialGizmo);
|
||||||
|
|
||||||
|
SpriteBase3D *sprite;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool can_draw() const;
|
||||||
|
void redraw();
|
||||||
|
Sprite3DSpatialGizmo(SpriteBase3D *p_sprite = NULL);
|
||||||
|
};
|
||||||
|
|
||||||
class Position3DSpatialGizmo : public EditorSpatialGizmo {
|
class Position3DSpatialGizmo : public EditorSpatialGizmo {
|
||||||
|
|
||||||
GDCLASS(Position3DSpatialGizmo, EditorSpatialGizmo);
|
GDCLASS(Position3DSpatialGizmo, EditorSpatialGizmo);
|
||||||
|
|
|
@ -185,6 +185,9 @@ void SpriteBase3D::_queue_update() {
|
||||||
if (pending_update)
|
if (pending_update)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
triangle_mesh.unref();
|
||||||
|
update_gizmo();
|
||||||
|
|
||||||
pending_update = true;
|
pending_update = true;
|
||||||
call_deferred(SceneStringNames::get_singleton()->_im_update);
|
call_deferred(SceneStringNames::get_singleton()->_im_update);
|
||||||
}
|
}
|
||||||
|
@ -198,6 +201,66 @@ PoolVector<Face3> SpriteBase3D::get_faces(uint32_t p_usage_flags) const {
|
||||||
return PoolVector<Face3>();
|
return PoolVector<Face3>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const {
|
||||||
|
if (triangle_mesh.is_valid())
|
||||||
|
return triangle_mesh;
|
||||||
|
|
||||||
|
PoolVector<Vector3> faces;
|
||||||
|
faces.resize(6);
|
||||||
|
PoolVector<Vector3>::Write facesw = faces.write();
|
||||||
|
|
||||||
|
Rect2 final_rect = get_item_rect();
|
||||||
|
|
||||||
|
if (final_rect.size.x == 0 || final_rect.size.y == 0)
|
||||||
|
return Ref<TriangleMesh>();
|
||||||
|
|
||||||
|
float pixel_size = get_pixel_size();
|
||||||
|
|
||||||
|
Vector2 vertices[4] = {
|
||||||
|
|
||||||
|
(final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
|
||||||
|
(final_rect.position + final_rect.size) * pixel_size,
|
||||||
|
(final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
|
||||||
|
final_rect.position * pixel_size,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
int x_axis = ((axis + 1) % 3);
|
||||||
|
int y_axis = ((axis + 2) % 3);
|
||||||
|
|
||||||
|
if (axis != Vector3::AXIS_Z) {
|
||||||
|
SWAP(x_axis, y_axis);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (axis == Vector3::AXIS_Y) {
|
||||||
|
vertices[i].y = -vertices[i].y;
|
||||||
|
} else if (axis == Vector3::AXIS_X) {
|
||||||
|
vertices[i].x = -vertices[i].x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int indices[6] = {
|
||||||
|
0, 1, 2,
|
||||||
|
0, 2, 3
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int j = 0; j < 6; j++) {
|
||||||
|
int i = indices[j];
|
||||||
|
Vector3 vtx;
|
||||||
|
vtx[x_axis] = vertices[i][0];
|
||||||
|
vtx[y_axis] = vertices[i][1];
|
||||||
|
facesw[j] = vtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
facesw = PoolVector<Vector3>::Write();
|
||||||
|
|
||||||
|
triangle_mesh = Ref<TriangleMesh>(memnew(TriangleMesh));
|
||||||
|
triangle_mesh->create(faces);
|
||||||
|
|
||||||
|
return triangle_mesh;
|
||||||
|
}
|
||||||
|
|
||||||
void SpriteBase3D::set_draw_flag(DrawFlags p_flag, bool p_enable) {
|
void SpriteBase3D::set_draw_flag(DrawFlags p_flag, bool p_enable) {
|
||||||
|
|
||||||
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
|
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
|
||||||
|
@ -255,6 +318,7 @@ void SpriteBase3D::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("get_alpha_cut_mode"), &SpriteBase3D::get_alpha_cut_mode);
|
ClassDB::bind_method(D_METHOD("get_alpha_cut_mode"), &SpriteBase3D::get_alpha_cut_mode);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect);
|
ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect);
|
||||||
|
ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &SpriteBase3D::generate_triangle_mesh);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("_queue_update"), &SpriteBase3D::_queue_update);
|
ClassDB::bind_method(D_METHOD("_queue_update"), &SpriteBase3D::_queue_update);
|
||||||
ClassDB::bind_method(D_METHOD("_im_update"), &SpriteBase3D::_im_update);
|
ClassDB::bind_method(D_METHOD("_im_update"), &SpriteBase3D::_im_update);
|
||||||
|
@ -901,7 +965,7 @@ Rect2 AnimatedSprite3D::get_item_rect() const {
|
||||||
return Rect2(0, 0, 1, 1);
|
return Rect2(0, 0, 1, 1);
|
||||||
Size2i s = t->get_size();
|
Size2i s = t->get_size();
|
||||||
|
|
||||||
Point2 ofs = offset;
|
Point2 ofs = get_offset();
|
||||||
if (centered)
|
if (centered)
|
||||||
ofs -= s / 2;
|
ofs -= s / 2;
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,8 @@ class SpriteBase3D : public GeometryInstance {
|
||||||
|
|
||||||
GDCLASS(SpriteBase3D, GeometryInstance);
|
GDCLASS(SpriteBase3D, GeometryInstance);
|
||||||
|
|
||||||
|
mutable Ref<TriangleMesh> triangle_mesh; //cached
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum DrawFlags {
|
enum DrawFlags {
|
||||||
FLAG_TRANSPARENT,
|
FLAG_TRANSPARENT,
|
||||||
|
@ -133,6 +135,7 @@ public:
|
||||||
|
|
||||||
virtual AABB get_aabb() const;
|
virtual AABB get_aabb() const;
|
||||||
virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
|
virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
|
||||||
|
Ref<TriangleMesh> generate_triangle_mesh() const;
|
||||||
|
|
||||||
SpriteBase3D();
|
SpriteBase3D();
|
||||||
~SpriteBase3D();
|
~SpriteBase3D();
|
||||||
|
@ -192,7 +195,6 @@ class AnimatedSprite3D : public SpriteBase3D {
|
||||||
int frame;
|
int frame;
|
||||||
|
|
||||||
bool centered;
|
bool centered;
|
||||||
Point2 offset;
|
|
||||||
|
|
||||||
float timeout;
|
float timeout;
|
||||||
|
|
||||||
|
|
|
@ -1352,10 +1352,10 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const {
|
||||||
PoolVector<float> tangents;
|
PoolVector<float> tangents;
|
||||||
PoolVector<Vector2> uvs;
|
PoolVector<Vector2> uvs;
|
||||||
|
|
||||||
faces.resize(4);
|
faces.resize(6);
|
||||||
normals.resize(4);
|
normals.resize(6);
|
||||||
tangents.resize(4 * 4);
|
tangents.resize(6 * 4);
|
||||||
uvs.resize(4);
|
uvs.resize(6);
|
||||||
|
|
||||||
Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f);
|
Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f);
|
||||||
|
|
||||||
|
@ -1366,9 +1366,15 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const {
|
||||||
Vector3(_size.x, -_size.y, 0),
|
Vector3(_size.x, -_size.y, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
static const int indices[6] = {
|
||||||
|
0, 1, 2,
|
||||||
|
0, 2, 3
|
||||||
|
};
|
||||||
|
|
||||||
faces.set(i, quad_faces[i]);
|
for (int i = 0; i < 6; i++) {
|
||||||
|
|
||||||
|
int j = indices[i];
|
||||||
|
faces.set(i, quad_faces[j]);
|
||||||
normals.set(i, Vector3(0, 0, 1));
|
normals.set(i, Vector3(0, 0, 1));
|
||||||
tangents.set(i * 4 + 0, 1.0);
|
tangents.set(i * 4 + 0, 1.0);
|
||||||
tangents.set(i * 4 + 1, 0.0);
|
tangents.set(i * 4 + 1, 0.0);
|
||||||
|
@ -1382,14 +1388,14 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const {
|
||||||
Vector2(1, 1),
|
Vector2(1, 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
uvs.set(i, quad_uv[i]);
|
uvs.set(i, quad_uv[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
p_arr[VS::ARRAY_VERTEX] = faces;
|
p_arr[VS::ARRAY_VERTEX] = faces;
|
||||||
p_arr[VS::ARRAY_NORMAL] = normals;
|
p_arr[VS::ARRAY_NORMAL] = normals;
|
||||||
p_arr[VS::ARRAY_TANGENT] = tangents;
|
p_arr[VS::ARRAY_TANGENT] = tangents;
|
||||||
p_arr[VS::ARRAY_TEX_UV] = uvs;
|
p_arr[VS::ARRAY_TEX_UV] = uvs;
|
||||||
};
|
}
|
||||||
|
|
||||||
void QuadMesh::_bind_methods() {
|
void QuadMesh::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_size", "size"), &QuadMesh::set_size);
|
ClassDB::bind_method(D_METHOD("set_size", "size"), &QuadMesh::set_size);
|
||||||
|
@ -1398,7 +1404,7 @@ void QuadMesh::_bind_methods() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QuadMesh::QuadMesh() {
|
QuadMesh::QuadMesh() {
|
||||||
primitive_type = PRIMITIVE_TRIANGLE_FAN;
|
primitive_type = PRIMITIVE_TRIANGLES;
|
||||||
size = Size2(1.0, 1.0);
|
size = Size2(1.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue