Search Unity

Fur Shader

Discussion in 'Shaders' started by cgoran, Apr 11, 2007.

  1. cgoran

    cgoran

    Joined:
    Jun 11, 2005
    Posts:
    176
    Does anyone have a fur shader?
     
  2. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
    cg-I dont but if your any shadersmith you could try to mod the grassonmeshgenerator? I might know how to do it in about 3 years from now I estimate... :wink:

    When I tried the grass thingy, I got hair but it floated in 3d space around my model, which is not the effect we're after. I would say its do-able, I just dont know how...yet...

    Hows your wicked nature scene going?
    AC
     
  3. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    I've considered modifying the grass on mesh generator to work with fur, but it would take a LOT of effort to make:
    1) the "grass" stay normalized to the skin's normals, and also billboarded to the camera
    2) to keep its positions on the surface of an animated mesh
     
  4. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
    Good points.

    I'd be very suprised if the freakin' genius's' round here havent tried it because based on billboarding, It should work, and , it would look awesome (if it ran fast enough) and would be a cool advertisment for unity.

    It just occured to me to try the mesh particle emmitter inna oneshot style sometime, of course it only emits from verts ( I may be wrong) and getting the rotation of each particle will be a trick. I cant try it yet, too much to do.
    AC
     
  5. shaun

    shaun

    Joined:
    Mar 23, 2007
    Posts:
    728
    Ive been using this Fur shader in another 3D engine - I'm not familiar enough with Unity/Shaders to know how to update it. Maybe one of our resident Shader gurus can help ;)

    Code (csharp):
    1.  
    2. float4x4 World      : WORLD;                // Object World Matrix
    3. float4x4 Wvp        : WORLDVIEWPROJECTION;  // World x View x Projection Matrix
    4.  
    5. int PassCount       : PASSCOUNT;            // Shader's Pass Count
    6. int PassIndex       : PASSINDEX;            // Current Rendering Pass Index
    7.  
    8. float4   mat_diffuse  : DIFFUSE;            // material default diffuse color
    9.  
    10. float3  localLightPos   : NEARESTLIGHT <string Space="Local";>;
    11. float4  LightColor      : NEARESTLIGHT <float4 Default={1,1,1,1};>;
    12. float   FurLength       <float UIMin=0.5; float UIMax=3;> = 1.5;
    13. float   FurThickness    <float UIMin=1.0; float UIMax=5;> = 3.0;
    14.  
    15. /******************************************************
    16. Compute Diffuse color using a position, normal
    17. and light position
    18. *******************************************************/
    19. float4 DiffuseLighting(float3 lPos,float3 lNorm)  
    20. {
    21.     float3 lightDir = normalize( localLightPos - lPos );
    22.    
    23.     //--- Compute resulting diffuse
    24.     return clamp((mat_diffuse * LightColor * dot(lNorm, lightDir)),0,1) + mat_diffuse*0.5f;
    25. }
    26.  
    27.  
    28.  
    29. //---------------------------------------------------------------------------------
    30. //Output vertex format
    31. struct vOUTPUT
    32. {
    33.     float4 Position     : POSITION;
    34.     float4 Color        : COLOR;
    35.     float2 TexCoord     : TEXCOORD0;   
    36.     float2 TexCoord1    : TEXCOORD1;   
    37. };
    38.  
    39. /**********************************************
    40. Vertex shader is the same for all 20 passes:
    41. Automatic parameters (PassIndex and PassCount) are used
    42. to compute the correct position of the current shell
    43. ***********************************************/
    44. vOUTPUT FurVertexShaderPass( float3 Position : POSITION,
    45.                              float3 Normal   : NORMAL,
    46.                              float2 Tex0     : TEXCOORD0 )
    47. {
    48.     vOUTPUT Out = (vOUTPUT)0;
    49.  
    50.  
    51.     //--- Compute current pass ratio[0..1]
    52.     float passRatio = (float)(PassIndex) / (float)PassCount;
    53.    
    54.     //--- Square it so that is not linear
    55.     passRatio  *= passRatio;
    56.  
    57.     //--- Compute position for this shell
    58.     float3 p =  Position + (Normal * passRatio * FurLength);
    59.    
    60.     Out.Position = mul(float4(p,1),Wvp);                    
    61.     Out.Color = DiffuseLighting(p,Normal);
    62.     Out.Color.a = (1.0f - passRatio);
    63.  
    64.     Out.TexCoord = Tex0;
    65.     Out.TexCoord1 = Tex0 * FurThickness;
    66.  
    67.     return Out;
    68. }
    69.  
    70. texture BaseTexture : TEXTURE;  // Current Material Texture
    71. texture NoiseTexture;
    72.  
    73. //---------- Sampler
    74. sampler BaseSampler = sampler_state {
    75.     texture = <BaseTexture>;
    76.     MipFilter = LINEAR;
    77.     Minfilter = LINEAR;
    78.     Magfilter = LINEAR;
    79. };
    80. sampler NoiseSampler = sampler_state {
    81.     texture = <NoiseTexture>;
    82.     MipFilter = LINEAR;
    83.     Minfilter = LINEAR;
    84.     Magfilter = LINEAR;
    85. };
    86.  
    87.  
    88. /**********************************************
    89. The pixel shader is the same for all 20 passes:
    90. It multiplies the color of the base texture with iterated color
    91. and the fur texture color.
    92. ***********************************************/
    93. float4 FurPixelShader(vOUTPUT In) : COLOR
    94. {
    95.     float4 bCol = tex2D( BaseSampler, In.TexCoord );
    96.     float4 nCol = tex2D( NoiseSampler, In.TexCoord1 );
    97.     float4 alpha = float4(1,1,1,nCol.a);
    98.     return (bCol+bCol.a*nCol.a*0.35) * alpha * In.Color;
    99. }
    100.  
    101. /************************************
    102. This technique consists in rendering 20 shells
    103. of the same object using a decreasing alpha
    104. **************************************/
    105. technique Fur
    106. {
    107.     pass p0
    108.     {
    109.         AlphaTestEnable = TRUE;
    110.         AlphaFunc       = GREATER;
    111.         AlphaRef        = 3;       
    112.  
    113.         AlphaBlendEnable= TRUE;
    114.  
    115.         DestBlend       = INVSRCALPHA;
    116.         SrcBlend        = SRCALPHA;
    117.    
    118.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    119.         PixelShader = compile ps_1_1 FurPixelShader();
    120.     }
    121.     pass p1 {
    122.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    123.         PixelShader = compile ps_1_1 FurPixelShader(); 
    124.     }
    125.     pass p2 {
    126.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    127.         PixelShader = compile ps_1_1 FurPixelShader(); 
    128.     }
    129.     pass p3
    130.     {
    131.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    132.         PixelShader = compile ps_1_1 FurPixelShader(); 
    133.     }
    134.     pass p4
    135.     {
    136.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    137.         PixelShader = compile ps_1_1 FurPixelShader(); 
    138.     }
    139.     pass p5
    140.     {
    141.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    142.         PixelShader = compile ps_1_1 FurPixelShader(); 
    143.     }
    144.     pass p6
    145.     {
    146.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    147.         PixelShader = compile ps_1_1 FurPixelShader(); 
    148.     }
    149.     pass p7
    150.     {
    151.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    152.         PixelShader = compile ps_1_1 FurPixelShader(); 
    153.     }
    154.     pass p8
    155.     {
    156.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    157.         PixelShader = compile ps_1_1 FurPixelShader(); 
    158.     }
    159.     pass p9
    160.     {
    161.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    162.         PixelShader = compile ps_1_1 FurPixelShader(); 
    163.     }
    164.     pass p10
    165.     {
    166.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    167.         PixelShader = compile ps_1_1 FurPixelShader(); 
    168.     }
    169.     pass p11
    170.     {
    171.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    172.         PixelShader = compile ps_1_1 FurPixelShader(); 
    173.     }
    174.     pass p12
    175.     {
    176.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    177.         PixelShader = compile ps_1_1 FurPixelShader(); 
    178.     }
    179.     pass p13
    180.     {
    181.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    182.         PixelShader = compile ps_1_1 FurPixelShader(); 
    183.     }
    184.     pass p14
    185.     {
    186.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    187.         PixelShader = compile ps_1_1 FurPixelShader(); 
    188.     }
    189.     pass p15
    190.     {
    191.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    192.         PixelShader = compile ps_1_1 FurPixelShader(); 
    193.     }
    194.     pass p16
    195.     {
    196.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    197.         PixelShader = compile ps_1_1 FurPixelShader(); 
    198.     }
    199.     pass p17
    200.     {
    201.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    202.         PixelShader = compile ps_1_1 FurPixelShader(); 
    203.     }              
    204.     pass p18
    205.     {
    206.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    207.         PixelShader = compile ps_1_1 FurPixelShader(); 
    208.     }
    209.     pass p19
    210.     {
    211.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    212.         PixelShader = compile ps_1_1 FurPixelShader(); 
    213.     }
    214.     pass p20
    215.     {
    216.         VertexShader = compile vs_1_1 FurVertexShaderPass();
    217.         PixelShader = compile ps_1_1 FurPixelShader(); 
    218.     }          
    219.  
    220. }
    221.  
     
  6. Jonathan Czeck

    Jonathan Czeck

    Joined:
    Mar 17, 2005
    Posts:
    1,713
    That technique would translate to Unity easily. I'm not sure vertex programs are required. Seems you coule just pregenerate the shell mesh. Maybe not without a Bone interface in Unity. But 20 passes seems a bit crazy. Is there a better technique out there than the shells/fins method? ... besides a GeForce 8800 and a geometry shader.

    -Jon
     
  7. shaun

    shaun

    Joined:
    Mar 23, 2007
    Posts:
    728
    I thought 20 passes seemed a lot too, but the performance seems to be very good. Ive also tried with only 10 passes and it still looks good for closely "cut" hair - maybe it should be called a fuzz shader rather than fur. Either way it softens the objects outline nicely and looks best at mid-distance to camera.

    What other techniques are there for doing fur? Would there be a more optimal way than the shell technique?
     

    Attached Files:

  8. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
    OMG look at that...Id.... to see this in unity......... :eek:
    AC
     
  9. cgoran

    cgoran

    Joined:
    Jun 11, 2005
    Posts:
    176
    Wow sweetness.

    I wonder if there is a way to drive the fur iterations based on alpha from a texture map?
     
  10. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    Usually you don't drive the iterations; instead you drive "fur length" from the texture map. The card still draws all the layers (=iterations), you just kill the pixels in higher layers based on the texture.