Search Unity

Thermal / infrared grabpass shader

Discussion in 'General Discussion' started by HonoraryBob, Nov 16, 2017.

  1. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214
    I've written grabpass shaders that modify the background (e.g. distorting it to create an underwater effect) but I'm not sure how to create an infrared effect like a FLIR device or military scope. The main problem is figuring out which pixels are supposed to be giving off heat. Heat-emitting entities (like people) would need to have a shader that writes data to something that the grabpass shader can pick up, but I'm drawing a blank on how to do that (either because I'm tired or just plain stupid, or maybe there's no feasible way to do it). A search didn't find what I'm trying to do.
     
  2. hoeftbri

    hoeftbri

    Joined:
    Aug 17, 2017
    Posts:
    11
    do you mean like using a script that targets a player tag when a condition is called while the thermal is active?
     
  3. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214
    No, I meant a shader that displays stuff behind it as if it were viewed through an infrared scope or FLIR device or similar - i.e. so that temperature is displayed rather than normal light. Basically just showing anything emitting heat in one color range (white for military scopes, a range of colors near white or red for a FLIR) and showing anything else in "faked" (random) ambient color tones (dark for a military scope, a range of blues and greens for a FLIR).
     
  4. nat42

    nat42

    Joined:
    Jun 10, 2017
    Posts:
    353
    Aren't you just rendering the scene with different colours? (rendering IR intensity say to 1 channel maybe with a stencil if you need both to coexist on the same screen without rendering to a texture)
     
  5. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214

    It's not just a matter of rendering the scene with different colors, because the colors need to be based on the heat emitted by each object, which means the shaders for those objects would need to pass that information to the shader rendering the infrared effect. Any ideas on how to do that?
     
  6. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    There's a MaterialPropertyBlock class:
    https://docs.unity3d.com/ScriptReference/MaterialPropertyBlock.html

    Basically, you can store properties of the object in it, and set the property block onto the renderer within either OnRenderObject() or just lateUpdate. This will allow you to pass object-specific data into the shader.

    Corresponding properties will need to be marked with [PerRendererData]:
    Code (csharp):
    1.  
    2.  
    3. Shader ....{
    4. Properties{
    5.     [PerRendererData]_MainTex ("Texture", 2D) = "white" {}
    6. ....
    7. }
    8.  
    As for the shader itself....

    First, thermal data is grayscale, that is mapped onto rainbow pattern. This is easy and can be done via texture lookup.

    However, the part where you look through objects....

    Basically, you'd need to render objects based on thermal data.

    The objects that "mute" termal data is pretty much transparent alpha planes (srcAlpha, oneMisSrcAlpha).
    The objects that emit heat can be treated as solid, but here you need to make them pproperly construct thermal "blob".

    Basically, I would consider doing it this way: render back facing planes with additive value, equal to "heat * distance_from_camera". Then render front-facing planes with similarly computed value, except I'd make it subtractive. This can be done in single pass with floating point target.

    This would make solid objects appear as "glowing blobs", which will need to be then mapped by thermal shader (maybe with some blur or noise applied afterwards.

    Does this make sense to you?
     
    HonoraryBob likes this.
  7. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214
    Not yet, but I appreciate your help and I'll try to figure it out (I'm running on about three hours of sleep). I should have mentioned that I would need it to work as follows: the player would be holding a FLIR or similar device in one hand and looking at its screen while still being able to see the other stuff around it (in normal rendering) - i.e. the FLIR's screen would be a quad with a shader that uses grabpass (or similar) to display an altered version of the stuff behind the quad (the back of the FLIR of course wouldn't be rendered since it's facing the other way, so the screen serves like a window showing the stuff behind it). Would your method work with something like this?
     
  8. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    You'll need to render the scene second time for displaying it on the the device. Via rendertarget, etc.
     
  9. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    Could Unity map materials or shaders to layers, it would reduce the Transform and mesh count by half for any scene that needs two or more viewing modes?
     
    Last edited: Nov 18, 2017