Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import bpy
- import bmesh
- import mathutils
- from bpy_extras import view3d_utils
- def get_3d_viewport_area():
- for area in bpy.context.screen.areas:
- if area.type == 'VIEW_3D':
- for region in area.regions:
- if region.type == 'WINDOW':
- return area, region
- return None, None
- def get_view_direction(region_3d):
- return -region_3d.view_rotation @ mathutils.Vector((0.0, 0.0, -1.0))
- def face_visible_on_screen(region, rv3d, face, obj):
- """Returns True if any vertex of the face is inside the viewport."""
- for vert in face.verts:
- world_co = obj.matrix_world @ vert.co
- screen_pos = view3d_utils.location_3d_to_region_2d(region, rv3d, world_co)
- if screen_pos:
- x, y = screen_pos
- if 0 <= x <= region.width and 0 <= y <= region.height:
- return True
- return False
- def select_offscreen_or_backfacing_inside():
- area, region = get_3d_viewport_area()
- if not area or not region:
- print("3D Viewport not found.")
- return
- space = next((s for s in area.spaces if s.type == 'VIEW_3D'), None)
- if not space:
- print("VIEW_3D space not found.")
- return
- rv3d = space.region_3d
- view_dir = get_view_direction(rv3d)
- obj = bpy.context.object
- if obj is None or obj.type != 'MESH':
- print("No mesh object selected.")
- return
- bpy.ops.object.mode_set(mode='EDIT')
- bm = bmesh.from_edit_mesh(obj.data)
- bm.faces.ensure_lookup_table()
- for f in bm.faces:
- f.select = False
- for face in bm.faces:
- normal_world = obj.matrix_world.to_3x3() @ face.normal
- dot = normal_world.normalized().dot(view_dir)
- is_backfacing = dot > 0.2
- is_onscreen = face_visible_on_screen(region, rv3d, face, obj)
- is_offscreen = not is_onscreen
- # ✅ Final logic
- if is_onscreen and not is_backfacing:
- face.select = True
- bmesh.update_edit_mesh(obj.data)
- print("Selected: offscreen OR backfacing onscreen faces.")
- select_offscreen_or_backfacing_inside()
Advertisement
Add Comment
Please, Sign In to add comment