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,
camera.location,
direction)
# 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)
sphere.data.materials.append(red_material)
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