THIS WILL ONLY WORK IN UNITY PRO
Had to make that warning pretty clear. This is a Unity limitation so there is no workaround for this.
Ok, so I've been looking into realtime reflections and the best I could find at the moment is realtime cubemap generation. The alternative is a post processing affect that pulls from buffer, but that's above my current experience.
The below PlayMaker action will generate cubemaps at realtime for the target object and update the shader as needed. It has built in optimization to prevent performance from dieing. Basically what it does is on start will populate all 6 sides then every 5 frames it'll populate 1 face. This keeps performance from going to crap while still giving realtime reflections. You can customize a lot of the camera properties from the playmaker action as well as debug it (helps to make sure your positioning is correct).
The camera generated to pull the cubemaps is added as a child object of the target object so all position/rotation supplied is local. This lets the cubemap generation follow the object (cars, marbles, etc..).
The action can also be used as a fire and forget usage. Meaning it'll generate the 6 sides then destroy the camera and end the action. This is good for static objects that you're reusing throughout your level and need each with their own cubemap.
using UnityEngine;
namespace HutongGames.PlayMaker.Actions {
[ActionCategory(ActionCategory.Camera)]
public class CameraRenderToCubemap : FsmStateAction {
[RequiredField]
public FsmOwnerDefault targetGameObject;
[ActionSection("Camera")]
public FsmVector3 position;
public FsmQuaternion rotation;
public FsmColor backgroundColor;
[RequiredField, HasFloatSlider(1,179)]
public FsmFloat fieldOfView;
[RequiredField]
public FsmFloat nearCipPlane;
[RequiredField]
public FsmFloat farClipPlane;
public FsmBool HDR;
[ActionSection("Culling")]
[UIHint(UIHint.Layer)]
public FsmInt[] cullingMask;
public FsmBool invertMask;
[ActionSection("Cubemap")]
[RequiredField]
public FsmInt cubemapSize;
[RequiredField]
public FsmString[] namedCubemaps;
[ActionSection("Realtime")]
public bool everyFrame;
public int frameDelay;
public bool oneFacePerFrame;
public bool debugCamera;
private GameObject target;
private GameObject camera;
private RenderTexture texture;
private int frames;
private int[] faces;
private int face;
public override void Reset() {
targetGameObject = null;
position = new FsmVector3 { UseVariable = true };
rotation = new FsmQuaternion { UseVariable = true };
backgroundColor = new FsmColor { UseVariable = true };
fieldOfView = new FsmFloat { Value = 60f };
nearCipPlane = new FsmFloat { Value = 0.01f };
farClipPlane = new FsmFloat { Value = 100f };
HDR = new FsmBool { Value = false };
namedCubemaps = new FsmString[1];
namedCubemaps[0] = new FsmString { Value = "_Cube" };
cubemapSize = new FsmInt { Value = 128 };
cullingMask = new FsmInt[0];
invertMask = false;
everyFrame = true;
frameDelay = 0;
oneFacePerFrame = true;
debugCamera = false;
faces = new int[6];
faces[0] = ( 1 << (int) CubemapFace.NegativeX ); // 2
faces[1] = ( 1 << (int) CubemapFace.NegativeY ); // 8
faces[2] = ( 1 << (int) CubemapFace.NegativeZ ); // 32
faces[3] = ( 1 << (int) CubemapFace.PositiveX ); // 1
faces[4] = ( 1 << (int) CubemapFace.PositiveY ); // 4
faces[5] = ( 1 << (int) CubemapFace.PositiveZ ); // 16
frames = 0;
face = 0;
}
public override void OnEnter() {
target = Fsm.GetOwnerDefaultTarget( targetGameObject );
if ( target == null ) {
return;
}
camera = new GameObject( "CubemapCamera", typeof( Camera ) );
camera.hideFlags = ( debugCamera ? HideFlags.DontSave : HideFlags.HideAndDontSave );
camera.transform.parent = target.transform;
camera.transform.localPosition = position.Value;
camera.transform.localRotation = rotation.Value;
camera.camera.backgroundColor = backgroundColor.Value;
camera.camera.cullingMask = ActionHelpers.LayerArrayToLayerMask( cullingMask, invertMask.Value );
camera.camera.fieldOfView = fieldOfView.Value;
camera.camera.nearClipPlane = Mathf.Min( 0.01f, nearCipPlane.Value );
camera.camera.farClipPlane = farClipPlane.Value;
camera.camera.hdr = HDR.Value;
camera.camera.enabled = false;
texture = new RenderTexture( cubemapSize.Value, cubemapSize.Value, 16 );
texture.isCubemap = true;
texture.hideFlags = HideFlags.HideAndDontSave;
if ( namedCubemaps.Length > 0 ) foreach ( FsmString namedCubemap in namedCubemaps ) {
target.renderer.material.SetTexture( namedCubemap.Value, texture );
}
camera.camera.RenderToCubemap( texture, 63 );
if ( ! everyFrame ) {
Object.Destroy( camera );
Finish();
}
}
public override void OnLateUpdate() {
if ( ( target == null ) || ( camera == null ) ) {
return;
}
if ( frameDelay > 0 ) {
if ( frames == frameDelay ) {
frames = 0;
} else {
frames++;
return;
}
}
if ( oneFacePerFrame ) {
camera.camera.RenderToCubemap( texture, faces[face] );
if ( face == 5 ) {
face = 0;
} else {
face++;
}
} else {
camera.camera.RenderToCubemap( texture, 63 );
}
}
public override void OnExit() {
if ( camera == null ) {
return;
}
Object.Destroy( camera );
}
}
}
Please understand I do not have time to provide support. I'm providing this as it was a nightmare for me to figure this out on my own and Unity documentation sucks. So hopefully this will reduce the pain and suffering for another.