The specific RM shader.

I spent the whole afternoon yesterday writing the shader for this specific project, trying to make it as minimalistic as possible. The result became pretty good, the shader does everything I want it to do, and nothing more. 

Implementation in CG:

Defining the variables that should be used in this shader:

  sampler2D _MainTex;
  sampler2D _NormalMap;
  sampler2D _HeightMap;
  float _Height;
  float _Gloss;
  float _ColorIntensity;
  float _Specular;
  struct Input { // vertex input
   float2 uv_MainTex;
   float2 uv_NormalMap;
   float2 uv_HeightMap;
   float3 viewDir;

I think each of them is pretty self-explained.  The struct represent the incoming parameters; uv coordinates of the textures applied and view direction.

Luckily, writing shaders in CG for Unity doesn't involve that much math. The ray is set up:

  IN.viewDir = normalize(IN.viewDir); 
  // set up the ray
  float3 p = float3(IN.uv_MainTex,0);
  float3 v = normalize(IN.viewDir*-1);
  v.z = abs(v.z);
  v.xy *= _Height;

Implementing the ray tracer:

  // ray tracer with linear and binary search
  const int linearSearchSteps = 20;
  const int binarySearchSteps = 20;
  v /= v.z * linearSearchSteps;
  int i;
  for( i=0;i(lessthen)linearSearchSteps;i++ )
      float tex = tex2D(_HeightMap, p.xy).a;
      if (p.z(lessthen)tex) p+=v;
  for( i=0;i(lessthen)binarySearchSteps;i++ )
      v *= 0.5;
      float tex = tex2D(_HeightMap, p.xy).a;
      if (p.z(lessthen)tex) p += v; else p -= v;
This the exact same procedure that was explained in the post about Relief Mapping. As you can see in the binary search, we move up if the height map shows a greater value. If it shows a smaller value, we move down.
Note: The html editor didn't want me to use > and < signs.

Next thing is to generate the output:

  // generate the output  
  half4 tex = tex2D(_MainTex, p.xy);
  half3 normal = UnpackNormal(tex2D(_NormalMap,p.xy)); // normal map

  normal.z = sqrt(1.0 - dot(normal.xy,  normal.xy));
  OUT.Normal = normal; 
  OUT.Gloss = tex.a*_Gloss;
  OUT.Specular = _Specular;
  OUT.Albedo = tex.rgb *_ColorIntensity;

 The _Gloss, _Specular and _ColorIntensity variables manipulates the output of the texture. Which is basically created out of the mods I did to the test shader.

The last thing is to implement what parameters that should be modified from the Unity interface. In addition to the most obvious (textures, specular color, height), I added those variables showed above.
  _ColorIntensity ("Color Intensity", Range(0.5, 1.5)) = 1
  _SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
  _Gloss ("Gloss", Range(0.5, 1.5)) = 1
  _Height ("Height", Range(-0.05, 0.05)) = -0.01
  _Specular ("Shininess", Range (0.01, 0.1)) = 0.014
  _MainTex ("Base (RGB), Spec (A)", 2D) = "white" {}
  _NormalMap ("Normalmap", 2D) = "bump" {}
  _HeightMap ("Height (A)", 2D) = "bump" {} 

This is about it for the implementation. A very minimal relief mapping shader, that works flawless for its purpose. When I've created a proper height map, I'm gonna post some result using this shader and the new height map. 

No comments:

Post a Comment