[Bf-blender-cvs] [6bb58ce] object_nodes: Boolean modifier node, based on the new bmesh boolean operations.

Lukas Tönne noreply at git.blender.org
Fri Dec 11 16:28:10 CET 2015


Commit: 6bb58ce842f620182cd9bdbfd38d444fa5d8a87f
Author: Lukas Tönne
Date:   Fri Dec 11 13:49:09 2015 +0100
Branches: object_nodes
https://developer.blender.org/rB6bb58ce842f620182cd9bdbfd38d444fa5d8a87f

Boolean modifier node, based on the new bmesh boolean operations.

===================================================================

M	release/scripts/nodes/geometry_nodes.py
M	source/blender/blenvm/bvm/CMakeLists.txt
M	source/blender/blenvm/bvm/bvm_eval.cc
M	source/blender/blenvm/bvm/bvm_eval_mesh.h
M	source/blender/blenvm/bvm/bvm_opcode.h
M	source/blender/blenvm/compile/bvm_nodegraph.cc

===================================================================

diff --git a/release/scripts/nodes/geometry_nodes.py b/release/scripts/nodes/geometry_nodes.py
index 65311a8..ea7f8e0 100644
--- a/release/scripts/nodes/geometry_nodes.py
+++ b/release/scripts/nodes/geometry_nodes.py
@@ -24,7 +24,7 @@ from bpy.types import Operator, ObjectNode, NodeTree, Node
 from bpy.props import *
 from nodeitems_utils import NodeCategory, NodeItem
 from mathutils import *
-from common_nodes import NodeTreeBase, NodeBase
+from common_nodes import NodeTreeBase, NodeBase, enum_property_copy, enum_property_value_prop
 import group_nodes
 
 ###############################################################################
@@ -216,6 +216,68 @@ class GeometryMeshDisplaceNode(GeometryNodeBase, ObjectNode):
         compiler.map_input(1, node.inputs["vector"])
         compiler.map_output(0, node.outputs["mesh_out"])
 
+
+class GeometryBooleanNode(GeometryNodeBase, ObjectNode):
+    '''Boolean operation with another mesh'''
+    bl_idname = 'GeometryBooleanNode'
+    bl_label = 'Boolean'
+
+    bl_id_property_type = 'OBJECT'
+    def bl_id_property_poll(self, ob):
+        return ob.type == 'MESH'
+
+    operation = enum_property_copy(bpy.types.BooleanModifier, "operation")
+    operation_value = enum_property_value_prop("operation")
+
+    use_separate = BoolProperty(name="Separate",
+                                description="Keep edges separate",
+                                default=False)
+    use_dissolve = BoolProperty(name="Dissolve",
+                                description="Dissolve verts created from tessellated intersection",
+                                default=True)
+    use_connect_regions = BoolProperty(name="Calculate Holes",
+                                       description="Connect regions (needed for hole filling)",
+                                       default=True)
+    threshold = FloatProperty(name="Threshold",
+                              default=0.0,
+                              min=0.0,
+                              max=1.0)
+
+    def draw_buttons(self, context, layout):
+        layout.template_ID(self, "id")
+        layout.prop(self, "operation")
+        layout.prop(self, "use_separate")
+        layout.prop(self, "use_dissolve")
+        layout.prop(self, "use_connect_regions")
+        layout.prop(self, "threshold")
+
+    def relations_update(self, depsnode):
+        if self.id is not None:
+            depsnode.add_object_relation(self.id, 'TRANSFORM')
+            depsnode.add_object_relation(self.id, 'GEOMETRY')
+
+    def init(self, context):
+        self.inputs.new('GeometrySocket', "")
+        self.outputs.new('GeometrySocket', "")
+
+    def compile(self, compiler):
+        if self.id is None:
+            return
+        
+        obkey = compiler.get_id_key(self.id)
+        obnode = compiler.add_node("OBJECT_LOOKUP")
+        obnode.inputs[0].set_value(obkey)
+        
+        node = compiler.add_node("MESH_BOOLEAN")
+        compiler.map_input(0, node.inputs[0])
+        compiler.link(obnode.outputs[0], node.inputs[1])
+        node.inputs[2].set_value(self.operation_value)
+        node.inputs[3].set_value(self.use_separate)
+        node.inputs[4].set_value(self.use_dissolve)
+        node.inputs[5].set_value(self.use_connect_regions)
+        node.inputs[6].set_value(self.threshold)
+        compiler.map_output(0, node.outputs[0])
+
 ###############################################################################
 
 class CurveNodeBase(NodeBase):
@@ -308,6 +370,7 @@ def register():
         GeometryNodeCategory("GEO_MODIFIER", "Modifier", items=[
             NodeItem("GeometryMeshArrayNode"),
             NodeItem("GeometryMeshDisplaceNode"),
+            NodeItem("GeometryBooleanNode"),
             ]),
         GeometryNodeCategory("GEO_CONVERTER", "Converter", items=[
             NodeItem("ObjectSeparateVectorNode"),
diff --git a/source/blender/blenvm/bvm/CMakeLists.txt b/source/blender/blenvm/bvm/CMakeLists.txt
index 97b0de2..31f8b08 100644
--- a/source/blender/blenvm/bvm/CMakeLists.txt
+++ b/source/blender/blenvm/bvm/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
 	../util
 	../../blenkernel
 	../../blenlib
+	../../bmesh
 	../../makesdna
 	../../makesrna
 	../../../../intern/guardedalloc
diff --git a/source/blender/blenvm/bvm/bvm_eval.cc b/source/blender/blenvm/bvm/bvm_eval.cc
index 81491bb..7756bae 100644
--- a/source/blender/blenvm/bvm/bvm_eval.cc
+++ b/source/blender/blenvm/bvm/bvm_eval.cc
@@ -826,6 +826,21 @@ void EvalContext::eval_instructions(const EvalGlobals *globals, const Function *
 				                      offset_elem_index, offset_elem_loc);
 				break;
 			}
+			case OP_MESH_BOOLEAN: {
+				StackIndex offset_mesh_in = fn->read_stack_index(&instr);
+				StackIndex offset_object = fn->read_stack_index(&instr);
+				StackIndex offset_operation = fn->read_stack_index(&instr);
+				StackIndex offset_separate = fn->read_stack_index(&instr);
+				StackIndex offset_dissolve = fn->read_stack_index(&instr);
+				StackIndex offset_connect_regions = fn->read_stack_index(&instr);
+				StackIndex offset_threshold = fn->read_stack_index(&instr);
+				StackIndex offset_mesh_out = fn->read_stack_index(&instr);
+				eval_op_mesh_boolean(globals, &kd, stack, offset_mesh_in,
+				                     offset_object, offset_operation,
+				                     offset_separate, offset_dissolve, offset_connect_regions,
+				                     offset_threshold, offset_mesh_out);
+				break;
+			}
 			
 			case OP_CURVE_PATH: {
 				StackIndex offset_object = fn->read_stack_index(&instr);
diff --git a/source/blender/blenvm/bvm/bvm_eval_mesh.h b/source/blender/blenvm/bvm/bvm_eval_mesh.h
index 7bf9f83..9159464 100644
--- a/source/blender/blenvm/bvm/bvm_eval_mesh.h
+++ b/source/blender/blenvm/bvm/bvm_eval_mesh.h
@@ -34,6 +34,12 @@
 
 extern "C" {
 #include "BLI_math.h"
+
+#include "DNA_object_types.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+#include "tools/bmesh_intersect.h"
 }
 
 #include "bvm_eval_common.h"
@@ -312,6 +318,168 @@ static void eval_op_mesh_displace(const EvalGlobals *globals, const EvalKernelDa
 	stack_store_mesh(stack, offset_mesh_out, result);
 }
 
+#if 0
+static DerivedMesh *boolean_get_quick_derivedMesh(DerivedMesh *derivedData, DerivedMesh *dm, int operation)
+{
+	DerivedMesh *result = NULL;
+
+	if (derivedData->getNumPolys(derivedData) == 0 || dm->getNumPolys(dm) == 0) {
+		switch (operation) {
+			case eBooleanModifierOp_Intersect:
+				result = CDDM_new(0, 0, 0, 0, 0);
+				break;
+
+			case eBooleanModifierOp_Union:
+				if (derivedData->getNumPolys(derivedData)) result = derivedData;
+				else result = CDDM_copy(dm);
+
+				break;
+
+			case eBooleanModifierOp_Difference:
+				result = derivedData;
+				break;
+		}
+	}
+
+	return result;
+}
+#endif
+
+/* has no meaning for faces, do this so we can tell which face is which */
+#define BM_FACE_TAG BM_ELEM_DRAW
+
+/**
+ * Compare selected/unselected.
+ */
+static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data))
+{
+	return BM_elem_flag_test(f, BM_FACE_TAG) ? 1 : 0;
+}
+
+static DerivedMesh *do_boolean(DerivedMesh *dm, DerivedMesh *dm_other, matrix44 &omat,
+                               bool separate, bool dissolve, bool connect_regions,
+                               int boolean_mode, float threshold)
+{
+	DerivedMesh *result = NULL;
+	BMesh *bm;
+	const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm, dm_other);
+
+//	TIMEIT_START(boolean_bmesh);
+	bm = BM_mesh_create(&allocsize);
+
+	DM_to_bmesh_ex(dm_other, bm, true);
+	DM_to_bmesh_ex(dm, bm, true);
+
+	if (1) {
+		/* create tessface & intersect */
+		const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
+		int tottri;
+		BMLoop *(*looptris)[3];
+
+		looptris = (BMLoop *(*)[3])MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__);
+
+		BM_bmesh_calc_tessellation(bm, looptris, &tottri);
+
+		/* postpone this until after tessellating
+		 * so we can use the original normals before the vertex are moved */
+		{
+			BMIter iter;
+			int i;
+			const int i_verts_end = dm_other->getNumVerts(dm_other);
+			const int i_faces_end = dm_other->getNumPolys(dm_other);
+
+			BMVert *eve;
+			i = 0;
+			BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+				mul_m4_v3(omat.data, eve->co);
+				if (++i == i_verts_end) {
+					break;
+				}
+			}
+
+			/* we need face normals because of 'BM_face_split_edgenet'
+			 * we could calculate on the fly too (before calling split). */
+			float nmat[4][4];
+			invert_m4_m4(nmat, omat.data);
+
+			BMFace *efa;
+			i = 0;
+			BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+				mul_transposed_mat3_m4_v3(nmat, efa->no);
+				normalize_v3(efa->no);
+				BM_elem_flag_enable(efa, BM_FACE_TAG);  /* temp tag to test which side split faces are from */
+				if (++i == i_faces_end) {
+					break;
+				}
+			}
+		}
+
+		/* not needed, but normals for 'dm' will be invalid,
+		 * currently this is ok for 'BM_mesh_intersect' */
+		// BM_mesh_normals_update(bm);
+
+		BM_mesh_intersect(
+		        bm,
+		        looptris, tottri,
+		        bm_face_isect_pair, NULL,
+		        false,
+		        separate,
+		        dissolve,
+		        connect_regions,
+		        boolean_mode,
+		        threshold);
+
+		MEM_freeN(looptris);
+	}
+
+	result = CDDM_from_bmesh(bm, true);
+
+	BM_mesh_free(bm);
+
+	result->dirty = (DMDirtyFlag)((int)result->dirty | DM_DIRTY_NORMALS);
+
+//	TIMEIT_END(boolean_bmesh);
+
+	return result;
+}
+
+#undef BM_FACE_TAG
+
+static void eval_op_mesh_boolean(const EvalGlobals *UNUSED(globals), const EvalKernelData *UNUSED(kernel_data), float *stack,
+                                 StackIndex offset_mesh_in, StackIndex offset_object, StackIndex offset_operation,
+                                 StackIndex offset_separate, StackIndex offset_dissolve,
+                                 StackIndex offset_connect_regions, StackIndex offset_threshold,
+                                 StackIndex offset_mesh_out)
+{
+	PointerRNA ptr = stack_load_pointer(stack, offset_object);
+	DerivedMesh *dm = stack_load_mesh(stack, offset_mesh_in);
+	
+	DerivedMesh *result = NULL;
+	if (ptr.data && RNA_struct_is_a(&RNA_Object, ptr.type)) {
+		Object *ob = (Object *)ptr.data;
+		DerivedMesh *dm_o

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list