- Home /
Water in cubemap
Does the built-in Water layer, particularly as it exists in the stock Island demo, have any special render handling?
I'm asking because I'm playing with real-time environment mapping (e.g. shiny chrome object) and while I can get cubemap rendering working correctly when I tell the cubemap camera not to render the water layer but keep the water reflection rendering the cubemapped object (meaning the object would show up in the water if it was ever in a position to, but the water doesn't show up on the object), the reverse fails. If I put the cubemapped object on its own layer, mask it off from the water camera/script/shader and try to render the water layer onto the cubemap (even with a custom cubemap shader set to the Overlay queue, and even playing with the camera depth so the cubemap is the last thing rendered before the screen)... any cubemap faces that point towards the water plane fail to render, even if they contain no actual water. It's as if Unity is actively preventing situations that might cause infinite reflection, even if I've manually headed off the possibility in my render order...
When set up in this manner, Unity also throws:
RenderTexture error: failed to retrieve color surface [invalid call] UnityEngine.Camera.Render()
on the reflectionCamera.Render() line of IslandWater.cs
(Unity 2.6.1f3, Pro license, under 64-bit Windows 7; Radeon HD 5850 if it matters)
From your description, and from similar experience myself, you are getting that error when the object cubemap is rendered (and so those faces fail to render) not the water cubemap being rendered, so I don't see how your "do the reverse" is doing anything other than simply not doing the former. i.e. you'll get the above error message whenever you have water in a camera render to cubemap.
I don't know why this is the case (it just "is" for me, and I'm avoiding the situation, in exactly the way you describe), so I'm interested in a full answer too.
exactly- if the water renders I-can-only-assume-before the object, the object's cubemap doesn't render the sides facing the water, unless I exclude the water layer from rendering. If I set up the water shader to exclude the cubemapped object's own personal layer, and/or do everything I can to try to get the real-time-cubemap camera to render after everything but the main camera... the object's cubemap ~still~ doesn't render the sides facing the water :P
There's an off chance, I suppose, that both being dynamic script-generated cameras, they render in the order the scripts execute regardless of their order setting, and I believe the dirty work in both is going on in LateUpdate, so it may be a question of specifying ~script~ execution order rather than anything camera-related.
oooookay. Tracing the call stack from the actual error log, looks like the cubemap script's RenderCube$$anonymous$$ap call is doing its thing and rendering everything including, if it's enabled, the water layer. Since the water's script triggers OnWillRender, the water being rendered by the cubemap runs the water's update script (which would normally not be touched until the main camera renders the scene after everything else is finalized), whereupon the reflectionCamera.Render() fails "unable to retrieve color surface," which propagates all the way back up and kills the cubemap capture.
Answer by sean · May 07, 2010 at 08:09 PM
Partial answer: Turns out this is a pathological interaction between a cubemap that captures a render at the end of the frame because it's set to, and a water layer that captures a render when it itself is rendered, which would normally happen at the end of the frame, but gets thrown off something fierce when it's the cubemap render that triggers it rather than the last-thing-ever-per-frame final screen camera render. The error itself may even be less related to reflections trying to render reflections and more due to a standard camera trying to clone its view parameters off a cubemap camera.
Setting the water script (and the cubemap script) to be LateUpdate rather than OnWillRender allows everything to happen sufficiently close to the end of the update that everything does render. The side-effect will be that when the water script flushes its cameras, the main screen render hasn't completed, which will throw additional errors. Even converting the OnDisables to OnPostRenders and throwing a yield WaitForEndOfFrame() (or in c#, yield return new WaitForEndOfFrame(); with the functin return changed from void to EIterator) doesn't seem to stave these off, probably because they happen relative to the cameras in the scripts rather than the final scene camera. But at least the scene renders...
Of course, while this does allow you to get full cubemap renders, and even (layers masked appropritately) reflections in one object visible reflected in another, such interreflections are themselves borked, and there's no way you're getting around that, I don't think, short of rendering a new reflection RT for ~each angle~ of the one object that you're seeing the second object's reflections of the scene in.
Your answer
![](https://koobas.hobune.stream/wayback/20220612194040im_/https://answers.unity.com/themes/thub/images/avi.jpg)