本文参考SIKI老师的Shader视频教程进行的学习总结
Shader介绍
unity中GameObject由Component组成,与渲染有关的两个组件Mesh Filter、Mesh Renderer
- Mesh Filter:存储一个Mesh(模型网格,就是模型由哪些三角面组成,组成一个什么样子的模型,三角面的一些顶点信息)
- Mesh Renderer:用来渲染模型的外观,就是样子,按照Mesh给它的皮肤,给它的颜色。通过Material(材质)控制模型渲染的样子
- Material:由贴图(可以没有,可以是单纯的颜色)和Shader组成
- Shader(着色器):实际上就是一小段程序它负责将输入的Mesh(网格)以指定的方式和输入的贴图或者颜色等组合作用,然后输出。绘图单元可以依据这个输出来将图像绘制到屏幕上。输入的贴图或者颜色等,加上对应的Shader,以及对Shader的特定的参数设置,将这些内容(Shader及输入参数)打包存储在一起,得到的就是一个Material(材质)。之后,我们便可以将材质赋予合适的renderer(渲染器)来进行渲染(输出)了。
OpenGL、DirectX介绍
图像编程接口。OpenGL稳定,可跨平台使用。DirectX由微软开发,Windows平台游戏基本上都使用DirectX开发。
shader可以认为是一种渲染命令 ,由opengl 或者dx进行解析,来控制渲染丰富多彩的图形。
Shader Language介绍
- OpenGL: 使用GLSL 编写shader
- DirectX 使用HLSL 编写shader
- 英伟达 CG 编写shader(跨平台)
- Unity中使用的是ShaderLab编写Unity中的Shader,是基于CG进行了封装
Unity Shader的分类
- 表面着色器 Surface Shader
- 顶点/片元着色器 Vertex/Fragment Shader
- 固定函数着色器 Fixed Function Shader
Unity Shader的基本结构
Shader "Custom/MyShader"{
Properties{
}
SubShader{
Pass{
CGPROGRAM
ENDCG
}
}
FallBack "Diffuse"
}
- Custom/MyShader :定义了Shader在Inspector面板中的路径
- Properties :Shader属性
- SubShader :利用定义的Shader属性而实现的渲染代码来控制渲染的效果,Shader中可以包含多个SubShader,显卡运行效果的时候从第一个SubShader开始,如果第一个SubShader的效果都可以实现,那么就使用第一个SubShader,如果显卡发现这个SubShader里面的某些效果实现不了,它会自动运行下一个SubShader
- Pass :一个SubShader 中必须包含一个Pass
- FallBack :后备方案如果显卡发现没有满足的SubShader则会使用FallBack中定义的Shader
Properties属性介绍
Properties{
_Color("Color",Color) = (1,1,1,1) //颜色rgba
_Vector("Vector",Vector) = (1,2,3,4) //一个四维向量
_Int("Int",Int) = 123 //整数
_Float("Float",Float) = 4.5 //浮点数
_Range("Range",Range(0,100)) = 61 //浮点数范围
_2D("2D",2D) = "white"{} //2D贴图
_Cube("Cube",Cube) = "red"{} //Cube贴图(天空盒)
_3D("3D",3D) = "white"{} //3D贴图
}
- 属性定义格式:变量名(Inpsector显示名,类型) = 默认值
- _2D、_Cube、 _3D:默认值为通过一个字符串后跟一个花括号指定。字符串要么为空,要么是内置的纹理名称,如“white”、“black”、“gray”或者”bump”,当在Inspector面板中该属性未指定图片时,则值为设置的纹理颜色,若设置了图片则值为图片的颜色
- 属性的使用 :需在SubShader中重新定义
SubShader{
Pass{
CGPROGRAM
float4 _Color; //float4对应Color
float4 _Vector; //float4对应Vector
float _Int; //float对应Int
float _Float; //float对应Float
float _Range; //float对应Range
sampler2D _2D; //sampler2D对应2D
samplerCube _Cube; //samplerCube对应Cube
sampler3D _3D; //sampler3D对应3D
ENDCG
}
}
- float、half、fixed 的区别:float为32位存储、half为16位存储范围为(-6万~6万)、fixed为11位存储范围为(-2~2),根据数据的类型对应相应的类型可节约显存空间
顶点、片元函数介绍
- 基本结构:
SubShader{
Pass{
CGPROGRAM
#pragma vertex vert //顶点函数,这里只是申明了顶点函数的函数名为vert
#pragma fragment frag //片元函数,这里只是申明了片元函数的函数名为frag
//a2v application to vertex
struct a2v {
float4 vertex : POSITION; //告诉Unity将模型空间下的顶点坐标填充给vertex
float3 normal : NORMAL; //告诉Unity将模型空间下的法线方向填充给normal
float4 texcoord : TEXCOORD0; //告诉Unity把第一套纹理坐标填充给texcoord
};
struct v2f {
float4 position : SV_POSITION;
float3 tempColor : COLOR0;
};
v2f vert(a2v v){
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex); //将顶点坐标通过矩阵运算从模型空间转换到裁剪空间
f.tempColor = v.normal;
return f;
}
fixed4 frag(v2f f) : SV_TARGET{
return fixed4(f.tempColor,1); //顶点的法线作为返回的颜色值
}
ENDCG
}
}
- 声明
#pragma vertex vert //顶点函数,这里只是申明了顶点函数的函数名为vert
#pragma fragment frag //片元函数,这里只是申明了片元函数的函数名为frag
- 顶点函数的基本作用:是将顶点从模型空间变换到裁剪空间
- 片元函数的基本作用:返回模型对应的屏幕上的每一个像素的颜色值
- 参数语义
从应用程序传递到顶点函数的语义有哪些a2v
struct a2v {
float4 vertex : POSITION; //告诉Unity将模型空间下的顶点坐标填充给vertex
float3 normal : NORMAL; //告诉Unity将模型空间下的法线方向填充给normal
float4 texcoord : TEXCOORD0; //告诉Unity把第一套纹理坐标填充给texcoord
};
POSITION 顶点坐标(模型空间下的)
NORMAL 法线( 模型空间下)
TANGENT 切线(模型空间)
TEXCOORD0 ~n 纹理坐标
COLOR 顶点颜色
从顶点函数传递给片元函数的时候可以使用的语义
struct v2f {
float4 position : SV_POSITION;
float3 tempColor : COLOR0;
};
SV_POSITION 剪裁空间中的顶点坐标(一般是系统直接使用)
COLOR0 可以传递一组值 4个
COLOR1 可以传递一组值 4个
TEXCOORD0~7 传递纹理坐标
片元函数传递给系统
fixed4 frag(v2f f) : SV_TARGET{
return fixed4(f.tempColor,1); //顶点的法线作为返回的颜色值
}
SV_Target 颜色值,显示到屏幕上的颜色
- 运行效果