1
$\begingroup$

I am new to blender, I have an object that during the animation some armatures are going to be hidden by other parts, How I could find these hidden armatures? As you can see in the picture leftHandRing4 is not visible in the rendered image. https://imgur.com/a/g1HDLIN

My problem is different from Python: Check if vertex is on camera field of view, my armatures are just hidden by the other parts and they are still in the camera view.

$\endgroup$
5
  • $\begingroup$ Hi. What do you want to check exactly? If heads/tails are visible or if the bones in the shape they have are visible? $\endgroup$
    – lemon
    Sep 27 '20 at 9:43
  • $\begingroup$ Actually knowing if the head is visible or not $\endgroup$ Sep 27 '20 at 15:06
  • $\begingroup$ Similar to this blender.stackexchange.com/questions/77607/…. Also check the second answer by Debaditya. Note that there is a scene raycast too. $\endgroup$
    – lemon
    Sep 27 '20 at 15:08
  • $\begingroup$ So you want to find armature that are parent and inside meshes? Which other kind of cases (I've seen the picture you've added), I mean how are visible armatures? $\endgroup$
    – lemon
    Sep 27 '20 at 15:41
  • $\begingroup$ Yes, exactly, they are inside meshes and parent, as you can see in the picture leftHandRing4 is not visible in the rendered image. $\endgroup$ Sep 27 '20 at 15:46
0
$\begingroup$

you can go to the viewport display settings , and then check In front setting do that you can see the bones in the front of all the mesh enter image description here

$\endgroup$
0
$\begingroup$

Not totally sure this answer the question, but here is some code to check if an armature has bone heads visible by the camera.

The alternative way to understand the question could be: which armature is not totally enclosed by a mesh.

enter image description here

But, the principles of the script:

  • create and use a sphere that will be placed and scaled at bone heads locations
  • parse armature bones, place the sphere, raycast on it
  • if a bone is hit, the armature is visible by the camera
  • select visible armatures
  • delete the sphere

Here is the script:

import bpy
import bmesh
from mathutils import Vector
from bpy_extras.object_utils import world_to_camera_view

# Create a sphere that will be used to ray cast on
def create_sphere(view_layer, collection):
    
    mesh = bpy.data.meshes.new('sphere')

    bm = bmesh.new()
    bmesh.ops.create_uvsphere(bm, u_segments=32, v_segments=16, diameter=1)
    bm.to_mesh(mesh)
    bm.free()

    sphere = bpy.data.objects.new("sphere", mesh)

    collection.objects.link(sphere)
    view_layer.update()
    
    return sphere

# Sphere clean up
def delete_sphere(sphere):
    bpy.data.objects.remove(sphere, do_unlink=True)

# Test the armature visibility
def test_armature(scene, view_layer, camera, sphere, armature):
    world_matrix = armature.matrix_world

    # map the bones
    for bone in armature.pose.bones:
        head = bone.head
        tail = bone.tail
        # scales and places the sphere 
        # This ratio seems to be the one to have a sphere at the good scale
        factor = Vector(armature.scale) * 0.05
        sphere.scale = factor * (head - tail).length
        sphere.location = world_matrix @ head
        view_layer.update()
        
        # calculates the sphere location in camera view 
        co2D = world_to_camera_view( scene, camera, sphere.location )
        
        # if inside visible cone
        if 0.0 <= co2D.x <= 1.0 and 0.0 <= co2D.y <= 1.0:
            # ray cast from camera to sphere
            from_location = camera.location
            direction = (sphere.location - camera.location).normalized()
            hit, loc, norm, idx, ob, M = scene.ray_cast(
                        view_layer,
                        from_location,
                        direction)

            # if hit the sphere, head is visible
            if hit and ob == sphere:
                return True

    # No hit occured            
    return False 


camera = bpy.data.objects['Camera']
scene = bpy.context.scene
view_layer = bpy.context.view_layer

# Create the sphere to ray cast on
sphere = create_sphere(view_layer, bpy.context.scene.collection)

# Maps the armatures and select the ones that the camera can see
for armature in [obj for obj in scene.collection.all_objects if obj.type == "ARMATURE"]:
    visible = test_armature(scene, view_layer, camera, sphere, armature)
    armature.select_set(visible)

# Clean up the sphere
delete_sphere(sphere)

Test file:

Note: this script is basically a variation (eventually enhancement) of these answers from Debaditya and from myself).

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.