环境的反射算在间接光的镜面反射中
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)存储了转化的信息
右键创建资源->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不是线性的关系,所以要转化一下
上面的采样操作可以由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次
https://catlikecoding.com/unity/tutorials/rendering/part-8/
http://gad.qq.com/program/translateview/7173985