怎样找回网站备案密码错误,图片站wordpress模板下载,哪个网站可以免费学设计,舆情监测关键词本文主要介绍Untiy5以后的GI#xff0c;PBS#xff0c;以及光源探头#xff0c;反射探头的用法以及在着色器代码中如何发挥作用#xff0c;GI是如何影响渲染的#xff0c;主要分成三个部分#xff0c;最开始说明PBS需要的材质与相应概念#xff0c;二是Unity 里相应GI的… 本文主要介绍Untiy5以后的GIPBS以及光源探头反射探头的用法以及在着色器代码中如何发挥作用GI是如何影响渲染的主要分成三个部分最开始说明PBS需要的材质与相应概念二是Unity 里相应GI的操作三是对应着色器代码的理解。如果没有特殊声明所有操作与代码都是针对Unity5.3. PBS材质与概念 简单来说PBS的优点不同的照明下获得一致的外观更容易实现更直观的参数。 PBS材质概念 1.albedo 反照率 反照率贴图定义漫反射的基本颜色与原来的漫反射贴图相比不包含定向光与AO在这我们应该由环境自己的定向光与AO来影响Unity里我们用GI得到相应烘培或是实时的方向光与AO。 2.Smoothness/Microsurface 表面细节 材料细节 光滑度 光滑度:描述物体微表面的一个参数可以用来定义法线分布函数这样粗糙的表面呈现宽淡的镜面反射光滑呈现集中和明亮的镜面反射。 3.Metal/reflectivity 金属性/反射 金属与绝缘体应该使用不同的反射设置导体的反射率 60-90%绝缘体0-20%高反射光分子不容易到达内部和散射这样金属的高表现出来比较淡。 如下全局设置 对于固定的材料反射率趋于稳定,这样一般来说一个模型的metal相对变化较少如泥水木头这些他们的反射率相关并不大只有金属与绝缘体会有相对比较大的反差而模型表面的粗糙度应该用上面的图光滑性来表示这个相对变化会比较大些,如下水和泥土有相似的金属性反射率,但是光滑度相差大所以相差比较明显。 上图来自pbr-theory: http://www.marmoset.co/toolbag/learn/pbr-theory Unity中事项,Metallic 贴图,金属性质占用R通道光滑性占用A通道GB被忽略。 物体的本来颜色用albedo表示光滑性用Smoothness表示材质特性用Metal表示其中Unity 二种PBS标准着色Standard其中金属性越高本身镜面颜色占比越高灯光的颜色占比越低而高光可以设置自己的镜面反射。 PS: pbr-practice http://www.marmoset.co/toolbag/learn/pbr-practice BRDF 光照模型 概念 1 能量守恒一个对象不能反射比他接收的光多。 粗糙的材料有更多比较淡的亮点而光滑的材料有更集中更明亮的亮点也可以这么理解漫反射越多镜面反射相对越少镜面反射越多漫反射越少。 2 菲涅尔效应边缘的反射更亮。 更具体的可以看http://filmicgames.com/archives/557 3 微表面模型模型 普通的着色模型假定着色的区域是一个平滑的表面表面有一个法线而微表面则认为着色区域是一个无数比入射光线覆盖范围更小的微小表面组成的粗糙区域这个微小表面是光滑的镜面反射。表面细微细节对扩散的影响表面越粗糙反射光越发散或模糊。 GI结合BRDF渲染 GI全局照明指的是全局照明会模拟光线在场景中的多次反射所有的东西都是一个潜在的光源任何可见的模型不是辐射光线就是反射光线其中GI(渲染间接光源本身一般也用BRDF渲染) 配合BRDF生成带灯光直射环境内模型互想影响的逼真场景。 天空盒是GI的组成部分反射天空盒可以改变场景所有模型接受反射量。 GI结合PBS如下摄像机的镜头是一样的材质在不同的环境下 更详细的可以点进这个链接: http://docs.unity3d.com/Manual/shader-StandardShader.html GI操作 全局光照的特点在于能够捕捉间接光照,所以5以后除开原来的direct light的效果增加indirect light的效果简单来说就是除开光源之后然后模型本身做为光源幅射到别的模型上层层递归后的效果。现不管是预计算实时GI还是烘培GI都只是针对静态模型。预计算Gi的实时光源与烘陪对应的烘培光源里的强度与反射强度都会影响幅射图与方向图的内容。需要注意预计算Gi针对的是实时方向光而烘培GI针对的是烘培方向光。 全局光源 Skybox :天空盒参考材质Skybox/Cubemap如果全局光源与全局反射探头都选择Skybox模式则会把Skybox当做一个Cubemap场景所有模型静态与非静态的一部分光源从这个Cubemap反射上得到。 Sun:Skybox选择一个方向光,以这个方向光的方向做方向这个方向光如颜色与强度不影响全局本身如果没有设置方向光选择强度最大的那个方向光源。 Ambient Source:全局光源如果设置天空盒但是天空盒本身没有设置自动选择下面的全局颜色设置全局反射探头以Ambient Source当做光源。 Ambient Intensity:全局光源强度越高越亮为0时光源不起作用。 Ambient GI:当预计算GI与烘培GI二个都选择后这个可以选择是用实时还是烘培。 Reflection Source:Unity默认放入的全局反射探头选择Skybox会以Ambient Source里提供的光源颜色做反射,同时也可以自己提供cubemap当做反射源。 Resolution:反射探头解析度应该是对应RTT的cubemap六张纹理的分辨率。 Compression:是否压缩。 Reflection Intensity:Reflection Source针对所有模型反射强度值越大相应的模型面上显示越清晰的Reflection Source。 Reflection Bounces:当设置多个Reflection Probe时互相反射对方信息的次数如二面镜子。 GI设置 Precomputed Realtime GI 预计算实时GI针对实时静态物体之间的幅射光故相应的幅射图与方向图都是低分辨率下的。动态物体可以使用光照探头来得到相应反射光源信息,注意动态模型与光探头的距离。 Realtime Resolution:预计算实时GI,把场景分成许多格得到每个格的幅射信息。那么这个值越高计算量将以平方增加最终值还将和General GI里的光源参数里的Resolution相乘。 CPU Usage:生成相应GI的数据时在游戏运行时分配多少CPU计算能力。 Baked GI 烘培GI因此能得到更精确的模型之间的反射光信息但是不能运行时更改相应的光源信息如颜色方向预计算实时GI没有这个问题。 Baked Resolution:一般来说是Realtime Resolution 10因为相应的幅射图与方向图精确度要高很多。 Baked Padding:网上说是光照贴图中分隔的距离还需要验证。 Compressed:是否压缩 Ambient Occlusion:值越高遮挡地区得到的光比差越大。 Final Gather:用FG技术来产生烘培数据这种技术时间会长一些。参考http://blog.sina.com.cn/s/blog_46c56d9a0100gqbv.html Ray Count:Final Gather所用的光线追踪光线数目。 Atlas Size:图集里贴图的大小越低实际占用越精确也就是越小但是贴图产生越多应该选择一个合适的大小。 General GI 预计算实时GI还是烘培如何生成. Direction Mode:幅射图/带方向光/加镜面,具体看Shader分析其中预计算实时GI与烘培GI在这生成的相应幅射图方向图等有所不同后面会提到。 Indirect Intensity:间接光的强度。 Default Parameters:生成相应贴图所需要的信息。 其中全局预计算GI烘培GI全局反射探头相应的改动需要重新烘培如果选择自动相关改动会自动在后台烘培。 上面这些说实话写这么操作没啥用自己对着每项实践一篇什么都清楚了。 Light Probe: 对于GI来说不管是预计算GI与烘培GI都不会对非静态模型计算间接反射光探头的加入可以使非静态模型得到周围静态模型的幅射光主要技术原理使用一种球谐光照的技术注意light probe一般不会对静态模型有影响你看到的影响只是因为非静态模型的颜色变化大造成的反差。 相关球谐光照的技术原理可以参见本人也看不懂只能说看了后有点印象是怎么回事 球谐光照(上) http://www.yasrt.org/shlighting/ http://www.cppblog.com/init/archive/2012/09/19/191182.html 一种2D傅立叶级数的球形推广,可以把光照函数展开成SH基函数的叠加类似傅立叶变换能把任何函数展开成正弦波的叠加对光照图来说一般只用2 bands 4 RGB textures通过丢失高频细节来压缩存储。 Reflection Probe: 定义一个Cubemap用来影响周围模型的镜面反射给镜面高光模型使用。 一般来说我们想得到一个实时场景的Cubemap,只需要在一个点用摄像机对着前后左右上下各拍摄一次形成6个面组合成Cubemap. Type:烘培用户自动。其中烘培就是用户来控制生成一个当前的场景cubemap,用户就是用户自己提供一个cubemap,实时就是不断更新这个cubemap以映射最新的场景。 当选择实时Refresh mode:On awake启动时每桢用户脚本控制当每桢时如下选择。 Time slicing:一桢先生成6个面后面8桢每桢生成一个mipmap一共9桢。 Individual face:6面6桢加后面8桢每个mipmap,一共14桢。 No time slicing:一桢内把mipmap与cubemap全部生成。 Importance:当多个反射探头影响一个模型时这个参数影响这个反射探头的比重。 Intensity:间接光强度强度影响镜面反射,镜面反射越亮。 Box Projection:从着色代码来看应该根据当前反射探头的源点与AABB影响是模型原来法线。 Size:大小范围内的模型使用这个。 Probe Origin:原点。 Cubemap capture sttings: Resolution:cubempa材质的大小。 HDR高光。 Shadow Distance:阴影距离数值越少阴影越近。 下面就是RTT对应摄像机的属性。 GI间接光源算法辐射度算法 辐射度算法就是:把场景细分到很细很细的面片(如1个像素那么大的三角形),分别计算它们接受和发出的光能,然后逐次递归,直到每个面片的光能数据不再变化(或者到一定的阀值)为止.因此,计算量很大(要计算很多次),而且难以并行(因为递归)参考http://blog.sina.com.cn/s/blog_537cc4d90101iiil.html Unity中GI选择non-direction模式生成的辐射度使用一张图储存每个位置收到的间接光照其中假定都只是扩散没有镜面反射。 GI Directional LightMap算法 把半球面的入射辐射度用某种方法进行采样保存起来在运行时根据法线图中的法线方向来进行一次合成由于带方向信息也可以支持高光计算了可以参考http://www.fseraph.com/?p193 Unity中GI选择direction模型,会在上面辐射图添加一张图用来存储接收到的光的方向选择specular,烘培GI与预计算GI使用不同的方式烘培GI在上面二张图各扩大一倍原来的保存直接光的影响新增加的位置用来保存间接光的影响其中预计算GI新增加一张贴图三张图分别保存辐射光照光源方向法线需要结合实时方向光源。 PS 探讨Unity5中全局光照(Enlighten) http://unity.jb51.net/meigongsheji/Unitymeihua/18.html Unity 5.0新功能教学http://tieba.baidu.com/p/3690939628 Unity 5 中的全局光照技术详解 http://www.cocoachina.com/game/20150701/12339.html Unity5 官网文档GI三种模式具体区别 http://docs.unity3d.com/Manual/LightmappingDirectional.html Unity GI BRDF Shader 主要参考对照如下Shader文件 UnityStandardCore.cginc:前向渲染base,顶点着色入口vertForwardBase,片断着色入口fragForwardBase这个是着色器的主要Pass,全局方向光GI信息合并都在这个pass中。 UnityStandardBRDF.cginc:BRDF的具体实现. UnityGloballllumination.cginc:提取GI信息包含烘陪GI与预计算GI。 预计算Gi针对的是实时方向光而烘培GI针对的是烘培方向光所以当说预计算GI的light时指的是实时方向光而烘培GI的light说的是烘培方向光。 相应主要代码我都已经加上注释相信还是比较容易看懂的。 1 ---------UnityStandardCore2 //顶点着色器入口3 VertexOutputForwardBase vertForwardBase (VertexInput v)4 {5 VertexOutputForwardBase o;6 UNITY_INITIALIZE_OUTPUT(VertexOutputForwardBase, o);7 //世界坐标下位置8 float4 posWorld mul(_Object2World, v.vertex);9 #if UNITY_SPECCUBE_BOX_PROJECTION10 o.posWorld posWorld.xyz;11 #endif12 //屏幕空间位置13 o.pos mul(UNITY_MATRIX_MVP, v.vertex);14 o.tex TexCoords(v);15 o.eyeVec NormalizePerVertexNormal(posWorld.xyz - _WorldSpaceCameraPos);16 float3 normalWorld UnityObjectToWorldNormal(v.normal);17 #ifdef _TANGENT_TO_WORLD18 float4 tangentWorld float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);19 20 float3x3 tangentToWorld CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w);21 o.tangentToWorldAndParallax[0].xyz tangentToWorld[0];22 o.tangentToWorldAndParallax[1].xyz tangentToWorld[1];23 o.tangentToWorldAndParallax[2].xyz tangentToWorld[2];24 #else25 o.tangentToWorldAndParallax[0].xyz 0;26 o.tangentToWorldAndParallax[1].xyz 0;27 o.tangentToWorldAndParallax[2].xyz normalWorld;28 #endif29 //We need this for shadow receving30 TRANSFER_SHADOW(o);31 32 // Static lightmaps33 #ifndef LIGHTMAP_OFF34 //开启烘培GI后35 o.ambientOrLightmapUV.xy v.uv1.xy * unity_LightmapST.xy unity_LightmapST.zw;36 o.ambientOrLightmapUV.zw 0;37 // Sample light probe for Dynamic objects only (no static or dynamic lightmaps)38 //光源探头对动态模型的影响rgb(颜色)根据SH系数还原光源探头与不重要的点光源上的颜色信息39 #elif UNITY_SHOULD_SAMPLE_SH40 #if UNITY_SAMPLE_FULL_SH_PER_PIXEL41 o.ambientOrLightmapUV.rgb 0;42 #elif (SHADER_TARGET 30)43 o.ambientOrLightmapUV.rgb ShadeSH9(half4(normalWorld, 1.0));44 #else45 // Optimization: L2 per-vertex, L0..L1 per-pixel46 o.ambientOrLightmapUV.rgb ShadeSH3Order(half4(normalWorld, 1.0));47 #endif48 // Add approximated illumination from non-important point lights49 #ifdef VERTEXLIGHT_ON50 o.ambientOrLightmapUV.rgb Shade4PointLights (51 unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,52 unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,53 unity_4LightAtten0, posWorld, normalWorld);54 #endif55 #endif56 //开启预计算GI后57 #ifdef DYNAMICLIGHTMAP_ON58 o.ambientOrLightmapUV.zw v.uv2.xy * unity_DynamicLightmapST.xy unity_DynamicLightmapST.zw;59 #endif60 61 #ifdef _PARALLAXMAP62 TANGENT_SPACE_ROTATION;63 half3 viewDirForParallax mul (rotation, ObjSpaceViewDir(v.vertex));64 o.tangentToWorldAndParallax[0].w viewDirForParallax.x;65 o.tangentToWorldAndParallax[1].w viewDirForParallax.y;66 o.tangentToWorldAndParallax[2].w viewDirForParallax.z;67 #endif68 69 UNITY_TRANSFER_FOG(o,o.pos);70 return o;71 }72 //片断着色器入口73 half4 fragForwardBase (VertexOutputForwardBase i) : SV_Target74 {75 FRAGMENT_SETUP(s)76 UnityLight mainLight MainLight (s.normalWorld);77 half atten SHADOW_ATTENUATION(i);78 79 half occlusion Occlusion(i.tex.xy);80 //提取GI里的信息到UnityGI中。81 UnityGI gi FragmentGI (82 s.posWorld, occlusion, i.ambientOrLightmapUV, atten, s.oneMinusRoughness, s.normalWorld, s.eyeVec, mainLight);83 // 如果是预计算GI或动态模型gi.light表示主光源焙烘取84 half4 c UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect);85 // GI生成类型是spceular才会计算86 c.rgb UNITY_BRDF_GI (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, occlusion, gi);87 c.rgb Emission(i.tex.xy);88 89 UNITY_APPLY_FOG(i.fogCoord, c.rgb);90 return OutputForward (c, s.alpha);91 }92 93 //填充UnityGIInput用来得到UnityGI信息。94 inline UnityGI FragmentGI (95 float3 posWorld, 96 half occlusion, half4 i_ambientOrLightmapUV, half atten, half oneMinusRoughness, half3 normalWorld, half3 eyeVec,97 UnityLight light)98 {99 UnityGIInput d;
100 d.light light;
101 d.worldPos posWorld;
102 d.worldViewDir -eyeVec;
103 d.atten atten;
104 //如果有GI信息。
105 #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
106 d.ambient 0;
107 d.lightmapUV i_ambientOrLightmapUV;
108 #else
109 //一般来说非静态模型得到环境光
110 d.ambient i_ambientOrLightmapUV.rgb;
111 d.lightmapUV 0;
112 #endif
113 //全局反射探头的AABB
114 d.boxMax[0] unity_SpecCube0_BoxMax;
115 d.boxMin[0] unity_SpecCube0_BoxMin;
116 //位置
117 d.probePosition[0] unity_SpecCube0_ProbePosition;
118 d.probeHDR[0] unity_SpecCube0_HDR;
119
120 //用户定义的反射探头AABB
121 d.boxMax[1] unity_SpecCube1_BoxMax;
122 d.boxMin[1] unity_SpecCube1_BoxMin;
123 d.probePosition[1] unity_SpecCube1_ProbePosition;
124 d.probeHDR[1] unity_SpecCube1_HDR;
125
126 return UnityGlobalIllumination (
127 d, occlusion, oneMinusRoughness, normalWorld);
128 }
129
130 --------UnityGloballllumination.cginc
131 //FragmentGI 跳转到这
132 inline UnityGI UnityGlobalIllumination (UnityGIInput data, half occlusion, half oneMinusRoughness, half3 normalWorld, bool reflections)
133 {
134 UnityGI o_gi;
135 UNITY_INITIALIZE_OUTPUT(UnityGI, o_gi);
136
137 // Explicitly reset all members of UnityGI
138 ResetUnityGI(o_gi);
139
140 //动态模型使用 SH得到的漫反射信息。
141 #if UNITY_SHOULD_SAMPLE_SH
142 #if UNITY_SAMPLE_FULL_SH_PER_PIXEL
143 half3 sh ShadeSH9(half4(normalWorld, 1.0));
144 #elif (SHADER_TARGET 30)
145 half3 sh data.ambient ShadeSH12Order(half4(normalWorld, 1.0));
146 #else
147 half3 sh data.ambient;
148 #endif
149
150 o_gi.indirect.diffuse sh;
151 #endif
152
153 //如果没有烘培GI需要当前全局方向光源的信息
154 #if !defined(LIGHTMAP_ON)
155 o_gi.light data.light;
156 //atten阴影信息值越小阴影越重
157 o_gi.light.color * data.atten;
158 //烘培GI
159 #else
160 // Baked lightmaps
161 fixed4 bakedColorTex UNITY_SAMPLE_TEX2D(unity_Lightmap, data.lightmapUV.xy);
162 half3 bakedColor DecodeLightmap(bakedColorTex);
163 //没有方向贴图
164 #ifdef DIRLIGHTMAP_OFF
165 //设置漫反射
166 o_gi.indirect.diffuse bakedColor;
167
168 #ifdef SHADOWS_SCREEN
169 o_gi.indirect.diffuse MixLightmapWithRealtimeAttenuation (o_gi.indirect.diffuse, data.atten, bakedColorTex);
170 #endif // SHADOWS_SCREEN
171 //方向与漫反射
172 #elif DIRLIGHTMAP_COMBINED
173 fixed4 bakedDirTex UNITY_SAMPLE_TEX2D_SAMPLER (unity_LightmapInd, unity_Lightmap, data.lightmapUV.xy);
174 //更精准的漫反射 调整过后的half Lambert
175 o_gi.indirect.diffuse DecodeDirectionalLightmap (bakedColor, bakedDirTex, normalWorld);
176
177 #ifdef SHADOWS_SCREEN
178 o_gi.indirect.diffuse MixLightmapWithRealtimeAttenuation (o_gi.indirect.diffuse, data.atten, bakedColorTex);
179 #endif // SHADOWS_SCREEN
180 //漫反射方向高光
181 #elif DIRLIGHTMAP_SEPARATE
182 // Left halves of both intensity and direction lightmaps store direct light; right halves - indirect.
183
184 // Direct 调整o_gi.light
185 fixed4 bakedDirTex UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, data.lightmapUV.xy);
186 o_gi.indirect.diffuse DecodeDirectionalSpecularLightmap (bakedColor, bakedDirTex, normalWorld, false, 0, o_gi.light);
187
188 // Indirect 漫反射镜面都是保存在unity_Lightmap中竖直中间分开
189 //调整o_gi.light2
190 half2 uvIndirect data.lightmapUV.xy half2(0.5, 0);
191 bakedColor DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, uvIndirect));
192 bakedDirTex UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, uvIndirect);
193 o_gi.indirect.diffuse DecodeDirectionalSpecularLightmap (bakedColor, bakedDirTex, normalWorld, false, 0, o_gi.light2);
194 #endif
195 #endif
196
197 //预计算GI
198 #ifdef DYNAMICLIGHTMAP_ON
199 // Dynamic lightmaps unity_DynamicLightmap unity_DynamicDirectionality unity_DynamicNormal
200 fixed4 realtimeColorTex UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, data.lightmapUV.zw);
201 //间接漫反射
202 half3 realtimeColor DecodeRealtimeLightmap (realtimeColorTex);
203
204 #ifdef DIRLIGHTMAP_OFF
205 o_gi.indirect.diffuse realtimeColor;
206
207 #elif DIRLIGHTMAP_COMBINED
208 half4 realtimeDirTex UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, data.lightmapUV.zw);
209 //调整漫反射
210 o_gi.indirect.diffuse DecodeDirectionalLightmap (realtimeColor, realtimeDirTex, normalWorld);
211
212 #elif DIRLIGHTMAP_SEPARATE
213 half4 realtimeDirTex UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, data.lightmapUV.zw);
214 half4 realtimeNormalTex UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicNormal, unity_DynamicLightmap, data.lightmapUV.zw);
215 //调整o_gi.light3
216 o_gi.indirect.diffuse DecodeDirectionalSpecularLightmap (realtimeColor, realtimeDirTex, normalWorld, true, realtimeNormalTex, o_gi.light3);
217 #endif
218 #endif
219 //gi里的信息全放入indirect的diffuse中
220 o_gi.indirect.diffuse * occlusion;
221 //有反射探头设置镜面光源信息。
222 if (reflections)
223 {
224 half3 worldNormal reflect(-data.worldViewDir, normalWorld);
225
226 #if UNITY_SPECCUBE_BOX_PROJECTION
227 half3 worldNormal0 BoxProjectedCubemapDirection (worldNormal, data.worldPos, data.probePosition[0], data.boxMin[0], data.boxMax[0]);
228 #else
229 half3 worldNormal0 worldNormal;
230 #endif
231
232 half3 env0 Unity_GlossyEnvironment (UNITY_PASS_TEXCUBE(unity_SpecCube0), data.probeHDR[0], worldNormal0, 1-oneMinusRoughness);
233 #if UNITY_SPECCUBE_BLENDING
234 const float kBlendFactor 0.99999;
235 float blendLerp data.boxMin[0].w;
236 UNITY_BRANCH
237 if (blendLerp kBlendFactor)
238 {
239 #if UNITY_SPECCUBE_BOX_PROJECTION
240 half3 worldNormal1 BoxProjectedCubemapDirection (worldNormal, data.worldPos, data.probePosition[1], data.boxMin[1], data.boxMax[1]);
241 #else
242 half3 worldNormal1 worldNormal;
243 #endif
244
245 half3 env1 Unity_GlossyEnvironment (UNITY_PASS_TEXCUBE(unity_SpecCube1), data.probeHDR[1], worldNormal1, 1-oneMinusRoughness);
246 o_gi.indirect.specular lerp(env1, env0, blendLerp);
247 }
248 else
249 {
250 o_gi.indirect.specular env0;
251 }
252 #else
253 o_gi.indirect.specular env0;
254 #endif
255 }
256 //反射探头的信息存入到gi的indirect镜面中
257 o_gi.indirect.specular * occlusion;
258
259 return o_gi;
260 }
261
262 --------UnityStandardBRDF.cginc
263 // Main Physically Based BRDF
264 // Derived from Disney work and based on Torrance-Sparrow micro-facet model
265 //
266 // BRDF kD / pi kS * (D * V * F) / 4
267 // I BRDF * NdotL
268 //
269 // * NDF (depending on UNITY_BRDF_GGX):
270 // a) Normalized BlinnPhong
271 // b) GGX
272 // * Smith for Visiblity term
273 // * Schlick approximation for Fresnel
274 half4 BRDF1_Unity_PBS (half3 diffColor, half3 specColor, half oneMinusReflectivity, half oneMinusRoughness,
275 half3 normal, half3 viewDir,
276 UnityLight light, UnityIndirect gi)
277 {
278 half roughness 1-oneMinusRoughness;
279 //nh,能射入眼睛的光线的角度 也叫半线
280 half3 halfDir Unity_SafeNormalize (light.dir viewDir);
281 half nl light.ndotl;
282 //nh半线与法线夹角夹角越少射入眼睛的光越大
283 half nh BlinnTerm (normal, halfDir);
284 //射线与法线夹角
285 half nv DotClamped (normal, viewDir);
286 //光线与法线夹角
287 half lv DotClamped (light.dir, viewDir);
288 //半线与光线夹角
289 half lh DotClamped (light.dir, halfDir);
290
291 #if UNITY_BRDF_GGX
292 //遮挡函数
293 half V SmithGGXVisibilityTerm (nl, nv, roughness);
294 //法线分布函数 1/Pi
295 half D GGXTerm (nh, roughness);
296 #else
297 //遮挡函数
298 half V SmithBeckmannVisibilityTerm (nl, nv, roughness);
299 //法线分布函数 1/Pi
300 half D NDFBlinnPhongNormalizedTerm (nh, RoughnessToSpecPower (roughness));
301 #endif
302 half nlPow5 Pow5 (1-nl);
303 half nvPow5 Pow5 (1-nv);
304 half Fd90 0.5 2 * lh * lh * roughness;
305 //disney Diffuse 菲涅尔 边角有更亮的光
306 half disneyDiffuse (1 (Fd90-1) * nlPow5) * (1 (Fd90-1) * nvPow5);
307 // HACK: theoretically we should divide by Pi diffuseTerm and not multiply specularTerm!
308 // BUT 1) that will make shader look significantly darker than Legacy ones
309 // and 2) on engine side Non-important lights have to be divided by Pi to in cases when they are injected into ambient SH
310 // NOTE: multiplication by Pi is part of single constant together with 1/4 now
311 //镜面系数
312 half specularTerm max(0, (V * D * nl) * unity_LightGammaCorrectionConsts_PIDiv4);// Torrance-Sparrow model, Fresnel is applied later (for optimization reasons)
313 half diffuseTerm disneyDiffuse * nl;
314 //Gi镜面可以看到oneMinusReflectivity越高grazingTerm越低specColor越高(本身镜面颜色)
315 half grazingTerm saturate(oneMinusRoughness (1-oneMinusReflectivity));
316 //GI non-direction与direction的BRDF如下情况
317 // 烘培GI 预计算GI 动态模型
318 //light.color 空 实时方向光直接信息 实时方向光直接信息
319 //gi.diffuse 直接与间接光源信息 间接光源信息 SH(光源探头)间接光源信息
320 //gi.specular 反射探头 反射探头 反射探头
321 half3 color diffColor * (gi.diffuse light.color * diffuseTerm)
322 specularTerm * light.color * FresnelTerm (specColor, lh)
323 gi.specular * FresnelLerp (specColor, grazingTerm, nv);
324 return half4(color, 1);
325 } BRDF GI 整个代码并不多但是对于前面所说所有东东在这都有一个完整的解释这份代码来告诉我们那些金属性光滑度GI中幅射图方向图还有光源探头反射探头所起的作用。 BRDF 光照模型 如下是现有光照模型没有考虑的问题 光照现象漫反射并不是各个方面平均发散. ----微表面模型(NDF). 菲涅尔定理(Fresnel) ----光源在边角处有更明亮的反光。 能量守恒反射的光不能超过入射的光. ----遮挡因素越光滑镜面越集中越亮 普通的着色模型假定着色的区域是一个平滑的表面表面有一个法线而微表面则认为着色区域是一个无数比入射光线覆盖范围更小的微小表面组成的粗糙区域这个微小表面是光滑的镜面反射因为着色区域并不能一个法向量来表示表面的方向转面代替用一概率分布函数NDF来表示。一般来说分别用如下字母表示 D 用来表示法线分布。 F 用来菲涅尔影响光源在边角处有更明亮的反光。 G/V 用来表示凹凸表面间的遮挡因素Unity用V来表示 如下是Unity相对应BRDF的处理 先要说明每个引擎对BRDF处理各不同在这只介绍Untiy的实现 D 采用GGX与BlinnPhong二种法线分布函数BlinnPhong比较简单效率高。 F 采用简化的Disney Fresnel方式求得菲涅尔影响。 G/V 采用GGX与Beckmann二种技术可以看到光滑度是个关键参数。 针对Unity5.3简化过的Disney Fresnel简单分析下. Nl:法线与灯光的夹角夹角越大这个值越小。 Nv:法线与视线的夹角夹角越大这个值越小。 Lh:灯光与视线的半线与法线的夹角其中灯光与视线的半线就是灯光与视线的平均线简单来说这个线与法线重合这条由灯光发出来的射线才能进入我们的眼镜。 假定 fd90不变nl与nl的角度越大那么nlPow5与nvPow5的值越大最终结果越大这也是菲涅尔想表达的光源在边角处有更明亮的反光。 在Unity中可以看到D与V影响镜面反射,F影响漫反射,特别说明只有Unity是这样处理。 其中可以看到反射率也就是金属性影响的是GI的镜面反射也就是反射探头。 其余的部分挑的说明下: 顶点着色器中填充VertexOutputForwardBase 信息其中ambientOrLightmapUV(half4) 如果包含烘培GIxy填充相应烘培GI的UV坐标如果包含预计算GIzw填充为预计算GI的UV坐标。如果是非静态模型不包含GI信息相应light probe提供的光源信息放入rgb中。 片断着色器中每个像素要得到对应像素上的Unity GI信息相应的Unity GI中的属性light并不是表示光源而是当前像素受如主光源幅射镜面对当前像素的影响每个像素对应的light都有差别千万不要看到写的是个light就把它当做光照这样所有理解都不对了。 其中如果只有烘培GI当前像素的Unity GI中参数light不提供信息indirect里的漫反射包含烘培光源的光照。而预计算GI中当前像素的light本身就是全局光源indirect只包含物体之间的漫反射信息而非静态模型中当前像素只有实时光源等直接光照信息其周围的静态模型的反射光只有通过光探头得到SH信息。 FragmentGI里常见结构 1 UnityLight 包含当前像素中光源颜色方向法线与光源方向点积 2 UnityIndirect 包含当前像素中diffuse漫反射specular镜面信息 3 UnityGI特别注意里面的light是UnityLight类型并不表示光源而是用来表示当前像素受光源影响的量。 Gi.light 如果烘陪GI信息则使用当前主光源填充UnityLight如果有烘陪GI信息则填充为空。 Gi.light2 当烘培GI启用高光后才会调用。 Gi.light3 预计算GI启用高光后才会调用。 UnityGI在根据函数UnityGlobalIllumination被填充我们可以分析得到动态模型使用SH得到漫反射信息。如果没有烘培GI我们需要实时全局光源故gi.light是像素所受全局方向光。烘培GIGI光照信息保存在gl.light2中gi漫反射直接取光照图里的diffuse.预计算GIGI光照信息保存在gl.light3中,gi漫反射添加光照图里的diffuse.而反射探头用来添加反射的信息到GI里的镜面信息中了其中Occlusion 控制gi的diffuse与specular系数。(n*occlusion) 其中UNITY_SHOULD_SAMPLE_SH 当前渲染的动态模型使用SH得到间接的漫反射信息其中UNITY_SHOULD_SAMPLE_SH如下定义。#define UNITY_SHOULD_SAMPLE_SH ( defined (LIGHTMAP_OFF) defined(DYNAMICLIGHTMAP_OFF) ) 预计算GI与烘培GI 烘培GI如上代码中分析得到选择non-direction只有一张图保存直接与间接光照所有信息选择direction后会保存方向选择specular后上面二张图长度扩大一倍保存镜面有关信息。 其中预计算GI选择non-direction只有一张图不保存直接光照只保存间接光照选择direction保存方向选择specular后不同于烘培GI会新增一张纹理保存镜面相关信息从代码来上看可能是组织过的法线 反射探头 unity_SpecCube0_ 全局反射探头 unity_SpecCube1_当前模型受影响的反射探头。 FragmnetGI:得到全局反射探头与用户定义的反射探头位置AABBIsHDR. UnityGlobalIllumination:片断像素中得到反射探头影响镜面值,可以看到SpecCube0与SpecCube1通过深度影响gi间接光源上的镜面颜色。 BoxProjectedCubemapDirection影响worldNormal(反视线进过法线后的反射 Unity_GlossyEnvironment可以看到 光滑值影响LOD值越光滑越清晰。 UNITY_SAMPLE_TEXCUBE 从cubemap取值。 光源探头 vertForwardBaseVertexOutputForwardBase的ambientOrLightmapUV设置颜色从这可以看到光源探头实际不影响静态的物体你如果看到有影响只是因为周围的非静态模型颜色反差造成给你的影响。 UnityGlobalIllumination灯光探头的值赋到gi间接光源上的漫反射上。 PS 基于物理着色一基于物理着色二基于物理着色三 Disney这个Principled BRD 维基BRDF 深入理解Unity5中的Standard Shader(三) Unity3d 基于物理渲染Physically-Based Rendering之specular BRDF 2016/2/1今天看UE4中的环境反射文档我去Unity里的做法完全是参照UE4的通过上面的着色器代码我们可以完全理解下面这个链接里所说的。 UE4中的环境反射