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;

{

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;

{
playerMimic = new Node3D();
_mirrorMesh = GetParent() as MeshInstance3D;
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 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;

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!