I am trying to write a function that will return true if an object is visible in a rendered image, and false if it's blocked by another object (or not in the frame at all). To do so i have implemented the next function:

def is_mesh_visible(mesh_object, camera):
    # mesh_object is an Object object representing the mesh
    # camera is an Object object representing the camera
    # returns True if any part of the mesh is visible to the camera, False otherwise
    # get the dependency graph
    depsgraph = bpy.context.evaluated_depsgraph_get()
    # get the scene
    scene = bpy.context.scene
    # get the objects world matrix
    matrix_world = mesh_object.matrix_world
    # get the camera's near and far clipping distance
    near = camera.data.clip_start
    far = camera.data.clip_end
    # get the camera's view matrix and projection matrix
    view_matrix = camera.matrix_world.inverted()
    projection_matrix = camera.calc_matrix_camera(depsgraph, x=1, y=1)
    # iterate through the mesh vertices
    for vertex in mesh_object.data.vertices:
        # get the vertex's world coordinates
        vertex_world = matrix_world @ vertex.co
        # calculate the direction vector from the camera to the vertex
        direction = vertex_world - camera.location
        # cast a ray from the camera to the vertex
        result, location, normal, index, object, matrix = scene.ray_cast(depsgraph,
        # check if the ray hit anything
        if result:
            if object == mesh_object:
                # check if the ray hit the front face
                if normal.dot(direction) > 0: 
                    return True
    # no part of the mesh is visible
    return False

To check the function I have positioned a camera in the positions: location (-10,0,0.35), Rotation (90,0,-90)

I have checked my function with the next script:

def create_sphere(x, y, z, R=1/10, segments=16, rings=8, name=''):
    location = Vector((x, y, z))
    bpy.ops.mesh.primitive_uv_sphere_add(location=location, radius=R, segments=segments, ring_count=rings)
    sphere = bpy.context.active_object
    red_material = bpy.data.materials.new(name="RedMaterial")
    red_material.diffuse_color = (1, 0, 0, 1)
    if name:
        sphere.name = name
    return sphere

camera = bpy.data.objects.get("Camera")
a = create_sphere(0.0027, 0.01, 0.31, R=1 / 10, name='a')
b = create_sphere(0.03, -0.06, 0.35, R=1 / 10, name='b')
c = create_sphere(-0.03, -0.06, 0.35, R=1 / (10+0.001) , name='c')

print("camera", camera.location)
print("a",is_mesh_visible(a, camera))
print("b",is_mesh_visible(b, camera))
print("c",is_mesh_visible(c, camera))

I am not sure if this is the correct way to do so, but the function doesn't work properly... I would really appreciate any help in implementing this logic. Files can be found here - https://drive.google.com/drive/folders/1yAP5-HE48L-ov1mPekqque6tKIdCd9dc?usp=sharing



You must log in to answer this question.

Browse other questions tagged .