I am working on an ocean shader currently, and have everything working as expected, until I decided to see if I could make it translucent. I know there are many issues with translucency at the moment, but I have not come across any other threads with this specific issue.
First, here is a video showing my problem, note that the banding is worse on the left/right side of the mesh, and in the middle it seems to look just fine.
DFAO +LPV turned on (turning them off has no effect)
Not using refraction at this time
Switching TXAA/FXAA/None does not change the look at all
Set up uses the Gerstner wave formula from GPU Gems (equations 9-12), using 4x large & 4x small detail waves that both affect World Displacement & Normals
Rotating the direction the waves travel has no effect on the banding, it remains in the same direction
Standard mesh plane, 8192x8192 subdivided and scaled up 10x, with a standard flat plane UV applied, multiple meshes tested, all have the same issue
Tessellation (flat) and multiplier of 1
Turning off/on Separate Translucency (as well as all other translucent settings) has no effect
Turning on use 2 sided makes things worse
I have attached below my current setup for the base properties as they are now (video uses the values shown in image #2), and Normal & World Displacement wires go to the calculations for the waves. This issue only began when using translucency, with an opaque material there are no lines visible whatsoever, and nothing seems to make them disappear or even reduce the effect.
Any ideas on what might be causing this and/or any suggestions on a better approach to achieving translucency? Thanks!
I had a look through the thread and noticed that his issue was caused by Refraction. I have seen a similar issue to that before but I have turned Refraction off in my material until I get the banding issue fixed. Just to be sure, I did try adding in the refraction setup he has shown, but it had no effect on the banding issue.
So unfortunately this isn’t my issue, but thanks for the reply!
This is probably caused by the fact that transparent materials don’t write to the depth buffer. This means that when a closer wave is occluding a further wave, which one ends up on top depends on the order in which the GPU renders them. Fixing this is harder than it should be because Unreal doesn’t seem to have a depth only material domain and it doesn’t write custom depth for meshes with transparent materials. So you’ll need to make a few things: an opaque material that does your wave vertex displacement only, and a blueprint that has an extra ocean mesh component placed exactly on top of the original component, and a few extra nodes in your current ocean material. On the extra mesh, you want to use the opaque vertex displacement only material, mark it Render Custom Depth, and not Render in Main Pass. This will write your oceans mesh into the custom depth buffer. Now in your normal transparent ocean material, add these nodes to depth test against the custom depth buffer:
First of all, thank you for taking the time to create an example for me. Even better is the fact your method worked first try!
I have put together the 2 planes in a BP that I was working on (all parameters are adjustable from the BP) with a trimmed down version of the material, and everything worked as expected. I had to adjust the Custom node’s formula a bit however, as using .999 caused the ocean to disappear at the far end when zoomed out, with the boundary between giving off a lot of noise and flickering. Is there a minimum level you can recommend for this value? I have pulled it down to .8 and the issue goes away without affecting the wave depth test.
The only concern I have with this is the performance, I have noticed a fps reduction (basic 2k landscape, GTX 660 ti) from ~80 to ~70 fps, most of that is likely from using 2 planes, but how much performance concern is there for using a SceneTexture, is it similar to using a RenderTarget performance wise?
Thank you very much for your help on this, I thought it had something to do with rendering order but did not know how to fix it.
**Edit - One last question, with this method when using the Two Sided material setting, everything falls apart, and the banding issue becomes extreme. Is there a method aside from duplicating the meshes underneath to get around this?
The good news is that your use case means that pretty much any depth test will work well enough, try “CurrentDepth - CurrentDepth * 0.01 <= CustomDepth”. The bad news is that you’re bumping up against a fundamental problem in realtime 3d graphics, which is the problem of order independent transparency. Since UE4 doesn’t have OIT, you’ll have to do it the old fashioned and less accurate way with depth masking (which should still be ok for your use case). The problem is you need the normal depth buffer to do your depth fade in your material, which means you have to use a separate buffer to mask out your ocean mesh. There are faster ways than using custom depth in your material, but they all involve editing the engines rendering code.
If you set the ocean material to be two sided, you’ll need to set the vertex displacement material to be two sided as well.
Yeah I figured code would be required at some point here, for now I will tweak the values in my materials until I run into further issues. I tried the modified custom note value and it works great with the value mentioned above, I had to bump the previous value up to .95 as I noticed the issue re-appearing with any values lower than that. I will have to keep an eye on the release notes to see epic changes the the depth masking to OIT in the future, thanks for the info!
Doh! I thought I had done that, obviously I didn’t though…
Anything to do with Transluceny / Transparency or Alpha blending is problematic with deferred rendering… You need a FR (Forward Rendering) solution for it to work right as a multipass. I’ve not looked how Epic do things yet, but I can tell you now a TDS w / TFR is the best way to go:
Every ocean shader or the likes still looks like blue goo to me…
Hi, as far as I understand, you recommended to use 2 different materials, first one is the same with the original tessellated material on opaque domain, other one would be translucent with settings that you demonstrated with opacity connection.
I was using a blueprint based mesh already, added one static mesh component more and set new translucent material as its material. By your suggestion, I set the old original mesh with tesselated opaque material to “not render in main pass” and “render custom depth”, if I understand correctly. And other new mesh is set to “render in main pass”, “not render custom depth”.
Is there any other necessary connection in new translucent material? Probably it is, because it has not worked
The other question is, how do you connect these to materials together? I mean, first one is rendering data to custom depth buffer, the other one gets that and adds translucency. There should be a connection between them, or should not.
Hey Burak, I have been able to get this working so maybe I can help.
The first material is your original translucent water material, you need to add the nodes shown above and plug them into the opacity slot. Then take your nodes that were plugged into opacity slot and plug them into the first slot of the Multiply node shown above. You are now done with the setup for the translucent water material.
Next I created a new material and copied all of the nodes that were connected to the Displacement slot and pasted them in the new material, then hooked them up to Displacement, and add in the same tessellation settings as your original material. This should be all you need for this material.
Yes this sounds correct, one of the mesh with the translucent material applied and the other mesh with the opaque material, I left all the settings as default for the translucent mesh, and turned off render in main pass, and turned on render custom depth for the opaque material.
If you could post a screenshot of your setup I could try and help you debug it, you can also download the project I have linked below in my signature, it has a working version of this material setup that may help as well.
The connection is through the “SceneTexture : Custom Depth” node shown by TheBeej, the translucent material uses it to read from the Custom Depth buffer, and the other material is rendering to the Custom Depth buffer, this is how they are connected.
If you can’t get it to work, post some screenshots I can have a look for you.
It has been a year since the last post.
I was wondering if there had been any other solutions to the translucent water/depth artifact issues (see screenshot).
My issue happens at certain angles when there is a big swell
and buoys are down in the trough on the far side of that swell.
I am trying to avoid the double-mesh solution as I would prefer to avoid duplicate ocean meshes if possible, though I suspect there still aren’t any other solutions.
Also, does using the custom expression (HLSL) depth-check force the material to only be optimised for Windsows? I always avoided custom expressions because I was warned that there was no guarantee for cross-platform compatability, however, a depth test is pretty standard and should in theory be ok on other devices.
I also get the banding if I am close enough to the water surface.
The only immediate workaround I have is to keep the Gerstner wave amplitute down (no big swells) so the translucency artifacts don’t have time/space to present themselves.
I will try the recommended soluition above but let me know if there have been any other solutions since last year.
I didn’t have anything connected to my refraction node (not using it), so I added 0.9 as a test, unfortunately it doesn’t result in any improvement. I added a scalar parameter to refraction to test a range of values but it only makes the artifact worse by distorting the material.
Did your fix eliminate translucency artifacts completely or are they still there and you have to be conservative with your wave settings?
I believe I have everything set up precisely and even have a scalar param linked to the custom
depth node so I can tweak the *0.999 threshold. The parameter is working because ramping it up
gradually truncates the Z depth of the ocean.
My 2nd mesh/material is in sync with the main material, confirmed by toggling the pass/visibility.
Despite this, 0.0 to 0.999 has no effect on the artifacts.
I’m not sure if there is more that can be done or whether the artifacts you see (screenshot)
are the best I’ll get out of UE4 w.r.t the deferred rendering limitations.
I know this is an old post but I’m just wondering if the solution provided by [USER=“10934”]The Beej[/USER] would still be a good solution for this issue? Or has the engine been modified since the original post to make this more straight forward? (outside of now being able to write translucent materials to the depth buffer). Secondly - could anyone share any code/pseudocode for the HLSL in the custom node from the above BP example?
It is not a good a solution, yet still the only one available in stock engine. What changed since then, is that materials with translucent materials can write to custom depth and it is unnecessary to duplicate the object. Custom node code is there on the screenshot.