RenderToCubemap issue

hi

I'm using a static camera to render a cubemap for use with a reflective shader on a material for mirror effects. The trouble is the cubemap shows that the camera only renders my terrain (created with the unity terrain editor) in one of the six images, and always the 'right' or +X image, all others show all other game objects but not the terrain.

I've checked my layers etc., but it all looks fine, and should be since it does render (on one image). Also used the same camera with a mouse look to check view from it at runtime and it seems fine.

Anyone else had this issue, or have any ideas?

Thanks

Are you using this script from the manual?

I've used this, and it works perfectly (renders all 6 sides, either every frame, or one side per frame, depending on which you choose).

I also added a couple of modifications which you might find useful:

  1. Modified to apply the cubemap reflection to any renderer on the object or on any child of the object which has a CubeMap texture slot, so that the same reflection could be used on multiple materials of the object (for example, on the paintwork,

  2. Added 'nearClip' and 'farClip' properties, to be able to set the reflection cam clipping planes in the inspector

  3. Added a 'layerMask' property, so that you can adjust the layers to be rendered in the inspector.

Here 's my modified version:

using UnityEngine;
using System;

// Attach this script to an object that uses a Reflective shader.
// Realtime reflective cubemaps!
[ExecuteInEditMode()]

class RenderCubemapReflection : MonoBehaviour
{
    public int cubemapSize = 128;
    public float nearClip = 0.01f;
    public float farClip = 500;
    public bool oneFacePerFrame = false;
    public LayerMask layerMask;
    private Camera cam;
    private RenderTexture rtex;

    void Start()
    {
        // render all six faces at startup
        UpdateCubemap(63);
    }

    void LateUpdate()
    {
        if (oneFacePerFrame)
        {
            int faceToRender = Time.frameCount % 6;
            int faceMask = 1 << faceToRender;
            UpdateCubemap(faceMask);
        }
        else
        {
            UpdateCubemap(63); // all six faces
        }
    }

    void UpdateCubemap(int faceMask)
    {
        if (!cam)
        {
            GameObject go = new GameObject("CubemapCamera", typeof(Camera));
            go.hideFlags = HideFlags.HideAndDontSave;
            go.transform.position = transform.position;
            go.transform.rotation = Quaternion.identity;
            cam = go.camera;
            cam.cullingMask = layerMask;
            cam.nearClipPlane = nearClip;
            cam.farClipPlane = farClip;
            cam.enabled = false;
        }

        if (!rtex)
        {
            rtex = new RenderTexture(cubemapSize, cubemapSize, 16);
            rtex.isPowerOfTwo = true;
            rtex.isCubemap = true;
            rtex.hideFlags = HideFlags.HideAndDontSave;
            foreach (Renderer r in GetComponentsInChildren<Renderer>())
            {
                foreach (Material m in r.sharedMaterials)
                {
                    if (m.HasProperty("_Cube"))
                    {
                        m.SetTexture("_Cube", rtex);
                    }
                }
            }
        }

        cam.transform.position = transform.position;
        cam.RenderToCubemap(rtex, faceMask);
    }

    void OnDisable()
    {
        DestroyImmediate(cam);
        DestroyImmediate(rtex);
    }
}

Update 4 (as good a solution as I think you're going to get): see http://answers.unity3d.com/questions/8881/water-in-cubemap Basically, you need to hack up both the cubemap and water scripts so the cubemap render doesn't trigger the water render at the wrong time, and mask the appropriate one out of the other depending on the effect you want. Interreflections will still be borked, no real way around it, but at least you get everything rendering, and even pick up "reflections" of one object in its reflections off the second, even if the reflected-reflected image may be utterly wrong.


I'm also having this problem. Stock Island Demo plus one sphere with the manual's real-time cubemap script. For me, the top (y+?) side renders and updates in real time, the rest of the sphere is black. On a new Radeon HD 5850, this is kinda disappointing...

For reference, I'm on Unity 2.6.1f3, Windows 7 64-bit, and the problem manifests in the development environment (game and scene windows), and in stand-alone exes on both this box and an older XP32 box (as stated in the comment).

Update: There appears to be something in the IslandWaterScript that is affecting rendering on other cubemap cameras. I turn off the script entirely, and I get full texturing on my sphere. I'll poke at this a bit more, but if it's not a pathological render-order corner-case artifact, there's a chance it's a bug in Unity that may need to be addressed.

Update2: Yep. That's it. Something in the engine is smart enough not to even try to render recursive reflections. When I'm above the (reflective) waterline, only the top of my cubemap renders, when I'm below the waterline, the sides and bottom render. Is there a quick-and-easy way to tell a temporary script camera not to bother rendering certain objects? With scene cameras I know I can just group/mask objects off...

Update3: I stole the camera.cullingMask line from the water script's disable-self-reflection clause and stuck it at the end of UpdateCubemap: if(!cam). I don't get the water in my sphere, now (of course), but it renders. If I were less lazy and this was more than a tech demo, I'd probably mask my sphere out of the water script instead.

private var m_ReflectLayers : LayerMask = -1;

//...

function UpdateCubemap (faceMask : int) {
    if (!cam) {
        var go = new GameObject ("CubemapCamera", Camera);
        go.hideFlags = HideFlags.HideAndDontSave;
        go.transform.position = transform.position;
        go.transform.rotation = Quaternion.identity;
        cam = go.camera;
        cam.farClipPlane = 100; // don't render very far into cubemap
        cam.enabled = false;

        cam.cullingMask = ~(1<<4) & m_ReflectLayers.value; // never render water layer
        }
//...
}

Can you post the code you are using?