Skip to content

Commit 8677866

Browse files
committed
Consider material's cull_mode
1 parent 93195f5 commit 8677866

File tree

4 files changed

+136
-7
lines changed

4 files changed

+136
-7
lines changed

core/math/triangle_mesh.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_en
290290
return inters;
291291
}
292292

293-
bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index, int32_t *r_face_index, bool p_ignore_backfaces) const {
293+
bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index, int32_t *r_face_index, CullMode p_cull_mode) const {
294294
if (!valid) {
295295
return false;
296296
}
@@ -339,9 +339,17 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V
339339

340340
if (f3.intersects_ray(p_begin, p_dir, &res)) {
341341
Vector3 face_normal = f3.get_plane().get_normal();
342-
if (p_ignore_backfaces && p_dir.dot(face_normal) >= 0) {
343-
// Skip this triangle.
344-
} else {
342+
real_t dot = p_dir.dot(face_normal);
343+
bool is_backface = dot >= 0;
344+
345+
bool skip_triangle = false;
346+
if (p_cull_mode == CULL_BACK && is_backface) {
347+
skip_triangle = true;
348+
} else if (p_cull_mode == CULL_FRONT && !is_backface) {
349+
skip_triangle = true;
350+
}
351+
352+
if (!skip_triangle) {
345353
real_t nd = n.dot(res);
346354
if (nd < d) {
347355
d = nd;

core/math/triangle_mesh.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,12 @@ class TriangleMesh : public RefCounted {
8585
public:
8686
bool is_valid() const;
8787
bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr, int32_t *r_face_index = nullptr) const;
88-
bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr, int32_t *r_face_index = nullptr, bool p_ignore_backfaces = false) const;
88+
enum CullMode {
89+
CULL_BACK = 0,
90+
CULL_FRONT = 1,
91+
CULL_DISABLED = 2,
92+
};
93+
bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr, int32_t *r_face_index = nullptr, CullMode p_cull_mode = CULL_BACK) const;
8994
bool inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale = Vector3(1, 1, 1)) const;
9095
Vector<Face3> get_faces() const;
9196

editor/scene/3d/node_3d_editor_gizmos.cpp

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@
3636
#include "editor/editor_string_names.h"
3737
#include "editor/scene/3d/node_3d_editor_plugin.h"
3838
#include "editor/settings/editor_settings.h"
39+
#include "scene/3d/mesh_instance_3d.h"
40+
#include "scene/3d/sprite_3d.h"
3941
#include "scene/resources/3d/primitive_meshes.h"
42+
#include "scene/resources/material.h"
43+
#include "scene/resources/mesh.h"
44+
#include "modules/csg/csg_shape.h"
4045

4146
#define HANDLE_HALF_SIZE 9.5
4247

@@ -751,6 +756,60 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
751756
}
752757

753758
if (!collision_meshes.is_empty()) {
759+
TriangleMesh::CullMode cull_mode = TriangleMesh::CULL_BACK;
760+
761+
GeometryInstance3D *geom = Object::cast_to<GeometryInstance3D>(spatial_node);
762+
if (geom) {
763+
Ref<Material> mat;
764+
BaseMaterial3D::CullMode material_cull_mode = BaseMaterial3D::CULL_BACK;
765+
766+
MeshInstance3D *mesh_inst = Object::cast_to<MeshInstance3D>(spatial_node);
767+
if (mesh_inst) {
768+
mat = mesh_inst->get_active_material(0);
769+
} else {
770+
// Override takes precedence.
771+
mat = geom->get_material_override();
772+
if (!mat.is_valid()) {
773+
SpriteBase3D *sprite = Object::cast_to<SpriteBase3D>(spatial_node);
774+
if (sprite) {
775+
if (sprite->get_draw_flag(SpriteBase3D::FLAG_DOUBLE_SIDED)) {
776+
material_cull_mode = BaseMaterial3D::CULL_DISABLED;
777+
}
778+
} else {
779+
// Each CSGShape has it's own get_material method.
780+
CSGPrimitive3D *csg_prim = Object::cast_to<CSGPrimitive3D>(spatial_node);
781+
if (csg_prim) {
782+
#define CHECK_CSG_TYPE(TypeName) \
783+
if (!mat.is_valid()) { \
784+
TypeName *csg = Object::cast_to<TypeName>(csg_prim); \
785+
if (csg) { \
786+
mat = csg->get_material(); \
787+
} \
788+
}
789+
790+
CHECK_CSG_TYPE(CSGBox3D)
791+
CHECK_CSG_TYPE(CSGSphere3D)
792+
CHECK_CSG_TYPE(CSGCylinder3D)
793+
CHECK_CSG_TYPE(CSGTorus3D)
794+
CHECK_CSG_TYPE(CSGPolygon3D)
795+
CHECK_CSG_TYPE(CSGMesh3D)
796+
797+
#undef CHECK_CSG_TYPE
798+
}
799+
}
800+
}
801+
}
802+
803+
if (mat.is_valid()) {
804+
Ref<BaseMaterial3D> base_mat = mat;
805+
if (base_mat.is_valid()) {
806+
material_cull_mode = base_mat->get_cull_mode();
807+
}
808+
}
809+
810+
cull_mode = static_cast<TriangleMesh::CullMode>(material_cull_mode);
811+
}
812+
754813
Transform3D gt = spatial_node->get_global_transform();
755814

756815
if (billboard_handle) {
@@ -764,7 +823,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
764823

765824
for (Ref<TriangleMesh> collision_mesh : collision_meshes) {
766825
if (collision_mesh.is_valid()) {
767-
if (collision_mesh->intersect_ray(ray_from, ray_dir, rpos, rnorm, nullptr, nullptr, true)) {
826+
if (collision_mesh->intersect_ray(ray_from, ray_dir, rpos, rnorm, nullptr, nullptr, cull_mode)) {
768827
r_pos = gt.xform(rpos);
769828
r_normal = gt.basis.xform(rnorm).normalized();
770829
return true;

scene/debugger/scene_debugger.cpp

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,18 @@
5454

5555
#ifndef _3D_DISABLED
5656
#include "scene/3d/camera_3d.h"
57+
#include "scene/3d/mesh_instance_3d.h"
58+
#include "scene/3d/sprite_3d.h"
5759
#ifndef PHYSICS_3D_DISABLED
5860
#include "scene/3d/physics/collision_object_3d.h"
5961
#include "scene/3d/physics/collision_shape_3d.h"
6062
#endif // PHYSICS_3D_DISABLED
6163
#include "scene/3d/visual_instance_3d.h"
6264
#include "scene/resources/3d/convex_polygon_shape_3d.h"
65+
#include "scene/resources/material.h"
66+
#include "scene/resources/mesh.h"
6367
#include "scene/resources/surface_tool.h"
68+
#include "modules/csg/csg_shape.h"
6469
#endif // _3D_DISABLED
6570

6671
SceneDebugger::SceneDebugger() {
@@ -2559,10 +2564,62 @@ void RuntimeNodeSelect::_find_3d_items_at_pos(const Point2 &p_pos, Vector<Select
25592564
Ref<TriangleMesh> mesh_collision = geo_instance->generate_triangle_mesh();
25602565

25612566
if (mesh_collision.is_valid()) {
2567+
TriangleMesh::CullMode cull_mode = TriangleMesh::CULL_BACK;
2568+
2569+
Ref<Material> mat;
2570+
BaseMaterial3D::CullMode material_cull_mode = BaseMaterial3D::CULL_BACK;
2571+
2572+
MeshInstance3D *mesh_inst = Object::cast_to<MeshInstance3D>(geo_instance);
2573+
if (mesh_inst) {
2574+
mat = mesh_inst->get_active_material(0);
2575+
} else {
2576+
// Override takes precedence.
2577+
mat = geo_instance->get_material_override();
2578+
2579+
if (!mat.is_valid()) {
2580+
SpriteBase3D *sprite = Object::cast_to<SpriteBase3D>(geo_instance);
2581+
if (sprite) {
2582+
if (sprite->get_draw_flag(SpriteBase3D::FLAG_DOUBLE_SIDED)) {
2583+
material_cull_mode = BaseMaterial3D::CULL_DISABLED;
2584+
}
2585+
} else {
2586+
CSGPrimitive3D *csg_prim = Object::cast_to<CSGPrimitive3D>(geo_instance);
2587+
// Each CSGShape has it's own get_material method.
2588+
if (csg_prim) {
2589+
#define CHECK_CSG_TYPE(TypeName) \
2590+
if (!mat.is_valid()) { \
2591+
TypeName *csg = Object::cast_to<TypeName>(csg_prim); \
2592+
if (csg) { \
2593+
mat = csg->get_material(); \
2594+
} \
2595+
}
2596+
2597+
CHECK_CSG_TYPE(CSGBox3D)
2598+
CHECK_CSG_TYPE(CSGSphere3D)
2599+
CHECK_CSG_TYPE(CSGCylinder3D)
2600+
CHECK_CSG_TYPE(CSGTorus3D)
2601+
CHECK_CSG_TYPE(CSGPolygon3D)
2602+
CHECK_CSG_TYPE(CSGMesh3D)
2603+
2604+
#undef CHECK_CSG_TYPE
2605+
}
2606+
}
2607+
}
2608+
}
2609+
2610+
if (mat.is_valid()) {
2611+
Ref<BaseMaterial3D> base_mat = mat;
2612+
if (base_mat.is_valid()) {
2613+
material_cull_mode = base_mat->get_cull_mode();
2614+
}
2615+
}
2616+
2617+
cull_mode = static_cast<TriangleMesh::CullMode>(material_cull_mode);
2618+
25622619
Transform3D gt = geo_instance->get_global_transform();
25632620
Transform3D ai = gt.affine_inverse();
25642621
Vector3 point, normal;
2565-
if (mesh_collision->intersect_ray(ai.xform(pos), ai.basis.xform(ray).normalized(), point, normal, nullptr, nullptr, true)) {
2622+
if (mesh_collision->intersect_ray(ai.xform(pos), ai.basis.xform(ray).normalized(), point, normal, nullptr, nullptr, cull_mode)) {
25662623
SelectResult res;
25672624
res.item = Object::cast_to<Node>(obj);
25682625
res.order = -pos.distance_to(gt.xform(point));

0 commit comments

Comments
 (0)