Search Unity

Temperature map shader

Discussion in 'Shaders' started by Scale2MVP, Jul 11, 2013.

  1. Scale2MVP

    Scale2MVP

    Joined:
    Jul 11, 2013
    Posts:
    6
    Hello everyone!

    I have a Unity project.
    $globe.png

    And I want to write a shader which represents a temperature map in Unity.
    It is necessary to provide closed lines with borders, which shows tonality of temperature and the corresponding color gradation areas with different temperatures. Shader Language is Cg...

    Input data
    $T5B260000.png

    On output I want to get something like this texture, stretched to the globe sphere.
    $Fig4-2.png


    I certainly can check every pixel, but maybe there are standard approaches to this problem? I would be grateful for any advice!
     
  2. Lulucifer

    Lulucifer

    Joined:
    Jul 8, 2012
    Posts:
    358
    I think it actually is a toon style, you can achive this by some math trick,like this diffuse=floor(diffuse*count)/count,
    but for the black line,i think there has to be one more caculate,or you can do something remap,check the toon shader on unitywiki
     
  3. Scale2MVP

    Scale2MVP

    Joined:
    Jul 11, 2013
    Posts:
    6
    I don`t need a shadow boundaries of the object... I need to cut around the various temperature regions.
    I tried to find the boundary at which the color changes by checking all the surrounding pixels and did not get anything good.

    $Check.png

    Code (csharp):
    1.  
    2. Shader "FFFFarik/8thPix1" {
    3.    Properties {
    4.       _MainTex ("Texture For Diffuse Material Color", 2D) = "white" {}
    5.    }
    6.    
    7.    SubShader {
    8.       Pass {
    9.  
    10.          
    11.          CGPROGRAM
    12.  
    13.          #pragma vertex vert // vert function is the vertex shader
    14.          #pragma fragment frag // frag function is the fragment shader
    15.          #pragma target 3.0
    16.          
    17.          uniform sampler2D _MainTex;
    18.  
    19.          
    20.          struct vertexInput {
    21.             float4 vertex : POSITION;
    22.             float4 texcoord : TEXCOORD0;
    23.          };
    24.          
    25.          struct vertexOutput {
    26.             float4 pos : SV_POSITION;
    27.             float4 tex : TEXCOORD0;
    28.             float3 posInObjectCoords : TEXCOORD1;
    29.          };
    30.  
    31.          vertexOutput vert(vertexInput input)
    32.          {
    33.             vertexOutput output;
    34.  
    35.             output.pos =  mul(UNITY_MATRIX_MVP, input.vertex);
    36.             output.tex = input.texcoord;
    37.             output.posInObjectCoords = float3(input.vertex);
    38.            
    39.             return output;
    40.          }
    41.  
    42.            
    43.          float4 frag(vertexOutput input) : COLOR
    44.          {
    45.             float3 k;
    46.             k.x = input.posInObjectCoords.x;
    47.             k.y = input.posInObjectCoords.y;
    48.             k.z = tex2D(_MainTex, float2(input.tex)).x;            
    49.            
    50.            
    51.            
    52.             float t_col = tex2D(_MainTex, float2(k.x, k.y));
    53.            
    54.            
    55.            
    56.             float a0, a1, a2, a3, a4, a5, a6, a7;
    57.             float dx = 1.0 / 360.0;
    58.             float dy = 1.0 / 181.0;
    59.            
    60.             a0 = tex2D(_MainTex, float2(k.x-dx,k.y-dy) );       a1 = tex2D(_MainTex, float2(k.x-dx,k.y) );          a2 = tex2D(_MainTex, float2(k.x-dx,k.y+dy) );
    61.             a3 = tex2D(_MainTex, float2(k.x,k.y-dy) );                                                              a4 = tex2D(_MainTex, float2(k.x,k.y+dy) );
    62.             a5 = tex2D(_MainTex, float2(k.x+dx,k.y-dy) );       a6 = tex2D(_MainTex, float2(k.x+dx,k.y) );          a7 = tex2D(_MainTex, float2(k.x+dx,k.y+dy) );
    63.  
    64.            
    65.             if ( a0 != a7 || a2 != a5 || a1 != a6 || a3 != a4) return float4(1.0, 1.0, 1.0, 1.0);
    66.            
    67.             return float4(k, 1.0);  
    68.          }
    69.  
    70.          ENDCG  
    71.       }
    72.    }
    73. }
    74.  

    Result:
    $ssssssss.png
     
    Last edited: Jul 19, 2013
  4. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,880
    If your input data is that grayscale image, all you need is to saturate heat colors through it. You can even achieve the black lines if you use a nicely prepared gradient map.
    EDIT: For an example, you can use my thermal vision effect in my "post processing pack" Or "fire shader", from the assetstore.
     
  5. Scale2MVP

    Scale2MVP

    Joined:
    Jul 11, 2013
    Posts:
    6
    I dont understand, why i need to use saturate function, i already have color from 0 to 1? What it gives me? Why it is not floor?

    But how i can make this lines?
     
  6. Acegikmo

    Acegikmo

    Joined:
    Jun 23, 2011
    Posts:
    1,294
    What you'll want is a color ramp texture, where the U coordinate of the ramp UVs is the grayscale texture pixel data.

    The lines are tricky though, not sure what the best way to achieve uniform width and smoothness. Blurring the input data helps.

    Looks quite bad, but it works:
    $ramp.png

    Here's the ramp I used:
    $ramp_heat_01.png

    Semi-pseudo code:
    Code (csharp):
    1. fixed tempData = tex2D(_MyData, input.tex.xy).;
    2. fixed2 rampUV = fixed2(tempData, 0);
    3. fixed3 heatColor = tex2d(_MyRamp, rampUV);
     
    Last edited: Jul 20, 2013
  7. Scale2MVP

    Scale2MVP

    Joined:
    Jul 11, 2013
    Posts:
    6
    Thank you very much!!!! That's great! It was much easier than I thought...

    If anyone is interested, here the alternative way, where I try to find intersection of some grayscale level with some height level (from 1 to 500).

    Code (csharp):
    1.  
    2. Shader "Contours/MyShader3" {
    3.    Properties {
    4.       _MainTex ("Texture For Diffuse Material Color", 2D) = "white" {}
    5.    }
    6.    
    7.    SubShader {
    8.       Pass {
    9.          
    10.          CGPROGRAM
    11.  
    12.          #pragma vertex vert // vert function is the vertex shader
    13.          #pragma fragment frag // frag function is the fragment shader
    14.          #pragma target 3.0
    15.          
    16.          uniform sampler2D _MainTex;
    17.  
    18.          
    19.          struct vertexInput {
    20.             float4 vertex : POSITION;
    21.             float4 texcoord : TEXCOORD0;
    22.          };
    23.          
    24.          struct vertexOutput {
    25.             float4 pos : SV_POSITION;
    26.             float4 tex : TEXCOORD0;
    27.             float3 posInObjectCoords : TEXCOORD1;
    28.          };
    29.  
    30.          vertexOutput vert(vertexInput input)
    31.          {
    32.             vertexOutput output;
    33.  
    34.             output.pos =  mul(UNITY_MATRIX_MVP, input.vertex);
    35.             output.tex = input.texcoord;
    36.             output.posInObjectCoords = float3(input.vertex);
    37.  
    38.             return output;
    39.          }
    40.  
    41.            
    42.          float4 frag(vertexOutput input) : COLOR
    43.          {
    44.             float3 k;
    45.             k.x = input.posInObjectCoords.x;
    46.             k.y = input.posInObjectCoords.y;
    47.             k.z = tex2D(_MainTex, float2(input.tex)).x;            
    48.            
    49.             float3 f = floor(k * 500);
    50.  
    51.             for(float i = 1.0; i < 500.0; i += 50.0) {
    52.                 if(f.z == i) {
    53.                     return float4(1.0, 1.0, 1.0, 1.0);
    54.                 }
    55.             }
    56.            
    57.             return float4(k, 1.0);  
    58.          }
    59.  
    60.          ENDCG  
    61.       }
    62.    }
    63. }
    64.  
    But they have some problems with line width, which is shown on the screenshot:
    $MyShader3.png
     
  8. Scale2MVP

    Scale2MVP

    Joined:
    Jul 11, 2013
    Posts:
    6
    Hello again! I solved the problem with line width by calculating distance between camera and fragment position.

    Code (csharp):
    1.  
    2. float base_dist = 800.0;
    3. float dist = distance(_WorldSpaceCameraPos, input.position_in_world_space);
    4. float scale_level = base_dist  / dist;
    5.  
    Part of the problem is solved, but the lines at the edges still have a different width(smaller):
    $noEdge.png


    To solve the problem, I also calculated the angle between the camera and a fragment normal:
    Code (csharp):
    1.  
    2. float3 normalDirection = normalize(input.normal);
    3. float3 viewDirection = normalize(input.viewDir);
    4. float base_dist = 800.0;
    5.  
    6. float dist = distance(_WorldSpaceCameraPos, input.position_in_world_space);
    7. float edge = abs(dot(normalDirection, viewDirection));
    8. edge = edge < 0.4 ? edge*1.5 : edge;
    9. float scale_level = (base_dist * edge) / dist;
    10.  
    $edge.png

    But this does not solve the problem completely... How can i achieve 1px smooth contours with constant width?


    As alternative way in this thread discusses the same problem: LINK
    But not all platforms support the derivatives. How can I avoid this problem?
     
    Last edited: Aug 15, 2013
  9. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    I think its a similar problem to making a shader generate antialiased output.. whereby you need the rate of change across the pixel (like ddx/ddy commands) to figure out *in screen space* how many pixels away from the perimeter a given fragment is.
     
  10. Scale2MVP

    Scale2MVP

    Joined:
    Jul 11, 2013
    Posts:
    6
    I do not understand. I can't use ddx/ddy... How can i do it without derivatives?