2. First Steps
5. Your first shader
5.1 Create a shader
The resources includes two unity projects shared is complete and shared as learned shared as complete as the final finished version of each example that we going to work through in the course.
Create a single Quad and use this.
Now we create a simply shader:
Shader "YaoShaders/Shader1Unlit"
{
Properties
{
}
SubShader
{
//we will find out more about random typer later
Tags { "RenderType"="Opaque" }
//LOD 100 is simpleast detail option for unity standard types
//it means we not concerned about lighting
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#include "UnityCG.cginc"
fixed4 frag (v2f_img i) : SV_Target
{
//we don't use the data.we just simply return a
//vector value of 1,0,0,1.
return fixed4(1,0,0,1);
}
ENDCG
}
}
}
5.2 Summary
- You need a vertex shader and a fragment shader.
- The fragment shader function must return the color of the pixel it is current working on as a 4 compoent vector, an rgba value.In the example we return a fixed value of (1,0,0,1)
- Each channel of an rgba format color takes a value between 0 and 1.
6. Working with vectors in GG
6.1 CG vectors
- CG vectors can type2,type3,type4
- Where type can be int,bool,half,fixed,float or double
- Convert a type3 to a type4 using a type4 constructor.Eg
fixed3 color = fixed3(1,0,0);
fixed4 finalColor = fixed4(color,1);
6.2 Setting the color
fixed3(sin(_Time.y)+1)/2,(cos(_Time.y)+1)/2)
Red chanel = (sin(_Time.y)+1)/2
6.3 The sin function
Unity passes a number of useful variables sometimes called uniforms because they have the same value
- Unity passes values to shader called uniforms.
- One is a float4 value called _Time
- Time is measured in seconds since the game started
_Time.x = time/20
_Time.y = time
_Time.z = time * 2
_Time.w = time * 3
- So sin(_Time.y) return a value that varies from 0 to 1 to 0 to -1 to 0 every 6.28 seconds.
- By adding 1 the range is now 0 to 2.
- Diving by 2 takes the range to 0 to 1.
6.4 Creating vectors with CG
How to combine:
fixed4 v = 1;//v.x = 1,v.y = 1,v.z = 1 ,v.2 = 1
fixed2 v1 = 1;
fixed v2 = fixed4(v1,v1);
fixed4 v3 = fixed4(v1,1,1);
//Error:fixed4 v3 = fixed4(v1,1);Take care!
How to vary the color with time:
fixed4 frag (v2f_img i) : SV_Target
{
fixed3 color = fixed3((sin(_Time.y)+1)/2,0,(cos(_Time.y)+1)/2);
return fixed4(color,1);//combine
}
then our material will change between red and blue
6.5 Swizzling
It's a methon to **change chanel**.
Example:
fixed4(color,1).gbra
——means green chanel is applie to original red chanel ,blue to green and red to blue.Now color switch between green and blue.
也就是说,这里最后传出去的是RGBA固定的,而点出来的比如gbra,就是color的数值,g = 0,b = cos,r = sin,然后按0,cos,sin的顺序传到RGBA中,得到的就是(0,cos,sin,1),即是绿蓝变换。
总结:把点出来的按顺序,仅看做数值,传到RGBA中。
//rgba red - blue
//rbga green_red
//gbra green_blue
//grba blue_green
//bgra red - blue
//brga green - red
//rrra white _ black
6.6 Summary
- How to create a really simple shader
- How to apply a color to the shader
- How to vary the color with time
- How to create,combine and swizzle vectors
7. Unity Properties
- Int,Float,Vector,Range,Color,2D,CUBE
7.1 The Color Property
- Takes 4 values
- Each value is in the range 0 to 1
- Channels are red,green,blue and alpha
7.2 The CG function lerp
lerp(_ColorA,_ColorB,delta)
- Performs a linear interpolation between _ColorA and _ColorB based on delta
- if delta = 0, return _ColorA
- if delta = 1, return _ColorB
- Return value is
(1-delta)*_ColorA + delta*_ColorB
//code is pseudocode
//"T" only means any type
T lerp(T _ColorA,T _ColorB,float delta)
{
return (1-delta)*_ColorA + delta*_ColorB;
}
Shader:
Shader "NiksShaders/Shader3Unlit"
{
Properties
{
//show in Inspector panel
_ColorA("ColorA",Color) = (1,0,0,1)
_ColorB("ColorB",Color) = (0,0,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#include "UnityCG.cginc"
//used in shader pass
fixed4 _ColorA;
fixed4 _ColorB;
fixed4 frag (v2f_img i) : SV_Target
{
float delta = (sin(_Time.y) + 1)/2;
//lerp return fixed4 but color is fixed3
//so alpha is ignored
fixed3 color = lerp(_ColorA,_ColorB,delta);
return fixed4(color, 1.0);
}
ENDCG
}
}
}
8. Blending Colors
8.1 UV value
- This is a float2 type.
- It has x and y values.
- Each component takes values between 0 and 1.
The fragemnt shader receivers an interpolated value.
When handing this pixel,the v2f_img struct i,will get passed the value(0.0,0.5)for the uv value.
We can see the change in follow shader:
Shader "NiksShaders/Shader4Unlit"
{
Properties
{
_ColorA("Color A", Color) = (1,0,0,1)
_ColorB("Color B", Color) = (0,0,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#include "UnityCG.cginc"
fixed4 _ColorA;
fixed4 _ColorB;
fixed4 frag (v2f_img i) : SV_Target
{
float delta = i.uv.x;//x
fixed3 color = lerp(_ColorA,_ColorB,delta);
return fixed4(color, 1.0);
}
ENDCG
}
}
}
8.2 Passing data from the vertex shader to the fragment shader
- Create a struct.
- Create a vertex shader function.
- All values set in the vertex shader will be interpolated based on fragments(pixel) position within the triangle being rendered.
- Interpolation is a very important point.
8.3 Semantics语义
A semantic is the glue that binds a shader input or output to the rendering hardware.
- SV_POSITION shows the value indicates the position
- Use TEXCOORDn for custom data——其他的TEXCOORDn都是float4最多,按需求来写
- usually TEXCOORD0 for uv——这里只有uv是float2
i.position * 2 = (1,-1,0) : WHY USE POSITION?
- Using saturate this becomes (1,0,0).
- Fixed3(1,0,0) ——red
Shader "NiksShaders/Shader5Unlit"
{
Properties
{
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float4 positon : TEXCOORD1;
};
v2f vert(appdata_base v)
{
v2f o;
o.vertex = UnityWorldToClipPos(v.vertex);//clip coordinates positon
o.positon = v.vertex;//model coordinates position
o.uv = v.texcoord;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
//(-0.5,-0.5,0)->(-1,-1,0)->(0,0,0)
//(0.5,0.5,0)->(1,1,0)->(1,1,0)也就是将坐标系放缩
fixed3 color = saturate(i.positon*2);
return fixed4(color, 1.0);
}
ENDCG
}
}
}
这里说明,颜色是不需要进行坐标变换的,由于片元着色器,是进行逐像素插值,所以,顶点进行了变换,只需要在片元里面按模型空间去着色,就行。
9. Using step and smoothstep
How to divide edge:
9.1 step(edge,n)??
Sharp Edge:
//this function return 0 or 1
int step(float edge,float n)
{
if(n < edge)
return 0;
else if(n > edge)
return 1;
}
So shader:
fixed4 frag (v2f i) : SV_Target
{
//这个位置应该是正交相机下的位置
fixed3 color = i.position * 2;//这就是按位置涂个色
color.r = step(0,color.r);
color.g = step(0,color.g);
return fixed4(color, 1.0);
}
9.2 smoothstep(edge0,edge1,n)
How to blure the edge:
Simply **increase the gap** between edge0 and edge1 **blur** the edge,
and decrease the gap to sharpen the edge .
//pseudocode
int smoothstep(edge0,edge1,n)
{
if(n<edge0)
return 0;
else if(n > edge1)
return 1;
else
{
float t = clamp((n - edge0)/(edge1 - edge0),0,1);
return t*t*(3.0 - 2.0 * t);
}
}
9.3 Challenge
- Draw a yellow circle in the centre of the screen.
- Use i.position and the step method.
- Tip: use length(i.position.xy)
i.position.xy
means (i.position.x,i.position.y)
length
means return sqrt(x^2,y^2)
;