Sunday 17 July 2016

Learning Shader Writing - Unity Tutorial



I don't really know what possessed me to do it, but I took a course, again from Coursera, this time on Robotics flight of all things.

Almost, but not quite managed to pass. The last assignment took me too much time, and I could not complete it by the deadline. The maths was pretty tough, given I have very little background in it. But the plus side is that I can do matrix operations, and sort of calculate rotations and vectors in 3D space now.

And of course, 3D is all about matrices, vectors and trigonometry! I have been considering for a while now to moving into a tech artist position, and shader writing seems to be a really desirable skill to have. What do you know? That matrix, vector, and trigonometry stuff is running the show behind the back. Amazing, I can actually understand how the rim light, reflection, ambient light etc is derived now. Still going through the tutorial, which is from https://cgcookie.com/learn-unity/. The tutorial is by Alex Telford. It's archived now, but you can grab the stuff here.

Been really interesting so far!

Some sample code:


----------------------------

Shader "unityCookie/tut/beginner/6_textures"{
Properties{
_Color("Color Tint", Color)=(1.0, 1.0, 1.0, 1.0)
_MainTex("Diffuse Texture", 2D) = "white" {}
_SpecColor("Specular Color", Color) = (1.0, 1.0, 1.0, 1.0)
_Shininess("Shininess", Float) = 10
_RimColor("Rim Color", Color) = (1.0, 1.0, 1.0, 1.0)
_RimPower("Rim Power", Range(0.1, 10.0)) = 3.0 

}
SubShader {
Pass{
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

//user-define variables
uniform float4 _Color;
uniform float4 _SpecColor;
uniform float4 _RimColor;
uniform float _Shininess;
uniform float _RimPower;
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;

//unity defined variables
uniform float4 _LightColor0;

//base input structs
struct vertexInput{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;

};

struct vertexOutput{
float4 pos : SV_POSITION;
float4 tex : TEXCOORD0;
float4 posWorld : TEXCOORD1;
float3 normalDir : TEXCOORD2;

};

//vertex function

vertexOutput vert(vertexInput v){
vertexOutput o;

o.posWorld = mul(_Object2World, v.vertex);
o.normalDir = normalize(mul(float4(v.normal, 0.0), _World2Object).xyz);
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.tex = v.texcoord;

return o;

}

//fragment function
float4 frag(vertexOutput i) : COLOR{
float3 normalDirection = i.normalDir;
float3 viewDirection = normalize( _WorldSpaceCameraPos.xyz - i.posWorld.xyz );
float3 lightDirection;
float atten;

if(_WorldSpaceLightPos0.w == 0.0){//directional light
atten = 1.0;
lightDirection = normalize(_WorldSpaceLightPos0.xyz);

}
else{
float3 fragmentToLightSource = _WorldSpaceLightPos0.xyz - i.posWorld.xyz;
float distance = length(fragmentToLightSource);
atten = 1.0/distance;
lightDirection = normalize(fragmentToLightSource);
}

//Lighting

float3 diffuseReflection = atten * _LightColor0.xyz * saturate(dot(normalDirection, lightDirection));
float3 specularReflection = diffuseReflection * _SpecColor.xyz * pow(saturate(dot(reflect(-lightDirection, normalDirection), viewDirection)) ,_Shininess);

//Rim Lighting
float rim = 1 - saturate(dot(viewDirection, normalDirection));
float3 rimLighting = saturate(dot(normalDirection, lightDirection) * _RimColor.xyz * _LightColor0.xyz * pow(rim, _RimPower));

float3 lightFinal = UNITY_LIGHTMODEL_AMBIENT.xyz + diffuseReflection + specularReflection + rimLighting;

//Texture Maps
float4 tex = tex2D(_MainTex, i.tex.xy * _MainTex_ST.xy + _MainTex_ST.zw);

return float4(tex.xyz * lightFinal * _Color.xyz, 1.0);
}
ENDCG
}

Pass{
Tags {"LightMode" = "ForwardAdd"}
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

//user-define variables
uniform float4 _Color;
uniform float4 _SpecColor;
uniform float4 _RimColor;
uniform float _Shininess;
uniform float _RimPower;
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;

//unity defined variables
uniform float4 _LightColor0;

//base input structs
struct vertexInput{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;

};

struct vertexOutput{
float4 pos : SV_POSITION;
float4 tex : TEXCOORD0;
float4 posWorld : TEXCOORD1;
float3 normalDir : TEXCOORD2;

};

//vertex function

vertexOutput vert(vertexInput v){
vertexOutput o;

o.posWorld = mul(_Object2World, v.vertex);
o.normalDir = normalize(mul(float4(v.normal, 0.0), _World2Object).xyz);
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.tex = v.texcoord;

return o;

}

//fragment function
float4 frag(vertexOutput i) : COLOR{
float3 normalDirection = i.normalDir;
float3 viewDirection = normalize( _WorldSpaceCameraPos.xyz - i.posWorld.xyz );
float3 lightDirection;
float atten;

if(_WorldSpaceLightPos0.w == 0.0){//directional light
atten = 1.0;
lightDirection = normalize(_WorldSpaceLightPos0.xyz);

}
else{
float3 fragmentToLightSource = _WorldSpaceLightPos0.xyz - i.posWorld.xyz;
float distance = length(fragmentToLightSource);
atten = 1.0/distance;
lightDirection = normalize(fragmentToLightSource);
}

//Lighting

float3 diffuseReflection = atten * _LightColor0.xyz * saturate(dot(normalDirection, lightDirection));
float3 specularReflection = diffuseReflection * _SpecColor.xyz * pow(saturate(dot(reflect(-lightDirection, normalDirection), viewDirection)) ,_Shininess);

//Rim Lighting
float rim = 1 - saturate(dot(viewDirection, normalDirection));
float3 rimLighting = saturate(dot(normalDirection, lightDirection) * _RimColor.xyz * _LightColor0.xyz * pow(rim, _RimPower));

float3 lightFinal = diffuseReflection + specularReflection + rimLighting;

//Texture Maps
float4 tex = tex2D(_MainTex, i.tex.xy * _MainTex_ST.xy + _MainTex_ST.zw);

return float4(tex.xyz * lightFinal * _Color.xyz, 1.0);
}
ENDCG
}
}
//Fallback "Specular"
}

----------------------------

No comments:

Post a Comment