- Home /
Shaders making raw image invisible
Problem: I am currently implementing fog of war into my RTS 2D game. I read an article written by Andrew Huang on how to implement this, however, in order to render the actual 'fog' he used a projector which I realized would not work with 2D games (At this stage, I have the correct RenderTexture that will update in runtime to work with). My initial idea is to setup a quad mesh in front of my camera and use a shader to render the textures onto the quad, however, I have no idea how to achieve that, as I am a completely beginner at shaders. Currently, my idea is to use a world space canvas with 2 Raw images. When the textures are assigned correctly, (and without assigning a material to the raw image), the raw image will show pink color where a character is (I have sphere mesh on each character to simulate the "FIeld of view"). However, when I attached this material with this shader (Shader Script below, written by Andrew Huang), the raw image is completely invisible. On my raw images, I also have 2 scripts that help smooth out the fog of war effect (See below too).
(I am completely new to shaders, but my current solution is to rewrite the shaders myself, but I have no idea how to start or which direction to head towards)
Shader Script: Shader "Custom/FogProjection" { Properties { _PrevTexture("Previous Texture", 2D) = "white" {} _CurrTexture("Current Texture", 2D) = "white" {} _Color("Color", Color) = (0, 0, 0, 0) _Blend("Blend", Float) = 0 _FCurr("CurrFloat", Float) = 0 } SubShader { Tags { "Queue" = "Transparent+100" } // to cover other transparent non-z-write things
Pass
{
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
ZTest Equal
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float4 uv : TEXCOORD0;
};
struct v2f
{
float4 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
float4x4 unity_Projector;
sampler2D _CurrTexture;
sampler2D _PrevTexture;
fixed4 _Color;
float _Blend;
float _FCurr;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = mul(unity_Projector, v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
float aPrev = tex2Dproj(_PrevTexture, i.uv).a;
float aCurr = tex2Dproj(_CurrTexture, i.uv).a;
fixed a = lerp(aPrev, aCurr, _Blend);
// weird things happen to minimap if alpha value gets negative
_Color.a = max(0, _Color.a - a);
return _Color;
}
ENDCG
}
}
}
The blend/smooth script on the raw image: using System.Collections; using UnityEngine; using UnityEngine.UI;
public class FogRaw : MonoBehaviour
{
public Material projectorMaterial;
public float blendSpeed;
public int textureScale;
public RenderTexture fogTexture;
private RenderTexture prevTexture;
private RenderTexture currTexture;
private RawImage screen;
private float blendAmount;
private void Awake()
{
screen = GetComponent<RawImage>();
screen.enabled = true;
prevTexture = GenerateTexture();
currTexture = GenerateTexture();
// Projector materials aren't instanced, resulting in the material asset getting changed.
// Instance it here to prevent us from having to check in or discard these changes manually.
screen.material = new Material(projectorMaterial);
screen.material.SetTexture("_PrevTexture", prevTexture);
screen.material.SetTexture("_CurrTexture", currTexture);
StartNewBlend();
}
RenderTexture GenerateTexture()
{
RenderTexture rt = new RenderTexture(
fogTexture.width * textureScale,
fogTexture.height * textureScale,
0,
fogTexture.format)
{ filterMode = FilterMode.Bilinear };
rt.antiAliasing = fogTexture.antiAliasing;
return rt;
}
public void StartNewBlend()
{
StopCoroutine(BlendFog());
blendAmount = 0;
print(screen.material.GetColor("_Color").a);
// Swap the textures
Graphics.Blit(currTexture, prevTexture);
Graphics.Blit(fogTexture, currTexture);
StartCoroutine(BlendFog());
}
IEnumerator BlendFog()
{
while (blendAmount < 1)
{
// increase the interpolation amount
blendAmount += Time.deltaTime * blendSpeed;
// Set the blend property so the shader knows how much to lerp
// by when checking the alpha value
screen.material.SetFloat("_Blend", blendAmount);
yield return null;
}
// once finished blending, swap the textures and start a new blend
StartNewBlend();
}
}
I desperately need help, I have been stuck on this for a few days now. Appreciate any feedbacks :D