Matrix calculation for mirror Camera

Godot Version

v4.2.2.stable.mono.official [15073afe3]

Question

I’m trying to make mirrors for a game, as realistic as I can. I played around with reflection probes but too many of them were laggy (I need a lot of mirrors sometimes)
So I went back to the old classic: a camera pointing at the player.

Test scene is setup like this:
Level

  • Ground
  • Player
    • MainCamera
  • PlaneMirror
    • Subviewport
      • Camera

Problem: to make it realistic the camera would need to move and rotate in opposed sync with the player, using the mirror as its “pivot”
Looking everywhere, the closest I could find to what I wanted was an old unity tutorial for portal making: tuto. I thought “that’s what I’m doing except the entry and exit portal are the same plane, I just need to adjust for that”
And using it I got a result where the camera rotation was a perfect match, but not the position. The mirror camera would go to the center of the mirror and not move to match the player mouvements.
So I tried to tinker with positions etc, and I kinda got somewhere? But not really. It’s still not fully accurate.
I feel like I made a mess of the whole matrix thing and if I could figure it out it would solve most of the issues but I’ve no idea where to start.

using Godot;

public partial class MirrorCamera : Camera3D
{
	public Node3D playerCam;
    [Export] public Node3D _mirrorMesh;
    Transform3D _mirrorTransform;


	public override void _Ready()
	{
        
		playerCam = GetTree().Root.GetChild(0).FindChild("Player", true, false).GetNode<Node3D>("MainCamera");
        _mirrorTransform = _mirrorMesh.GlobalTransform;
	}

  public override void _Process(double delta)
    {
        //Calculate the reflection matrix
        Transform3D reflectionTransform = _mirrorTransform *  playerCam.GlobalTransform;
        GlobalTransform = reflectionTransform;
        float distanceZ = _mirrorMesh.GlobalPosition.Z - playerCam.GlobalPosition.Z;
        float distanceX = _mirrorMesh.GlobalPosition.X - playerCam.GlobalPosition.X;
        GlobalPosition = new Vector3(GlobalPosition.X + distanceX, playerCam.GlobalPosition.Y, _mirrorMesh.GlobalPosition.Z + distanceZ); 

    }

}

Thanks in advance to anyone that would take a look.

I found a solution after a loooong while of trying just about everything, and dusting some old geometry school notes.
Leaving the solution here if anyone want it:

using Godot;

public partial class MirrorCam : Node3D
{
	public Camera3D playerCam;
    public Node3D player;
    public MeshInstance3D _mirrorMesh;
    Node3D playerMimic;

	public override void _Ready()
	{
        playerMimic = new Node3D();
        _mirrorMesh = GetParent() as MeshInstance3D;
        GetParent().CallDeferred("add_child",playerMimic);
        player = GetTree().Root.GetChild(0).FindChild("Player") as Node3D;
		playerCam = player.GetNode<Camera3D>("MainCamera");
	}

  public override void _Process(double delta)
    {
        //PHYSIC CLASSES DE 5e MY OLD NEMESIS
        float angleOfIncidenceY = Mathf.RadToDeg(_mirrorMesh.GlobalRotation.Y- player.GlobalRotation.Y);
        float reflectiveY = -_mirrorMesh.GlobalRotation.Y - Mathf.DegToRad(angleOfIncidenceY);

        float angleOfIncidenceX = Mathf.RadToDeg(_mirrorMesh.GlobalRotation.X - playerCam.GlobalRotation.X);
        float reflectiveX = -_mirrorMesh.GlobalRotation.X - Mathf.DegToRad(angleOfIncidenceX);

        //Calculate the reflection rotation
        Vector3 reflection = new Vector3(reflectiveX, -reflectiveY, GlobalRotation.Z);
        GlobalRotation = reflection;

        //copy player mouvement rotation etc
        playerMimic.GlobalPosition = playerCam.GlobalPosition;

        //reflected position
        Position = new Vector3(playerMimic.Position.X, playerMimic.Position.Y, -playerMimic.Position.Z);
    }

}

And the shader that goes with it

shader_type spatial;
render_mode unshaded;

uniform sampler2D albedo:hint_default_black, source_color;

void fragment() {
    vec3 portal_color = texture(albedo, vec2(-SCREEN_UV.x, SCREEN_UV.y)).rgb;
    
    ALBEDO = portal_color;
}
3 Likes

Im also trying to implement mirrors, so I have two questions:

What do you need the shader for if you could just use a viewport texture?

Is there a way to only render the stuff in front of the mirror? I ran into the problem that a room behind the mirror was rendered as well, since the camera is moved behind the mirror.
Thanks!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.