Search code examples
3dgodot

Display different Materials/Textures on different Camera3Ds


My Godot 4 project has split-screen multiplayer. Each player gets a Camera3D and Viewport. Some 3D meshes need to appear semitransparent for one player, but solid for another - and vise versa.

Mock up. P2 can see through the 3D model of the house, but it is solid for P1. The opposite is true for the tree.

When I had just one camera, I could change the opacity of the Material's albedo. But that affects every camera at once. How can I accomplish having 2 different appearances for the same 3D mesh, depending on which camera is being used to view it?

I could duplicate the mesh, make the copy transparent, and give it a different cull_mask. But duplicating every single mesh in the game isn't feasible. I need to keep one mesh per object, and instead have different cameras see it differently. (Such as giving the mesh two materials and having each camera choose which material it sees. Or handling the effect via a shader.)


Solution

  • Use a ShaderMaterial that makes use of the CAMERA_VISIBLE_LAYERS keyword.

    Let's say Camera 1 should only see through Blue objects, and Camera 2 only see through Red. Here are the steps:

    1. Designate two unused Layers as Red Layer and Blue Layer. Do NOT put the meshes into these new Layers. I opted keep all meshes in a third one called Default Layer.
    2. Set the Cull Mask for Camera 1 to include Default Layer + Red Layer ...but not Blue Layer.
    3. Set the Cull Mask for Camera 2 to include Default Layer + Blue Layer ...but not Red Layer.
    4. Create a ShaderMaterial and apply it to all Red and Blue objects. The shader will have a cull_mask parameter. Set the parameter for red meshes to the binary value for Red Layer. Do the same for blue meshes.

    This line in the ShaderMaterial checks CAMERA_VISIBLE_LAYERS. If Red Layer is included, red meshes will appear solid. If not, they will be semitransparent.

    void fragment() {
        ALPHA = (int(CAMERA_VISIBLE_LAYERS) & cull_mask) == cull_mask ? 1. : .125;
    }
    

    Two cameras looking at the same scene. P1 can see through blue. P2 can see through red.

    To switch which meshes a Camera can see through on the fly, just change the cull_mask on the Camera itself.