- Home /
Trying to have sprites affected by fog without having to use default/diffuse shader.
The game I'm making uses a bunch of mobile/unlit textures on quads for walls, and this works well with fog. Walls fade away/appear as the camera moves away/towards them.
However when it comes to sprites, they are bright and unaffected by fog no matter the distance from them. I tried using the diffuse shader, but since my scene is completely unlit and I do not want to use lighting in general, I end up with really dark sprites. These dark sprites are affected by the fog, but they are too dark and the sprite only renders on one side.
Is there any way to have sprites affected by fog just like how mobile/unlit quads are? I did a lot of searching relating to this issue and found that sprites are technically quads, but I find that quads are behaving as desired with regards to fog while sprites are not.
I have tried using the mobile/unlit shader on a material I created and assigned to sprites, but this caused all the transparent parts of the sprite to become full of artifacts and stretched out textures for some reason.
Any help would be greatly appreciated.
Answer by vikingsoulgames · Jul 13, 2019 at 06:52 PM
Although the post is from some time ago, I just had the same small problem and I want to provide the solution I found, thanks to the fact that someone charitable shared a shader just for this in the following link:
https://www.reddit.com/r/Unity3D/comments/6scjlo/a_friend_of_mine_made_a_sprite_shader_which/
The shader what Im talking about is the next: // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
Shader "Sprites/Default with Fog"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
[HideInInspector] _RendererColor ("RendererColor", Color) = (1,1,1,1)
[HideInInspector] _Flip ("Flip", Vector) = (1,1,1,1)
[PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
[PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Cull Off
Lighting Off
ZWrite Off
Blend One OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex SpriteVertFog
#pragma fragment SpriteFragFog
#pragma target 2.0
#pragma multi_compile_instancing
#pragma multi_compile _ PIXELSNAP_ON
#pragma multi_compile _ ETC1_EXTERNAL_ALPHA
#pragma multi_compile_fog
#include "UnitySprites.cginc"
struct v2f_fog
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_FOG_COORDS(1)
UNITY_VERTEX_OUTPUT_STEREO
};
v2f_fog SpriteVertFog(appdata_t IN)
{
v2f_fog OUT;
UNITY_SETUP_INSTANCE_ID (IN);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
#ifdef UNITY_INSTANCING_ENABLED
IN.vertex.xy *= _Flip.xy;
#endif
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color * _RendererColor;
#ifdef PIXELSNAP_ON
OUT.vertex = UnityPixelSnap (OUT.vertex);
#endif
UNITY_TRANSFER_FOG(OUT, OUT.vertex);
return OUT;
}
fixed4 SpriteFragFog(v2f_fog IN) : SV_Target
{
fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
// apply fog
UNITY_APPLY_FOG(IN.fogCoord, c);
c.rgb *= c.a;
return c;
}
ENDCG
}
}
}
It was enough for me to create a material, assign it to this shader and then assign it to my sprites that material.
Answer by DungeonBrickStudios · Sep 17, 2016 at 09:16 AM
So I've managed to solve the problem by modifying the default sprite shader to accept fog. I didn't really know exactly what I was doing as I'm not familiar with how to program shaders, but I just took two partial solutions and glued them together to one full solution using the default unity shaders' code (downloaded off this site).
Step 1: Create a new shader in your assets folder. I called mine "SpritesDefaultModded" and filed it under "Custom". This is the code used for the shader (a combination of the default sprite shader and the mobile unlit shader aka mobile unlit-alpha shader):
Shader "Custom/SpritesDefaultModded"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Cull Off
Lighting Off
ZWrite Off
Blend One OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#pragma multi_compile _ PIXELSNAP_ON
#pragma multi_compile _ ETC1_EXTERNAL_ALPHA
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_FOG_COORDS(1)
};
fixed4 _Color;
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color;
#ifdef PIXELSNAP_ON
OUT.vertex = UnityPixelSnap (OUT.vertex);
#endif
UNITY_TRANSFER_FOG(OUT,OUT.vertex);
return OUT;
}
sampler2D _MainTex;
sampler2D _AlphaTex;
fixed4 SampleSpriteTexture (float2 uv)
{
fixed4 color = tex2D (_MainTex, uv);
#if ETC1_EXTERNAL_ALPHA
// get the color from an external texture (usecase: Alpha support for ETC1 on android)
color.a = tex2D (_AlphaTex, uv).r;
#endif //ETC1_EXTERNAL_ALPHA
return color;
}
fixed4 frag(v2f IN) : SV_Target
{
fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
c.rgb *= c.a;
UNITY_APPLY_FOG(IN.fogCoord, c);
return c;
}
ENDCG
}
}
}
Step 2: Create a new material, I called mine simply "SpritesMaterial". Set the new material's shader to the "SpritesDefaultModded" shader we just created. Make sure the tint of this new material's alpha value is not 0, otherwise you will find your sprite is completely transparent/invisible. For some reason mine defaulted to that value.
Step3: In your sprite renderer, set the material to the "SpritesMaterial" we just created.
This should solve the problem. The result I got was:
Sprite is now affected by fog and darkens/lightens along with everything else in the scene despite being unlit.
Sprite renders on both sides (other shaders seem to make sprites' back sides disappear).
All transparent parts of the sprite are intact, no artifacts or corruption to be seen.
Thank you! I've been looking for this everywhere. You're a life saver :D
Answer by RemDust · Sep 16, 2016 at 12:08 PM
You can set the global lightning of the scene in the Window panel ->lightning->scene. That should do the trick !
Thanks for the answer but my scene does not use any lighting whatsoever, so the lighting options didn't help me there. But yeah if I wanted to use lighting I could just use the diffuse shader on a material and adjust my lighting.
Anyway I've managed to solve the problem and will post an answer for anyone who might have come across the same thing.