Cg/HLSL shaders

The shading language used in Unity is a variety of HLSL, or sometimes referred to as Cg. This shading variant provides two different forms of shaders: surface and vertex/fragment shaders. Now, coming from Android, this may sound confusing, since GLSL treats vertex and fragment shaders differently. However, variety of HLSL in Unity treats vertex and fragment shaders as the same, since they reside in the same file and are in the same workflow. A surface shader, which handles the lighting of our model, can be simple or quite complex. The Standard Unity surface shader uses a PBR lighting model, which is quite advanced and not supported on most mobile devices. This issue, combined with our limited ability to track scene lights, limits us to writing our own shaders in order to get our object lighting correct. ARCore provides us with a very simple surface shader that is used in the sample to light the Andy model. Let's open up Unity and take a look at what that shader looks like by following the given steps:

  1. Load up the HelloAR sample project and scene.
  2. Select the AndyMaterial in the Assets/GoogleARCore/HelloARExample/Materials/Andy folder. Ensure that the Shader is set to ARCore/DiffuseWithLightEstimation. Switch it back if you changed it.
  3. Click on the Gear icon and from the context menu, select Edit Shader. This will open the shader in your code editor, and it is also shown here for reference:
Shader "ARCore/DiffuseWithLightEstimation"
{
Properties
{
_MainTex ("Base (RGB)", 2D) = "white" {}
}

SubShader
{
Tags { "RenderType"="Opaque" }
LOD 150

CGPROGRAM
#pragma surface surf Lambert noforwardadd finalcolor:lightEstimation

sampler2D _MainTex;
fixed _GlobalLightEstimation;

struct Input
{
float2 uv_MainTex;
};

void lightEstimation(Input IN, SurfaceOutput o, inout fixed4
color)
{
color *= _GlobalLightEstimation;
}

void surf (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}

Fallback "Mobile/VertexLit"
}
  1. This is a fairly simple diffuse lighting shader that uses the global light estimate we calculated earlier. It starts by defining itself with this line:
Shader "ARCore/DiffuseWithLightEstimation"
  1. Next, it defines Properties in the next code block, where _MainTex represents the base texture, is called "Base (RGB)", and is set to 2D. If you quickly look back at Unity, you can see this property in the Inspector window.
  2. The block of code that starts with SubShader is where the action happens. We first define Tags, which are sets of key/value pairs that set the rendering order and type parameters. In our example, we set this to Opaque. Then, we have the following line:
LOD 150
  1. This determines the level of detail of the shader. The LOD directive is used to determine the complexity or performance requirements of the shader. You can set the value to anything, but typical values are shown in the following list:
    • VertexLit kind of shaders = 100
    • Decal, Reflective VertexLit = 150
    • Diffuse = 200
    • Diffuse Detail, Reflective Bumped Unlit, Reflective Bumped VertexLit = 250
    • Bumped, Specular = 300
    • Bumped Specular = 400
    • Parallax = 500
    • Parallax Specular = 600
  2. As you can see from the list, the simple shader represents a low level of detail. This means that lower-level hardware should be able to run this shader without any issue. You can set the maximum shader LOD per shader or globally; check the Unity documentation for further details.
  3. We start our actual shader code with CGPROGRAM and then define the form of surface shader with the #pragma directive, as shown in the following code:
#pragma surface surf Lambert noforwardadd finalcolor:lightEstimation

#pragma surface surfaceFunction lightModel [optionalparams]
  1. The first part of the directive, surface, defines this as a surface shader. Then, we see that the surf function name refers to the main surface function. Then comes the lighting model, Lambert in this case. After that, the options are set to noforwardadd, which is just a simple way to limit the number of lights to one. Finally, we use a custom modification function called lightEstimation that is set with finalcolor:lightEstimation.
This shader uses the Lambert lighting model. You can find plenty of examples of what lighting models Unity supports or how to write your own model at https://docs.unity3d.com/Manual/SL-SurfaceShaderLightingExamples.html.
  1. Just inside the #pragma directive, we see the definition of the shader inputs: _MainTex, _GlobalLightEstimation, and struct Input. If you recall, _GlobalLightEstimation is the variable we set inside the EnvironmentalLight script to represent our global light.
  2. Next, we will jump down a few lines to the surf function, as follows:
void surf (Input IN, inout SurfaceOutput o)
{
fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
  1. This function simply samples the color from our _MainTex using tex2D and the input uv coordinates. Then, it sets the color (Albedo) and Alpha from the lookup. This function is called first to determine the color of the surface, and then, its output is passed to the Lambert lighting model, after which the final color is set by the lightEstimation function.
    An input marked as inout represents a value that can be modified and will automatically be returned.
  2. Scroll up a bit to the lightEstimation function. Inside this function, the code, shown as follows, modifies the color based on the value that was set for _GlobalLightEstimation:
color *= _GlobalLightEstimation;
  1. Multiplying the color by the global light estimation is the same as adjusting the brightness with a dimmer switch.
  2. Finally, we complete the shader with Fallback and the name of another shader. This sets the fall back or backup shader if the current shader is unable to run. A shader can fail due to compilation errors or hardware limitations.

Now that we have a clear understanding of how the light estimation value we saw generated earlier is used in the shader, we can move to perhaps enhancing our lighting. If you recall, our current light just points straight down, but ideally, we would like to position the light to match the strongest light source. We will look at a simple but effective technique to track and position a light in AR in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.156.25