Portal-like mirror

I was working an implementing portals (as in the eponymous game), but nerd-sniped myself when it occurred to me that a similar method might work for a mirror (I also thought it might be easier to implement. :grinning: Hah! :crazy_face:) So…

Two portals, two cameras. Each portal has a camera pointing outwards and each portal surface is rendered by the other camera. Then some serious fiddling about.

One mirror, one camera. A single camera points outwards from the surface of the mirror and what it sees is rendered to the surface of the mirror.
I’ve given it the old college try and you can see the results here (https://playcanvas.com/project/872435/overview/portallike-mirror-public)

It’s vaguely in the right area, I get an image but it’s the wrong size, and seems to be from the wrong angle (two other issues are the sky box not rendering and the “reflection” is reversed without me even trying, but neither is really pertinent at this point).

The camera position mirrors* the player position, but I’m unsure where the camera should point. Should it point at the mirror, the player, or should it, too, mirror the player orientation?

Additionally, I suspect that I need to scale and clip the image before it’s rendered to the mirror surface, but I have no idea how to do so.
How do I scale an image before rendering?
How do I clip the image from the camera? Can clipping planes be applied? Do I need to clip the image before rendering or is it possible to set clipping planes on the camera?
Do I need to write a custom shader to do this?

Any help or useful suggestions gratefully received.

Hi @CarlBateman, that’s quite interesting! I haven’t looked at your project, posting this portal engine example here in case you haven’t seen it:


1 Like

Thanks, I’ve seen this but I’m not sure that it helps.

I think it would need an entirely different approach to the one I’m trying at the mo. :thinking:

1 Like

I think the issue (at least for now) is that the camera sees and renders this

But should only render what it sees within the black area.

1 Like

Maybe using a stencil buffer could help here?


1 Like

Having looked at that project and a few others, from what I can tell, the stencil masks off areas, discarding/not rendering them, resulting in something like this (please correct me if I’m wrong).

Whereas, I need the render to be cropped/triimed/resized, giving something like this.

Also, I can’t see how it would work with multiple cameras/layers. :cry:

The other thing you could do is change the offset and tiling properties on the material based on size of rge mirror on the screen?

Not sure how well that works when looking at it at an angle :thinking: maybe the UVs can be manipulated instead?

Edit: the more I think about it, changing the UVs would make more sense with the render texture for the reflection being the same aspect ratio as the browser window.

This isn’t a direct answer to your question, but there is this in-depth talk by Valve developers discussing how they overcame all sorts of problems while developing Portal. It’s a long talk but they cover some fascinating situations in detail that we don’t typically encounter in 3D game dev.

1 Like

I’ll check that out.

Yeesh! Despite some progress, I must admit this is doing in my noodle somewhat. :crazy_face:

So, I’ve tried to make things even simpler to visualise by trying to make a window using the same principles Which results in this.


It looks like the next step should be getting that inner blue area to render to the outer green area.
Most likely a scaling and UV issue, but I really have no idea where to even start. :scream: :question: :thinking:

A brief diversion for a bit of research.

I think the answer lies with a custom projection matrix and accompanying asymmetric frustum.

Now I just need to derive the matrix and the frustum. Easy. :scream:

1 Like

By the way, if you’re trying to set up mirror rendering, you don’t need off-center camera as discussed in a separate thread. You just need to reflect the camera position / facing by the mirror plane. The concept here is that the camera will not be positioned at the surface of the mirror, as you’re trying to do … but behind the mirror (same distance as the main camera is in front it it). I’m sure there are some online tutorials with detail explanations for this as well.

Unfortunately that won’t work. As can be see from the images above, the area seen by the camera is too big (and is offset, but that may not be clear from the images). I’m trying to reduce the area seen by the camera to the “area of interest” as indicated by the blue frame.

Ideally, this would be done by setting glViewport appropriately (I think) but (1) it isn’t exposed (2) the PlayCanvas viewport is normalised (3) I’m not sure the PlayCanvas viewport is the same as glViewport.

Also, see below.

White is the main camera viewport/frustum.
Green is the (much smaller) window camera’s “area of interest” desired viewport/frustum.

Well, I’ve made significant progress with the window (thanks in no small part to @mvaligursky’s help in a different thread).

It’s about 90%(?) done. Check it out (https://playcanvas.com/project/873297/overview/portallike-window).
It sort of works, but the scale and offset are off by a small factor, and I can’t figure out where I’ve gone wrong.

So, once again, I’m asking for any suggestions as what may be wrong and how to fix it.


1 Like

After quite a bit of research, I’d just about convinced myself that my approach was flawed due differences in the view render and the target texture being asymmetric and different shapes.

But after tweaking values I was able to get the result below, which looks pretty darn good.

There’s seems to be some non-linear factor or error I’m overlooking, but I have no idea what.

Help me, Obi Wan Kenobi! You’re my only hope!


I’ve made significant progress with the window… until… the player gets close and then it breaks :crazy_face:

Portal window video

A fudge factor is calculated in code, but it’s pretty much random numbers.

let fudge = dist * 1.5 + 0.625;
fudge = 1 + tFOV / fudge;
tFOV *= (180 / Math.PI);

I think I need to take a breath and try to understand what’s going on :thinking: :scream:

1 Like

Hi @CarlBateman! Sorry, I didn’t follow this topic, but could it be that the player is behind the camera at that point? If that’s the case you need to flip some values.

@Albertos Not really, the camera is attached to the player so can never be behind them.

Whoops! Another major issue.

When the player gets too close to the “window” surface, the rendered image becomes blurry (I know why, but I don’t want to come up with a fix until the other issues are sorted).

This looks fun!