赞
踩
环境的反射算在间接光的镜面反射中
- UnityIndirect CreateIndirectLight(v2f i,float3 viewDir){
- ...
- #if defined(FORWARD_BASE_PASS)
- ...
- //得到反射方向
- float3 reflectDir=reflect(-viewDir,i.normal);
- //得到环境采样
- float4 envSample = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, reflectDir);
- //天空盒可能是HDR的,要转回普通的颜色
- indirectLight.specular=DecodeHDR(envSample, unity_SpecCube0_HDR);;
- #endif
- ...
- }
unity_SpecCube0保存了环境的立体贴图(天空盒和后面的反射探针形成的立体贴图,都算在这里)
UNITY_SAMPLE_TEXCUBE 用于采样立体贴图
DecodeHDR将高动态贴图转为正常RGB,如果导入的不是HDR贴图,就没有变化,我这里默认的天空盒不是HDR的,所以加不加都一样 unity_SpecCube0_HDR.xy和颜色的alpha通道(M)存储了转化的信息
finalcolor=xMy∗hdrcolor
右键创建资源->Light->Reflection Probe
黄框就是渲染的立方体贴图的范围,一共三个模式,一般用Bake模式,它只会烘焙静态物体,就是下面这个选项是静态的
物体进入黄框范围,他的unity_SpecCube0就有这个反射探针的立体贴图了,
但此时环境反射还不收Smoothness的影响,所以要换一下采样贴图的方法,让他根据粗糙度读取不同层级的mipmap
- float roughness = 1 - _Smoothness;
- roughness *= 1.7 - 0.7 * roughness;
- float4 envSample = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectDir,roughness*UNITY_SPECCUBE_LOD_STEPS);
Unity会为环境贴图生成不同层级的mipmap,0-5级从模糊到清晰,所以UNITY_SPECCUBE_LOD_STEPS定义为6。
粗糙度是光滑度的相反,
粗糙度和mipmap不是线性的关系,所以要转化一下
m=1.7r−0.7r2
上面的采样操作可以由Unity的Unity_GlossyEnvironment()方法统一处理
float3 reflectDir=reflect(-viewDir,i.normal); Unity_GlossyEnvironmentData envData; envData.roughness = 1 - _Smoothness; envData.reflUVW = reflectDir; indirectLight.specular=Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData);
反射探针可以开启BoxProjection,这样就可以根据物体的位置来采样,如果没开启,就像前面那样,那么无论物体在方框内的哪个位置,同一个角度采样得到的数据都是一样的。
所以重新计算采样方向,把这个过程独立写在一个函数里
- float3 BoxProjection (float3 direction, float3 position,float4 cubemapPosition, float3 boxMin, float3 boxMax)
- {
- //boxMin加BoxMax可以用于表示一个立方体的范围
-
- //1、将立方体坐标相对物体位置。note:物体坐标变为(0,0,0),但不一定是立方体中心,仍是之前的相对关系,不要搞混
- boxMin -= position;
- boxMax -= position;
- //2、我们要找到一个倍数k,可以让单位反射向量*k=刚好到边界的向量(SD)
- //我们要找最近的面,一共有6个面,direction.x正负判断可以减去3面,也就是在xyz三个方向的面里找最近的面
-
- float x = (direction.x > 0 ? boxMax.x : boxMin.x) / direction.x;
- float y = (direction.y > 0 ? boxMax.y : boxMin.y) / direction.y;
- float z = (direction.z > 0 ? boxMax.z : boxMin.z) / direction.z;
- float scalar = min(min(x, y), z);
-
- //上述的合并操作
- //float3 factors = ((direction > 0 ? boxMax : boxMin) - position) / direction;
- //float scalar = min(min(factors.x, factors.y), factors.z);
-
- //CD=SD+CS
- return direction * scalar + (position - cubemapPosition);
- }
envData.reflUVW = BoxProjection(reflectDir, i.worldPos,unity_SpecCube0_ProbePosition,unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
下图是2D的情况,我们可以通过相似三角形得到Scale,x是scale较小的一方,用它的缩放值可以得到想要的OB,而y的scale较大,如果用它缩放,得到的就是错误的OC ,三维同理。
用cubemapPosition.w 判断是否要使用box projection,>0就是开启
- #if UNITY_SPECCUBE_BOX_PROJECTION //判断平台能不能用box projection
- if(cubemapPosition.w>0){判断是否开启box projection
- float3 factors = ((direction > 0 ? boxMax : boxMin) - position) / direction;
- float scalar = min(min(factors.x, factors.y), factors.z);
- direction=direction * scalar + (position - cubemapPosition);
- }
- #endif
- return direction;
BoxProjection启用后,移动物体可以发现反射变化(不仅仅是视角变化带来的变化的变化)
左关闭右开启
混合开关不在反射探针组件上,而是在每个物体的MeshRenderer上
off 关闭反射探针
simple 不混合
blend probes 混合
blend probes and skybox 能和天空盒混合
混合就需要采样多次,shader中unity_SpecCube1_xxx表示第二个立方体贴图的相关信息,但是采样器只有一个,所以要把unity_SpecCube1绑定到unity_SpecCube0的采样器上。
- float3 reflectDir=reflect(-viewDir,i.normal);
- //第一份贴图采样
- envData.reflUVW = BoxProjection(reflectDir, i.worldPos,unity_SpecCube0_ProbePosition,unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
- float3 probe0=Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData);
-
- #if UNITY_SPECCUBE_BLENDING //判断是否开启混合
- if (interpolator < 0.99999){//虽然开启了混合,但如果目前只受一个探针影响,就不需要计算了
-
- //第二份贴图采样 用UNITY_PASS_TEXCUBE_SAMPLER来绑定unity_SpecCube0的采样器采样 unity_SpecCube1
- envData.reflUVW = BoxProjection(reflectDir, i.worldPos,unity_SpecCube1_ProbePosition,unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
- float3 probe1=Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1,unity_SpecCube0), unity_SpecCube1_HDR, envData);
-
- //混合 unity_SpecCube0_BoxMin.w保存了两个贴图的混合权重
- indirectLight.specular=lerp(probe0,probe1,unity_SpecCube0_BoxMin.w);
- }
- #else
- indirectLight.specular=probe0;
- #endif
多次反射
反射探针可以烘焙多次,出现镜中镜的类似效果,最多反弹5次
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。