simple CG surface shader breakdown
A simple shader in Unity has a certain structure..
It starts with the main block:
shader("folder/name")
{
//everything in here
}
We have the word "shader" that tells Unity we're writing a shader. The "folder" part will create a folder in the shader drop down menu of the Unity Material. The "name" will be the name of your shader that sits in that folder.
Next comes the Properties - these are the exposed properties that the user will see in the Unity inspector. These sit inside the shader block, as does everything else we're going to add.
shader("folder/name")
{
Properties
{
_myColor("My Color",color)=(1,1,1,1)
_myTex("My Texture",2D)="White"{}
_myFloat("My Float Value",float)=1.3
}
}
So this is our first sub block of the shader. It seems like a lot of coders like to put the underscore in front of their defined _names. I guess this is good for identifying user-created variable names. You don't actually have to do this. Generally the pattern for defining properties is - name("name that will show up in Unity inspector", type of data)=value (followed by {} sometimes).
It's good to note - there are no semicolons after each of these definitions. Also notice that 2D is 2D and not 2d. Remembering this will be useful!
After the Properties we typically add the Subshader block. This is the meat of the Shader, so lets add that in & some of the other essential parts.
shader("folder/name")
{
Properties
{
_myColor("My Color",color)=(1,1,1,1)
_myTex("My Texture",2D)="White"{}
_myFloat("My Float Value",float)=1.3
}
Subshader
{
CGPROGRAM
#pragma surface surf Lambert
fixed4 _myColor;
Sampler2D _myTex;
float _myFloat;
ENDCG
}
Fallback "Diffuse"
}
Our next sub block is the Subshader, it starts and ends with CGPROGRAM and ENDCG, which tells Unity that we're using the CG language (an earlier version of HLSL, something we've met in the Compute Shader notes). Next we have a pragma defining a "surface" called "surf" of type "Lambert"
We will actually flesh out "surf" in a bit! After this, we now bring all of the properties we defined at the start into the subshader. It is important to use the same names here, otherwise we'll get errors. Notice the datatypes we use - fixed4 for colours, sampler2D for the texture..
After the Subshader block we add the Fallback "Diffuse", which just gives the shader a standard default diffuse look if the device cannot support our shader code.
Next up is a struct for our input and the defining of the surface "surf".
shader("folder/name")
{
Properties
{
_myColor("My Color",color)=(1,1,1,1)
_myTex("My Texture",2D)="White"{}
_myFloat("My Float Value",float)=1.3
}
Subshader
{
CGPROGRAM
#pragma surface surf Lambert
fixed4 _myColor;
Sampler2D _myTex;
float _myFloat;
struct Input{
float2 uv_myTex;
};
void surf(Input IN, inout SurfaceOutput o)
{
fixed3 texCol=tex2D(_myTex,IN.uv_myTex).rgb;
o.Albedo=_myColor*texCol*_myFloat;
}
ENDCG
}
Fallback "Diffuse"
}
Our Input struct is very basic - it holds the uv info specfically for our _myTex texture. You can have 2 uv sets in Unity. If you were using the 2nd group this would be called "uv2_myTex". Typically the uv variables are always uvNAMEYOUUSED.
Defining the surface "surf" - we name our "Input" IN and also name our SurfaceOutput "o" in the arguments. We define a temporary variable "texCol" of type fixed3 (since we only want the rgb at the moment) - and we call the tex2D function to get the rgb value from texture _myTex at the uv values from our input IN.
o.Albedo is just one of the outputs we can output here I'm multiplying (or tinting) the texture colour we just got by the picked colour and also by the float value for good measure.
And that's it for a very simple/basic surface shader. I think I'll cover fragment vertex shaders next, which are a little bit more complex.
Comments
Post a Comment