How to interact with linked libraries in depsgraph?

When looping through an evaluated depsgraph, what’s the recommended way to work with linked libraries? I can see the instancer object is passed through the depsgraph, but it has no concept of the object(s) it’s instancing. I’m working on a render engine add-on, so I’d need to be able to pull mesh objects to bake down geometry, lights to light the scene, etc. As far as I can tell there isn’t any established documentation on this yet.

To be a little more specific, I can send objects from the linked library to the render engine, but they seem to render at the origin of the scene at roughly 3x the scale than expected. If you move, scale, or rotate the instancer empty it has no effect on the linked group in the render.

If I “make instances real” but don’t make them local, they render as expected. It’s only when it’s still linked through the instancer that it’s a problem.

Linked libraries should make no difference to the depsgraph. I guess this is specifically about collection instances? Those can be either linked or local to a single .blend file.

In general use depsgraph.object_instances to iterate over all instances, and for each instance use matrix_world, instead of the original object matrix.
https://docs.blender.org/api/current/bpy.types.Depsgraph.html#bpy.types.Depsgraph.object_instances
https://docs.blender.org/api/current/bpy.types.DepsgraphObjectInstance.html

This makes sense, and it seems to line up with some tests I was doing last night after I posted.

I’m already iterating over depsgraph.object_instances, and using matrix_world to set the position of the mesh. The weird thing is, when rendering with collection instances, the world matrix that gets passed through the depsgraph for each object in the instance does not match the matrix I get when check in the interactive console. If I make instances real, the matrices match as expected.

For example, this is the matrix that gets passed to the depsgraph for a collection instance in my scene that has a single Suzanne head in it.

image

And this is what I get when I look in the interactive console.

image

For reference, here are the transformation values in the 3D view.

The moment I make the instance “real”, it works perfect fine. For what it’s worth, I’m testing on Blender 2.90.0 at the moment.

Afterthought: I think what’s happening is the matrix that’s being passed is the one the mesh holds in the original linked file. Is there something special I have to do to multiply it by the world matrix of the instancer?

I assume multiply it by object_instance.parent.matrix_world?

C.object.matrix_world is not intended to match the instance matrix in the depsgraph. It is not an instance of the object with associated transform, it’s the original object in its original location.

It should not be necessary to use object_instance.parent.matrix_world. The intent is to use object_instance.matrix_world where you would otherwise use object.matrix_world.

I really appreciate you taking the time to talk through it with me. One last clarifying question then.

In my render() function I try to distinguish between instances and emitting objects with:

for dup in depsgraph.object_instances:
    if dup.is_instance:
        ob = dup.instance_object
    else:
        ob = dup.object

Does that mean that dup.instance_object.matrix_world and dup.object.matrix_world are the same? I should be calling dup.matrix_world instead?

EDIT: It appears yes, using dup.matrix_world was the way to go here. So that’s solved. Now I’m facing an interesting problem where local meshes don’t render if there’s a linked datablock with the same name, but I don’t think it’s specifically related to this. I’ll do some more research and make a new post if I think it’s necessary.