Search Unity

sobel operator - height to normal map on GPU

Discussion in 'Shaders' started by apple_motion, Oct 30, 2009.

  1. apple_motion

    apple_motion

    Joined:
    Jul 2, 2009
    Posts:
    169
    For some reason (mostly lazy), I don't want to make the normal map on the editor. so that, I made it on runtime :) That is based on the Sobel operator



    sobel operation...
    Code (csharp):
    1. float3 height2normal_sobel(float3x3 c)
    2. {      
    3.     float3x3 x = float3x3(   1.0, 0.0, -1.0,
    4.                                     2.0, 0.0, -2.0,
    5.                                     1.0, 0.0, -1.0  );
    6.  
    7.     float3x3 y = float3x3(   1.0,  2.0,  1.0,
    8.                                     0.0,  0.0,  0.0,
    9.                                    -1.0, -2.0, -1.0 );
    10.    
    11.     x = x * c;
    12.     y = y * c;
    13.  
    14.     float cx =  x[0][0] +x[0][2]
    15.                    +x[1][0] +x[1][2]
    16.                    +x[2][0] +x[2][2];
    17.    
    18.     float cy =  y[0][0] +y[0][1] +y[0][2]
    19.                   +y[2][0] +y[2][1] +y[2][2];
    20.                
    21.     float cz =  sqrt(1-(cx*cx+cy*cy));
    22.    
    23.     return float3(cx, cy, cz);
    24. }
    ( Edit: almost forget the float3x3 could do multiply directly :p)

    texture read in...
    Code (csharp):
    1. float3x3 img3x3(sampler2D color_map, float2 tc, float ts, int ch)
    2. {
    3.     float   d = 1.0/ts; // ts, texture sampling size
    4.     float3x3 c;    
    5.     c[0][0] = tex2D(color_map,tc + float2(-d,-d))[ch];
    6.     c[0][1] = tex2D(color_map,tc + float2( 0,-d))[ch];
    7.     c[0][2] = tex2D(color_map,tc + float2( d,-d))[ch]; 
    8.        
    9.     c[1][0] = tex2D(color_map,tc + float2(-d, 0))[ch];
    10.     c[1][1] = tex2D(color_map,tc                )[ch];
    11.     c[1][2] = tex2D(color_map,tc + float2( d, 0))[ch];
    12.        
    13.     c[2][0] = tex2D(color_map,tc + float2(-d, d))[ch];
    14.     c[2][1] = tex2D(color_map,tc + float2( 0, d))[ch];
    15.     c[2][2] = tex2D(color_map,tc + float2( d, d))[ch];
    16.    
    17.     return c;
    18. }
    19.  
    how to use ...
    Code (csharp):
    1. float3x3 c = img3x3(color_map, IN.texcoord, texture_size, 0 );// red only
    2. float3 normal = height2normal_sobel(c);
    3. normal = normalize(float3(normal.xy, normal.z *bump_level));
    Hope that is useful for someone like me (lazy :p)
     
    kristoof likes this.
  2. MattFS

    MattFS

    Joined:
    Jul 14, 2009
    Posts:
    219
    good one - this sort of thing could be very useful for web deployment, if all you wanted was some noisy normalmaps (well, you could make it generate stuff like crazybump does) then this would save having to upload (and having to consider compressing) normalmaps!
    good work :)
     
  3. kristoof

    kristoof

    Joined:
    Aug 26, 2013
    Posts:
    89
    Thank you som much for this :D
    I know this is kind of an old thread but i extended the default surface shader with this if anyone intrested.



    Code (CSharp):
    1. Shader "Custom/H2nTest"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Color", Color) = (1,1,1,1)
    6.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    7.         _heightNrm ("Height2nrm (R)", 2D) = "white" {}
    8.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    9.         _Metallic ("Metallic", Range(0,1)) = 0.0
    10.         _BumpLvl ("bumpscale", Range(-1,1)) = 0.0
    11.     }
    12.     SubShader
    13.     {
    14.         Tags { "RenderType"="Opaque" }
    15.         LOD 200
    16.  
    17.         CGPROGRAM
    18.         // Physically based Standard lighting model, and enable shadows on all light types
    19.         #pragma surface surf Standard fullforwardshadows
    20.  
    21.         // Use shader model 3.0 target, to get nicer looking lighting
    22.         #pragma target 3.0
    23.  
    24.         sampler2D _MainTex, _heightNrm;
    25.  
    26.         struct Input
    27.         {
    28.             float2 uv_MainTex;
    29.         };
    30.  
    31.         half _Glossiness;
    32.         half _Metallic;
    33.         fixed4 _Color;
    34.         float4 _heightNrm_TexelSize;
    35.         float _BumpLvl;
    36.  
    37.         // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    38.         // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    39.         // #pragma instancing_options assumeuniformscaling
    40.         UNITY_INSTANCING_BUFFER_START(Props)
    41.             // put more per-instance properties here
    42.         UNITY_INSTANCING_BUFFER_END(Props)
    43.  
    44.  
    45.  
    46.  
    47. float3 height2normal_sobel(float3x3 c)
    48. {    
    49.     float3x3 x = float3x3(   1.0, 0.0, -1.0,
    50.                                     2.0, 0.0, -2.0,
    51.                                     1.0, 0.0, -1.0  );
    52.     float3x3 y = float3x3(   1.0,  2.0,  1.0,
    53.                                     0.0,  0.0,  0.0,
    54.                                    -1.0, -2.0, -1.0 );
    55.  
    56.     x = x * c;
    57.     y = y * c;
    58.     float cx =  x[0][0] +x[0][2]
    59.                    +x[1][0] +x[1][2]
    60.                    +x[2][0] +x[2][2];
    61.  
    62.     float cy =  y[0][0] +y[0][1] +y[0][2]
    63.                   +y[2][0] +y[2][1] +y[2][2];
    64.              
    65.     float cz =  sqrt(1-(cx*cx+cy*cy));
    66.  
    67.     return float3(cx, cy, cz);
    68. }
    69.  
    70.  
    71.         float3x3 img3x3(sampler2D color_map, float2 tc, float ts, int ch)
    72. {
    73.     float   d = 1.0/ts; // ts, texture sampling size
    74.     float3x3 c;  
    75.     c[0][0] = tex2D(color_map,tc + float2(-d,-d))[ch];
    76.     c[0][1] = tex2D(color_map,tc + float2( 0,-d))[ch];
    77.     c[0][2] = tex2D(color_map,tc + float2( d,-d))[ch];
    78.      
    79.     c[1][0] = tex2D(color_map,tc + float2(-d, 0))[ch];
    80.     c[1][1] = tex2D(color_map,tc                )[ch];
    81.     c[1][2] = tex2D(color_map,tc + float2( d, 0))[ch];
    82.      
    83.     c[2][0] = tex2D(color_map,tc + float2(-d, d))[ch];
    84.     c[2][1] = tex2D(color_map,tc + float2( 0, d))[ch];
    85.     c[2][2] = tex2D(color_map,tc + float2( d, d))[ch];
    86.  
    87.     return c;
    88. }
    89.  
    90.  
    91.         void surf (Input IN, inout SurfaceOutputStandard o)
    92.         {
    93.  
    94.             float3x3 ce = img3x3(_heightNrm, IN.uv_MainTex, _heightNrm_TexelSize.w, 0 );// red only
    95.             float3 normal = height2normal_sobel(ce);
    96.             normal = normalize(float3(normal.xy, normal.z *_BumpLvl));
    97.  
    98.  
    99.             // Albedo comes from a texture tinted by color
    100.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    101.             o.Albedo = c.rgb;
    102.             o.Normal = normal;
    103.             // Metallic and smoothness come from slider variables
    104.             o.Metallic = _Metallic;
    105.             o.Smoothness = _Glossiness;
    106.             o.Alpha = c.a;
    107.            
    108.         }
    109.         ENDCG
    110.     }
    111.     FallBack "Diffuse"
    112. }
    113.  
     
    bb8_1 likes this.
  4. mouurusai

    mouurusai

    Joined:
    Dec 2, 2011
    Posts:
    350
    Why not just regular bump?

    On top "sobel", on bottom regular bump like here, but with texel size multiplied with an value. For 2 cases from 3 regular one seems look better for me.
     
    Last edited: Aug 31, 2019
    kristoof likes this.