Hi, I want to make a water shader and distort UV of what's behind the surface of the water. So far I did the grabPass and distort UV with a normalmap, but I have one problem. The border of the objects that are in front of the surface get distort too, like if the grabpass was taking not only what's on the back of the surface but what's in the front too. here's my code so far: Code (csharp): SubShader { Tags { "Queue" = "Transparent" } GrabPass {"_GrabTexture"} Pass { Name "GrabOffset" Cull Back ZWrite Off Blend Off CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest #include "UnityCG.cginc" sampler2D _GrabTexture; sampler2D _NormalMap; float4 _NormalMap_ST; float _Distortion; fixed4 _Color; struct appdata { float4 vertex : POSITION; float2 texcoord : TEXCOORD0; }; struct v2f { float4 pos : POSITION; float2 texcoord : TEXCOORD0; float4 GrabUV : TEXCOORD2; }; v2f vert (appdata v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.texcoord = TRANSFORM_TEX(v.texcoord, _NormalMap); o.GrabUV = ComputeGrabScreenPos(o.pos); return o; } fixed4 frag (v2f i) : COLOR { fixed3 bump = UnpackNormal(tex2D(_NormalMap, i.texcoord)); i.GrabUV.xy += bump * _Distortion; fixed4 refraction = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.GrabUV)); return fixed4(refraction.rgb,1) * _Color; } ENDCG } If someone can help me with that it would be appreciated! Thanks!
Code (csharp): SubShader { Tags { "Queue" = "Transparent" } GrabPass {"_GrabTexture"} Pass { Name "GrabOffset" Cull Back ZWrite Off Blend Off CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest #include "UnityCG.cginc" sampler2D _GrabTexture; sampler2D _NormalMap; float4 _NormalMap_ST; float _Distortion; fixed4 _Color; sampler2D _CameraDepthTexture; struct appdata { float4 vertex : POSITION; float2 texcoord : TEXCOORD0; }; struct v2f { float4 pos : POSITION; float2 texcoord : TEXCOORD0; float4 GrabUV : TEXCOORD2; }; v2f vert (appdata v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.texcoord = TRANSFORM_TEX(v.texcoord, _NormalMap); o.GrabUV = ComputeGrabScreenPos(o.pos); return o; } fixed4 frag (v2f i) : COLOR { fixed4 bump = fixed4(UnpackNormal(tex2D(_NormalMap, i.texcoord)),0); bump = normalize(bump); fixed4 DistUV = i.GrabUV + (bump * _Distortion); fixed4 refraction = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(DistUV)); fixed4 refractionN = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.GrabUV)); fixed refrFix = UNITY_SAMPLE_DEPTH(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(DistUV))); if(LinearEyeDepth(refrFix) < i.GrabUV.z) refraction = refractionN; return fixed4(refraction.rgb,1) * _Color; } ENDCG } }
I came across this thread with the exact same problem, however the solution posted by @rea doesn't seem to completely fix the issue for me. It does reduce the amount of distortion when an object is in front of the plane, however the object still seems to be influencing the surrounding pixels. I made sure my camera has Code (csharp): camera.depthTextureMode = DepthTextureMode.Depth; enabled and the depth texture seems correct when debug rendering it to the screen. I'm running on a Windows 8.1 machine with Unity 4.5.1f3 on an NVidia GTX770. At this point I'm pretty stuck. Any help would be great, thanks!
Yeah I haven't really fixed it either. adding the DepthTextureMode didn't seem to change anything for me. There is an article on nVidia's website about this, but I don't really know how to implement this in unity... http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter19.html
Thanks for the quick reply Phantomx! I'll give that article a read. Here are some screenshots to better explain what I'm seeing. I was going for a heat haze effect using a 3D camera-facing plane in the world, as opposed to a post process. As you can see from the last image, the pillar is still affecting the plane (albeit less), even though the plane is always behind the pillar.
I see, I must say in my case that it fixes it much better than this.I think the orientation of the plane has something to do with it, try an horizontal plane to see if it helps.
Digging this thread up from the grave, but I wanted to report that the problem seems to have mostly fixed itself after six months of development changes... Not sure exactly what did it, but the biggest changes we made (in order of most likely) over the past couple months were: Upgrading to Unity 4.6 (this did have other small side effects for our project so I wouldn't be surprised) Disabling default AA and replacing with Unity's ImageEffect AA Lots of game-specific camera code changes (ie, the distortion plane is now a distortion sphere with inward-facing normals that's childed to the camera with some custom rotation-restriction logic) Upgrading my graphics card drivers, finding a new distortion normal map texture, tweaking the shader values, etc. (exaggerated normal map for demonstration purposes. some artifacts can still be seen when zoomed)
The solution proposed in the second post here works perfectly well, dont know whats youre problem other than that
The solution in the second post doesn't work. While it removes most of refraction, it inevitably leaves ghost lines around borders. The cube on the screenshot is completely above the green plane with the refraction shader, and these artifacts are clearly visible. I'm looking for solution of this issue, too. I spent about two months trying every single refraction and distortion shader I found online (as well as trying to write my own solution), but all of them inevitably ended up with the "ghost lines" issue as seen in the picture...
Afaik that is how grabpass always work, if you don't want to deal with grabpass artifact you can use render texture with custom clipping plane (this is only work with planar shape) Oh just in case you guys having problem with unity 5.5+. Due unity using reverse z-buffer change this line Code (csharp): if(LinearEyeDepth(refrFix) < i.GrabUV.z) to this Code (csharp): if(LinearEyeDepth(refrFix) < i.GrabUV.w)
Tried right now. Doesn't make any difference. The same border issues. On my computer a lake with a render texture used for its surface to show refractions drops FPS to like 5-10, so it's not usable for any real applications. Grabpass refraction shader from above (or a similar one) produces around 40 FPS for the same scene (but with border refraction bugs). Since the shader correctly removes most of unwanted refractions above surface and leaves only very thin (but very annoying) artifacts around borders, maybe there is some solution on how to increase area around objects clearing unwanted refractions?
Depend on your GPU and how you setup your render texture. I use render texture for my water mostly, using the same shared refraction buffer also there's an advantage of using RTT in my opinion, - i can use it on Opaque Shader, to receive shadow and SSR - can be downsampled - can be post processed before applied to the material, mostly i used blur to get murky water
Of course it depends on GPU. Two times better GPU = two times better fps. Using grab pass instead of render textures = two times better fps. I can't install two times better GPU for every person playing my game, so I was hoping to go for the second route - which is using grab pass instead of render textures. Since there are only very thin outlines remaining, I suppose there is some kind of imprecision in calculations of pixels to be replaced with non-distorted versions. Maybe other people can provide further ideas for potential solutions. My own technical knowledge is not sufficient to even understand properly why this bug happens, unfortunately.