1
$\begingroup$
obj = bpy.context.active_object 

me = obj.data 
bm = bmesh.from_edit_mesh(me)
bvh = bvhtree.BVHTree.FromBMesh(bm)

matrix = obj.matrix_world
for face in bm.faces[:]:
    center = face.calc_center_median()
    v_2d = view3d_utils.location_3d_to_region_2d(
            region, rv3d, matrix @ center)
    v_3d = view3d_utils.region_2d_to_origin_3d(
            region, rv3d, v_2d)
    loc_3d = v_3d @ obj.matrix_local
    direction =  (center - loc_3d).normalized()
    # location, normal, index, distance
    _, _, index, _ = bvh.ray_cast(loc_3d, direction)
    if index == face.index:
        face.select_set(True)
bmesh.update_edit_mesh(me)

The model is subdivided into 4 levels

time cost: 2.458038568496704

enter image description here

The code above works fine, but if I make the ray_cast work in reverse:

obj = bpy.context.active_object 

me = obj.data 
bm = bmesh.from_edit_mesh(me)
bvh = bvhtree.BVHTree.FromBMesh(bm)
distance = obj.dimensions.length * 2
screen_normal = view3d_utils.region_2d_to_vector_3d(
            region, rv3d, (0,0))
direction = screen_normal * -1

matrix = obj.matrix_world
for face in bm.faces[:]:
    center = face.calc_center_median() + direction * 0.001
    # location, normal, index, distance
    _, _, index, _ = bvh.ray_cast(center, direction, distance)
    if index is None:
        face.select_set(True)
bmesh.update_edit_mesh(me)

The model is subdivided into 4 levels

time cost: 0.6839139461517334

enter image description here

The above code is not working properly

The first code needs to get the orthographic projection of each point as the starting point of the ray.

The second one uses the center of the face as the starting point of the ray. If no object is found, the face is visible, in theory.

Why doesn't the second one work as expected?

At first I thought it was caused by ray_cast not capturing the back face, after trying to flip the face normal, the result did not change.

$\endgroup$

1 Answer 1

0
$\begingroup$

I think i found the best solution:

import bpy
import bmesh
import time
from mathutils import Vector, bvhtree, Matrix
from bpy_extras import view3d_utils

import math
print("#"*72)
def get_view_regions(context):
    screen = context.screen
    view_region = None
    view_region_3d = None
    for a in screen.areas:
       if a.type == "VIEW_3D":
            view_region_3d = a.spaces[0].region_3d
            for reg in a.regions[:]:
                if reg.type == "WINDOW":
                    view_region = reg
                    break
            break
    return view_region, view_region_3d
def get_screen_normal(region, rv3d, coord):
    return view3d_utils.region_2d_to_vector_3d(
            region, rv3d, coord)
            
region, rv3d = get_view_regions(bpy.context)
obj = bpy.context.active_object 

start = time.time()


me = obj.data 
bm = bmesh.from_edit_mesh(me)
bvh = bvhtree.BVHTree.FromBMesh(bm)

matrix = obj.matrix_world

screen_normal = get_screen_normal(region, rv3d, (region.width // 2, region.height  2))


size = obj.dimensions.length 
distance = size * 2
matrix_local = obj.matrix_local
direction = screen_normal @ matrix_local
offset = direction * size * 1.5

print("time 0", time.time() - start)

for face in bm.faces[:]:
    end_point = face.calc_center_median()    
    start_point = end_point - offset
    direction =  (end_point - start_point).normalized()
    # location, normal, index, distance
    _, _, index, _ = bvh.ray_cast(start_point, direction, distance)
    if index == face.index:
        face.select_set(True)
print("time 1", time.time() - start)        
bmesh.update_edit_mesh(me)

The total number of faces after subdividing 4 times: 125,952

time cost: 0.572655200958252


It was my mistake, I ignored the transformation of the object

obj = bpy.context.active_object 

me = obj.data 
bm = bmesh.from_edit_mesh(me)
bvh = bvhtree.BVHTree.FromBMesh(bm)
distance = obj.dimensions.length * 2
screen_normal = view3d_utils.region_2d_to_vector_3d(
            region, rv3d, (0,0))
direction = (screen_normal * -1) @ obj.matrix_local
for face in bm.faces[:]:
    center = face.calc_center_median() + direction * 0.001
    location, _, index, _ = bvh.ray_cast(center, direction, distance)
    if index is None:
        face.select_set(True)

# select vertices
# for vert in bm.verts[:]:
#     center = vert.co + direction * 0.001
#     # location, normal, index, distance
#     _, _, index, _ = bvh.ray_cast(center, direction, distance)
#     if index is None:
#         vert.select_set(True)

bmesh.update_edit_mesh(me)

The above script is used to select the previous vertices enough, but the selection surface is not infallible. The problem is the offset distance:

center = face.calc_center_median() + direction * 0.001

I don't know how to explain it. If you are interested, try it yourself.

$\endgroup$

You must log in to answer this question.

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