2
$\begingroup$

I am currently writing a python script to automate creation of flats from polygons. Currently I am trying to correctly identify the insides of the generated rooms. An example for a room looks like this:

enter image description here

Each wall is a generated mesh with six faces. Generally each wall has one to three faces that are pointed outwards or inwards at a time. I want to correctly identify the faces that are inside, to add different materials to them, or even add baseboards to the insides of the flat.

So my question now is: Is there a way to select all faces of each wall, that is a face that points inwards automatically, using Blender Python? (Like the example below)

enter image description here

$\endgroup$
4
  • $\begingroup$ Hello, it's not that straightforward since the wall parts don't look like they are connected. You can't check face neighbors to see if they are concave or convex. Did you apply the solidify modifiers ? $\endgroup$
    – Gorgious
    Commented May 3, 2021 at 16:22
  • $\begingroup$ Hi @Gorgious! It would be possible to join the walls into a single object pretty easily. Would it be easier then? I haven't tried the solidify modifiers, what would they do? $\endgroup$
    – aaronabebe
    Commented May 3, 2021 at 16:30
  • $\begingroup$ It would be possible but would require a bit of work, see the cross hatch on the wall in the lower right ? that's because there are 2 faces overlapping, and there is the same issue at each corner. Scratch that about the solidify modifier, that's not relevant $\endgroup$
    – Gorgious
    Commented May 3, 2021 at 16:52
  • 3
    $\begingroup$ Consider using scene raycast. blender.stackexchange.com/questions/192799/… in this example a raycast in direction of outer wall normal will hit nothing. (pre-hide any non contributing objects) $\endgroup$
    – batFINGER
    Commented May 3, 2021 at 16:59

1 Answer 1

4
$\begingroup$

So with the tip from @batFINGER I was able to build a solution using scene raycast.

for obj in bpy.data.objects:

            if 'wall_' in obj.name:
                bpy.context.view_layer.objects.active = obj

                mesh = obj.data
                bm = bmesh.new()
                bm.from_mesh(mesh)
                bm.faces.ensure_lookup_table()

                for i in range(len(bm.faces)):
                    mesh.polygons[i].select = False
                    face_location = bm.faces[i].calc_center_median()

                    # side face
                    if face_location[2] != self.wall_height and face_location[2] != 0:
                        hit, loc, norm, idx, ob, M = bpy.context.scene.ray_cast(
                            bpy.context.view_layer,
                            face_location + mesh.polygons[i].normal,
                            mesh.polygons[i].normal
                        )

                        if hit: 
                            mesh.polygons[i].select = True

                # toggle to edit mode
                bpy.ops.object.mode_set(mode='EDIT')

                # make sure face select mode is enabled
                bpy.context.tool_settings.mesh_select_mode = [False, False, True]

                # use second material slot
                obj.active_material_index = 2

                # assign the material
                bpy.ops.object.material_slot_assign()

                # toggle to object mode
                bpy.ops.object.mode_set(mode='OBJECT')

enter image description here

$\endgroup$
5
  • 1
    $\begingroup$ Good one. Quicker to set the face.material_index directly. $\endgroup$
    – batFINGER
    Commented May 7, 2021 at 19:31
  • $\begingroup$ Nice ! Side note, it fails in this configuration : i.sstatic.net/dHsLG.png (Concave rooms) $\endgroup$
    – Gorgious
    Commented May 14, 2021 at 17:23
  • 1
    $\begingroup$ Also, in newer versions of blender you need to pass the Depsgraph instead of the view layer as the first argument of ray_cast (eg bpy.context.scene.ray_cast( bpy.context.evaluated_depsgraph_get(),...) $\endgroup$
    – Gorgious
    Commented May 14, 2021 at 17:24
  • $\begingroup$ I wonder if this is still valid for Blender 3.3? I get an error "NameError: name 'self' is not defined". $\endgroup$ Commented Jan 31, 2023 at 9:34
  • $\begingroup$ @user2404987 the error probably stems from the reference to self.wall_height. i just copied an excerpt from the class i implemented it in. so to reuse this you would have to change some of the variables that reference things in my particular implementation. $\endgroup$
    – aaronabebe
    Commented Feb 14, 2023 at 13:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .