Shader编程
Shader是可编程图形管线的算法片段,下面就给大家汇总了shader的基础知识,帮助大家去了解Shader,并通过案例让大家了解shader固定着色器、表面着色器的使用。
管线渲染
定义:图形数据在GPU上经过运算处理,最后输出到屏幕的过程
1. 顶点处理: 接收模型顶点数据、坐标系装换
2. 图元装配: 组装面、连接相邻的顶点,绘制为三角面
3. 光栅化 : 计算三角面上的像素,并为后面着色阶段提供合理的插值参数(以及深度值)
4. 像素处理: 对每个像素区域进行着色、写入到缓存
5. 缓存: 一个存储像素数据的内存块,最重要的缓存是帧缓存与深度缓存
帧缓存:存储每个像素的色彩(缓冲)
深度缓存Z-buffer:前后排序(深度信息,物体到摄像机的距离)
6. Draw Call 绘制调用:每帧调用显卡渲染物体的次数
什么是缓冲?
一个像素有如下缓冲
颜色缓冲Color buffer/prixel buffer: 储存该点即将显示的颜色,RGBA值
深度缓存 depth buffer/Z buffer: 储存该点的深度Z
模板缓存stencil buffer : 通常作用限制渲染区域。更高级用法需结合深度缓存,例如某像素的模板缓冲值会随着其是否通过深度缓冲测试而改变
什么是图元装配(Primitive Assembly)
经过变换的顶点 被装配成几何(三角形等)图集
什么是光栅化(栅格化)(Rasterization)
栅格化这个术语:可以用于任何将矢量图形转化成栅格图像的过程
在3D渲染中主要是指,三角形等图元(矢量)转化成像素碎片的过程。或者说决定哪些像素几何图元覆盖的过程。栅格化的结果是像素位置的集合和片段的集合
什么是光栅操作(Raster Operation)
指在碎片fragment处理后,在更新帧缓存前最后执行的一系列操作。通过包括裁剪,深度测试,alpha测试,alpha混合等。
Shader常见术语
Alpha 透明的(黑透白不透、灰色半透半不透)
Bump凹凸 (法线贴图)
Specular (高光)
Shader主要看Game视窗
Shader显示名称与Shader名不冲突
什么是GPU?
GPU:Graphic Processing Unit,中文翻译为“图形处理器”。显卡包括(GPU,显存,显卡BLOS,显卡PCB板)
什么是Shader?
Shader程序:GPU执行的,针对3D对象进行操作的程序
Shader编程有那几种?
CG:与DirectX 9.0 以上以及OpenGL 完全兼容。运行时或事先编译成GPU汇编代码
HLSL: 主要用于Direct3D。平台:Windows
GLSL: 主要用于OPenGL。 平台:移动平台(IOS,Android),Mac(only use when you target Mac OS X or OpenGL ES 2.0)
为什么Shader中选择CG?
因为CG/HLSL 比GLSL支持更多的平台。
Unity3d 里CG输出什么?
Windows平台:Direct3D,GPU汇编代码
Mac: OpenGL GPU汇编代码
Flash: Flash GPU 汇编代码
IOS/Android : unity 会将CG转换成GLSL代码。
总结:也就是除了移动平台会把CG转换成GLSL代码,其余平台都是转化成汇编代码。
Unity 中的三种自定义Shade:
1.surface shaders, 表面着色器(最常用,比固定功能管线高级)(之前默认创建的shader类型)它是 Vertex and fragment shaders 的包装,让我们可以不用关心这些顶点和片段程序的细节,可以直接得到我们想要的着色器。
2.Vertex and fragment shaders 顶点和片元着色器(细节处理,偏底层)
3.fixed function shaders. 固定功能管线着色器(更简单),在可编程渲染管线硬件出现之前,很多光照都会放在硬件级处理(可以理解为对固定管线硬件的操作),一般放在项目前绝大多数硬件都可支持,应用就可以使用,比如光照、纹理采样
//Shader中没有注明是前两种shader,即为第三种shader
先从ShaderLab基本语法开始入手,再去阅读surface shader,或者vertex and fragment shaders
ShaderLab 基本结构
Unity中的Shader 都是要通过ShaderLab的基本语法进行编写,unity就是想通过Shaderlab的方案进行Shader的编写。将三种定义的Shader通过同一种格式进行编写,避免不同Shader使用不同的方法。
Shader "name" { //[Properties] 属性 查看ShaderLab:Properties //作用:在可视化面板提供美工可使用的属性 Properties { } //[Subshader] 算法用于执行给定的数据 SubShader { } //[FallBack] 后退 一般会填写所有硬件都支持的渲染方式 FallBack "Diffuse" }
关于SubShaders (处理ShaderLab中的语言片段) 在ShaderLab中至少有一个SubShader,当然也可多个。但是,显卡每次渲染处理的时候只能选择一个SubShaders执行。那多个SubShader的作用是为了不同的硬件的渲染支持,为了Shader能在比较老的图形显卡中也能支持。一般比较往下的Subshader要简化,运算指令要简单。
Fixed function shader固定功能管线
所有硬件平台都可支持,针对硬件能够执行的基本命令的Shader,当然有,但是,速度最快
Properties 属性
Material 材质
Lighting 光照
Settexture 设置纹理
Pass通道(存储图像的色彩RGB)(只有Surface 可以不写)
Surface shaders
surfaceOutPut输出
Input 输入
Lighting 光照
常用公式
环境反射
Ambient= Ka*globalAmbient;
Ka是材质的环境反射系数
globalAmbient是入射环境光的颜色
漫反射
Diffuse=Kd*lightColor*max(N*L,0);
Kd 是材质的漫反射颜色
lightColor是入射漫反射光的颜色
N 是规范化的表面法向量
L 是规范化的纸箱光源对的向量;
镜面反射
Specular=Ks * lightColor *facing*max((N*H),0) shininess
Ks 是材质的镜面反射颜色;
lightColor是入射镜面反射光的颜色
N是规范化的表面法向量
V是指向视点的规范化的向量
L是指向光源的规范化的向量
H是V和L的中间向量的规范化向量
P是要被着色的点
Faceing是1如果N*L是大于0的,否者为0
写Shader不区分大小写
和灯光有呼应的 ------ 漫反射 高光 背光 阴影 环境光
固定着色器格式
hader "Unlit/Test2"//不区分大小写 { //声明属性 Properties { //默认颜色颜色 //变量名 在监视面板显示的名称 类型=值 _Color("MyColor",Color)=(1,0,0,1) //环境光 _Ambient("Ambient",Color)=(1,0,0,1) //高光 _Specular("Specular",Color)=(1,0,0,1) _Shininess("Shininess",Range(0,1))=0.5 //range 0-8的值 //自发光 _Emission("Emission",Color)=(1,0,0,1) // _MainTexture("Main Texture",2D)="white"{} //默认颜色 } SubShader { pass { Color[_Color] //使用默认颜色进行颜色的写入 Material{ //漫反射 Diffuse[_Color] //环境光 Ambient[_Ambient] //亮度 Shininess[_Shininess] //高光反射系数 Specular[_Specular] //自发光 Emission[_Emission] } //启动光照 Lighting On //启动高光反射 SeparateSpecular On SetTexture[_MainTexture] { Combine Texture*primary double } } } FallBack "Diffuse" }
表面着色器格式
Shader "Custom/Test1" { //属性 //属性变量 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" } //描述渲染类型,当前是不透明的物体 //Tags{"RenderType"="Opaque" "queue"="transparent"}//透明的物体 LOD 200 //层级细节 CGPROGRAM //CG代码块 CG开始 // Physically based Standard lighting model, and enable shadows on all light types //如果是Standard fullforwardshadows光照模型,则对应用SurfaceOutputStandard, //如果是Lambert光照模型(其他版本Unity默认的光照模型),则对应SurfaceOutput。 //对应的SurfaceOutputStandard/SurfaceOutput结构体不用写出来 #pragma surface surf Standard fullforwardshadows//编译指令 //surface表面着色器 surf调用的方法 Standard基于物理的光照模型(原来是漫反射 Lambert) //fullforwardshadows 阴影表现(平行光、点光、聚光都是有阴影的) // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 //GPU硬件支持3.0 (不写默认是2.0) sampler2D _MainTex; //CG中图片的类型 struct Input { float2 uv_MainTex; //记录uv纹理坐标 }; half _Glossiness; //CG中的浮点型 half _Metallic; fixed4 _Color; //CG中的四阶向量(0,0,0,0)rgb // 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_CBUFFER_START(Props) // put more per-instance properties here UNITY_INSTANCING_CBUFFER_END //Input 传入值 inout 传出值(基于物理的要加Standard) void surf (Input IN, inout SurfaceOutputStandard o) { // Albedo comes from a texture tinted by color fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; // Metallic and smoothness come from slider variables o.Metallic = _Metallic; //金属光泽表现 o.Smoothness = _Glossiness; //高光光泽度 o.Alpha = c.a; } ENDCG //CG结束 } FallBack "Diffuse" }
表面着色器示例练习
Shader "Custom/Test5" { Properties { //2D ---图片 white----默认格式 “”内也可以不写 //大括号也可以不写(大括号内可以给值) _MainTex("Texture",2D)="white"{} _BumpMap("Bumpmap",2D)="bump"{} //cube 立方体贴图 _Cube("Cubemap",CUBE)=""{} } SubShader { //不透明 Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM // Physically based Standard lighting model, and enable shadows on all light types //如果是Standard fullforwardshadows光照模型,则对应用SurfaceOutputStandard, //如果是Lambert光照模型(其他版本Unity默认的光照模型),则对应SurfaceOutput。 //对应的SurfaceOutputStandard/SurfaceOutput结构体不用写出来 #pragma surface surf Lambert // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 struct Input { //只要是纹理相关都需要UV float2 uv_MainTex; float2 uv_BumpMap; float3 worldRef1; INTERNAL_DATA //反射与法线效果配合 }; //再次声明变量 sampler2D _MainTex; sampler2D _BumpMap; samplerCUBE _Cube; // 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_CBUFFER_START(Props) // put more per-instance properties here UNITY_INSTANCING_CBUFFER_END void surf (Input IN, inout SurfaceOutput o) { o.Albedo=tex2D(_MainTex,IN.uv_MainTex).rgb; //不需要法线的反射效果 //o.Emission=texCUBE(_Cube,IN.worldRefl).rgb; //法线与反射效果配合 //需要将INTERNAL_DATA添加到Input结构中 o.Normal=UnpackNormal(tex2D(_BumpMap,IN.uv_BumpMap)); //反射 o.Emission=texCUBE(_Cube,WorldReflectionVector(IN,o.Normal)).rgb; } ENDCG } FallBack "Diffuse" }