Search Unity

Texture Bombing - Let's tackle this one!

Discussion in 'Shaders' started by Annihlator, Jun 10, 2013.

  1. Annihlator

    Annihlator

    Joined:
    Oct 15, 2012
    Posts:
    378
    Hello everyone, after trying to do some more digwork on Texture Bombing i didn't just run into Nvidia's GPU Gems article, no i also ran into a russian forum topic where someone was in the process of converting the code to unity! (Topic: http://unity3d.ru/distribution/viewtopic.php?f=35&t=3003 , In russian though! i could understand small bits using google translate)

    The code is based on an excisting GLSL shader that employs texture bombing.
    The most up-to-date version of the code i found is the following;

    Code (csharp):
    1. Shader "TextureBombing"
    2. {
    3.         Properties
    4.         {
    5.                 _MainTex("Texture (RGB)", 2D) = "black" {}
    6.                 _BombTex("Bomb Texture (RGB)", 2D) = "black" {}
    7.                 _RandomTex("Random Texture (RGB)", 2D) = "black" {}
    8.                 _Scale("Scale", Float) = 10
    9.         }
    10.    
    11.         SubShader
    12.         {
    13.                 Tags { "RenderType" = "Opaque" }
    14.                 Cull Back
    15.        
    16.                 CGPROGRAM
    17.                 #pragma surface surf Lambert
    18.                 #pragma target 3.0
    19.                
    20.                 sampler2D _MainTex;
    21.                 sampler2D _BombTex;
    22.                 sampler2D _RandomTex;
    23.                 uniform float _Scale;
    24.  
    25.                 struct Input {
    26.                         float2 uv_MainTex;
    27.                         float2 uv_BombTex;
    28.                         float2 uv_RandomTex;
    29.         };
    30.                
    31.         void surf (Input IN, inout SurfaceOutput o) {
    32.                         // get diffuse color
    33.                         float3 decalColor = tex2D ( _MainTex, IN.uv_MainTex ).xyz;
    34.                        
    35.                         // get cell no based on texture coordinates
    36.                         float2 ScaledUV = IN.uv_MainTex * _Scale;
    37.                         float2 cell = floor ( ScaledUV );
    38.                         float2 offset = ScaledUV - cell;
    39.                         float3 rnd;
    40.                         float4 decCol;
    41.                
    42.                         //loop1
    43.                         float2 curCell = cell + float2 ( -1, -1 );
    44.                         float2 curoffset = offset - float2 ( -1, -1 );
    45.                         float2 randomUV = curCell * float2 ( 0.037, 0.119 );
    46.                        
    47.                         //sample 1
    48.                         #if !defined(SHADER_API_OPENGL)
    49.                                 rnd = tex2Dlod ( _RandomTex, float4(offset, 0.0, 0.0) ).xyz;
    50.                                 decCol = tex2Dlod( _BombTex, float4(curoffset.xy - rnd.xy, 0.0, 0.0));
    51.                         #else
    52.                                 rnd = tex2D ( _RandomTex, randomUV ).xyz;
    53.                                 decCol = tex2D ( _BombTex, curoffset.xy - rnd.xy );
    54.                         #endif
    55.                         decalColor += decCol.xyz*decCol.w;
    56.                        
    57.                         //loop2
    58.                         curCell = cell + float2 ( -1, 0 );
    59.                         curoffset = offset - float2 ( -1, 0 );
    60.                         randomUV = curCell * float2 ( 0.037, 0.119 );
    61.                        
    62.                         //sample 1
    63.                         #if !defined(SHADER_API_OPENGL)
    64.                                 rnd = tex2Dlod ( _RandomTex, float4(randomUV, 0.0, 0.0) ).xyz;
    65.                                 decCol = tex2Dlod( _BombTex, float4(curoffset.xy - rnd.xy, 0.0, 0.0));
    66.                         #else
    67.                                 rnd = tex2D ( _RandomTex, randomUV ).xyz;
    68.                                 decCol = tex2D ( _BombTex, curoffset.xy - rnd.xy );
    69.                         #endif
    70.                         decalColor += decCol.xyz*decCol.w;                      
    71.                        
    72.                         //loop3
    73.                         curCell = cell + float2 ( 0, -1 );
    74.                         curoffset = offset - float2 ( 0, -1 );
    75.                         randomUV = curCell * float2 ( 0.037, 0.119 );
    76.                        
    77.                         //sample 1
    78.                         #if !defined(SHADER_API_OPENGL)
    79.                                 rnd = tex2Dlod ( _RandomTex, float4(randomUV, 0.0, 0.0) ).xyz;
    80.                                 decCol = tex2Dlod( _BombTex, float4(curoffset.xy - rnd.xy, 0.0, 0.0));
    81.                         #else
    82.                                 rnd = tex2D ( _RandomTex, randomUV ).xyz;
    83.                                 decCol = tex2D ( _BombTex, curoffset.xy - rnd.xy );
    84.                         #endif
    85.                         decalColor += decCol.xyz*decCol.w;
    86.                        
    87.                         //loop4
    88.                         curCell = cell;
    89.                         curoffset = offset;
    90.                         randomUV = curCell * float2 ( 0.037, 0.119 );
    91.                        
    92.                         //sample 1
    93.                         #if !defined(SHADER_API_OPENGL)
    94.                                 rnd = tex2Dlod ( _RandomTex, float4(randomUV, 0.0, 0.0) ).xyz;
    95.                                 decCol = tex2Dlod( _BombTex, float4(curoffset.xy - rnd.xy, 0.0, 0.0));
    96.                         #else
    97.                                 rnd = tex2D ( _RandomTex, randomUV ).xyz;
    98.                                 decCol = tex2D ( _BombTex, curoffset.xy - rnd.xy );
    99.                         #endif
    100.                         decalColor += decCol.xyz*decCol.w;
    101.                                                
    102.                         o.Albedo = decalColor;
    103.         }
    104.         ENDCG
    105.     }
    106.    
    107.     FallBack "Diffuse"
    108. }
    I've tested it a bit but it seems the texture bomb can't make seamless bombing this way :p

    I'm going to try an take a knack at it later this week, but decided to post this bit of code for anyone who didn't find it before and who feels like experimenting a bit :)
    When i'm finished i'll upload finished code too ;)

    Enjoy!
     
  2. Lulucifer

    Lulucifer

    Joined:
    Jul 8, 2012
    Posts:
    358
    Tanks a lot, Annihlator.
    Unbelieveable,you can read russian:)
     
  3. Cameron_SM

    Cameron_SM

    Joined:
    Jun 1, 2009
    Posts:
    915
    Confused by this, where would anyone want to use it?

    Procedural art techniques rarely end up looking good in practice, and the GPU gems article never really gave any convincing examples of why I'd ever want something like this.
     
  4. Annihlator

    Annihlator

    Joined:
    Oct 15, 2012
    Posts:
    378
    Ok, so the error in the code was a single "offset" value written where it should say "randomuv" How stupidiously easy, i can't understand i've been fighting the code for some hours to find out that was the only mistake... i was thinking the negative values resulted in errors somehow -.-

    Corrected Code;
    Code (csharp):
    1.  
    2. Shader "TextureBombing"
    3. {
    4.         Properties
    5.         {
    6.                 _MainTex("Texture (RGB)", 2D) = "black" {}
    7.                 _BombTex("Bomb Texture (RGB)", 2D) = "black" {}
    8.                 _RandomTex("Random Texture (RGB)", 2D) = "black" {}
    9.                 _Scale("Scale", Float) = 10
    10.         }
    11.    
    12.         SubShader
    13.         {
    14.                 Tags { "RenderType" = "Opaque" }
    15.                 Cull Back
    16.        
    17.                 CGPROGRAM
    18.                 #pragma surface surf Lambert
    19.                 #pragma target 3.0
    20.                
    21.                 sampler2D _MainTex;
    22.                 sampler2D _BombTex;
    23.                 sampler2D _RandomTex;
    24.                 uniform float _Scale;
    25.  
    26.                 struct Input {
    27.                         float2 uv_MainTex;
    28.                         float2 uv_BombTex;
    29.                         float2 uv_RandomTex;
    30.         };
    31.                
    32.         void surf (Input IN, inout SurfaceOutput o) {
    33.                         // get diffuse color
    34.                         float3 decalColor = tex2D ( _MainTex, IN.uv_MainTex ).xyz;
    35.                        
    36.                         // get cell no based on texture coordinates
    37.                         float2 ScaledUV = IN.uv_MainTex * _Scale;
    38.                         float2 cell = floor ( ScaledUV );
    39.                         float2 offset = ScaledUV - cell;
    40.                         float3 rnd;
    41.                         float4 decCol;
    42.                        
    43.                         float2 curCell;
    44.                         float2 curoffset;
    45.                         float2 randomUV;
    46.                
    47.                         //loop1
    48.                         curCell = cell + float2 ( -1, -1 );
    49.                         curoffset = offset - float2 ( -1, -1 );
    50.                         randomUV = curCell * float2 ( 0.037, 0.119 );
    51.                        
    52.                         //sample 1
    53.                         #if !defined(SHADER_API_OPENGL)
    54.                                 rnd = tex2Dlod ( _RandomTex, float4(randomUV, 0.0, 0.0) ).xyz;
    55.                                 decCol = tex2Dlod( _BombTex, float4(curoffset.xy - rnd.xy, 0.0, 0.0));
    56.                         #else
    57.                                 rnd = tex2D ( _RandomTex, randomUV ).xyz;
    58.                                 decCol = tex2D ( _BombTex, curoffset.xy - rnd.xy );
    59.                         #endif
    60.                         decalColor += decCol.xyz*decCol.w;
    61.                        
    62.                         //loop2
    63.                         curCell = cell + float2 ( -1, 0 );
    64.                         curoffset = offset - float2 ( -1, 0 );
    65.                         randomUV = curCell * float2 ( 0.037, 0.119 );
    66.                        
    67.                         //sample 1
    68.                         #if !defined(SHADER_API_OPENGL)
    69.                                 rnd = tex2Dlod ( _RandomTex, float4(randomUV, 0.0, 0.0) ).xyz;
    70.                                 decCol = tex2Dlod( _BombTex, float4(curoffset.xy - rnd.xy, 0.0, 0.0));
    71.                         #else
    72.                                 rnd = tex2D ( _RandomTex, randomUV ).xyz;
    73.                                 decCol = tex2D ( _BombTex, curoffset.xy - rnd.xy );
    74.                         #endif
    75.                         decalColor += decCol.xyz*decCol.w;                      
    76.                        
    77.                         //loop3
    78.                         curCell = cell + float2 ( 0, -1 );
    79.                         curoffset = offset - float2 ( 0, -1 );
    80.                         randomUV = curCell * float2 ( 0.037, 0.119 );
    81.                        
    82.                         //sample 1
    83.                         #if !defined(SHADER_API_OPENGL)
    84.                                 rnd = tex2Dlod ( _RandomTex, float4(randomUV, 0.0, 0.0) ).xyz;
    85.                                 decCol = tex2Dlod( _BombTex, float4(curoffset.xy - rnd.xy, 0.0, 0.0));
    86.                         #else
    87.                                 rnd = tex2D ( _RandomTex, randomUV ).xyz;
    88.                                 decCol = tex2D ( _BombTex, curoffset.xy - rnd.xy );
    89.                         #endif
    90.                         decalColor += decCol.xyz*decCol.w;
    91.                        
    92.                         //loop4
    93.                         curCell = cell;
    94.                         curoffset = offset;
    95.                         randomUV = curCell * float2 ( 0.037, 0.119 );
    96.                        
    97.                         //sample 1
    98.                         #if !defined(SHADER_API_OPENGL)
    99.                                 rnd = tex2Dlod ( _RandomTex, float4(randomUV, 0.0, 0.0) ).xyz;
    100.                                 decCol = tex2Dlod( _BombTex, float4(curoffset.xy - rnd.xy, 0.0, 0.0));
    101.                         #else
    102.                                 rnd = tex2D ( _RandomTex, randomUV ).xyz;
    103.                                 decCol = tex2D ( _BombTex, curoffset.xy - rnd.xy );
    104.                         #endif
    105.                         decalColor += decCol.xyz*decCol.w;
    106.                                                
    107.                         o.Albedo = decalColor;
    108.         }
    109.         ENDCG
    110.     }
    111.    
    112.     FallBack "Diffuse"
    113. }
    114.  
    When someone could possibly want to use this? Texture bombing is a technique which can be applied for any kind of randomisation of a pattern. I want to use it for showing multiple Raindrops, without repetition patterns myself.

    In this first version you can simply blend a bomber texture, but it would also be possible to draw procedural shapes, etc. Imagine dynamically bombed normal maps of ripples and then you'll start to see where i see it's use.

    Mainly when i compare it to the method i'm using right now for my ripples; animated quad-way-tiling normal maps, the pro would be the loss of the repetition pattern. and especially the need to create 4-way-tileable animated normalmaps, which is a pain by itself.
     
  5. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,880
    Texture bombing is only good for (in my opinion) for rain drops on water or wet surfaces. Im using it in my own projects water shader for rain drops.
    I will also release this water in one of my packs soon. I also saw it being used in several games like skyrim.
    What matters is, its simple operation and nearly same expensive as couple texture lookups.
     
  6. Annihlator

    Annihlator

    Joined:
    Oct 15, 2012
    Posts:
    378
    Texture bombing could also help in simplifying repetition removal.
    I.e. one could also use Texture Bombing to randomly bomb some darkening/lightening artifacts on an underlying surface, imagine dropping parts of sand/dirt on rocks. Or to give more randomisation to a texture channel you may be using for data (imagine where you're using a texturemap with red, green, blue channels for data... you could let more data be randomly dropped for use).
    Im also considering to use some of the bombing's values to have some effect on the randomisation of my puddles by having it alter the "height" of the surface.

    In the end there is a myriad of ways you could use it, even though it's not always as practical.
     
  7. Cameron_SM

    Cameron_SM

    Joined:
    Jun 1, 2009
    Posts:
    915
    Yeah, maybe, think I'd rather just use substance materials though: http://blogs.unity3d.com/2011/08/09/substances-procedural-materials-in-unity/ as that's basically what they were designed to do.
     
  8. Annihlator

    Annihlator

    Joined:
    Oct 15, 2012
    Posts:
    378
    Yeah however i can't design my own substances as of yet (not without purchasing the software of allegorithmic, anyway...) :p I wouldn't even be suprised to find out some substances actually do use texture bombing.

    Currently i'm busy with tweaking the shader so it will be able to bomb normalmaps in a way that it actually looks the way it should :) since my own intention still is to use it for rain ripples first :)
     
  9. Annihlator

    Annihlator

    Joined:
    Oct 15, 2012
    Posts:
    378
    Update to the code!

    WebPlayer Fullscreen:
    http://www.annihlator.nl/RainTest/Web-TexBombed/WebFS.html
    Other webplayers: www.annihlator.nl/RainTest
    The shader used is my own RainShader, but it uses the exact same code below to generate it's normal map for the rain splashes.

    Full shader for texture-bombing a normal map is posted here;
    Code (csharp):
    1.  
    2. Shader "Annihlator/Raindrop TextureBomber" {
    3.     Properties {
    4.         _MainTex("Texture (RGB)", 2D) = "black" {}
    5.         _BumpMap ("Normalmap", 2D) = "bump" {}
    6.         _BombTex("Bomb Texture (RGB)", 2D) = "black" {}
    7.         _RandomTex("Random Texture (RGB)", 2D) = "black" {}
    8.         _Slider("Slider", Range(0,1)) = 1
    9.         _Params("Params, Z = Scale",Vector) = (0.037, 0.119, 5, 0)
    10.         _ReflectionTex ("Reflection", 2D) = "white" { TexGen ObjectLinear }
    11.     }
    12.     SubShader {
    13.         Tags { "RenderType"="Opaque" }
    14.         Cull back
    15.         LOD 200
    16.        
    17.         CGPROGRAM
    18.         #pragma surface surf Lambert
    19.         #pragma target 3.0
    20.         #include "UnityCG.cginc"
    21.  
    22.         sampler2D _MainTex;
    23.                 sampler2D _BombTex;
    24.                 sampler2D _RandomTex;
    25.                 sampler2D _BumpMap;
    26.                 float _Slider;
    27.                 float4 _Params;
    28.                 sampler2D _ReflectionTex;
    29.  
    30.         struct Input {
    31.             float2 uv_MainTex;
    32.             float2 uv_RandomTex;
    33.             float4 screenPos;
    34.         };
    35.        
    36.         float4 MakeLoop(float2 offset, float2 cell, float3 rnd, float2 movement){
    37.         float2 curCell = cell + movement;
    38.         float2 curoffset = offset - movement;
    39.         float TimeMulti = floor((_Time.z+1));
    40.         float2 randomUV = curCell * float2 ( _Params.x*TimeMulti, _Params.y*TimeMulti );
    41.         #if !defined(SHADER_API_OPENGL)
    42.             rnd = tex2Dlod ( _RandomTex, float4(randomUV, 0.0, 0.0) ).xyz;
    43.             float4 decCol = tex2Dlod( _BombTex, float4(curoffset.xy - rnd.xy, 0.0, 0.0));
    44.             #else
    45.             rnd = tex2D ( _RandomTex, randomUV ).xyz;
    46.             float4 decCol = tex2D ( _BombTex, curoffset.xy - rnd.xy );
    47.             #endif
    48.         float Visibility = _Time.z+rnd.b*2;
    49.         Visibility = (Visibility-floor(Visibility));
    50.         float4 StackedDecal = decCol*smoothstep(0.5,0.75,Visibility-0.15);
    51.         return StackedDecal;
    52.         }
    53.  
    54.         void surf (Input IN, inout SurfaceOutput o) {
    55.        
    56.             fixed2 screenUV = (IN.screenPos.xy) / (IN.screenPos.w);
    57.             fixed4 refl = tex2D(_ReflectionTex, screenUV);
    58.        
    59.             fixed3 norm = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
    60.             float3 decalColor = tex2D ( _MainTex, IN.uv_MainTex ).xyz;
    61.             fixed4 StackedDecal = 0;
    62.            
    63.             float2 ScaledUV = IN.uv_MainTex * _Params.z;
    64.             float2 cell = floor ( ScaledUV );
    65.             float2 offset = ScaledUV - cell;
    66.             float3 rnd;
    67.            
    68.             StackedDecal = MakeLoop(offset,cell,rnd,float2(-1,-1))+MakeLoop(offset,cell,rnd,float2(-1,0))+MakeLoop(offset,cell,rnd,float2(0,-1))+MakeLoop(offset,cell,rnd,float2(0,0));
    69.             o.Albedo = decalColor;
    70.             fixed4 RainNormal = normalize(float4(0,0,1,1)+StackedDecal);
    71.             o.Normal = normalize(lerp(norm,UnpackNormal(RainNormal),_Slider));
    72.             o.Emission = refl*0.5 ;
    73.         }
    74.         ENDCG
    75.     }
    76.     FallBack "Diffuse"
    77. }
    78.  
    I am also hosting the shader as .txt and the images i used for testing here;
    http://annihlator.nl/unity/Shared/Raindrop TextureBomb/

    RANDOM TEXTURE: http://annihlator.nl/unity/Shared/Raindrop TextureBomb/random.gif (forked from the linked topic posted earlier)
    Normalmap Torus (for the raindrops): http://annihlator.nl/unity/Shared/Raindrop TextureBomb/Torus.png
    Alternative normal map (smaller torus): http://www.annihlator.nl/unity/Shared/Raindrop TextureBomb/SmallTorus.png
    Alternative normal map, three small tori (works best for me): http://www.annihlator.nl/unity/Shared/Raindrop TextureBomb/TriSmallTorus.png
    Shader source: http://annihlator.nl/unity/Shared/Raindrop TextureBomb/Raindrop TextureBomb.txt

    Feel free to toy around with it, later this afternoon i'll see if i can combine it into a small webplayer build too.
    ENJOY! DONE, added link on top of this post

    note; the shader currently is NOT sm2.0 compatible, and there should be an easier method of passing variables between my MakeLoop function, can anyone help me out? i can't seem to find an alternative to pass the values :$
     
    Last edited: Jun 20, 2013
    tinyant likes this.
  10. tinyant

    tinyant

    Joined:
    Aug 28, 2015
    Posts:
    127

    example is out of date.
    we want see it's magic.
    thanks