Shader编程

发表于2017-12-27
评论0 8.2k浏览

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"  
}  
链接:http://blog.csdn.net/leonardo_davinci/article/details/78869587

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引