Realtime reflections in Unity 5
March 8, 2015 | 11 comments

Realtime reflections in Unity 5

Here's a quick tutorial on how to create realtime reflections in Unity 5. This approach is very hacky, but you can use the new reflection probes in Unity 5 to easily create realtime reflections for something like a reflective floor.

You can probably use this for more things, like wall mirrors and multiple reflections in the same scene, but that would require quite a bit more scripting magic. This is just a quick and dirty way which can be used for something like the floor in an architectural visualization or similar. For more elaborate effects you should consider something like screen space reflections.

Scroll to the bottom if you just want to see the effect in action or download the project folder.

When you first fire up Unity 5 and look at the inspector for a reflection probe you notice that you can set the type to "Realtime" as well as set it to update every frame. You think that's neat and immediately try it out only to be hugely disappointed when it doesn't look like your reflection probe is updating in realtime at all. All the reflections are wonky and they don't line up with the geometry. It's not at all what you were expecting.

Image showing that reflection probes are not suited for realtime reflections by default
This doesn't look right. Why isn't it reflecting my balls? It's not realtime at all! Or is it?

But the reflection probe is actually updating every frame, it's just not what you, or at least I expected when I first tried it out. A reflection probe is sort of a point in space with 6 virtual cameras that render your scene from all directions and then assemble those 6 images into a cubemap. Your materials can query this cubemap for reflection data. At least that's how I think it works. By setting the reflection probe to realtime and the refresh mode to every frame you're telling Unity that you want a new cubemap generated every frame. The problem is that you're generating all these cubemaps at the probe's position. That's why things look wonky and don't line up. You want to generate these cubemaps from the position of the player's camera.

To accomplish this we need to write a small script which we attach to our reflection probe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using UnityEngine;
using System.Collections;
 
public class RealtimeReflection : MonoBehaviour {
    
    ReflectionProbe probe;
    
    void Awake() {
        probe = GetComponent<ReflectionProbe>();
    }
    
    void Update () {
        probe.transform.position = new Vector3(
            Camera.main.transform.position.x, 
            Camera.main.transform.position.y * -1, 
            Camera.main.transform.position.z
        );
 
        probe.RenderProbe();
    }
}

The above script makes sure the reflection probe is always positioned where the camera is, but at the "opposite" height. So if the camera is 1.8 meters above the floor then the reflection probe is 1.8 meters below it. That way it renders everything the player's camera sees except from the opposite side of the floor. It's sort of like the duplicate room mirror hack in very old games. Here I make the assumption that your floor is at y = 0. If your floor is at a different y-value you have to change the code to account for that, or move your floor.

I originally wanted to move just the origin for the probe so that the projection bounds would stay in place, but I wasn't able to do that easily through scripting. If you know how I would be interested to hear it. Basically the way I'm doing it here means you'll be moving the bounds with you so you must ensure that no matter where you move in your scene the bounds for the box projection encompass the area you want to reflect.

After attaching the script to your reflection probe you'll notice you get no reflections at all. This is because the reflection probe is now below the floor. How can it render what's going on above the floor when it can't see what's up there? To let the probe see through the floor we need to assign the floor to a layer and then uncheck that layer in the reflection probe's "Culling Mask" setting in the inspector.

Now things should start to look good. If you feel like the reflections are lagging behind when you move around you can change the "Time slicing" setting in the inspector to "No time slicing". You can check out the official documentation about reflection probes to see what time slicing is. I have put a link at the bottom. But basically it's a performance setting and "No time slicing" means: "Fuck it! I don't care about performance, I just want it to look good!".

Here are my reflection probe settings:

Image showing my reflection probe settings
The only important parts are the top 3 settings. The rest have nothing to do with this effect. At first I thought "Box Projection" had to be on, but it makes no difference apparently.

This is a massively expensive effect. You can bring even on a beastly machine to a halt with the simplest test scene if you set the reflection probe to render at 2048 resolution. After all you're rendering six 2048x2048 resolution textures every frame if I understand this correctly. Not something you want in a game. But I'm using 1024x1024 without problem in an architectural visualization scene I'm working on. And If you have blurry or rough reflections on your floor you can go much lower as well. 1024 or higher is just to get that perfect mirror look.

Obviously you could speed up this technique a ton if you were able to just render from 1 camera instead of 6. We don't need the left, right, back, forward and down cameras from the reflection probe because our probe is below the ground. We only care about the camera facing up. But that would probably require custom shaders and a bunch of scripting, ie. much more work than just using what we already have in a hacky way.

You can see that there are a number of limitations to this effect, but it's a neat trick which can come in handy. And perhaps it can be used in other ways as well. And you can of course use texture maps or glossy/rough reflections with this effect. I just thought the mirror effect was the most impressive for the example scene seeing as mirrors have forever been the bane of realtime graphics.

Check out an example webplayer here:
http://twiik.net/projects/realtime-reflection-example-scene

Or download the entire project folder here if you want to have a look:
http://twiik.net/sites/default/files/unity/project/real-time-reflections-1.0.1.zip

And lastly there's a massive entry in the official Unity documentation about reflection probes. It goes in detail about the different reflection probe types, refresh modes, time slicing and more:
http://docs.unity3d.com/Manual/class-ReflectionProbe.html

Øyvind Strømsvik's picture

About Øyvind Strømsvik (TwiiK)

I've been passionate about games all my life and started dabbling in game development about 15 years ago with BlitzBasic,... read more but I quickly lost interest and began doing 3d modeling instead. 3d modeling remained a hobby and I picked up game development again around the release of Unity 2.0. My driving force behind wanting to get back into game development was my lost interest in commercial games as they started appealing to a group of gamers I was no longer in. Indie games were the only games that still looked interesting, but at the same time some of them looked like they would be just as fun to make as to actually play. And many of them were made by just one guy.

Tagged with: 3D, Tutorial, Unity
Ziad's picture

Ziad

Nice workaround! The proper way to achieve this however is to use the mirror reflection shader available here:
http://wiki.unity3d.com/index.php/MirrorReflection4

However this new version targeting Unity 5 is giving me a 'could not find entry point' error. It used to work fine in Unity 4 so it's either a bug or may be I'm missing something. Right now my workaround is to use the 'Fx/Water' shader instead.

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Ziad: Yeah, I'm aware there are much better alternatives out there and by the look of things built in screen space reflections is not to far off. But it was just a fun thing to try out.

And the title is pure click bait. :p

Ziad's picture

Ziad

Ok, speaking of screen space reflections it's worth mentioning that there's an open source version available for everyone here:
https://github.com/kode80/kode80SSR

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Ziad: Neat, thanks. Just found it on the forums here as well:
http://forum.unity3d.com/threads/reflections-ssr.307670

Seems like it's fresh out of the oven. :p

Edit: Bleh, I need to do some more work on my commenting solution. :p

Cinder's picture

Cinder

Hey man,
So I was trying to get a real time mirror working in unity, and with the reflection probe API I eventually got it to work kind of. I took a break then found this post. It all kind of fell into place when I read through this because I realized why what I had done worked (which I didn't fully understand when I got it working) which let me make a simple script to make a dynamic mirror that can face any direction and behave how you'd expect. I have it all explained in this video here: https://www.youtube.com/watch?v=AmwfMpf499U&feature=youtu.be
But if you're just after the script it's here: http://thirdshiftgames.com/Downloads.html

Let me know what you think, Øyvind : ]

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Cinder: That's really cool. I was considering doing something like that myself, but the whole approach seemed so hacky I didn't want to take it any further.

I'm working on an architectural visualization at the moment where I want all the windows to behave realistically, ie. reflect things. This would require multiple reflective surfaces surrounding a room. Not sure how or if there is a way to accomplish that. Someone who knows their way around shaders or render textures could probably work it out, but I'm technically challenged. :p

Sorry about the late reply, I was messing about on my site and managed to turn of comment notifications for my own user. :/

Cinder's picture

Cinder

@Øyvind Strømsvik: I understand that. I think this is best for just set piece moments if you want a really perfect sheen.

And if you take this method, make the material transparent, then put a texture with about 50% opacity in the albedo texture spot, it gives a very realistic glass look. You see both the reflection and whatever is places behind your glass. If you don't need realtime reflections you can just bake this and it will look just fine and not be too taxing.

All of this could be accomplished with shaders I'm sure, but I'm still very new at writing them, so I stick to the Unity toys :P

Cinder's picture

Cinder

@Cinder:
oh and you need to turn the metallic to about .50 with the slider

Øyvind Strømsvik's picture

Øyvind Strømsvik

@Cinder: Thanks for the tips. I'll take them into consideration and I'll look at your scripts when I get home from work. :)

I'm far enough along with the arch viz project that I'll make a WIP thread on the Unity forums in a couple of days I guess. I will probably ask for advice on reflections in general if I haven't found satisfactory solutions by then.

GaryDave's picture

GaryDave

Hey man, I'm working on water at the moment and thought I'd give this a quick whirl to test a reflection, but I can't for the life of me get it working. I'm 80% sure I haven't done anything stupid. I have a flat plane with a standard shader (metallic and smoothness set to 1)

I have a reflection probe, with your script attached to it, and the same settings. Followed your other advice too (setting my plane in a layer and culling it in the reflection probe) But, when I press the play button I'm greeted with this:

NullReferenceException: Object reference not set to an instance of an object
RealtimeReflection.Update () (at Assets/Scripts/Textures/RealtimeReflection.cs:14)

Any ideas?

GaryDave's picture

GaryDave

@GaryDave:

Never mind! The programmer had set the camera to delete itself on play in that particular scene I was testing. fun fun.

Add new comment