什么是shader?
shader,中文翻译即着色器,是一种较为短小的程序片断,用于告诉图形硬件如何计算和输出图像,过去由汇编语言来编写现在也可以使用高级语言来编写。一句话概括: shader是可编程图形管线的算法片段。
它主要分为两类,Vertex Shader和Fragment Shader.
什么是渲染管线?
渲染管线也称为渲染流水线,是显示芯片内部处理图形信号相互独立的的并行处理单元。一个流水线是一序列可以并行和按照固定顺序进行的阶段。每个阶段都从它的前一阶段接收输入,然后把输出发给随后的阶段。就像一个在同一时间内,不同阶段不同的汽车一起制造的装配线,传统的图形硬件流水线以流水的方式处理大量的顶点、几何图元和片段。
cpu阶段:3D启用或游戏 -> 调用openGL 等接口
gpu阶段:顶点着色器(图形变换运算、光照运算等)片段着色器(计算屏幕上每一个像素应该是什么颜色)
shader和材质、贴图的关系
shader(着色器)实际上就是一小段程序,它负责将输入的顶点数据以指定的方式和输入的贴图或者颜色等组合起来,然后输出。绘图单元可以依据这个输出来将图像绘制到屏幕上。输入的贴图或者颜色等,加上对应的shader,以及对shader的特定的参数设置,将这些内容 (Shader及输入参数)打包存储在一起,得到的就是一个Material (材质)。之后,我们便可以将材质赋予三维物体来进行渲染(输出)了。
材质好比引擎最终使用的商品,shader好比是生产这种商品的加工方法,而贴图就是原材料。
shader三大主流编程语言
Shaderlanguage目前主要有3 种语言:基于OpenGL的OpenGL Shading Language,简称 GLSL,基于DirectX 的High LevelShading Language 简称 HLSL,还有NVIDIA公司的C for Graphic 简称 Cg语言。
GLSL(OpenGL Shading Language,)
openGL的发展一直处于一种较为迟缓的态势,每次版本的提高新增的技术很少,大多只是对其中部分做出修改和完善。1992年7月,SGI公司发布了OpenGL的1.0版本,随后又与微软公司共同开发了Windows NT版本的OpenGL,从而使一些原来必须在高档图形工作站上运行的大型3D图形处理软件也可以在微机上运用。1995年openGL的1.1版本面市,该版本比1.0的性能有许多提高,并加入了一些新的功能。其中包括改进打印机支持,在增强元文件中包含OpenGL的调用,顶点数组的新特性,提高顶点位置、法线、颜色、色彩指数、纹理坐标、多边形边缘标识的传输速度,引入了新的纹理特性等等。OpenGL1.5又新增了“OpenGLShading Language”,该语言是“OpenGL 2.0”的底核,用于着色对象、顶点着色以及片断着色技术的扩展功能。
HLSL 基于DirectX的(High LevelShading Language)
DirectX加强3D图形和声音效果,并提供设计人员一个共同的硬件驱动标准,让游戏开发者不必为每一品牌的硬件来写不同的驱动程序,也降低了用户安装及设置硬件的复杂度。从字面意义上说,Direct就是直接的意思,而后边的X则代表了很多的意思,从这一点上可以看出DirectX的出现就是为了为众多软件提供直接服务的。
cg (C for Graphic)
GLSL与HLSL分别基于OpenGL和Direct3D 的接口,两者不能混用,事实上OpenGL和Direct3D直都是冤家对头,争斗良久。OpenGL在其长期发展中积累下的用户群庞大,这些用户会选择GLSL学习。GLSL继承了OpenGL 的良好移植性,一度在unix 等操作系统上独领风骚。但GLSL 的语法体系自成一家。微软的HLSL移植性较差,在windows 平台上可谓一家独大,这一点在很大程度上限制了HLSL 的推广和发展。但是HLSL 用于DX游戏领域却是深入人心。
Cg 是一个可以被OpenGL和Direct3D 广泛支持的图形处理器编程语言。Cg 语言和OpenGL、DirectX 并不是同一层次的语言,而是OpenGL和DirectX的上层即,Cg程序是运行在OpenGL和DirectX 标准顶点和像素着色的基础上的。
ShaderLab的基本结构
shader“name”{
[Properties]
SubShaders
[FallBack]
}
properties: unity材质中的属性
subshaders:GPU编程的主要代码,subshader可以为多个,当当前subshader与此GPU不适配就进入到下一个shader。
Fallback:确保当所有shader都不适配的情况下回滚到前面较为简单的着色器。
固定渲染管线(fixed functions shader1)
Shader "folder/filename"{
properties{
_Color("Main Color",color) = (1,1,1,1) //主颜色
_Ambient("Ambient",color)=(0.3,0.3,0.3,0.3,0.3)//环境光 0.3是为了让环境光不是全白,否则看不出光照效果
_Specular("Specular",color) = (1,1,1,1)//高光
_Shininess("Shininess",range(0,8)) = 4 //高光度范围0-8 默认为4
_Emission("Emission",color)=(1,1,1,1)
}
SubShader{
pass{
//color[_Color] 中括号代表放入的是一个变量,这样会导致三维物体在任何方位显示的都是同一个颜色
//要解决次问题
material{
diffuse[_Color]//漫反射 要配合光照不然物体是全黑的
ambient[_Ambient]//环境光
specular[_Specular]//高光 需要配合sepratespecular使用
shininess[_Shininess] //用来描述specular这个高光的大小(光滑程度)
emission[]//自发光
}
lingting on //打开光照 物体才可以被看见
sepratespecular on //镜面高光
}
}
}
固定渲染管线(fixed functions shader2)
Shader "folder/filename"{
properties{
_Color("Main Color",color) = (1,1,1,1) //主颜色
_Ambient("Ambient",color)=(0.3,0.3,0.3,0.3,0.3)//环境光 0.3是为了让环境光不是全白,否则看不出光照效果
_Specular("Specular",color) = (1,1,1,1)//高光
_Shininess("Shininess",range(0,8)) = 4 //高光度范围0-8 默认为4
_Emission("Emission",color)=(1,1,1,1)
_Constant("Constant",color) = (1,1,1,0.3)
_MainTex("MainTex",2d) = "" // 设置贴图
_SecondTex("SecondTex",2d) = ""
}
SubShader{
Tags{"queue"="Transparent"}//不使用的话由于Shader计算顺序原因而达不到前面的物体透明
pass{
Blend srcAlpha oneMinusSrcAlpha //设置透明
//color[_Color] 中括号代表放入的是一个变量,这样会导致三维物体在任何方位显示的都是同一个颜色
//要解决次问题
material{
diffuse[_Color]//漫反射 要配合光照不然物体是全黑的
ambient[_Ambient]//环境光
specular[_Specular]//高光 需要配合sepratespecular使用
shininess[_Shininess] //用来描述specular这个高光的大小(光滑程度)
emission[]//自发光
}
lingting on //打开光照 物体才可以被看见
sepratespecular on //镜面高光
settexture[_MainTex]{//设置贴图
combine texture * primary double //此时两个值都是0-1的浮点数,相乘就会变得更小所以图像显示就会变暗
// primary是先前代码的参数值
//为了解决此问题需要为combine的结果double 或 quad
settexture[_SecondTex]{//设置贴图
constantColor[_Constant]//设置贴图alpha值
combine texture * previous double,texture * constant //primary不会计算前一张贴图的值,如果想让两张贴图相混合,需要用previous
}
}
}
Surface Shader
SurfaceOutput
Input
Lighting
Shadow
Shader "Custom/3"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5 //光滑度
_Metallic ("Metallic", Range(0,1)) = 0.0//金属光泽
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
//编译指令 按照surface关键词来编译 surf函数名称 光照模型
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0//使用的硬件功能,越高则越高级
struct Input
{
float2 uv_MainTex;//纹理坐标
};
sampler2D _MainTex; // 声明properties在CG中,2d对应sampler2D
half _Glossiness; range对应half
half _Metallic;
fixed4 _Color; // color对应fixed4
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_BUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_BUFFER_END(Props)
void surf (Input IN, inout SurfaceOutputStandard o)
//SurfaceOutputStandard 是一个输入输出结构体
{
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;//输出结构体的rgb值
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;//输出结构体的alpha值
}
ENDCG
}
FallBack "Diffuse"
}