I am trying to build up a texture that represents where a player has visited on a level. (2d, topdown game).
The idea is to blit all the pixels currently in the player’s LOS into a texture, so over time as he visits more parts of the level, more of this texture is white (visited) as opposed to black (unvisited). The blitting uses a shader that chooses the max value when comparing two colors (ie white over black).
When I try to blit this way, the RenderTexture (“knownmap”), only shows the most recent light radius, and not any historical ones from previous frames. I don’t know why.
Camera Effect:
//pass latest 'in LOS' pixels to shader
material1.SetTexture("_LightMap", currentLOSAreaAsTexture);
//combine existing knownmap with latest 'in LOS' pixels
Graphics.Blit(knownmap, knownmap, material1);
//render to screen
Graphics.Blit(knownmap, destination);
Fragment Shader:
float4 frag(vertexOutput i) : COLOR
{
float4 known = tex2D(_MainTex, i.tex);
float4 light = tex2D(_LightMap, i.tex);
return float4(max(light.r,known.r), max(light.g, known.g),
max(light.b, known.b), max(light.a, known.a));
}
I’ve tried not blitting “knownmap” to itself, instead using an intermediate buffer, but same result. It’s as if “knownmap” has reverted to a fully black texture at the start of each frame. How can I preserve the blitting effect across time?
I still don’t fully understand the situation, but I’ve managed to blit the way I wanted to. I was under the misconception that the rendertexture blitted to could only be written over and not actually contribute to the final image - but I’ve learned that blending is a case where this is not so. Using a very simple shader I have achieved what I was after
Shader "AddTextures" {
Properties{
_MainTex("Texture 1", 2D) = ""
_Texture2("Texture 2", 2D) = ""
}
SubShader{ Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" }
ZWrite Off
Blend One One
Pass{
SetTexture[_MainTex]
SetTexture[_Texture2]
{
ConstantColor(0,0,0,[_Blend]) Combine texture + previous }
}
}
}
This was called in this manner,
protected void Update()
{
materialKnown.SetTexture("_Texture2", lightmap);
Graphics.Blit(black, knownmap, materialKnown);
}
“black” is a wholly black texture pretty much just there to satify the Blit function signature.
Good that you’ve figured a way around.
I thought I’d mention an alternative approach to doing this.
Have a secondary orthographic camera that looks down on your world; adjust its size to be as tight a fit.
On your player, attach a child game object with a mesh that approximates the viewing area.
Set it on another layer (“FogOfWar”) and then make the ortho cam’s mask only render this layer.
Disable this layer from your main camera.
Create a RenderTexture
and assign it to the ortho camera via script. Clear it once at the start.
Set the clear flags to Don't clear
On the child game object, drag a material that outputs a color (say red).
You now have a mask of the players vision for your scene.
Code is always helpful, so here you go. It shows a simple minimap of spots the player has visited.
I couldn’t get the mask to blend with the minimap to create a fog of war effect for all the visited areas though.