700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 《Unity Shader入门精要》笔记:高级篇(3)以及扩展

《Unity Shader入门精要》笔记:高级篇(3)以及扩展

时间:2020-03-25 04:12:16

相关推荐

《Unity Shader入门精要》笔记:高级篇(3)以及扩展

本篇博客主要为个人学习所编写读书笔记,不用于任何商业用途,以及不允许任何人以任何形式进行转载。本篇博客会补充一些扩展内容(例如其他博客链接)。本篇博客还会提供一些边读边做的效果截图。文章内所有数学公式都由Latex在线编辑器生成。本篇博客主要提供一个“glance”,知识点的总结。如有需要请到书店购买正版。博客提及所有官方文档基于.2版本,博客会更新一些书中的旧的知识点到.2版本。

个人博客网址:《Unity Shader入门精要》笔记:高级篇(3)以及扩展 - Sugar的博客,如文章转载中出现例如传送门失效等纰漏,建议直接访问原博客网址。

如有不对之处欢迎指正。我创建了一个游戏制作交流群:637959304 进群密码:(CSGO的拆包密码)欢迎各位大佬一起学习交流,不限于任何平台(U3D、UE、COCO2dx、GamesMaker等),以及欢迎编程,美术,音乐等游戏相关的任何人员一起进群学习交流。完结撒花~

目录

噪声

消融效果

水波效果

Unity中的渲染优化技术

影响性能的因素

Unity中的渲染分析工具

减少draw call数目

减少需要处理的顶点数目

减少需要处理的片元数目

减少带宽

减少计算复杂度

扩展

噪声

消融效果

原理:噪声纹理+透明度测试

//核心代码在于://第一个Passfloat4 frag (VertexOutput i) : SV_Target{fixed3 burn = tex2D(_BurnMap, i.uvBurnMap).rgb;//burn为噪声贴图,_BurnAmount为时间clip(burn.r - _BurnAmount);fixed t = 1 - smoothstep(0.0, _LineWidth, burn.r - _BurnAmount);fixed3 burnColor = lerp(_BurnFirstColor, _BurnSecondColor, t);burnColor = pow(burnColor, 5);//书里面写的是3D的,然后这里我改了改放在了2D上面fixed4 finalColor = lerp(这里填入你原本的颜色, fixed4(burnColor,1.0), t * step(0.0001, _BurnAmount));return finalColor;}//第二个用于裁剪的Passfixed4 frag(v2f i) : SV_Target {{fixed3 burn = tex2D(_BurnMap, i.uvBurnMap).rgb;clip(burn.r - _BurnAmount);SHADOW_CASTER_FRAGMENT(i)}

当你试图把你的砖块贴图当成噪声放上去的时候

水波效果

把噪声图当做高度图使用,不断修改水面的法线方向。

把立方纹理作为环境纹理贴图模拟折射效果。使用菲涅尔系数动态混合反射和折射颜色,v和n代表视角方向和法线方向。夹角越小,数值越小,反射越弱。

Shader "Example/Water Wave" {Properties {_Color ("Main Color", Color) = (0, 0.15, 0.115, 1)_MainTex ("Base (RGB)", 2D) = "white" {}_WaveMap ("Wave Map", 2D) = "bump" {}_Cubemap ("Environment Cubemap", Cube) = "_Skybox" {}_WaveXSpeed ("Wave Horizontal Speed", Range(-0.1, 0.1)) = 0.01_WaveYSpeed ("Wave Vertical Speed", Range(-0.1, 0.1)) = 0.01_Distortion ("Distortion", Range(0, 100)) = 10}SubShader {Tags { "Queue"="Transparent" "RenderType"="Opaque" }//抓取屏幕图像,并自定义名字传入到下方的Pass并采样GrabPass { "_RefractionTex" }Pass {Tags { "LightMode"="ForwardBase" }CGPROGRAM#include "UnityCG.cginc"#include "Lighting.cginc"#pragma multi_compile_fwdbase#pragma vertex vert#pragma fragment fragfixed4 _Color;sampler2D _MainTex;float4 _MainTex_ST;//水的关于波纹的法线噪声贴图sampler2D _WaveMap;float4 _WaveMap_ST;//环境贴图samplerCUBE _Cubemap;fixed _WaveXSpeed;fixed _WaveYSpeed;//控制扭曲程度float _Distortion;sampler2D _RefractionTex;float4 _RefractionTex_TexelSize;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;float4 tangent : TANGENT; float4 texcoord : TEXCOORD0;};struct v2f {float4 pos : SV_POSITION;float4 scrPos : TEXCOORD0;float4 uv : TEXCOORD1;float4 TtoW0 : TEXCOORD2; float4 TtoW1 : TEXCOORD3; float4 TtoW2 : TEXCOORD4; };v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.scrPos = ComputeGrabScreenPos(o.pos);o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);o.uv.zw = TRANSFORM_TEX(v.texcoord, _WaveMap);float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; fixed3 worldNormal = UnityObjectToWorldNormal(v.normal); fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz); fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; //得到切线空间下的3个坐标轴(切线、附切线和法线的方向)在世界空间下的表示o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x); o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y); o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z); return o;}fixed4 frag(v2f i) : SV_Target {float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));//计算法线纹理当前偏移量float2 speed = _Time.y * float2(_WaveXSpeed, _WaveYSpeed);//两次采样对应了模拟两层交叉的睡眠波动效果。fixed3 bump1 = UnpackNormal(tex2D(_WaveMap, i.uv.zw + speed)).rgb;fixed3 bump2 = UnpackNormal(tex2D(_WaveMap, i.uv.zw - speed)).rgb;fixed3 bump = normalize(bump1 + bump2);//选用切线空间下的法线进行便宜float2 offset = bump.xy * _Distortion * _RefractionTex_TexelSize.xy;i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy;//使用透视除法并采样得到折射颜色fixed3 refrCol = tex2D( _RefractionTex, i.scrPos.xy/i.scrPos.w).rgb;bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));fixed4 texColor = tex2D(_MainTex, i.uv.xy + speed);fixed3 reflDir = reflect(-viewDir, bump);//使用反射方向对CUBE采样,把结果和主纹理颜色相乘得到反射颜色。fixed3 reflCol = texCUBE(_Cubemap, reflDir).rgb * texColor.rgb * _Color.rgb;//计算菲涅尔系数并混合折射和反射。fixed fresnel = pow(1 - saturate(dot(viewDir, bump)), 4);fixed3 finalColor = reflCol * fresnel + refrCol * (1 - fresnel);return fixed4(finalColor, 1);}ENDCG}}// Do not cast shadowFallBack Off}

Unity中的渲染优化技术

不同平台不同手机型号所用架构都各有差异,这就要求在移动平台上需要花更大的功夫去做优化。例如:PowerVR芯片(用于IOS和部分安卓)使用基于瓦片的延迟渲染架构(TBDR)。Adreno(高通)和Mali(ARM的芯片)使用Early-z或相似技术进行一个低精度的深度检测,来剔除那些不需要渲染的片元。Tegra(英伟达芯片)使用传统架构设计,overdraw(一个像素被绘制多次)可能会造成性能瓶颈。

影响性能的因素

CPU:负责保证帧率。有可能的性能影响:1、过多的draw call 2、复杂的脚本或物理模拟GPU:负责分辨率相关的处理。有可能的性能影响

顶点处理:1、过多的顶点 2、过多的逐顶点计算

片元处理:1、过多的片元(有可能是分辨率,也有可能是overdraw)2、过多逐片元计算Draw Call:CPU在每次通知GPU进行渲染之前,都要提前准备好顶点数据(位置、颜色、法线、纹理坐标等),然后调用一系列API把他们放到GPU可以访问到的指定位置,最后调用绘制指令。而调用绘制命令会产生一个draw call,过多的draw call会造成CPU性能瓶颈。这是因为CPU往往需要盖面很多渲染状态的设置,这很好费时间。优化技术:

CPU:使用批处理技术减少draw call数目。

GPU:1、减少需要处理的顶点数目:优化几何体,使用模型的LOD(level of detail)技术,使用遮挡剔除(Occlusion Culling)技术 2、减少需要处理的片元数目:控制绘制程序,警惕透明物体,减少实时光照 3、减少计算复杂度:使用Shader的LOD技术,代码方面的优化

节省内存带宽:1、减少纹理大小 2、利用分辨率缩放

Unity中的渲染分析工具

渲染统计窗口:他会统计音频、图像、网络三个方面信息。FPS:帧率以及处理一帧所需的时间(括号内)Batches:一帧需要进行的批处理数目Saved by batching:合并的批处理数目(表明批处理为我们节省了多少draw call)Tris,Verts:需要绘制的三角面片和顶点数目Screen:屏幕大小以及占用内存大小SetPass calls:渲染使用的pass数目(每个pass都需要Unity的runtime绑定新的Shader,这可能造成CPU性能瓶颈)shadow casters:阴影映射数目Visible skinned meshes:渲染的蒙皮网格数目Animation/Animator components playing:播放动画数目性能分析器(Profiler):通过Window->Analysis->Profiler打开。帧调试器(Frame Debugger):Window->Analysis->Frame Debugger打开。在窗口中可以查看每个draw call的工作和结果。Drawing为10代表绘制工作需要10个draw call完成,剩余的4个draw call是准备处理工作。其他平台性能分析工具:

安卓:高通分析工具可以对不同测试机进行详细的性能分析。英伟达提供了NVPerfHUD工具。

IOS平台:Unity内置工具可以得到整个场景花费GPU的时间。PoweVRAM的PVRUniSCo shader也可以给出一些宏观上的性能信息。

减少draw call数目

Unity渲染优化的4种批处理:传送门动态批处理:如果场景中有一些模型共享了同一个材质并满足一些条件,Unity就可以自动把他们进行批处理,合并为一个draw call完成。

原理:每一帧把可以进行批处理的模型网络进行合并,再把合并后模型数据传递给GPU,然后使用同一个材质对其渲染。

条件限制:1、能够进行动态批处理的网格的顶点属性规模要小于900。(该规模大小为Unity5时所设定)2、所有对象最好使用同一个缩放尺度。 3、使用光照纹理的物体需要小心处理。 4、多Pass的Shader会被批处理中断。静态批处理:适用于任何大小的几何模型。在Unity中只需要勾选模型的Static可选框即可变为静态批处理。

原理:在运行开始阶段,把需要进行静态批处理的模型合并到一个新的网格结构中。但只需要进行一次合并操作,因此要比动态批处理更加高效。缺点有:模型不可以在运行时刻被移动,占用更多的内存空间来存储合并后的集合结构。

对于不同材质的物体,静态批处理可以减少draw call之间的切换,同样也可以优化性能。共享材质:如果两个材质之间只有使用的纹理不同,我们可以把这些文理合并到一张更大的纹理中,这张更大的纹理被称为一张图集(atlas),再次使用时采用不同的采样坐标即可。

减少需要处理的顶点数目

优化几何体:Unity和三维建模软件中都有相应优化选项。Unity中显示的顶点数目一般会多于三维建模软件中的,因为Unity要进行GPU计算,会进行顶点拆分。模型的LOD技术:当一个物体离摄像机很远时,模型上的细节无法被察觉到。因此LOD允许当对象原理摄像机时,减少模型上的面片数量。遮挡剔除技术:消除其他物件后面看不到的物件,因此就不会计算看不到的顶点。

减少需要处理的片元数目

这部分的重点在于减少overdraw控制绘制顺序:深度测试可以保证物体都是从前往后绘制的,可以很大程度上减少overdraw。

人为控制绘制顺序的经验:优先绘制主人公,敌人绘制顺序可以往后放,天空盒子放在渲染队列最后。透明物体:移动设备尽量避免半透明物体的绘制,或者考虑开启深度写入的透明方法。减少实时光照和阴影:使用逐像素点光源以及逐像素的Shader可能造成draw call数目成倍增加,同时也会增加overdraw的数量。同时同态批处理和静态批处理都无法优化逐像素点光源。

解决方法:1、提前进行光照烘焙得到光照纹理,进行光源模拟。 2、使用God Ray进行光源模拟,通过透明纹理的模拟来得到。 3、使用查找纹理,提前存储好内容,使用时根据光源方向,视角方向,法线方向等参数直接采样得到光照结果。这种方法可以得到更出色的光照模型。

减少带宽

减少纹理大小

1、纹理长宽比最好是正方形,且最少是2的整数幂。

2、尽可能使用多级渐远纹理技术(mipmapping)和纹理压缩。(书中所述的Advanced的Texture Type已经没有了,在Default类型中也可以直接设置是否生成Mip Maps,如下图所示)纹理压缩如下图最下方的Format选项所示,Unity会自动根据平台不同采用不同纹理压缩技术。利用分辨率缩放:过高屏幕分别率也会造成性能下降。Unity设置屏幕分辨率可以直接调用Screen.SetResolution

减少计算复杂度

Shader的LOD技术:和模型的LOD技术类似。只有Shader的LOD值小于某个设定的值,这个Shader才会被使用,而超过了的物体将不会被渲染。(difffuse的LOD为200,Bumped Specular为400)代码方面的优化:1、尽可能使用低精度的浮点值进行运算,高精度,float适用于存储顶点坐标等变量。half适用于一些标量、纹理坐标等变量,计算速度大约是float的两倍。fixed适用于绝大多数颜色变量和归一化后的方向矢量,计算速度大约是float的4倍。2、尽可能使用全屏的屏幕后处理效果。 3、尽可能不要使用分支语句和循环语句,避免三角函数、pow、log等复杂的数学运算(可以用查找表进行代替),尽可能不要使用discard操作会影响硬件某些优化。

扩展

书中的最后一个部分主要是一些扩展内容的讲解,这里不作过多赘述,推荐去原书中阅览一番。(另外原作者在Github中更新了最后一个章节的新内容,部分与原版书籍不同)根据书中扩展内容加之本人的理解,提到如下可以扩展的方向,也是值得有时间找专门教程仔细研究一番:表面着色器PBS基于物理的渲染光线追踪技术伽马校正、HDRSRP、URP、HDRPShaderGraph

完结撒花~

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。