Shader笔记(一)

tech2022-08-17  122

Shader

Fixed shader: shader1.0 固定管线

Vertex/Fragment shader : shader 2.0 顶点/片段

Surface shader :Unity3d 特有的 表面

Shader1.0

开关式编程

最终呈现效果计算公式

环境光 * Unity环境光设置 + 漫反射 * 灯光的颜色 + 镜面反射 * 灯光的颜色 + 自发光

流水线

过程:

顶点着色器光栅化片段着色器alpha测试模板测试深度测试blendgbufferframebufferfrontbuffer显示器

shader1.0 开关式编程

shader2.0 能够编程的

顶点着色器 计算顶点的位置 MVP:以相机为坐标系,超框不显示;计算顶点的大小计算顶点的颜色 光栅化: 将顶点变成像素 (计算插值) 片段(像素)着色器 计算像素颜色结合灯光计算像素的颜色结合贴图计算像素的颜色 alpha测试 淘汰像素 RGBA:根据a值淘汰i像素 深度测试 根据深度值淘汰像素(离相机远近) 模板测试 程序自定义的值淘汰像素分辨率:1280720 float[1280720] RGBA:32bit,颜色缓存区(RGBA float[1280720]),深度缓存区(深度值8bit Byte[1280720] 或 short[1280720]) 模板缓存区(模板值8bit Byte[1280720]): blend (每个相机都会有 模板深度颜色的buffer): 将已经渲染到屏幕上的像素和即将渲染到屏幕上的像素做混合,存到gbuffer里 framebuffer、frontbuffer: 将颜色缓存区里面的东西写入framebuffer里交换到显示器上去

Unity3D编程

Fixed shader:固定管线编程 shader1.0Vertex/fragement shader:顶点 片段着色器编程shader2.0Surface shader :表面着色器编程 U3D特有

四种光

光照公式: 光照I = 自发光+环境光+漫反射+镜面反射 环境光=环境光颜色 * 环境光向量 漫反射=漫反射光颜色 * 漫反射强度 * (光源向量·法线向量) 镜面反射=镜面光颜色 * 镜面反射强度 * (反射光向量·视角方向)^n

漫反射 (Diffuse)

跟观察角无关跟入射角有关Diffuse = 直射光颜色 * max(0,cos夹角(光和法线的夹角) ) Tip:cosθ = 光方向· 法线方向

镜面反射 (Specular)

跟观察角有关跟入射角有关Specular=直射光 * pow( max(cosθ,0),10) θ:是反射光方向和视野方向的夹角

环境光 (Ambient)

周围环境光线

自发光 (Emission)

自己发光

Ambient + Lighting Window’s Ambient Intensity Setting + (Light Color * Diffuse + Light Color * Specular) + Emission

顶点着色器

//路径名 Shader "Custom/TestProperty" { //属性:定义属性 Properties { //1.数值,滑动条 //2.颜色,向量 //3.贴图 //变量名,显示名,类型, 默认值 _MainTex ("Texture", 2D) = "white" {} _TestFloat("Test float", float) = 2.5 //GPU 只有浮点数 _TestInt("Test int", int) = 2 //滑动条 _TestRange("TestRange", Range(1,10)) = 5 //颜色 _TestColor("TestColor", Color) = (1,1,1,1) //向量 //四维向量xyzw,三维矩阵变换,w表示平移 _TestVector("TestVector", Vector) = (1,1,1,1) //贴图 _TestTexture("TestTexture", 2D) = "white" {} _TestCube("TestCube", Cube) = "white" {} _Test3D("Test3D", 3D) = "white" {} } //渲染流程:选择对应显卡,只用一个 SubShader { //渲染通道:每出现一次就渲染一次 //写代码 Pass { //sahder1.0顶点着色器编程(开关式编程): //Color:表示顶点颜色的定义 // Color (1,0,0,1) //使用变量 Color[_TestColor] //Material:定义物体自身材质属性: //设置物体自身四种光,漫反射,镜面反射,环境光,自发光 material{ } //sahder1.0开关式编程 SeparateSpecular On //灯光总开关 lighting On } } //可以适配多个显卡 SubShader { Pass { } } //没找到适配显卡,选择默认shader Fallback "Diffuse" }

片段着色器

SetTexture指令

Previous是上一次SetTexture的结果 previous指的是先前的数据,将代码改成“combine texture * previous”,这里的意思就是用当前纹理的值去乘上当前settexture操作之前所有计算和采样过后的结果。 Primary是来自光照计算的颜色或是当它绑定时的顶点颜色 primary代表了前面所有计算材质和光照后的颜色值,将贴图和这个值相乘,就会得到一个混合的新的颜色值。 Texture是在SetTexture中被定义的纹理的颜色Constant是被ConstantColor定义的颜色 SubShader { Pass { //设置图片指令 SetTexture[_BlendTex] { //代码逻辑 //combine texture //加减乘 当前贴图颜色 combine texture * Primary } SetTexture[_MainTex] { //加减乘 之前贴图颜色 combine texture * Previous } } }
lerp插值

lerp(a,b,t) = a* t + b*(1-t)

lerp(RGBA1, RGBA3, RGBA2.A)

Constant 常量指令
SetTexture[_BlendTex] { ConstantColor(0,1,0,1) combine texture * constant }

alpha测试 深度测试

/* ********************************************************************* *Copyright © 2019 Unity1903 *File Name: TestTexture.shader *Author: lvzhijie *CreateTime: 2019年10月29日 9:33:44 *Describe: Add a description here ********************************************************************* */ Shader "Shader02/TestTexture" { Properties { _MainTex ("Texture", 2D) = "white" {} _BlendTex("Blend", 2D) = "white"{} _BlendTex2 ("Blend2", 2D) = "white" {} _ConstantColor ("ConstantColor", Color) = (1,0,0,1) } SubShader { //消融效果 //Blend srcalpha oneminussrcalpha Pass { //01 练习 Primary Previous Constant //设置图片指令 /* SetTexture[_MainTex] { //加减乘 上当前贴图颜色 combine texture * Primary } SetTexture[_BlendTex] { //代码逻辑 combine texture + Previous } SetTexture[_BlendTex] { ConstantColor [_ConstantColor] combine texture * constant }*/ /* 02片段着色器 //顶点着色器写在最前面 Color[_ConstantColor] //片段着色器 SetTexture[_BlendTex] { combine texture } SetTexture[_MainTex] { // combine texture * Primary + Primary combine texture * Primary + Previous } SetTexture[_BlendTex2] { combine texture + Previous } */ //03 lerp 插值 视频52分钟 /*Color(1,0,0,1) SetTexture[_MainTex] { //调用Constant值设置变量 ConstantColor[_ConstantColor] //根据变量设置lerp的alpha值 combine Primary lerp(constant) texture } */ /* 三大测试 shader1.0 shader2.0通用 alpha测试, 模板测试, 深度测试 */ /* alpha测试: AlphaTest comparison AlphaValue 对比方法: Greater:大于 GEqual:大于等于 Less:小于 LEqual:钓鱼灯也 Equal:等于 NotEqual:不等于 Always:一直等于 Never:从不等于 */ //三大测试写在pass里只应用与pass,pass外应用于所有pass //取所有alpha大于0.9的值 //AlphaTest Greater 0.9 //Always 和 Never 后必须跟值,值无意义 //AlphaTest Always 0 /* 深度测试: 根据深度值判断淘汰像素 深度值:物体到相机的距离 深度缓冲区:跟颜色缓冲区匹配 Float[1024*768] 指令: Cull Back|Front|Off:剔除,不渲染前或后,或都渲染 ZWrite Off : 是否替换 ZTest : 判断替换 Offset : 微调 */ //前后都渲染,或两次渲染,从后往前,cull front 然后cull back //cull Off //一直显示 ZTest Always //微调 (防止同一位置的两个物体重叠闪烁) Offset -1,-1 SetTexture[_MainTex] { combine texture } } //Cube渲染前后两个面 //从后往前渲染 /*Pass { cull front SetTexture[_MainTex] { combine texture } } pass { cull back SetTexture[_MainTex] { combine texture } } Pass{ Offset -1,-1 cull back AlphaTest Greater [_TexTure01Float] SetTexture [_TexTure02]{ ConstantColor [_ConstantColor] combine Texture } } */ } }

模板测试

所使用的代码

referenceValue:即将渲染的像素模板值:0-255默认0ReadMask:加密值,默认255WriteMask:加密值,默认255comparisonFunction:大于小于等于。。。stencilBufferValue:模板缓存区里的值 if(referenceValue & readMask comparisonFunction stencilBufferValue & readMask ) 通过i像素 else 丢弃像素

关键字

Ref :设定讲讲渲染的像素模板值 referenceValue值ReadMask:设置读遮罩,做加密WriteMask:设置写遮罩,做加密Comp:设置对比表达式(大于小于等于) 取值范围Pass:深度测试通过,模板测试也通过的操作,后处理,对模板缓存区里面的值取一个操作Fail:两个测试都失败,取一个操作ZFail:表示当深度测试失败,模板测试通过,取一个操作 Keep:模板缓存区里的值保持不变Zero:模板缓存区里的值变成0Replace:模板缓存区里的值替换当前渲染的像素的模板值IncrSat:Increment,自增,到255,大于255为255DecrSat:自减,到0Invert:所有的位取反IncrWrap:循环自增,0-255-0-255DecrWrap:循环自减,255-0-255-0

使用方法

Pass { Stencil { Ref 2 Comp always 2 Pass replace } } 设定当前渲染的像素模板设定跟gbuffer里的值进行对比设定后处理

Blend

指令

Blend SrcFactor DstFactor: SrcFactor:即将渲染的像素RGBA DstFactor:已经渲染的RGBA

SrcColor:即将渲染的像素RGB SrcAlpha:即将渲染的A值

DstColor:已经渲染的RGB DstAlpha:已经渲染的A值

OneMinusSrcColor:1-即将渲染的RGB OneMinusDstColor:1-已经渲染的RGB

OneMinusSrcAlpha:1-即将渲染的A OneMinusDstAlpha:1-已经渲染的A

想改变+号

BlendOP Sub Add:加法 Sub:减法

Blend SrcAlpha OneMinusSrcAlpha 即将渲染的A值 * 即将渲染的像素RGBA + (1-即将渲染的像素A值) * 已经渲染的RGBA

Blend One OneMinusSrcAlpha 1 * 即将渲染的像素RGBA + (1-即将渲染的像素A值) * 已经渲染的RGBA

Blend One One 1 * 即将渲染的像素RGBA + 1 * 已经渲染的RGBA

Blend OneMinusDstColor One (1-已经渲染的像素RGB) * 即将渲染的像素RGBA + 1 * 已经渲染的RGBA

Blend DstColor One 已经渲染的像素RGB * 即将渲染的像素RGBA + 1 * 已经渲染的RGBA

Blend DstColor SrcColor 已经渲染的像素RGB * 即将渲染的像素RGBA + 即将渲染的像素RGB * 已经渲染的RGBA

Shader2.0

*** 1.0和2.0代码不能混用 *** 可以更改过程 不能直接跟灯光计算(可以间接计算),一般用来做屏幕后期特效

CG语言

CG宏指令

引申: Jit (just in time) :即时编译语言 例如Lua, python Aot (a head of time) : 预编译语言 例如C#,java

制作效果

制作UV贴图旋转

SubShader { /* 旋转贴图 UV动画,旋转需要用到矩阵转换, 1. 移动原点到中心 2. 旋转 3. 移动原点到原来位置 */ //混合透明 Blend SrcAlpha OneMinusSrcAlpha Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } sampler2D _MainTex; fixed4 frag (v2f i) : SV_Target { fixed2 tmpUV = i.uv; //移动中心到圆点 tmpUV -=fixed2(0.5,0.5); //设置长度范围,防止出现多余的图片 if(length(tmpUV) > 0.5) return fixed4(0,0,0,0); float angle = _Time.y; float xx = tmpUV.x * cos(angle) + tmpUV.y * sin(angle); float yy = -tmpUV.x * sin(angle) + tmpUV.y * cos(angle); tmpUV = fixed2(xx,yy); //还原中心 tmpUV += fixed2(0.5,0.5); fixed4 col = tex2D(_MainTex, tmpUV); return col; } ENDCG } }

制作流水效果

SubShader { // No culling or depth //Cull Off ZWrite Off ZTest Always Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; float _WaveW; float _WaveA; v2f vert (appdata v) { v2f o; v.vertex.y += _WaveA * sin(_WaveW * v.vertex.x + _Time.y); o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } sampler2D _MainTex; float _Speed; fixed4 frag (v2f i) : SV_Target { fixed2 tmpUV = i.uv; tmpUV.x += _Time.y * _Speed; fixed4 col = tex2D(_MainTex, tmpUV); //fixed4 col = tex2D(_MainTex, i.uv); // just invert the colors //col = 1 - col; return col; } ENDCG } }

OutLine

需要两次渲染,关闭需要显示物体的ZWrite,关闭ZTest则会一直显示,影响视觉,

SubShader { //渲染边框 Pass { ZWrite Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; float _OutLineWidth; v2f vert (appdata v) { v2f o; //加边框 v.vertex.xyz *= _OutLineWidth; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } sampler2D _MainTex; fixed4 _OutLineColor; fixed4 frag (v2f i) : SV_Target { //fixed4 col = tex2D(_MainTex, i.uv); // just invert the colors //col = 1 - col; return _OutLineColor; //return fixed4(1,0,0,1); } ENDCG } //渲染贴图 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert (appdata v) { v2f o; //加边框 v.vertex.xyz *=1.2; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } sampler2D _MainTex; fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); // just invert the colors //col = 1 - col; return col; } ENDCG } }

高斯模糊

通过设置多次贴图偏移,达到模糊效果

Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } sampler2D _MainTex; float _OffSet; fixed4 frag (v2f i) : SV_Target { //自己 fixed4 col = tex2D(_MainTex, i.uv); //上 fixed4 col2 = tex2D(_MainTex, i.uv + float2(0, _OffSet)); //下 fixed4 col3 = tex2D(_MainTex, i.uv - float2(0, _OffSet)); //左 fixed4 col4 = tex2D(_MainTex, i.uv + float2(-_OffSet,0)); //右 fixed4 col5 = tex2D(_MainTex, i.uv + float2(_OffSet, 0)); //上 col = (col + col2+ col3+ col4+ col5) / 5; // just invert the colors //col = 1 - col; return col; } ENDCG }

抗锯齿(多重采样)

时域进行卷积 = 频域乘积(叉乘低频滤波器),得到一张模糊处理的图片,对图片进行采样; 卷积操作类似这里的高斯模糊,这里写的高斯模糊是上下左右进行平均,卷积操作可以简化为n*n(n为大于2的奇数)的矩阵与原始图片叉乘取平均;

摄像机后处理

Unity生命周期里的后处理过程

/// <summary> /// /// </summary> /// <param name="src">OnRender以前的画面</param> /// <param name="dest">更改以后传递回去的画面</param> private void OnRenderImage(RenderTexture src, RenderTexture dest) { //用myMat对src图片渲染,之后存入dest //src, texture, dest renderTexture Graphics.Blit(src, dest, myMat); }

Surface Shader

Tag 标签

Queue 渲染队列

当场景中跟game窗口中不一样的时候要加Queue

Unity渲染整个场景 将场景中的所有物体分类

从小到大渲染(可以设置"Queue" = “Background+1”)

Background:最先渲染(1000)

Geometry :渲染不透明的物体,实体物体(2000)

AlphaTest:要经过alpha测试的队列(2450)

Transparent:透明的,半透明的物体(3000)

Overlay:最后渲染(如UI)(4000)

RenderPath 渲染通道

相机上的属性 Rendering Path:

Use Graphics SettingsForward:质量要求低的 (渲染2次,效率高)Deferred:延迟渲染,次时代游戏 (渲染2次,效率高。)Legacy Vertex Lit:渲染顶点 (渲染1次,最快,支持硬件最多,效率最高,效果最差)Legacy Deferred:Unity 5.0之前的算法 (渲染3次,效率低)

Project Setting-> Graphics: 可以设置渲染通道

Seuface Shader使用

SurfcaceOutputStandard

struct SurfcaceOutputStandard { fixed3 Albedo;像素颜色,RGB fixed3 Normal;法线 half Emission;自发光 half Metallic;金属光泽,0没有金属,1最强烈 half Smoothness;粗糙度,0粗糙,1光滑 half Occlusion;默认1 高光遮罩 fixed Alpha;透明度 }

高光颜色 struct SurfcaceOutputStandardSpecular { … fixed3 Specular;高光 … }

自定义surface shader

自定义灯光入口函数:

//unity5之前的 #pragma light surf Custom

void vert(inout appdata_full v, out Input o) { o.uv_MainTex = v.texcoord.xy; }

//自定义表面着色器入口 #pragma surface surf Custom vertex:vert finalcolor:myColor

void surf(inout appdata_full v, out Input o) {

}

//自定义灯光入口函数 half4 LightingCustom (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) { return half4 (1,0,0,1); }

//自定义雾效果 void myColor(Input IN, SurfaceOutput o, inout fixed4 color) {

}

计算公式:

冯氏着色: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IHpotTtY-1599059227728)(en-resource://database/402:1)]

Blinn phone着色:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vrDymkNp-1599059227731)(en-resource://database/403:1)]

雾:
float pos = length(UnityObjectToViewPos(v.vertex.xyz).xyz); //距离计算 //float dencity = (pos - _fogStart) / (pos - _fogEnd) //指数计算雾的浓度 float dencity = exp(- _fogDensity * abs(pos)); o.FogDensity = 1-dencity;

//菲尼尔公式 float fresnel = _fresnelBase + _fresnelScale*pow(1 - dot(N, V), _fresnelIndensity);

法线

设置法线贴图

void surf (Input IN, inout SurfaceOutputStandard o) { // Albedo comes from a texture tinted by color fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; //设置法线贴图 fixed4 normalColor = tex2D (_NormalTex, IN.uv_NormalTex); //从法线贴图到fixed3类型的法线 o.Normal = UnpackNormal(normalColor); o.Albedo = c.rgb; // Metallic and smoothness come from slider variables o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = c.a; }

边缘检测

o.Emission = _EmissionColor.rgb * (1-clamp( dot(o.Normal, IN.viewDir) , 0, 1)) * _Power;

立方体贴图

真假反射

真反射:RenderTexture

需要IO写操作,影响性能

假反射:采集环境做成立方体贴图

使用: 立方体贴图采样 反射

//设置反射天空盒颜色o.Emission = texCUBE(_CubeMap, IN.worldRefl); o.Emission = texCUBE(_CubeMap, IN.worldRefl);

C#编写代码

使用GL

https://docs.unity3d.com/ScriptReference/index.html

复制GL代码

透视投影变正交投影GL.LoadOrtho();

最新回复(0)