[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