You will setup a SubViewport
(you would not need a container for it, since - I presume - it would not be shown), make sure its render mode and its clear mode are set to always. And the SubViewport
can have its own world (I'll get back to this).
Inside the SubViewport
you want to have a different Camera3D
, and (maybe) a copy of the character model with a material override (I'll get back to this). The material override must be an all white material, unshaded (and you can also have depth test disabled).
You need the clear color to be black. If the clear color in project settings is black, you are done. Otherwise, you can also set a WorldEnviroment
inside the SubViewport
and set its background to custom color and pick black (this only works if the SubViewport
has its own world). I suppose that as last resort you could have black quad match the view (which you can do by giving it a material that moves the vertex), and either have it match the far plane, or have the material override for the character has depth test disable.
You would - by script - keep the Camera3D
and character inside the SubViewport
synchronized. Copy their global_transform
in _process
, and any other relevant property (e.g. field of view of the camera). I suppose animations might be a challenge, depending how you are handling them for your character.
Could you use the same character instead of a copy? Sure, if you do not set the SubViewport
to have its own world, it will default to the same as the parent. However, since you need different materials, you will have to duplicate the meshes. To make one copy of the mesh show in the SubViewport
and another outside, give them different layers (it is under VisualInstance3D
), and then give matching cull masks to the Camera3D
s.
Then you can get the texture from the SubViewport
.If you need to set it in the Inspector (for example as a parameter of your canvas shader), pick ViewportTexture
and point it to the SubViewport
. Note: The SubViewport
needs to be first in the scene tree (before where you use the ViewportTexture
) so that during initialization the SubViewport
is created before the ViewportTexture
that references it. Alternatively, could also take a texture from the SubViewport
from a script.