Hi there ! We're experiencing a strange issue with the Global Fog image effect. Top : without global fog, one particle system is rendered with a transparent shader, the other with a basic diffuse shader. Bottom : with global fog. The particle system rendered with the transparent shader is hidden by the global fog, despite the position of the emitter. Any idea for fixing this ?
Transparent shaders rarely write to the depth buffer, so fog in post process doesn't take their results into account. Unfortunately, writing to the depth buffer won't fix this issue, because fog won't be applied properly for the transparent parts of your particles. I'm not sure how this is dealt with.
The issue that you are encountering is as Daniel describes. Its quite an over site of the older Image effect system implementation. But the great news is ( I could hug the Devs at unity for doing this) that the Image effects in the latest 3.5 release can now be applied before transparent passes. Even cooler is that they now allow for Max and Min blend modes. This means in 3.5 it should be possible to draw your particles after the fog. With a bit of extra work put into your particle shaders you can get them to blend with the fog pretty well. Infact many very cool effects can be done. The unity Devs were pretty quiet about this feature, but its huge in my opinion.
Are you sure? How would you do this? I really want to use the crease image effect as it makes my game look really nice but the fact that it draws over my particles kind of ruins the whole look. I'm basically clueless about shaders.
Hello, I don't understand how to add the attribute ImageEffectOpaque to the OnRenderImage function . I have opened the file GlobalFog.js and I have found the OnRenderImage function but if I add the line "@script ImageEffectOpaque" inside the OnRenderImage function, it produces a syntax error. I have tried to add "@script ImageEffectOpaque" in the beginning of the file GlobalFog.js but all my particles systems and my 3d text meshes are still hidden by the fog. I think that I don't use the attribute ImageEffectOpaque correctly. Do you know how to use it?
Same problem here. Got no experience with shaders. Anyone got a more detailed solution? Gonna try to solve it anyway right now. Thanks.
here is my modified globalfog.It works transparent objects fine. Code (csharp): Shader "Hidden/MyGlobalFogShader" { Properties { _MainTex ("Base (RGB)", 2D) = "black" {} } CGINCLUDE #include "UnityCG.cginc" uniform sampler2D _MainTex; uniform sampler2D _CameraDepthTexture; uniform float _GlobalDensity; uniform float4 _FogColor; uniform float4 _StartDistance; uniform float4 _Y; uniform float4 _MainTex_TexelSize; // for fast world space reconstruction uniform float4x4 _FrustumCornersWS; uniform float4 _CameraWS; struct v2f { float4 pos : POSITION; float2 uv : TEXCOORD0; float4 interpolatedRay : TEXCOORD1; float2 uv2: TEXCOORD2; }; bool eq(float a,float b) { return abs(a-b) < 0.01; } v2f vert( appdata_img v ) { v2f o; float xx = v.texcoord.x; float yy = v.texcoord.y; float2 uv = v.texcoord.xy; o.uv = uv; #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) { uv.y = 1-uv.y; } else { yy = 1 - yy; } #endif int index = (int)floor(xx+yy*2 + 0.5); o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv2 = uv; o.interpolatedRay = _FrustumCornersWS[(int)index]; o.interpolatedRay.w = index; return o; } float ComputeFogForYAndDistance (in float3 camDir, in float3 wsPos) { float fogInt = saturate(length(camDir) * _StartDistance.x-1.0) * _StartDistance.y; float fogVert = max(0.0, (wsPos.y-_Y.x) * _Y.y); fogVert *= fogVert; return (1-exp(-_GlobalDensity*fogInt)) * exp (-fogVert); } half4 fragAbsoluteYAndDistance (v2f i) : COLOR { float dpth = Linear01Depth(UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture,i.uv2))); float4 wsDir = dpth * i.interpolatedRay; float4 wsPos = _CameraWS + wsDir; return lerp(tex2D(_MainTex, i.uv), _FogColor, ComputeFogForYAndDistance(wsDir.xyz,wsPos.xyz)); } half4 fragRelativeYAndDistance (v2f i) : COLOR { float dpth = Linear01Depth(UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture,i.uv2))); float4 wsDir = dpth * i.interpolatedRay; return lerp(tex2D(_MainTex, i.uv), _FogColor, ComputeFogForYAndDistance(wsDir.xyz, wsDir.xyz)); } half4 fragAbsoluteY (v2f i) : COLOR { float dpth = Linear01Depth(UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture,i.uv2))); float4 wsPos = (_CameraWS + dpth * i.interpolatedRay); float fogVert = max(0.0, (wsPos.y-_Y.x) * _Y.y); fogVert *= fogVert; fogVert = (exp (-fogVert)); return lerp(tex2D( _MainTex, i.uv ), _FogColor, fogVert); } half4 fragDistance (v2f i) : COLOR { float dpth = Linear01Depth(UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture,i.uv2))); float4 camDir = ( dpth * i.interpolatedRay); float fogInt = saturate(length( camDir ) * _StartDistance.x - 1.0) * _StartDistance.y; return lerp(_FogColor, tex2D(_MainTex, i.uv), exp(-_GlobalDensity*fogInt)); } ENDCG SubShader { Pass { ZTest Always Cull Off ZWrite Off Fog { Mode off } CGPROGRAM #pragma vertex vert #pragma fragment fragAbsoluteYAndDistance #pragma fragmentoption ARB_precision_hint_fastest ENDCG } Pass { ZTest Always Cull Off ZWrite Off Fog { Mode off } CGPROGRAM #pragma vertex vert #pragma fragment fragAbsoluteY #pragma fragmentoption ARB_precision_hint_fastest ENDCG } Pass { ZTest Always Cull Off ZWrite Off Fog { Mode off } CGPROGRAM #pragma vertex vert #pragma fragment fragDistance #pragma fragmentoption ARB_precision_hint_fastest ENDCG } Pass { ZTest Always Cull Off ZWrite Off Fog { Mode off } CGPROGRAM #pragma vertex vert #pragma fragment fragRelativeYAndDistance #pragma fragmentoption ARB_precision_hint_fastest ENDCG } } Fallback off } Code (csharp): using UnityEngine; using System.Collections; public class MyGlobalFog : MonoBehaviour { void Start () { } [ImageEffectOpaque] void OnRenderImage(RenderTexture source, RenderTexture destination) { DrawFog(source, destination); } //fog script public enum FogMode { AbsoluteYAndDistance = 0, AbsoluteY = 1, Distance = 2, RelativeYAndDistance = 3, } public bool bEnableFog = true; public FogMode fogMode = FogMode.AbsoluteYAndDistance; private float CAMERA_NEAR = 0.5f; private float CAMERA_FAR = 50.0f; private float CAMERA_FOV = 60.0f; private float CAMERA_ASPECT_RATIO = 1.333333f; public float startDistance = 200.0f; public float globalDensity = 1.0f; public float heightScale = 100.0f; public float height = 0.0f; public Color globalFogColor = Color.grey; public Shader fogShader; private Material fogMaterial = null; void DrawFog(RenderTexture source, RenderTexture destination) { if (!bEnableFog) { Graphics.Blit(source, destination); return; } if (fogMaterial == null) { fogMaterial = new Material(fogShader); } CAMERA_NEAR = camera.nearClipPlane; CAMERA_FAR = camera.farClipPlane; CAMERA_FOV = camera.fieldOfView; CAMERA_ASPECT_RATIO = camera.aspect; Matrix4x4 frustumCorners = Matrix4x4.identity; //Vector4 vec; //Vector3 corner; float fovWHalf = CAMERA_FOV * 0.5f; Vector3 toRight = camera.transform.right * CAMERA_NEAR * Mathf.Tan(fovWHalf * Mathf.Deg2Rad) * CAMERA_ASPECT_RATIO; Vector3 toTop = camera.transform.up * CAMERA_NEAR * Mathf.Tan(fovWHalf * Mathf.Deg2Rad); Vector3 topLeft = (camera.transform.forward * CAMERA_NEAR - toRight + toTop); float CAMERA_SCALE = topLeft.magnitude * CAMERA_FAR / CAMERA_NEAR; topLeft.Normalize(); topLeft *= CAMERA_SCALE; Vector3 topRight = (camera.transform.forward * CAMERA_NEAR + toRight + toTop); topRight.Normalize(); topRight *= CAMERA_SCALE; Vector3 bottomRight = (camera.transform.forward * CAMERA_NEAR + toRight - toTop); bottomRight.Normalize(); bottomRight *= CAMERA_SCALE; Vector3 bottomLeft = (camera.transform.forward * CAMERA_NEAR - toRight - toTop); bottomLeft.Normalize(); bottomLeft *= CAMERA_SCALE; frustumCorners.SetRow(0, topLeft); frustumCorners.SetRow(1, topRight); frustumCorners.SetRow(2, bottomRight); frustumCorners.SetRow(3, bottomLeft); fogMaterial.SetMatrix("_FrustumCornersWS", frustumCorners); fogMaterial.SetVector("_CameraWS", camera.transform.position); fogMaterial.SetVector("_StartDistance", new Vector4(1.0f / startDistance, (CAMERA_SCALE - startDistance))); fogMaterial.SetVector("_Y", new Vector4(height, 1.0f / heightScale)); fogMaterial.SetFloat("_GlobalDensity", globalDensity * 0.01f); fogMaterial.SetColor("_FogColor", globalFogColor); CustomGraphicsBlit(source, destination, fogMaterial, (int)fogMode); } static void CustomGraphicsBlit(RenderTexture source, RenderTexture dest, Material fxMaterial, int passNr) { Graphics.Blit(source, dest, fxMaterial, passNr); /* RenderTexture.active = dest; fxMaterial.SetTexture("_MainTex", source); GL.PushMatrix(); GL.LoadOrtho(); fxMaterial.SetPass(passNr); GL.Begin(GL.QUADS); GL.MultiTexCoord2(0, 0.0f, 0.0f); GL.Vertex3(0.0f, 0.0f, 3.0f); // BL GL.MultiTexCoord2(0, 1.0f, 0.0f); GL.Vertex3(1.0f, 0.0f, 2.0f); // BR GL.MultiTexCoord2(0, 1.0f, 1.0f); GL.Vertex3(1.0f, 1.0f, 1.0f); // TR GL.MultiTexCoord2(0, 0.0f, 1.0f); GL.Vertex3(0.0f, 1.0f, 0.0f); // TL GL.End(); GL.PopMatrix(); */ } }
This solution doesn't seem to work at all for me in either 3 or 4. No fog. Too bad, because it looked so promising! Does it work for anyone else? Any ideas why?
Hi Bren, just write @ImageEffectOpaque in the line just before the function OnRenderImage of the GlobalFog.js script. It should work. Also take a look at the EdgeDetectEffectNormals.js script , @ImageEffectOpaque is present there in the right location. Turi
make sure its the global fog shader file and not the js file you are editing, I just got it to work but made this mistake at first. I just copied and pasted the sample provided in this thread over the original in monodevelop.
Does anyone know what was meant by this, or have any ideas about this? I am somewhat savvy with shaders, but am pretty new to particle effects. What is the idea behind this?
I also try to find a fix for this GlobalFog Problem. I actually managed to make my particle Effects irgnore the GlobalFog by adding the attribute to the js OnRender Function: Code (csharp): @ImageEffectOpaque function OnRenderImage (source : RenderTexture, destination : RenderTexture) { But now I have an unwanted side effect: all particle effects seem to ignore opaque geometry now... they are always drawn on top. All I do is comment / uncomment the @ImageEffectOpaque attribute in the GlobalFog.js file to make it appear / disappear. Anyone got an idea what is going on here? Thanks Gian-Reto
Having the exact same problem. Same with transparent geometry, such as glass windows. It seems like @ImageEffectOpaque attrib causes it to clear the depth buffer, thus allowing trans geom to draw over opaque stuff it's not supposed to?
Ah, I fixed the issues using @ywq's modifications. Mainly, add @ImageEffectOpaque (makes it render fog before transparent things), and also very important is his mod to the CustomGraphicsBlit function - or rather, do NOT use that. I think using Graphics.Blit properly copies over the depth buffer, thus avoiding the issue of transparent stuff drawing over everything. This should solve @gian-reto alig's problem.
@ywq, Your reworked version did solve my sorting issue, however, with your code, the fog is not drawn correctly when the camera is rolled (rotated along its Z axis). Here are some shots to illustrate... When the camera is not rotated, the fog is drawn correctly. Here the camera is rotated along its Z Axis. Note the fog is drawn on the right hand side of the screen, not aligned with the horizon. Do you (or does anyone else) have any suggestions on how to get this fog script to align with the horizon? Cheers!
Hi all, I've actually managed to fix this after being pointed in the right direction by a helpful soul on Twitter. The issue was quite simple in the end; the bottom two frustum corners in ywq's script were reversed. Swapping these back around solved the rotation issue. Since I also had to exclude the Flash renderer to get it to work without errors, here are my two modified versions of ywq's scripts. They work 100% perfectly for me. AlphaSortedGlobalFog.shader Code (csharp): Shader "Hidden/AlphaSortedGlobalFog" { Properties { _MainTex ("Base (RGB)", 2D) = "black" {} } CGINCLUDE #include "UnityCG.cginc" #pragma exclude_renderers flash uniform sampler2D _MainTex; uniform sampler2D _CameraDepthTexture; uniform float _GlobalDensity; uniform float4 _FogColor; uniform float4 _StartDistance; uniform float4 _Y; uniform float4 _MainTex_TexelSize; // for fast world space reconstruction uniform float4x4 _FrustumCornersWS; uniform float4 _CameraWS; struct v2f { float4 pos : POSITION; float2 uv : TEXCOORD0; float4 interpolatedRay : TEXCOORD1; float2 uv2: TEXCOORD2; }; bool eq(float a,float b) { return abs(a-b) < 0.01; } v2f vert( appdata_img v ) { v2f o; float xx = v.texcoord.x; float yy = v.texcoord.y; float2 uv = v.texcoord.xy; o.uv = uv; #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) { uv.y = 1-uv.y; } else { yy = 1 - yy; } #endif int index = (int)floor(xx+yy*2 + 0.5); o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv2 = uv; o.interpolatedRay = _FrustumCornersWS[(int)index]; o.interpolatedRay.w = index; return o; } float ComputeFogForYAndDistance (in float3 camDir, in float3 wsPos) { float fogInt = saturate(length(camDir) * _StartDistance.x-1.0) * _StartDistance.y; float fogVert = max(0.0, (wsPos.y-_Y.x) * _Y.y); fogVert *= fogVert; return (1-exp(-_GlobalDensity*fogInt)) * exp (-fogVert); } half4 fragAbsoluteYAndDistance (v2f i) : COLOR { float dpth = Linear01Depth(UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture,i.uv2))); float4 wsDir = dpth * i.interpolatedRay; float4 wsPos = _CameraWS + wsDir; return lerp(tex2D(_MainTex, i.uv), _FogColor, ComputeFogForYAndDistance(wsDir.xyz,wsPos.xyz)); } half4 fragRelativeYAndDistance (v2f i) : COLOR { float dpth = Linear01Depth(UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture,i.uv2))); float4 wsDir = dpth * i.interpolatedRay; return lerp(tex2D(_MainTex, i.uv), _FogColor, ComputeFogForYAndDistance(wsDir.xyz, wsDir.xyz)); } half4 fragAbsoluteY (v2f i) : COLOR { float dpth = Linear01Depth(UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture,i.uv2))); float4 wsPos = (_CameraWS + dpth * i.interpolatedRay); float fogVert = max(0.0, (wsPos.y-_Y.x) * _Y.y); fogVert *= fogVert; fogVert = (exp (-fogVert)); return lerp(tex2D( _MainTex, i.uv ), _FogColor, fogVert); } half4 fragDistance (v2f i) : COLOR { float dpth = Linear01Depth(UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture,i.uv2))); float4 camDir = ( dpth * i.interpolatedRay); float fogInt = saturate(length( camDir ) * _StartDistance.x - 1.0) * _StartDistance.y; return lerp(_FogColor, tex2D(_MainTex, i.uv), exp(-_GlobalDensity*fogInt)); } ENDCG SubShader { Pass { ZTest Always Cull Off ZWrite Off Fog { Mode off } CGPROGRAM #pragma vertex vert #pragma fragment fragAbsoluteYAndDistance #pragma fragmentoption ARB_precision_hint_fastest ENDCG } Pass { ZTest Always Cull Off ZWrite Off Fog { Mode off } CGPROGRAM #pragma vertex vert #pragma fragment fragAbsoluteY #pragma fragmentoption ARB_precision_hint_fastest ENDCG } Pass { ZTest Always Cull Off ZWrite Off Fog { Mode off } CGPROGRAM #pragma vertex vert #pragma fragment fragDistance #pragma fragmentoption ARB_precision_hint_fastest ENDCG } Pass { ZTest Always Cull Off ZWrite Off Fog { Mode off } CGPROGRAM #pragma vertex vert #pragma fragment fragRelativeYAndDistance #pragma fragmentoption ARB_precision_hint_fastest ENDCG } } Fallback off } AlphaSortedGlobalFog.cs Code (csharp): using UnityEngine; using System.Collections; [ExecuteInEditMode] [AddComponentMenu("Image Effects/Fog/AlphaSortedGlobalFog")] public class AlphaSortedGlobalFog : MonoBehaviour { void Start () { } [ImageEffectOpaque] void OnRenderImage(RenderTexture source, RenderTexture destination) { DrawFog(source, destination); } //fog script public enum FogMode { AbsoluteYAndDistance = 0, AbsoluteY = 1, Distance = 2, RelativeYAndDistance = 3, } public bool bEnableFog = true; public FogMode fogMode = FogMode.AbsoluteYAndDistance; private float CAMERA_NEAR = 0.5f; private float CAMERA_FAR = 50.0f; private float CAMERA_FOV = 60.0f; private float CAMERA_ASPECT_RATIO = 1.333333f; public float startDistance = 200.0f; public float globalDensity = 1.0f; public float heightScale = 100.0f; public float height = 0.0f; public Color globalFogColor = Color.grey; public Shader fogShader; private Material fogMaterial = null; void DrawFog(RenderTexture source, RenderTexture destination) { if (!bEnableFog) { Graphics.Blit(source, destination); return; } if (fogMaterial == null) { fogMaterial = new Material(fogShader); } CAMERA_NEAR = camera.nearClipPlane; CAMERA_FAR = camera.farClipPlane; CAMERA_FOV = camera.fieldOfView; CAMERA_ASPECT_RATIO = camera.aspect; Matrix4x4 frustumCorners = Matrix4x4.identity; //Vector4 vec; //Vector3 corner; float fovWHalf = CAMERA_FOV * 0.5f; Vector3 toRight = camera.transform.right * CAMERA_NEAR * Mathf.Tan(fovWHalf * Mathf.Deg2Rad) * CAMERA_ASPECT_RATIO; Vector3 toTop = camera.transform.up * CAMERA_NEAR * Mathf.Tan(fovWHalf * Mathf.Deg2Rad); Vector3 topLeft = (camera.transform.forward * CAMERA_NEAR - toRight + toTop); float CAMERA_SCALE = topLeft.magnitude * CAMERA_FAR / CAMERA_NEAR; topLeft.Normalize(); topLeft *= CAMERA_SCALE; Vector3 topRight = (camera.transform.forward * CAMERA_NEAR + toRight + toTop); topRight.Normalize(); topRight *= CAMERA_SCALE; Vector3 bottomRight = (camera.transform.forward * CAMERA_NEAR + toRight - toTop); bottomRight.Normalize(); bottomRight *= CAMERA_SCALE; Vector3 bottomLeft = (camera.transform.forward * CAMERA_NEAR - toRight - toTop); bottomLeft.Normalize(); bottomLeft *= CAMERA_SCALE; frustumCorners.SetRow(0, topLeft); frustumCorners.SetRow(1, topRight); frustumCorners.SetRow(2, bottomLeft); frustumCorners.SetRow(3, bottomRight); fogMaterial.SetMatrix("_FrustumCornersWS", frustumCorners); fogMaterial.SetVector("_CameraWS", camera.transform.position); fogMaterial.SetVector("_StartDistance", new Vector4(1.0f / startDistance, (CAMERA_SCALE - startDistance))); fogMaterial.SetVector("_Y", new Vector4(height, 1.0f / heightScale)); fogMaterial.SetFloat("_GlobalDensity", globalDensity * 0.01f); fogMaterial.SetColor("_FogColor", globalFogColor); CustomGraphicsBlit(source, destination, fogMaterial, (int)fogMode); } static void CustomGraphicsBlit(RenderTexture source, RenderTexture dest, Material fxMaterial, int passNr) { Graphics.Blit(source, dest, fxMaterial, passNr); } } Thanks again to ywq for fixing the fog in the first place! Bidds
Tried out the above script, the Y position moves with the camera, in the script Unity provides y is a gobal position and does not move with the camera. Any way to fix this, or anyone else have this issue.
I tried the "AlphaSortedGlobalFog" Script+Shader on my Oculus Rift projekt. Using on one camera the effect works fine, but after activating the script on the second camera (eye) the effect completly disappears. any ideas?
I'm having a different but similar issue -- GlobalFog overwrites the outline in Toony/BasicOutline.shader. I've tried doing the render opaque thing, and also Tags {"Queue" = "Overlay" } for the outline shader with Tags {"Queue" = "Background" } for the fog shader, nothing seems to work -- the outlines are still overwritten by the fog. Help! How can I use global fog, but still have clear black outlines against it?
This is still occurring in the latest Unity as of 10/01/2018. Any particle with alpha that is activated at about 200meters away from the camera while Global Fog is on will not appear. Hopefully someone at Unity can fix this asap.