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.

[smlsubform prepend=”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” showname=” mailinglist=”deathmatch-dungeon-pre”]

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)”

Comments are closed.