ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

游戏开发Unity渲染场景光照性能优化 ShaderLOD

2019-04-09 08:54:01  阅读:447  来源: 互联网

标签:normalize LOD 渲染 fixed4 rgb fixed3 Unity ShaderLOD worldNormal


 

LODGroup VS ShaderLOD

https://gameinstitute.qq.com/community/detail/110113

前言
       LOD(Level Of Detais)多细节层次。在游戏中,根据摄像机与模型的距离,来决定显示哪一个模型,往往离得近显示高模,离得远显示低模。LOD技术在大场景的应用非常普遍,在展示远景作用非常大。
网络上关于UnityLOD技术大多是关于LODGroup,这里我会简单介绍,而实际上shader上的LOD功能对性能优化也是非常有用的。

LOD Group
        首先创建一个Cube并为其添加LOD Group组件




为Cube创建作为低模显示的子物体,这里使用一个球体和一个胶囊体。




设置LOD Group




点Add为每个lod等级设置显示模型,设置完毕后拖动相机距离就能查看效果了,简单实用。

Shader LOD 
       然而使用LOD Group必须为使用这个技术的模型再另外制作一套低精度模型,工作量为此会增加不少。
       着色器中的LOD技术则是渲染等级抉择,同类型的模型都可以使用。
       好,进入正题,首先创建一个Shader,写一个最简单的带高光的单张纹理着色器。代码如下

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 Shader "Custom/LODShader" {     Properties {         _Color ("Color", Color) = (1,1,1,1)         _MainTex ("Main Tex", 2D) = "white" {}         _Specular("Specular",Color) = (1,1,1,1)         _Gloss("Gloss",Range(8.0,256)) = 20     }     SubShader {
        LOD 300 //设置该SubShader的LOD等级为300         Pass{             Tags {"LightMode" = "ForwardBase"}             CGPROGRAM             #pragma vertex vert             #pragma fragment frag             #include "Lighting.cginc"             fixed4 _Color;             sampler2D _MainTex;             float4 _MainTex_ST;             fixed4 _Specular;             float _Gloss;               struct a2v{                 float4 vertex : POSITION;                 float3 normal : NORMAL;                 float4 texcoord : TEXCOORD0;             };             struct v2f{                 float4 pos:SV_POSITION;                 float3 worldNormal:TEXCOORD0;                 float3 worldPos:TEXCOORD1;                 float2 uv : TEXCOORD2;             };               v2f vert(a2v v){                 v2f o;                 o.pos = mul(UNITY_MATRIX_MVP,v.vertex);                 o.worldNormal = UnityObjectToWorldNormal(v.normal);                 o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;                 o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;                 return o;             }               fixed4 frag(v2f i) : SV_Target{                 fixed3 worldNormal = normalize(i.worldNormal);                 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));                 fixed3 albedo = tex2D(_MainTex,i.uv).rgb * _Color.rgb;                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;                 fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(worldNormal,worldLightDir));                 fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));                 fixed3 halfDir = normalize(worldLightDir + viewDir);                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss);                 return fixed4(ambient + diffuse + specular ,1.0);             }               ENDCG         }     } }
      第九行设置了LOD = 300。
      实际上Unity默认的LOD最大值是无限的,这意味着只要显卡支持这个shader就可以被使用。
      我们可以修改LOD的最大值来选择使用的shader。
       再写一个控制ShaderLOD最大值的脚本。
1 2 3 4 5 6 7 8 9 10 11 using UnityEngine; using System.Collections;   public class ChangeLOD : MonoBehaviour {       public int lodlevel;       void Update () {         Shader.globalMaximumLOD = lodlevel;     } }
        关键就是一句Shader.globalMaximumLOD = lodlevel;
        场景测试效果如下。


       结果很明显,shader中的LOD大于Shader.globalMaximumLOD就不会被显示。所以为了不同的硬件需求我们可以写多个subshader来应对。
  我们继续为shader添加两个subshader
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 SubShader {         LOD 200         Pass{             Tags {"LightMode" = "ForwardBase"}             CGPROGRAM             #pragma vertex vert             #pragma fragment frag             #include "Lighting.cginc"             fixed4 _Color;             sampler2D _MainTex;             float4 _MainTex_ST;             fixed4 _Specular;             float _Gloss;               struct a2v{                 float4 vertex : POSITION;                 float3 normal : NORMAL;             };             struct v2f{                 float4 pos:SV_POSITION;                 float3 worldNormal:TEXCOORD0;                 float3 worldPos:TEXCOORD1;             };               v2f vert(a2v v){                 v2f o;                 o.pos = mul(UNITY_MATRIX_MVP,v.vertex);                 o.worldNormal = UnityObjectToWorldNormal(v.normal);                 o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;                 return o;             }               fixed4 frag(v2f i) : SV_Target{                 fixed3 worldNormal = normalize(i.worldNormal);                 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;                 fixed3 diffuse = _LightColor0.rgb * max(0,dot(worldNormal,worldLightDir));                 fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));                 fixed3 halfDir = normalize(worldLightDir + viewDir);                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss);                 return fixed4(ambient + diffuse + specular ,1.0);             }               ENDCG         }     }     SubShader {         Lod 100         Pass{             Tags {"LightMode" = "ForwardBase"}             CGPROGRAM             #pragma vertex vert             #pragma fragment frag             #include "Lighting.cginc"             fixed4 _Specular;             float _Gloss;             fixed4 _Color;;             struct a2v{                 float4 vertex : POSITION;                 float4 normal : NORMAL;             };             struct v2f{                 float4 pos : SV_POSITION;                 fixed3 color : COLOR;             };               v2f vert(a2v v){                 v2f o;                 o.pos = mul(UNITY_MATRIX_MVP,v.vertex);                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;                 fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));                 fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);                 fixed3 diffuse = _LightColor0.rgb * _Color.rgb * saturate(dot(worldNormal,worldLightDir));                 fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));                 fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz);                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir,viewDir)),_Gloss);                 o.color = ambient + diffuse + specular;                   return o;             }               fixed4 frag (v2f i) : SV_Target{                 return fixed4(i.color,1.0);             }             ENDCG         }     }

       第二个subshader和第一个相比只是去除了对贴图渲染的部分,第三个subshader则是将所有的光照计算放到了顶点函数中。
       注意第二个subshader LOD为200,第三个subshader LOD为100。

结果如下


用这种方式可以动态的剔除复杂的Shader渲染,比如在低端的手机平台上,当检测到FPS低于一定数值可以考虑替换带有高度映射,法线贴图等功能的Shader,甚至可以降低贴图采样密度,停止UV动画。

 

游戏渠道心流游戏类型游戏引擎画面表现风格游戏视觉开放源码JavaS

标签:normalize,LOD,渲染,fixed4,rgb,fixed3,Unity,ShaderLOD,worldNormal
来源: https://www.cnblogs.com/cyct/p/10674740.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有