当前位置: 首页 > news >正文

提供网站建设备案报价公司网站维护建设的通知

提供网站建设备案报价,公司网站维护建设的通知,制作网页编码,网站联盟营销渲染管线 概念#xff1a;GPU绘制物体的时候#xff0c;标准的#xff0c;流水线一样的操作 游戏引擎如何绘制物体#xff1a;CPU提供绘制数据#xff08;顶点数据#xff0c;纹理贴图等#xff09;给GPU#xff0c;配置渲染管线#xff08;装载Shader代码到GPUGPU绘制物体的时候标准的流水线一样的操作 游戏引擎如何绘制物体CPU提供绘制数据顶点数据纹理贴图等给GPU配置渲染管线装载Shader代码到GPU配置一次称为一次SetPassCall并对GPU下命令DrawCall绘制。原来的顶点数据需要经过三次矩阵的变换。分别是映射到世界坐标以摄像机为中心的坐标投影坐标 纹理坐标当一个模型建好之后我们需要给模型上色上色的过程相当于在一张白纸上面画画只不过是这张白纸包住了模型模型顶点在白纸上的坐标就是纹理坐标。 材质其实是配置shader的配置文件CPU从材质中读取shader数据把shader程序装载进GPU 顶点数据 模型有一个个三角形面构成一个面包含三个顶点。 顶点数据包含模型坐标相对于模型原点纹理坐标法线向量切线向量。 流程 顶点初始化-顶点shader编程-Tellellation曲面化-几何shader-裁剪投影-三角形遍历-片元着色shader编程-输出2D图像 顶点初始化CPU提供顶点数据给GPU,顶点数据包括在模型中的位置UV纹理坐标法线切线等。Unity定义一些装固定数据的盒子SV_XXXX顶点shader从中拿数据其他没有固定数据的盒子用户可以自由使用 顶点Shader 形状变换可选 你通过代码改变顶点的模型坐标坐标变换绘制到准确位置经过三次坐标变换映射到2D平面数据传递由编程者决定内容把数据传回渲染管线有固定的数据盒子 片元着色shader 片元是涂色的最小单位可以看成像素点。每个片元的数据通过顶点数据插值得来可以引入光照计算。 Unity Shader模板 创建一个unlit Shader它是一个基础模板可以开发任意效果 Shader Unlit/Shader {// 属性列表可以在编辑器中赋值用户传递的不能在shader中修改在所有着色器可以访问Properties{// 变量名显示名字,类型 默认值_MainTex (Texture, 2D) white {}} SubShader{Tags { RenderTypeOpaque }// 细节距离离得远不用细节LOD 100// 一个Pass是一个完整的渲染管线绘制Pass{CGPROGRAM // CG代码的开始#pragma vertex vert //预编译告诉编译器顶点代码在哪#pragma fragment frag //预编译告诉编译器片元着色代码在哪// make fog work#pragma multi_compile_fog// Unity封装的Shader API#include UnityCG.cgincstruct appdata // shader中需要使用的数据Unity定义了一些语义描述来取对应的数据POSITIONTEXCOORD0对应的是一个个盒子数据这些数据会先进入顶点shader可以直接获取{float4 vertex : POSITION; // 模型坐标可改float2 uv : TEXCOORD0; // 开始时候存的纹理坐标可改};struct v2f // 给片元shader使用的数据经过顶点shader计算后得到{float2 uv : TEXCOORD0;UNITY_FOG_COORDS(1)float4 vertex : SV_POSITION;};// 定义用户的属性变量的数据变量刚好对应2D中的两种数据类型sampler2D _MainTex; // 图片float4 _MainTex_ST; // Tilling,offset四个分量// 顶点shaderv2f vert (appdata v){v2f o;// 坐标空间的转换直接转到投影空间o.vertex UnityObjectToClipPos(v.vertex);// 纹理坐标叠加上Tilling和offseto.uv TRANSFORM_TEX(v.uv, _MainTex);UNITY_TRANSFER_FOG(o,o.vertex);// 返回数据给渲染管线return o;}// 片元着色shader着色调用次数远远大于顶点shader调用次数// 着色好了放到SV_Target// 这个v2f的参数并不等于顶点里面返回的v2f而是插值后每个片元的v2ffixed4 frag (v2f i) : SV_Target{// sample the texturefixed4 col tex2D(_MainTex, i.uv);// apply fogUNITY_APPLY_FOG(i.fogCoord, col);return col;}ENDCG}} } 摄像机如何显示颜色 摄像机看见的颜色物体本身的发光反射环境中所有的光 除了太阳灯泡等物体大多数是不会自发光的只会反射光物体的颜色是因为反射了特定的颜色的光吸收了其他颜色的光得到的。 自然界的光照是一个非常多次叠加的效果非常复杂因此需要简化不考虑二次反射的光并且不考虑其他物体的遮挡但是考虑自己的遮挡。公式变为 摄像机看见的颜色物体本身的发光本色*(直接光照反射一次反射光考虑自己的遮挡)环境光 反射分为镜面反射和漫反射而环境直接光照和一次反射光可以分为这两种类型具体类型由材质决定。 每个光都可以用红绿蓝强度表示例如 白光(1,1,1,1) 红光(1,0,0,1) 光照的时候物体的颜色本色光照 白光照在红物体上(1,1,1,1)(1,0,0,1)(1,0,0,1)红色 物体本色在建模的时候就决定好了渲染的好的关键是调节反射 常用的终极简化 颜色本色休闲小游戏常用对光照无要求颜色本色*漫反射移动端常用兰伯特半兰伯特 法线与光照计算 光照计算研究方向有两种 基于经验模型不要求逼真用于卡通渲染 漫反射有 兰伯特半兰伯特 镜面反射 有冯高光布林冯高光 基于物理PBR遵循物理定律能量守恒模拟真实世界效果逼真 法线用于反射是光照计算的关键。每个片元的法线都可以由顶点法线插值得到。 如何增强模型细节 方案一做高模型面数多计算量大 方案二建一个高模型只导出法线贴图但是模型依旧用低模型但是法线到高模的法线贴图中取能做出同样的光暗细节。 一个贴图每个点都有对应的RGBA颜色分量法线向量可以存储在颜色分量中得到法线贴图。每个法线都是一个标准化向量通过将三维坐标映射到0到1的范围内通过颜色分量的前三维存储。取出同理映射和反向映射方法 (-1,1)*0.50.5–(0,1) (0,1)*2-1–(-1,1) 我们也可以只存储x,yz通过标准化向量来求解得到可以压缩存储空间。 逐顶点和逐像素光照 这部分计算发生在片元着色shader 逐像素根据顶点的数据给每个片元插值计算法线纹理坐标坐标。然后将这些像素逐个计算反射。这部分计算都在片元着色这是按照片元的法线计算的。 逐顶点在顶点shader时候我们算好顶点的光照颜色直射光反射光环境光然后通过插值得到每个片元的光照颜色在片元着色shader的时候只需要将对应纹理的 本色插值的光照 就可以了不用每个像素使用法线的计算光照了。计算量远远小于逐像素是移动平台主要采用的方式但效果可能不能那么细腻。 逐顶点光照 Shader Bycw/VertexLight {Properties{_MainTex (Texture, 2D) white {}}SubShader{Tags { RenderTypeOpaque LightModeForwardBase }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag// make fog work#pragma multi_compile_fog#include UnityCG.cginc#include Lighting.cgincstruct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;float3 normal: NORMAL;};struct v2f{float2 uv : TEXCOORD0;UNITY_FOG_COORDS(1)float4 vertex : SV_POSITION;// 存放片元光照float4 allLight : TEXCOORD1;};sampler2D _MainTex;float4 _MainTex_ST;v2f vert (appdata v){v2f o;o.vertex UnityObjectToClipPos(v.vertex);o.uv TRANSFORM_TEX(v.uv, _MainTex);UNITY_TRANSFER_FOG(o,o.vertex);// 计算我们的光照float3 N normalize(UnityObjectToWorldNormal(v.normal));float3 L normalize(_WorldSpaceLightPos0);float halfLam dot(L, N) * 0.5 0.5;float3 halfLamLight halfLam * _LightColor0.rgb;// 把光照传递给片元o.allLight float4(halfLamLight, 1);// endreturn o;}fixed4 frag (v2f i) : SV_Target{ fixed4 col tex2D(_MainTex, i.uv);//片元直接本色乘光照col * i.allLight;// apply fogUNITY_APPLY_FOG(i.fogCoord, col);return col;}ENDCG}} } 逐片元请看下一小节。 兰伯特漫反射模型 漫反射是指光照射在粗糙表明向各个方向反射的现象在这个模型中向各个方向反射的光强度一致反射光的强度等于反射光的方向和法线的点乘。因此这个值是0到1的一个范围负数置01代表入射光强度。也就是说光的入射方向如果正好在法线上那么漫反射的强度等于光照强度。 这也是符合直觉的在一个平面上靠近光源的点是最亮的因为光源刚好在法线上。 为了防止点乘之后的值为负可以把这个点乘后的值乘0.5再加0.5这样就能把范围映射到0到1这就是半兰伯特反射模型。 这个例子是逐片元光照对应上一小节的逐顶点 Shader Unlit/Shader {Properties{_MainTex (Texture, 2D) white {}}SubShader{// 配置模式Tags { RenderTypeOpaque LightModeForwardBase}LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include UnityCG.cginc// 使用光照头文件#include Lighting.cgincstruct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;// 拿到模型的法线float3 normal: NORMAL;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;//定义世界坐标系下的法线因为这里是逐像素片元要计算好后传给片元着色shader如果是逐顶点就传插值的光照就行float3 wNormal: TEXCOORD1; };sampler2D _MainTex;float4 _MainTex_ST;v2f vert (appdata v){v2f o;o.vertex UnityObjectToClipPos(v.vertex);o.uv TRANSFORM_TEX(v.uv, _MainTex);o.wNormal UnityObjectToWorldNormal(v.normal);return o;}fixed4 frag (v2f i) : SV_Target{// 光照方向的标准化向量float3 L normalize(_WorldSpaceLightPos0);// 法线向量float3 N i.wNornal;// 半兰伯特公式float halfLam dot(L,N) * 0.5 0.5// 反射光计算float3 diff halfLam * _LightColor0.rgb;// 转换单位到4维向量fixed4 diffColor fixed4(diffLight.rgb,1);fixed4 col tex2D(_MainTex, i.uv);// 本色 * 光照return col * diffColor;}ENDCG}} } 冯高光和布林冯高光经验模型 Phong镜面反射模型 镜面反射在物体表面绝对光滑的情况下只往法线另一侧相同的夹角反射光线。但是一般没有绝对光滑的物体因此也会往其他方向反射光线只是强度会随着偏移反射角而减弱。假设我们定义物体的光滑度为N标准反射角向量为R反射点到摄像机的向量为V则有 反射光强度 ( max ⁡ ( 0 , D o t ( R , V ) ) ) N 反射光强度 (\max(0,Dot(R,V)))^N 反射光强度(max(0,Dot(R,V)))N Blin-Phone镜面反射模型 反射光强度 ( max ⁡ ( 0 , D o t ( H , N ) ) ) N 反射光强度 (\max(0,Dot(H,N)))^N 反射光强度(max(0,Dot(H,N)))N 其中N是法线向量H是视角向量和光源向量的半角向量。也就是说这个向量平分视角向量和光源入射向量这个向量越接近法线则视角接收的反射光越强。 Shader Bycw/BycwPhong {Properties{_MainTex (Texture, 2D) white {}// 属性面板可以在编辑器中设置_Gloss(Gloss, Range(0, 5)) 1}SubShader{Tags { RenderTypeOpaque LightModeForwardBase}LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include UnityCG.cginc#include Lighting.cgincstruct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;// 拿到模型法线float3 normal: NORMAL;};struct v2f{float2 uv : TEXCOORD0;// 世界坐标系下法线 float3 wNormal: TEXCOORD1;// 顶点的世界坐标float3 worldPos: TEXCOORD2;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;// 属性float _Gloss;v2f vert (appdata v){v2f o;o.vertex UnityObjectToClipPos(v.vertex);o.uv TRANSFORM_TEX(v.uv, _MainTex);// 世界法线o.wNormal normalize(UnityObjectToWorldNormal(v.normal));// 顶点世界坐标o.worldPos mul(unity_ObjectToWorld, v.vertex);return o;}fixed4 frag (v2f i) : SV_Target{// 片元到光源的标准化向量float3 L normalize(-_WorldSpaceLightPos0);// 法线float3 N normalize(i.wNormal);// 反射向量float3 R reflect(L, N);// 片元到摄像机的向量float3 V normalize(_WorldSpaceCameraPos - i.worldPos);// float _Gloss 1;// Lambert计算光强float halfLambert dot(-L, N) * 0.5 0.5;float3 halfLight halfLambert * _LightColor0.rgb;// Phong高光计算光强float phong pow(max(0, dot(R, V)), _Gloss); float3 phoneLight phong * _LightColor0.rgb;// 0.3的漫反射0.7的镜面反射float4 allLight float4(phoneLight.rgb, 1) * 0.3 float4(halfLight.rgb, 1) * 0.7;fixed4 col tex2D(_MainTex, i.uv);return col * allLight;}ENDCG}} } Blin-Phong高光 Shader Bycw/BlinPhong {Properties{_MainTex (Texture, 2D) white {}_Gloss(Gloss, Range(0, 5)) 1}SubShader{Tags { RenderTypeOpaque LightModeForwardBase }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include UnityCG.cginc#include Lighting.cgincstruct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;float3 normal: NORMAL;};struct v2f{float3 wNormal: TEXCOORD1; float2 uv : TEXCOORD0;float3 worldPos: TEXCOORD2;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;float _Gloss;v2f vert (appdata v){v2f o;o.vertex UnityObjectToClipPos(v.vertex);o.uv TRANSFORM_TEX(v.uv, _MainTex);o.wNormal normalize(UnityObjectToWorldNormal(v.normal)); o.worldPos mul(unity_ObjectToWorld, v.vertex);return o;}fixed4 frag (v2f i) : SV_Target{float3 N i.wNormal;float3 V normalize(_WorldSpaceCameraPos - i.worldPos);float3 L normalize(_WorldSpaceLightPos0);// 半角向量float3 H normalize(L V);// Blin-Phony光强度float blinPhong pow(max(0, dot(H, N)), _Gloss);float halfLam dot(L, N) * 0.5 0.5;float3 blinPhoneLight _LightColor0.rgb * blinPhong;// 半兰伯特光强度float3 halfLamLight _LightColor0.rgb * halfLam;// 两者的光照叠加float4 allLight float4(blinPhoneLight, 0.5) float4(halfLamLight, 0.5);// sample the texturefixed4 col tex2D(_MainTex, i.uv);return col * allLight;}ENDCG}} } 法线贴图 次时代中法线贴图是标配 Shader Bycw/BycwNormal {Properties{_MainTex (Texture, 2D) white {}// 定义法线贴图_NormalTex (Normal, 2D) white {}}SubShader{Tags { RenderTypeOpaque LightModeForwardBase}LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag// make fog work#pragma multi_compile_fog#include UnityCG.cginc#include Lighting.cgincstruct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;float3 normal: NORMAL;};struct v2f{float2 uv : TEXCOORD0;UNITY_FOG_COORDS(1)float4 vertex : SV_POSITION;float3 wNormal: TEXCOORD1;float3 worldPos: TEXCOORD2;};sampler2D _MainTex;float4 _MainTex_ST;// 法线贴图sampler2D _NormalTex;v2f vert (appdata v){v2f o;o.vertex UnityObjectToClipPos(v.vertex);o.uv TRANSFORM_TEX(v.uv, _MainTex);UNITY_TRANSFER_FOG(o,o.vertex);// 可以不写这行o.wNormal normalize(UnityObjectToWorldNormal(v.normal));o.worldPos mul(unity_ObjectToWorld, v.vertex);return o;}fixed4 frag (v2f i) : SV_Target{float3 L normalize(_WorldSpaceLightPos0);// float3 N i.wNormal;// 法线向量(0,1)解包到(-1,1)得到对应片元的法线向量float3 N normalize(UnpackNormal(tex2D(_NormalTex, i.uv))); float3 V normalize(_WorldSpaceCameraPos - i.worldPos);float3 H normalize(V L);float _Gloss 4;float blinPhong pow(max(0, dot(H, N)), _Gloss);float halfLam dot(L, N) * 0.5 0.5;float3 blinPhoneLight _LightColor0.rgb * blinPhong;float3 halfLamLight _LightColor0.rgb * halfLam;// 镜面反射漫反射环境光强度float4 allLight float4(blinPhoneLight, 0.5) float4(halfLamLight, 0.5) UNITY_LIGHTMODEL_AMBIENT;// sample the texturefixed4 col tex2D(_MainTex, i.uv);col * allLight;// apply fogUNITY_APPLY_FOG(i.fogCoord, col);return col;}ENDCG}} } PBR次时代美术工作流 PBR(Physically Based Rendering)是基于物理原理来模拟计算光的反射。算法是成熟的我们不直接实现其原理而是调节参数。 PBR有两种工作流可以相互转换 金属与粗糙度工作流主要元素是颜色贴图金属度粗糙度法线贴图。金属度是模拟光线反射的强度的贴图例如皮肤是0盔甲是1。粗糙度是模拟漫反射的贴图更多细节。这个工作流的优点是更容易创作各个贴图是分开的纹理占用内存小金属和粗糙度贴图是灰度图更广泛被应用但是缺点是边缘的伪像更明显尤其是分辨率低的时候。 反射与光泽度工作流接近于真实物理主要元素是漫反射反射RGB贴图光泽度RGB贴图法线贴图。优点是边缘伪像不明显控制灵活缺点是灵活控制可能不遵守能量守恒破坏PBR原则并且RGB贴图多占用内存多。 高度贴图类似法线贴图有着增强细节的效果把高度值保存起来。 Unity支持两种工作流CocosLayaUE4只支持主流的金属与粗糙度 美术提供物体本身贴图金属度贴图粗糙度贴图。 在Unity中名为Standard的shader就是基于PBR的。 其中参数如下 Albedo本色贴图 Metallic金属度可以调一个值也可以传贴图 Smoothess光泽度可以调值里面的Source选项中可以选择粗糙度的来源本色贴图还是金属度因为一般金属度和粗糙度用两个通道R和A做到一个贴图中。 Normal Map法线贴图 Height Map高度贴图 Occlusion环境遮挡 Detail Mask细Detail Mask是一种用于控制细节纹理的遮罩或掩模。细节纹理通常用于增加表面的细微细节例如皮肤上的皱纹、石头上的裂纹等从而增加物体的真实感。通过定义一个遮罩图像来指定哪些区域应用细节纹理。这个遮罩图像是一个灰度图其中不同的灰度值表示不同的遮罩强度。通常灰度值较高的区域将更多地受到细节纹理的影响而灰度值较低的区域则保留原始的基础材质。 Emission自发光可以选择颜色或贴图 渲染队列与ZTestZWrite 普通情况下绘制画面时绘制最远处的物体然后绘制近处物体这样就能覆盖掉远处物体。但是绘制的时候做了优化先绘制近的再绘制远的如果远的被挡住了就不进行绘制远近不是相对于一整个物体来说的而是相对于一个个片元。 先绘制的物体会把片元放入颜色缓存区和深度缓冲区绘制后面的片元的时候比较深度如果深度比原来的小那么就把这个新的片元放入原来的颜色缓冲区和深度缓冲区。如果不是这个片元信息会被丢弃称为没有通过深度测试ZTest。把片元信息更新到深度缓存区称为ZWrite。如果关掉深度缓存虽然颜色会更新但是深度不会更新。 深度测试有不同规则 ALWAY颜色都会通过测试 NEVER颜色永远无法通过测试 LESS距离摄像机越近的通过测试 EQUAL距离相等的通过测试 GREATER距离摄像机越远的通过测试 NOT_EQUAL距离不相等的通过测试 如果一个物体的shader把深度测试设定为ALWAY那么永远都能绘制到屏幕中。 绘制透明物体第四维的透明度数值alpha不是1的时候可以采用不同的渲染队列每个队列有不同的编号场景的物体会根据队列存放。游戏引擎先绘制编号小的队列再绘制编号大的队列不同的队列都有不同的颜色和深度缓冲区。 不同队列直接的颜色不会被遮挡但是会混合所以通过不同渲染队列透明物体看其他物体时是两种物体的混合色。这个过程叫Blend。 Blend有几种混合模式 直接覆盖默认透明度混合常用 // 根据后面绘制物体的透明度混合例如后面队列的透明物体Alpha为30%则按照30%透明物体颜色和70%缓存的物体颜色绘制src是本色dst是颜色缓存 Blend SrcAlpha OneMinusSrcAlpha // 线性叠加 Blend One One // 正片叠底相乘Multiply Blend DstColor Zero通过在透明物体shader上设置上面代码可以达到对应效果 立方体纹理采样和自制天空盒 天空盒其实就是一个立方体或球体立方体有六个面每个面都可以对应一个纹理贴图。如果这六个贴图在边缘处是连续的那么就可以看成一个整体。 对于天空盒来说其渲染颜色只由本色决定创建天空盒立方体或球体包围住整个场景并编写Shader控制渲染盒子然后调整渲染队列顺序调到最小使其最先绘制。 我们需要创建一个Cubemap的纹理它可以设置立方体的六张贴图。 Shader Bycw/BycwSkyBox {Properties{// 这是Cube纹理不是一般的纹理_MainTex (Texture, Cube) white {}}SubShader{Tags { RenderTypeOpaque }LOD 100Cull Off // 背对摄像机的面不会被裁掉;ZWrite Off // 关掉深度缓存Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include UnityCG.cgincstruct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{// 立方体原点指向顶点的向量float3 dir : TEXCOORD0;float4 vertex : SV_POSITION;};// 纹理贴图samplerCUBE _MainTex; float4 _MainTex_ST;v2f vert (appdata v){v2f o;o.vertex UnityObjectToClipPos(v.vertex);// 通过模型顶点得到向量o.dir v.vertex;return o;}fixed4 frag (v2f i) : SV_Target{// i.uv变成i.dir了fixed4 col texCUBE(_MainTex, i.dir);// fixed4 col fixed4(1.0, 0, 0, 1.0);return col;}ENDCG}} } 向前渲染管线 向前渲染一种Unity内置的渲染管线其包含多光源的光照计算分为两个部分base和additional base包含最重要的逐像素光源逐顶点光源SH光源LightMap环境光称为一个PassAdditional其他重要的逐像素光源一个光源一个Pass 如何处理多光源光照计算 每个光源可以设置渲染模式为AutoImportantNot Important Important是逐像素光照Not Important是逐顶点光照和SH光源的计算。Important光源的数量决定Pass的数量。因此每个重要光源都会做一次光照计算。 float4 _LightColor0:该Pass处理的重要光源的颜色 float4 _WorldSpaceLightPos0重要光源的位置如果是平行光_WorldSpaceLightPos0.w为0其余为1 float4x4 LightMatrix0:从世界空间到光源空间的变换矩阵可以用于采样cookie和光强衰减(attenuation)纹理 unity_4LightPosX0: unity_4LightPosY0: unity_4LightPosZ0:仅用于BasePass前四个非重要点光源在世界空间中的位置 float4 unity_4LightAtten0:仅用于BasePass储存4个非重要点光源的刷减因子 float4 unity_4LightColor:仅用于BasePass储存4个非重要点光源的颜色 Shader Bycw/BycwForward {Properties{_MainTex (Texture, 2D) white {}}SubShader{LOD 100Pass{// 向前渲染Tags { RenderTypeOpaque LightModeForwardBase }CGPROGRAM#pragma vertex vert#pragma fragment frag//预编译指令用于前向渲染计算basePass#pragma multi_compile_fwdbase#include UnityCG.cginc#include Lighting.cgincstruct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;v2f vert (appdata v){v2f o;o.vertex UnityObjectToClipPos(v.vertex);o.uv TRANSFORM_TEX(v.uv, _MainTex);return o;}fixed4 frag (v2f i) : SV_Target{// sample the texturefixed4 col tex2D(_MainTex, i.uv);//unity_LightColor存储四个非重要光源颜色_LightColor0是本Pass唯一重要的光源float4 lightColor _LightColor0 unity_LightColor[0] unity_LightColor[1] unity_LightColor[2] unity_LightColor[3];// 本身乘光照col col * lightColor;return col;}ENDCG}Pass{// 一个其他重要的光源Tags { RenderTypeOpaque LightModeForwardAdd }// 混合光照Blend One OneCGPROGRAM#pragma vertex vert#pragma fragment frag// 预编译其他重要的光源#pragma multi_compile_fwdadd#include UnityCG.cginc#include Lighting.cgincstruct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;v2f vert (appdata v){v2f o;o.vertex UnityObjectToClipPos(v.vertex);o.uv TRANSFORM_TEX(v.uv, _MainTex);return o;}fixed4 frag (v2f i) : SV_Target{// sample the texturefixed4 col tex2D(_MainTex, i.uv);// fixed4 col fixed4(1, 1, 1, 1);col col * _LightColor0;return col;}ENDCG}}} 渲染管线设置 每个摄像机都会绘制一个场景因此渲染管线的设置在摄像机上 Rendering PathUse Graphics Setting默认是向前渲染在Player Setting-Graphics-Randing Path中设置Forward向前渲染Delay演示渲染重要光源数目可以在Project Setting-Quality-Pixel Light Count设置 光照衰减计算 计算方式 点光源球体衰减中心是1超过最远距离是0 聚光灯垂直衰减和水平衰减 衰减系数可以通过计算也可以事先存到纹理中读取主流 Shader Bycw/BycwLightAtten {Properties{_MainTex (Texture, 2D) white {}}SubShader{LOD 100Pass{Tags { RenderTypeOpaque LightModeForwardBase }CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#include UnityCG.cginc#include Lighting.cgincstruct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;v2f vert (appdata v){v2f o;o.vertex UnityObjectToClipPos(v.vertex);o.uv TRANSFORM_TEX(v.uv, _MainTex);return o;}fixed4 frag (v2f i) : SV_Target{// sample the texturefixed4 col tex2D(_MainTex, i.uv);// 平行光的衰减因子float atten 1.0;col col * _LightColor0 * atten;return col;}ENDCG}Pass{Tags { RenderTypeOpaque LightModeForwardAdd }Blend One OneCGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdadd#include UnityCG.cginc#include Lighting.cginc// 需要这个头文件#include AutoLight.cgincstruct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;float3 worldPos: TEXCOORD1;};sampler2D _MainTex;float4 _MainTex_ST;v2f vert (appdata v){v2f o;o.vertex UnityObjectToClipPos(v.vertex);o.uv TRANSFORM_TEX(v.uv, _MainTex);o.worldPos mul(unity_ObjectToWorld, v.vertex);return o;}// 重要光源;fixed4 frag (v2f i) : SV_Target{ /* float atten 1.0;#ifdef USING_DIRECTIONAL_LGITHfixed atten 1.0;#else//点光源#if defined(POINT)// 把片元的世界坐标转移到以点光源为参考的坐标float3 lightCoord mul(unity_WorldToLight,float4(i.worldPos,1)).xyz;//使用点到光源的距离值的平方来取样可以避开开方操作//使用宏UNITY_ATTEN_CHANNEL来得到衰减纹理中衰减值所在的分量以得到最终的衰减值。fixed atten tex2D(_LightTexture0,dot(lightCoord,lightCoord).rr).UNITY_ATTEN_CHANNEL;//聚光灯#elif defined(SPOT)float4 lightCoord mul(unity_WorldToLight,float4(i.worldPos,1));//角度衰减 * 距离衰减// _LightTexture0是衰减系数纹理fixed atten (lightCoord.z 0) * tex2D(_LightTexture0,lightCoord.xy/lightCoord.w 0.5).w * tex2D(_LightTextureB0,dot(lightCoord,lightCoord).rr).UNITY_ATTEN_CHANNEL;#elsefixed atten 1.0;#endif#endif*/// 采用Unity内置的宏计算原理和上面代码一致UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);// 自己算// float r distance(i.worldPos, _WorldSpaceLightPos0);// float atten 1- (r / 10);// endfixed4 col tex2D(_MainTex, i.uv);col col * _LightColor0 * atten;return col;}ENDCG}} } 阴影计算原理 步骤 计算阴影区域在阴影区域叠加颜色 计算区域的时候光源相当于摄像机光源看不见的地方没有阴影。Shader中会编写一个特殊的Pass计算阴影时调用。我们需要把片元坐标转换为以光源为中心的坐标并通过光源计算每个片元的深度信息如果某个地方的深度比光源照到的地方大那么就是阴影。这个深度信息会提供给引擎通过其他shader接收阴影。 在物体属性Mesh Renderer中可以在Lighting中调节Cast Shadows如果关闭物体阴影投射的pass不会被调用也就没有阴影。Receive Shadows可以设置是否接收阴影。 物体投射阴影的时候会产生Pass因此DrawCall会加1 Shader Bycw/BycwShadow {Properties{_MainTex (Texture, 2D) white {}}SubShader{Tags { RenderTypeOpaque }LOD 100// 投影Pass, 摄像机在我们光源的位置;Pass {// 标注模式为阴影投射Tags {LightModeShadowCaster}CGPROGRAM#pragma vertex vert#pragma fragment frag// 预编译#pragma multi_compile_shadowcaster#include UnityCG.cgincstruct v2f { V2F_SHADOW_CASTER; //宏相当于 float3 vec : TEXCOORD0; float4 pos : SV_POSITION};v2f vert(appdata_base v) {v2f o;TRANSFER_SHADOW_CASTER_NORMALOFFSET(o);// 相当于// o.vec mul(unity_ObjectToWorld, v.vertex).xyz - _LightPositionRange.xyz;//opos UnityObjectToClipPos(v.vertex)return o;}float4 frag(v2f i): SV_Target {SHADOW_CASTER_FRAGMENT(i)// 相当于// return UnityEncodeCubeShadowDepth((length(i.vec) unity_LightShadowBias.x) * _LightPositionRange.w)// 把深度信息传出去了}ENDCG }// Base PassPass{Tags {LightModeForwardBase}CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#include UnityCG.cginc#include Lighting.cginc#include AutoLight.cgincstruct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 pos : SV_POSITION;// 根据阴影坐标你可以获取深度信息,获取阴影的颜色值;SHADOW_COORDS(1) // unityShadowCoord4 _ShadowCoord : TEXCOORD1;};sampler2D _MainTex;float4 _MainTex_ST;v2f vert (appdata v){v2f o;o.pos UnityObjectToClipPos(v.vertex);o.uv TRANSFORM_TEX(v.uv, _MainTex);// 算出阴影坐标TRANSFER_SHADOW(o); // o._ShadowCoord ComputeScreenPos(o.pos);return o;}fixed4 frag (v2f i) : SV_Target{fixed4 col tex2D(_MainTex, i.uv);// 根据我们的阴影的坐标把阴影的数据获取出来,得到阴影颜色fixed shadow SHADOW_ATTENUATION(i); // unitySampleShadow(i._ShadowCoord)// 光的颜色乘以阴影0到1的值表示光线在阴影区域的衰减程度或透明度float4 lightColor _LightColor0 * shadow;return col * lightColor;}ENDCG}}}GPU并发计算compute shadder GPU的线程和CPU不同线程由硬件实现每个线程都有自己的执行上下文和寄存器可以单独执行计算任务而这种计算单元有成千上万个可以实现高效的并行计算。CPU缓存大、逻辑运算ALU较少GPU逻辑运算较多缓存较小。相较之下GPU有更多的运算单元即干活的人多了。GPU 包含数千个并行计算单元称为 CUDA 核心。这些 CUDA 核心可以同时处理多个数据流从而实现高效的并行计算。CUDA 核心还包含了一些特殊的硬件单元例如浮点数处理单元、整数处理单元、逻辑单元和共享内存等可以提供快速的数学运算和数据处理能力。 GPU中线程被组织成线程组每个线程组包含多个线程维度可以用numthreads(x,y,z)设置GPU会根据线程组的大小和维度自动分配线程资源并将计算任务分配给每个线程 案例控制GPU计算1024个sqrt计算 GPU代码Unity中创建Compute Shader,GPU的代码指令中有Kernel的概念并行计算的函数入口都可以放到kernel里面。 例如下面的函数CSSqrtMain会排到kernel0每个这样的函数都有一个KernalIndex // Each #kernel tells which function to compile; you can have many kernels #pragma kernel CSSqrtMainRWStructuredBufferfloat inputData; // 用于接受CPU传递过来的数据 RWStructuredBufferfloat outputData; // 用于返回给GPU的数据;// 分配线程组 [numthreads(64,1,1)] void CSSqrtMain(uint3 id : SV_DispatchThreadID)// id是三维的 {outputData[id.x] sqrt(inputData[id.x]); }常见的读写缓存区数据类型如下 RWBuffer这个类型是用于读写一维数据的缓冲区类型可以用于存储任意类型的数据例如float、int等。可以使用SetData和GetData函数将数据写入和读出缓冲区。 RWByteAddressBuffer这个类型也是用于读写一维数据的缓冲区类型但它是按字节寻址的可以用于存储任意类型的数据。可以使用SetData和GetData函数将数据写入和读出缓冲区。 RWStructuredBuffer这个类型是用于读写结构化数据的缓冲区类型可以用于存储自定义的结构体类型。可以使用SetData和GetData函数将数据写入和读出缓冲区。 RWTexture1D这个类型是用于读写一维纹理数据的缓冲区类型可以用于存储颜色或其他类型的数据。可以使用SetPixel和GetPixel函数将数据写入和读出缓冲区。 RWTexture1DArray这个类型是用于读写一维纹理数组数据的缓冲区类型可以用于存储颜色或其他类型的数据。可以使用SetPixel和GetPixel函数将数据写入和读出缓冲区。 RWTexture2D这个类型是用于读写二维纹理数据的缓冲区类型可以用于存储颜色或其他类型的数据。可以使用SetPixel和GetPixel函数将数据写入和读出缓冲区。 RWTexture2DArray这个类型是用于读写二维纹理数组数据的缓冲区类型可以用于存储颜色或其他类型的数据。可以使用SetPixel和GetPixel函数将数据写入和读出缓冲区。 RWTexture3D这个类型是用于读写三维纹理数据的缓冲区类型可以用于存储颜色或其他类型的数据。可以使用SetPixel和GetPixel函数将数据写入和读出缓冲区。 CPU传递数据需要使用ComputeBuffer using System.Collections; using System.Collections.Generic; using UnityEngine;public class MySqrtGPU : MonoBehaviour {private static int itemCount 1024;// 编辑器绑定GPU脚本public ComputeShader mysqrtGPUShader null;ComputeBuffer inputData null;ComputeBuffer outputData null;void Start(){inputData new ComputeBuffer(itemCount, sizeof(float));outputData new ComputeBuffer(itemCount, sizeof(float));float[] rawInputData new float[itemCount];for (int i 0; i itemCount; i) {rawInputData[i] (float)(i);}// 设置传递数据inputData.SetData(rawInputData);// 查找对应的KernalIndexint kernelIndex this.mysqrtGPUShader.FindKernel(CSSqrtMain);// 关联数据this.mysqrtGPUShader.SetBuffer(kernelIndex, inputData, inputData);this.mysqrtGPUShader.SetBuffer(kernelIndex, outputData, outputData);// 执行对应kernelIndex的函数this.mysqrtGPUShader.Dispatch(kernelIndex, itemCount / 64, 1, 1);// 取出结果float[] result new float[itemCount];outputData.GetData(result);for (int i 0; i itemCount; i) {Debug.Log(sqrt( i ) result[i]);}} } 查看Unity内置shader源码 查看Unity内置shader源码是我们学习shader的重要资源可以在Unity官网上的Built in shaders下载
http://www.w-s-a.com/news/6494/

相关文章:

  • 缺乏门户网站建设网页设计与制作项目教程第二版
  • 手机网站横竖屏一般做建设的是什么公司
  • 免费网站建设无广告网站开发 华景新城
  • 湖州网站制作报价西安网站开发有哪些公司
  • google 浏览器开源seo软件
  • 网站空间是什么意思自己怎样建设网站
  • 国外家装设计网站如何做软件开发
  • 凡科建站登录官网当当网网站建设策划书
  • 网站百度屏蔽关键词杭州排名优化公司
  • h5响应式网站模板下载wordpress鼠标指针
  • 摄影作品投稿网站目前最好的引流推广方法
  • 资源站源码永久dede网站搬家 空间转移的方法
  • 网站建设销售的技巧话语it培训机构
  • 自建本地网站服务器wordpress南充房产网最新楼盘最近房价
  • 郑州代做网站天津哪里能做网站
  • 网站如何做排名网站建设项目的工作分解
  • 洛阳网络建站公司网站开发主流语言
  • 广州各区正在进一步优化以下措施seo值是什么意思
  • 滨州建网站公司京东云 wordpress
  • 网站视频背景怎么做免费的网络推广有哪些
  • 申请网站怎样申请广西壮族自治区专升本业务系统
  • 写作网站哪个网站做ic外单好
  • 苏州和城乡建设局网站撸撸撸做最好的导航网站
  • 网站被同行抄袭怎么办深圳中装建设集团
  • 建站及推广瓦房店 网站建设
  • 怎么查网站是在哪里备案的广州电力建设有限公司网站
  • 做网站自己申请域名还是对方wordpress管理地址
  • 专门做二手书网站或appwordpress首页显示特定分类文章
  • 无锡网站设计厂家一建十个专业含金量排名
  • 网站刷链接怎么做成都高度网站技术建设公司