Cg Programming/Unity/Mirrors

From Wikibooks, open books for an open world
Jump to: navigation, search
“Toilet of Venus”, ca. 1644-48 by Diego Rodríguez de Silva y Velázquez.

This tutorial covers the rendering of plane mirrors.

It does not require any shader programming but it does require some understanding of Section “Vertex Transformations” and of texturing as discussed in Section “Textured Spheres”.

Rendering Plane Mirrors[edit]

There are various ways of rendering plane mirrors in computer graphics. If rendering to textures is possible, the most common method consists of the following steps:

  • Mirror the main camera's position at the plane mirror and place a “mirror camera” at this mirrored position behind the mirror.
  • Render the scene from the point of view of the mirror camera using the mirror plane as view plane. Render this image to a render texture.
  • Use the render texture as texture of the mirror plane when rendering the scene with the main camera.

This is the basic method. Let's implement it.

Mirroring the main camera's position at a plane can be achieved in various ways. In Unity, one simple way is to transform the main camera's position into the object coordinate system of the plane. Then one can easily mirror this position by changing the sign of its coordinate. This mirrored position is then transformed back to world space. Here is a JavaScript that implements this process:

// This script should be attached to a Camera object 
// in Unity which acts as a mirror camera behind a 
// mirror. Once a Plane object is specified as the 
// "mirrorPlane" and a "mainCamera" is set, the script
// computes the mirrored position of the "mainCamera" 
// and places the script's camera at that position.

@script ExecuteInEditMode()
#pragma strict

public var mirrorPlane : GameObject;
public var mainCamera : Camera;

private var cameraComponent : Camera;

function Update() {
   cameraComponent = GetComponent(Camera);
   if (null != mirrorPlane && null != mainCamera 
      && null != cameraComponent)
   {
   
      var positionInMirrorSpace : Vector3 = 
         mirrorPlane.transform.InverseTransformPoint(
         mainCamera.transform.position);
      positionInMirrorSpace.y = -positionInMirrorSpace.y;
      cameraComponent.transform.position = 
         mirrorPlane.transform.TransformPoint(
         positionInMirrorSpace);
   }
}

The script should be attached to a new camera object (in the main menu choose Game Object > Camera). The mirrorPlane should be a set to a built-in Plane object that represents the mirror and mainCamera should be set to the main game camera.

To use the plane mirror as view plane, we can use the script in Section “Projection for Virtual Reality”, which should be attached to our new mirror camera. Change the start of the script to include the line @script ExecuteInEditMode(). Make sure to check setNearClipPlane such that objects entering the mirror are clipped. If there are artifacts at the intersection of objects with the mirror plane, decrease the parameter nearClipDistanceOffset until these artifacts disappear.

To store the rendered image of the mirror camera in a render texture, create a new render texture by selecting Create > Render Texture in the Project Window. In the Inspector Window, make sure the size of the render texture is not too small (otherwise the image in the mirror will appear pixelated). Once you have a render texture, select the mirror camera and, in the Inspector Window, set the Target Texture to the new render texture. You should now be able to see the image in the mirror in the Inspector Window of the render texture.

To use the render texture as texture image for the mirror, apply a shader with texturing to the mirror plane, e.g., the Standard shader or the shader Unlit/Texture. Use the render texture for texturing like any other texture object. Note that you might have to rotate the mirror plane such that its front face is visible to the main camera. By default, the texture image will appeare mirrored horizontally. However, there is an easy fix using the shader properties for textures: set the X coordinate of Tiling to -1 and the X coordinate of Offset to 1.

Limitations[edit]

There are several limitations of this implementation which we haven't addressed. For example:

  • multiple mirrors (you might have to share the same render texture for all mirrors)
  • multiple reflections in multiple mirrors (this is complicated because you need an exponentially increasing number of mirror cameras)
  • reflection of light in mirrors (each light source should have a mirrored partner to take light into account that is first reflected in the mirror before lighting an object)
  • uneven mirrors (e.g. with a normal map)
  • etc.

Summary[edit]

Congratulations! Well done. Some of the things we have looked at:

  • How to mirror positions at a plane by transforming them into the object coordinate system of the plane and changing the sign of the object coordinate.
  • How to render a camera view into a render texture.
  • How to use a mirrored render texture for texturing.

Further Reading[edit]

If you still want to know more

  • about using the stencil buffer to render mirrors, you could read Section 9.3.1 of the SIGGRAPH '98 Course “Advanced Graphics Programming Techniques Using OpenGL” organized by Tom McReynolds, which is available online.


< Cg Programming/Unity

Unless stated otherwise, all example source code on this page is granted to the public domain.