Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

General purpose shader for fog of war

Discussion in 'Shaders' started by auau52, Jun 17, 2020.

  1. auau52

    auau52

    Joined:
    Apr 3, 2020
    Posts:
    16
    I'm using tile based fog of war; checking line of sight with bresenham algorithm.
    At every update, some sight sources(like player character) gather their in-sight-tiles. Then I can render some fog with these sight information. I'm happy with this, but my CPU isn't

    This update is heavy work for CPU (especially on mobile), so I want to GPU do this.
    My main idea is, storing whole sight blocking obstacles in large texture (like 2048 * 2048) and updating much smaller (like 150 * 150) sight texture around player. Every texel checks if it is in the line of sight from player with bresenham algorithm(or with simple lerp) in GPU. (referencing obstacle texture)

    1. Is it valid idea? I'm worried about memory bandwith usage; obstacle texture should be updated at CPU anyway.
    And total computation is increased; Each texel should run their own bresenham algorithm. (quite redundant)
    Moreover, my shader code contains dynamic loops and branches.

    2. Compute shader or Custom Render Texture?
    I'm less familiar with compute shader, but compute shader seems to be much proper in this case. Is there any big differences?

    3. Obstacles map; texture or compute buffer?
    For upload obstacle information to GPU, which one is better? Sampling from texture is quite tiresome because I'm working on integer coordinate but still need [0~1] uv. But I'm not sure about compute buffer, especially on low end mobiles. (IOS6 or galaxy S5)

    This is quite specific and cumbersome question @.@ Thanks in advance!
     
    spryx likes this.
  2. spryx

    spryx

    Joined:
    Jul 23, 2013
    Posts:
    557
    I'm doing this for my game and performance is ok, but i'm also interested to hear how this might be done in-shader
     
  3. Przemyslaw_Zaworski

    Przemyslaw_Zaworski

    Joined:
    Jun 9, 2017
    Posts:
    327
    Minimal Fog-Of-War example with high performance, where you can use WSAD keys to controls a circle to uncover fragments of map.

    Code (CSharp):
    1. // Edit -> Project Settings -> Graphics -> Always Included Shader -> Hidden/FogOfWar
    2.  
    3. using UnityEngine;
    4.  
    5. public class FogOfWar : MonoBehaviour
    6. {
    7.     public Texture2D Map;
    8.     public int Resolution = 1024;
    9.     public float Radius = 0.02f;
    10.     Material material;
    11.     RenderTexture input, output;
    12.     Vector4 center = new Vector4(0.5f,0.5f,0.0f,0.0f);
    13.     bool swap = true;
    14.    
    15.     void Load()
    16.     {
    17.         material = new Material(Shader.Find("Hidden/FogOfWar"));
    18.         input = new RenderTexture(Resolution, Resolution, 0, RenderTextureFormat.R8);      
    19.         output = new RenderTexture(Resolution, Resolution, 0, RenderTextureFormat.R8);      
    20.         GetComponent<Renderer>().material = material;
    21.         material.SetTexture("_Map", Map);      
    22.     }
    23.    
    24.     void Blit(RenderTexture source, RenderTexture destination, Material mat)
    25.     {
    26.         RenderTexture.active = destination;
    27.         mat.SetTexture("_MainTex", source);
    28.         GL.PushMatrix();
    29.         GL.LoadOrtho();
    30.         GL.invertCulling = true;
    31.         mat.SetPass(0);
    32.         GL.Begin(GL.QUADS);
    33.         GL.MultiTexCoord2(0, 0.0f, 0.0f);
    34.         GL.Vertex3(0.0f, 0.0f, 0.0f);
    35.         GL.MultiTexCoord2(0, 1.0f, 0.0f);
    36.         GL.Vertex3(1.0f, 0.0f, 0.0f);
    37.         GL.MultiTexCoord2(0, 1.0f, 1.0f);
    38.         GL.Vertex3(1.0f, 1.0f, 1.0f);
    39.         GL.MultiTexCoord2(0, 0.0f, 1.0f);
    40.         GL.Vertex3(0.0f, 1.0f, 0.0f);
    41.         GL.End();
    42.         GL.invertCulling = false;
    43.         GL.PopMatrix();      
    44.     }
    45.    
    46.     void GenerateFogOfWar ()
    47.     {
    48.         material.SetTexture("_Map", Map);
    49.         material.SetVector("Center",center);
    50.         material.SetFloat("Radius",Radius);  
    51.         if (swap)
    52.         {
    53.             material.SetTexture("_MainTex", input);
    54.             Blit(input,output,material);
    55.             material.SetTexture("_Buffer", output);
    56.         }
    57.         else
    58.         {
    59.             material.SetTexture("_MainTex", output);
    60.             Blit(output,input,material);
    61.             material.SetTexture("_Buffer", input);
    62.         }
    63.         swap = !swap;
    64.     }
    65.    
    66.     void Movement()
    67.     {
    68.         if (Input.GetKey("a")) center.x -= Time.deltaTime * 0.05f;
    69.         if (Input.GetKey("d")) center.x += Time.deltaTime * 0.05f;
    70.         if (Input.GetKey("s")) center.y -= Time.deltaTime * 0.05f;
    71.         if (Input.GetKey("w")) center.y += Time.deltaTime * 0.05f;
    72.     }
    73.    
    74.     void Start ()
    75.     {
    76.         Load();
    77.     }
    78.    
    79.     void Update ()
    80.     {
    81.         GenerateFogOfWar();
    82.         Movement();  
    83.     }
    84.    
    85.     void OnDestroy ()
    86.     {
    87.         input.Release();
    88.         output.Release();
    89.     }
    90. }
    Code (CSharp):
    1. Shader "Hidden/FogOfWar"
    2. {
    3.     SubShader
    4.     {
    5.    
    6.         CGINCLUDE
    7.         #pragma vertex SetVertexShader
    8.         #pragma fragment SetPixelShader
    9.        
    10.         void SetVertexShader (inout float4 vertex:POSITION, inout float2 uv:TEXCOORD0)
    11.         {
    12.             vertex = UnityObjectToClipPos(vertex);
    13.         }
    14.        
    15.         ENDCG
    16.        
    17.         Pass
    18.         {
    19.             CGPROGRAM          
    20.             float4 Center;
    21.             float Radius;
    22.             sampler2D _MainTex;  
    23.            
    24.             float circle(float2 p, float2 c, float r)
    25.             {
    26.                 return step(length(p-c)-r,0.0);
    27.             }  
    28.            
    29.             void SetPixelShader (float4 vertex:POSITION, float2 uv:TEXCOORD0, out float color:SV_TARGET)
    30.             {
    31.                 color = max(circle(uv,Center.xy,Radius), tex2D(_MainTex,uv).r);
    32.             }
    33.            
    34.             ENDCG
    35.         }
    36.        
    37.         Pass
    38.         {
    39.             CGPROGRAM
    40.             sampler2D _Buffer, _Map;
    41.            
    42.             void SetPixelShader (float4 vertex:POSITION, float2 uv:TEXCOORD0, out float4 color:SV_TARGET)
    43.             {
    44.                 color = tex2D(_Buffer,uv).r > 0.0 ? tex2D(_Map,uv) : float4(0,0,0,1);
    45.             }
    46.            
    47.             ENDCG
    48.         }      
    49.     }
    50. }
    upload_2020-6-21_22-47-56.png
     
    oen3, bgolus and spryx like this.