Creating real-time Mirrors in Unity Free (attempt 2)

OK, a completely different approach this time (based on the “new technique for Render to Texture” that I mentioned last time). And it works a lot better – lighting, shaders, etc is all there for free (but something is wrong with the side-to-side)

Note:

  1. The player model is a green cube “head” that can rotate up/down, and a blue cube body that can rotate left/right
  2. ALL LIGHTING ETC IS CORRECT, without needing to do anything
  3. when I’m looking at center of miror – from any angle – it appears 100% correct

What’s still wrong here…

I don’t understand why the mirror is wrong when you look away from the center. My best guess is that it’s something to do with Unity’s crappy (*) “Plane” class, that I’m using to answer the question “Where does line L intersect with plane P?”.

Ray rayToMirror = new Ray( objectBeforeMirror.transform.position, objectBeforeMirror.transform.forward );
planeOfMirror.Raycast( rayToMirror, out intersectionDistance );
Vector3 hitPoint = rayToMirror.GetPoint( intersectionDistance );
transform.LookAt( hitPoint );

How are you doing this?

In pseudo terms, because this is the most interesting bit, here’s what I did:

  1. Create a “mirror” plane in Unity
  2. Duplicate your main camera
  3. Remove EVERY COMPONENT from the duped camera (you only want the camera itself)
  4. Attach a mini script that moves the duped camera to the opposite side of the mirror, and re-positions it based on main-camera’s position … every frame
  5. Attach a tiny 1-line “DepthMask” Shader to the “mirror” so that it will “cut-out” of the game-world
  6. Set your camera “depths” so that main camera is rendered last (depth = 1), dupe camera is first (depth=0)
  7. Set your main camera to STOP clearing the screen every frame (set clear mode to “Depth”)
  8. … et voila!

Why are you doing this?

Because I can. And because: I’m planning an exciting game project where I’ll be hacking apart the whole of Unity’s rendering system to do as many weird tricks as I can. Stuff like this is helping me to learn how Unity abstracts the GL/D3D rendering – and what I can get away with.

If you're interested in the game I'm making - Deathmatch Dungeon - enter your email here and I'll contact you when I have some progress to share

And … it’s an interesting exercise just to see if I can do it at all – simply and high performance – without using RenderTexture (Unity’s implementation of Render to Texture)).

Of course, you should just buy Unity Pro instead; it has MANY improvements (including R-to-T).

My scripts so far

Move the duped camera – every frame – to opposite side of mirror

From: http://en.wikibooks.org/wiki/GLSL_Programming/Unity/Mirrors

NB: I have *heavily modified* the original – it did something weird with negative scales, and it got rotations mixed-up. I had to get the rotations precisely correct to make mine work, so … the rotations bit is different here.

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class MirrorMirrifyObject : MonoBehaviour
{
	public GameObject objectBeforeMirror;
	public GameObject mirrorPlane;
	
	void Update ()
	{
		if (null != mirrorPlane) {
			if (null != objectBeforeMirror) {
				transform.position = objectBeforeMirror.transform.position;
				transform.rotation = objectBeforeMirror.transform.rotation;
 
				Vector3 positionInMirrorSpace = mirrorPlane.transform.InverseTransformPoint( objectBeforeMirror.transform.position );
				
				positionInMirrorSpace.y = -positionInMirrorSpace.y;
								
				transform.position = mirrorPlane.transform.TransformPoint( positionInMirrorSpace );
				
				/** object is now in correct position, but looking in parallel look direction to original */
				/* So, cast a ray from the original object along look-direction until you hit the plane,
				 * then make the cloned object "look at" that position */
				Vector3 mirrorsNormal = mirrorPlane.transform.localRotation * new Vector3( 0f, 1, 0f ); // Unity planes always start with normal pointing up
				Plane planeOfMirror = new Plane(  mirrorsNormal, mirrorPlane.transform.position );
				float intersectionDistance;
				Ray rayToMirror = new Ray( objectBeforeMirror.transform.position, objectBeforeMirror.transform.forward );
				planeOfMirror.Raycast( rayToMirror, out intersectionDistance );
				Vector3 hitPoint = rayToMirror.GetPoint( intersectionDistance );
				
				transform.LookAt( hitPoint );
			}
		}
	}
}

Shader that makes an object “cut-out” a hole in the camera (depth-mask)

From: http://wiki.unity3d.com/index.php?title=DepthMask

NB: I tried some alternative versions of this that didn’t work
NB: *I have modified the original*. If you look at theirs, they do NOT want it to obscure the entire scene, but I did, so see how I moved it slightly higher in the render-queue…

Shader "Custom/DepthMask" {
 
	SubShader {
		// Render the mask BEFORE regular geometry, AND ALSO before masked geometry and
		// transparent things.
 
		Tags {"Queue" = "Geometry-10" }
 
		// Don't draw in the RGBA channels; just the depth buffer
                // ADAM: causes it to mask-out that part of the screen, and
                //       no further rendering will happen there
 
		ColorMask 0
		ZWrite On
 
		// Do nothing specific in the pass:
 
		Pass {}
	}
}

8 thoughts on “Creating real-time Mirrors in Unity Free (attempt 2)

  1. Pingback: new assets

  2. ghazali

    “Attach a mini script that moves the duped camera to the opposite side of the mirror, and re-positions it based on main-camera’s position … every frame”
    where is the mini script?? i try every step but it showing a warning “finish compile the script”
    can you help me. Thank you so much

  3. adam Post author

    @ghazali it’s in the post, right there, full source.

    If you can’t compile it, your version of Unity might be incompatible with the one I was using, in which case you’ll have to fix it yourself.

    PS: since no-one commented to point out the obvious problem I alluded to with my mirror view (obvious in the video above), think about what’s to the left of the viewer, and what appears to the left in the reflection…

  4. ghazali

    Ray rayToMirror = new Ray( objectBeforeMirror.transform.position, objectBeforeMirror.transform.forward );
    planeOfMirror.Raycast( rayToMirror, out intersectionDistance );
    Vector3 hitPoint = rayToMirror.GetPoint( intersectionDistance );
    transform.LookAt( hitPoint );

    that’s the mini script?? what version you use??

  5. adam Post author

    If you can’t debug it, I think this is the wrong solution for you – what I shared here needs additional coding to make a correct mirror. I suggest you use unity pro, or hire a unity coder to help. Sorry I can’t help

Leave a Reply

Your email address will not be published. Required fields are marked *