当前位置:   article > 正文

UnityShader-环境反射_unity_speccube0_hdr

unity_speccube0_hdr

 

环境的反射算在间接光的镜面反射中

  1. UnityIndirect CreateIndirectLight(v2f i,float3 viewDir){
  2. ...
  3. #if defined(FORWARD_BASE_PASS)
  4. ...
  5. //得到反射方向
  6. float3 reflectDir=reflect(-viewDir,i.normal);
  7. //得到环境采样
  8. float4 envSample = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, reflectDir);
  9. //天空盒可能是HDR的,要转回普通的颜色
  10. indirectLight.specular=DecodeHDR(envSample, unity_SpecCube0_HDR);;
  11. #endif
  12. ...
  13. }

unity_SpecCube0保存了环境的立体贴图(天空盒和后面的反射探针形成的立体贴图,都算在这里)

UNITY_SAMPLE_TEXCUBE 用于采样立体贴图

DecodeHDR将高动态贴图转为正常RGB,如果导入的不是HDR贴图,就没有变化,我这里默认的天空盒不是HDR的,所以加不加都一样 unity_SpecCube0_HDR.xy和颜色的alpha通道(M)存储了转化的信息

finalcolor=xMyhdrcolor

反射探针 

右键创建资源->Light->Reflection Probe

黄框就是渲染的立方体贴图的范围,一共三个模式,一般用Bake模式,它只会烘焙静态物体,就是下面这个选项是静态的

 物体进入黄框范围,他的unity_SpecCube0就有这个反射探针的立体贴图了,

但此时环境反射还不收Smoothness的影响,所以要换一下采样贴图的方法,让他根据粗糙度读取不同层级的mipmap

  1. float roughness = 1 - _Smoothness;
  2. roughness *= 1.7 - 0.7 * roughness;
  3. 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.7r0.7r2

上面的采样操作可以由Unity的Unity_GlossyEnvironment()方法统一处理

  1. float3 reflectDir=reflect(-viewDir,i.normal);
  2. Unity_GlossyEnvironmentData envData;
  3. envData.roughness = 1 - _Smoothness;
  4. envData.reflUVW = reflectDir;
  5. indirectLight.specular=Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData);

Box Projection

反射探针可以开启BoxProjection,这样就可以根据物体的位置来采样,如果没开启,就像前面那样,那么无论物体在方框内的哪个位置,同一个角度采样得到的数据都是一样的。

所以重新计算采样方向,把这个过程独立写在一个函数里

  1. float3 BoxProjection (float3 direction, float3 position,float4 cubemapPosition, float3 boxMin, float3 boxMax)
  2. {
  3. //boxMin加BoxMax可以用于表示一个立方体的范围
  4. //1、将立方体坐标相对物体位置。note:物体坐标变为(0,0,0),但不一定是立方体中心,仍是之前的相对关系,不要搞混
  5. boxMin -= position;
  6. boxMax -= position;
  7. //2、我们要找到一个倍数k,可以让单位反射向量*k=刚好到边界的向量(SD
  8. //我们要找最近的面,一共有6个面,direction.x正负判断可以减去3面,也就是在xyz三个方向的面里找最近的面
  9. float x = (direction.x > 0 ? boxMax.x : boxMin.x) / direction.x;
  10. float y = (direction.y > 0 ? boxMax.y : boxMin.y) / direction.y;
  11. float z = (direction.z > 0 ? boxMax.z : boxMin.z) / direction.z;
  12. float scalar = min(min(x, y), z);
  13. //上述的合并操作
  14. //float3 factors = ((direction > 0 ? boxMax : boxMin) - position) / direction;
  15. //float scalar = min(min(factors.x, factors.y), factors.z);
  16. //CD=SD+CS
  17. return direction * scalar + (position - cubemapPosition);
  18. }
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就是开启

  1. #if UNITY_SPECCUBE_BOX_PROJECTION //判断平台能不能用box projection
  2. if(cubemapPosition.w>0){判断是否开启box projection
  3. float3 factors = ((direction > 0 ? boxMax : boxMin) - position) / direction;
  4. float scalar = min(min(factors.x, factors.y), factors.z);
  5. direction=direction * scalar + (position - cubemapPosition);
  6. }
  7. #endif
  8. return direction;

 BoxProjection启用后,移动物体可以发现反射变化(不仅仅是视角变化带来的变化的变化)

左关闭右开启

混合反射探针 

混合开关不在反射探针组件上,而是在每个物体的MeshRenderer上

off 关闭反射探针

simple 不混合

blend probes 混合

blend probes and skybox 能和天空盒混合

混合就需要采样多次,shader中unity_SpecCube1_xxx表示第二个立方体贴图的相关信息,但是采样器只有一个,所以要把unity_SpecCube1绑定到unity_SpecCube0的采样器上。

  1. float3 reflectDir=reflect(-viewDir,i.normal);
  2. //第一份贴图采样
  3. envData.reflUVW = BoxProjection(reflectDir, i.worldPos,unity_SpecCube0_ProbePosition,unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
  4. float3 probe0=Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, envData);
  5. #if UNITY_SPECCUBE_BLENDING //判断是否开启混合
  6. if (interpolator < 0.99999){//虽然开启了混合,但如果目前只受一个探针影响,就不需要计算了
  7. //第二份贴图采样 用UNITY_PASS_TEXCUBE_SAMPLER来绑定unity_SpecCube0的采样器采样 unity_SpecCube1
  8. envData.reflUVW = BoxProjection(reflectDir, i.worldPos,unity_SpecCube1_ProbePosition,unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
  9. float3 probe1=Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1,unity_SpecCube0), unity_SpecCube1_HDR, envData);
  10. //混合 unity_SpecCube0_BoxMin.w保存了两个贴图的混合权重
  11. indirectLight.specular=lerp(probe0,probe1,unity_SpecCube0_BoxMin.w);
  12. }
  13. #else
  14. indirectLight.specular=probe0
  15. #endif

多次反射

反射探针可以烘焙多次,出现镜中镜的类似效果,最多反弹5次


https://catlikecoding.com/unity/tutorials/rendering/part-8/

http://gad.qq.com/program/translateview/7173985

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/92956
推荐阅读
相关标签
  

闽ICP备14008679号