学习笔记19

接上文Rendering 8

关于金属和非金属的区别,他们都可以有镜面高光,而金属的镜面高光部分是一个dominate主宰的,而非金属则不是这样,他们还有diffuse。这一点主要体现在,他们整个球还是有兰伯特那种面对光的亮,背对光的暗,而金属则完全没有这一现象,整体亮度比较均匀。

关于颜色的,主要就是金属的高光会有颜色,不论是直接的还是间接的。

首先考虑投影的本质是什么,是把光给你挡住了,让你接收到的光更少了,所以你整体表现出来的亮度相较于不在阴影中的部分更暗。

而这里高光,还是环境高光,这时候只受到环境光多少的影响。

如上,一个metallic球被一个柱子给挡住了,虽说是挡住了,但是我们的环境光来自各个方向,所以他只能挡住一部分,而我们这里考虑的是高光,也就是完整的镜面反射光,也就是说每一个点我们看到他的高光,他的入射光必须是指定方向的,如果说这个指定方向的光被挡住了,那么这个点的高光那确实会暗,否则就完全不受到影响。

而这里确实变暗了,变暗的部分就是金属球中映射出来的柱子,柱子部分是偏黑的,本该映射的是天空,但是天空的光被挡住了,所以就看柱子背面给到该点什么光,那么镜面反射我们就看到什么光。这里自然就受到柱子本身的颜色(决定它反光如何)和它的受光情况影响了。

所以说这里是一个物理正确的结果。

考虑杂质。

这就是一些探针的探讨,当位置不在中间时,我们需要单独搞一个以获得更真实的效果。

但是其实单独搞一个也不对,我们实际想要获得的是,每一个fragment周围的环境光情况,但是如果我们一个物体一个探针,我们所有的fragment都共用这一个,就会默认每一个fragment都是在中心探针的位置,所以这个记录的 也并不完全准,但是这个误差已经不用考虑了,效果已经相当不错了。

当我们把球换成flat面之后,效果是上边这样的。其实这个和实际偏差还是蛮大的。

关于以上形成的原因,其实和之前球的分析是类似的,我们只需要分析,按照实际情况,我们看某一个点,他的反射光路应该是如何的。而这里实际采样的时候又是如何的就行了。

比如为什么它变粗了,就拿:

这里本不该反射柱子的部分来说,现在我们的视线大致是正对着它的,所以我们计算他的反射的时候,会认为他在中心,然后采样cube之后就是显示柱子。而只有那些本来视角是比较偏向两侧的反射点

比如说这里的边界点,我们视线连接过去,入射的光线,应该从右上过来,而把这个点放在中心进行采样的时候,去采样的是右上方,所以采样不到柱子了。

而那些偏角比较小的,本不该反射到柱子,但是把他放在中心位置时,就会采样到柱子,所以有更多的区域采样到了柱子,所以看着柱子就变粗了。

还有柱子当前视角下变短了,

这个视角下变长了,都是这么分析。

当然这里放的探针的位置也会有一些影响,是否是正对着柱子的。

当视角偏移之后,出现更大的问题,其实都是同样的思路分析。

其实这里面的近似想要有一个很好的效果,其实有两个情况:要么是被反射的物体足够的远,这样把fragment认为是在中心采样的就不会有太大的误差。

要么就是这个球或者面足够的小,然后放在中心的时候,就算有那样一个不在中心却认为是中心的情况,由于距离小,偏差也不会大。

这也是球为什么效果比面好的原因。它小。

总之这一切的原因就是采样时,把我们实际的采样光线,平移到了中心再进行采样,从而带来了一些误差。

我们需要通过下方的蓝色线,推测出绿色,而不是拿蓝色用。

也就是这里所说的。

总的来说就是求交点。

但是这个外面的黑框是我们理想的,并不具有实际大小,但是他的实际大小是多少都可以。

修改probe box的offset,会让整个盒子发生偏移,注意他在采样的时候,永远是以球所在的位置来对环境采样,而盒子偏移的作用就是盒子内的物体变了,盒子作用就是让盒子内的物体使用这个probe。

(119条消息) Unity Shader-反射效果(CubeMap,Reflection Probe,Planar Reflection,Screen Space Reflection)_puppet_master的博客-CSDN博客_unity 地面反射

博客里面有很多值得参考的东西。游戏效果的复刻。

(119条消息) Unity Shader!!!_puppet_master的博客-CSDN博客

当我们对反射方向做了上边所叙述的纠正之后,其实会有一个要求,就是为什么要让探针的box和我们场景的边界保持一致,(为了保证这个的一致,有时候我们的probe需要放再场景正中心,而box对齐之后的中心可能不是场景的中心,这时候就需要之前不理解的offset选项。)

回到这个图中来,首先下面的蓝色光线是正确的反射光线这个没有疑问,但是疑问的是:蓝色光线和我们的cubemap box的交点处的图像,真的是实际反射看到的图像吗?

这个可不一定了。

如果说空间中存在这么一个紫色的小球,那么cubemap中交点处存储的就是该小球的图像,但是这从下面反射的路径来看,这完全不应该是通过这个视角看到的东西。

还有:

如果说这么来,假设紫色小球和中心点之间没有什么东西,那么交点处的图像记录的又是小球的图像,但是我们延长下面的蓝色方向线,看到的也不会是这个紫色球,这种情况也不对。

那么什么时候才是正确的,就是当紫色球放在盒子边界的地方,这样cubemap存储的才是蓝色反射方向上实际看到的东西。

这样也就要求,整个盒子和映射的边界是重合的,且边界内部是不能有东西的。

对于

这个选项。区别在于框外部的东西。

如果说我们的镜面是一部分在探针区域内部,一部分在探针外部。按照上边我们的算法,我们是把cubemap采样到的所有东西,都认为他们本身就放置在探针范围边缘的,这个对于天空盒其实效果并没有太大的影响。

如果不开启这个box projection选项,那么就是按照流程走一遍,我们可以得到如下结论:

这部分超出范围的,他们计算的fragment是在外面,而且计算的最小时间是负数,所以他们采样的cubemap是整个盒子的下半部分,这里就是反射到的地面的东西而,而不是天空,所以这里效果就明显错误了。

而如果勾选上,

上边是没有超出范围的,仔细观察和下面超出范围后的区别:

这里产生了拉伸,并且仔细观察右边边界可以看出右边是放大了一些的。

所以结论就是勾选上,超出范围以后,他会把cubemap对应的那一面进行放大,其实这也是这个选项的作用,就是确保超出探针范围的部分依旧反射cubemap正确的位置的信息。也就是超出的范围仍然反射的是cubemap上半部分存储的信息,不会说像折射一样往下射了。(但是由于位置出了边界,而cubemap存储都认为是边界上的信息,所以边界外反射边界上的物体,效果也有些奇怪,最后结果也不一定正确,有可能是你物体本身是在边界外,他认为是边界上了,而我们反射又把他反射到边界外,这样可能正确。但是这种情况应该不会去涉及,谁闲的把镜子放在框外面。)

Unity 反射从入门到跑偏(BoxProjection 到 Fake Interior) - 知乎 (zhihu.com)

这里只要mirror是在探针范围内,效果就一定会正确,而如果想要上边这种对称衔接的状态,那就要仔细调节大小了,因为柱子是要在边界上的,而mirror又要挨着柱子。

这里调节有一个点:就是我们让柱子处在边界上,柱子是有厚度的,应该怎么处在边界上,才能获得一个几乎完美的效果?

这个其实就想,我们认为它是在边界上,如果它实际就是在边界上,那么效果必然就是完全正确的。

其实就是:认为它在边界上,是认为我们在中心点看到的面在边界上。那么放置的时候,去保证看过去的面在边界上即可。

这个就是完美答案。

当然这里地面不要出现在镜子里,这一点可以通过调节高度来实现。

这时候换成球的反射,效果也是不错的,也成功的让不同位置的球有不一样的反射。

其实这里说明了外面的box projection的作用,也就是这个选项是否勾选,本该对应这里,如果勾选了那么w分量就大于0,否则就小于0.

所以这个作用就是:是否修正的。(他本来的作用是让我们使用宏,然后宏里面有这个条件判断。但是这个作用绝对不只这么一个判断,根据之前我们的对比,还有相关的区别。)

另外这里的if判断,在shader里面if分支会被优化掉,只剩下一个赋值的判断:

但是如果我们想要保留这个分支,就告诉编译器一下即可。

想要让我们刚刚的框外部也有一个较好的反射效果,这里尝试了两种都不完美:

一种是直接把范围拉大,但是由于采样的中心由于在框内部,所以外面的球,他们表面的反射效果也还是内部的东西,效果就错了:

另外一种操作方式就是:多添加一个探针,但是这个会导致过渡上有问题,过渡是一个突变。

然后就开始插值:

但是上边的写法是错误的,这里第二个贴图采样的时候需要依赖第一个的一些东西。

之前这个变黑了的bug,其实仔细思考,这个黑球我们是见过的,就是在金属度和光滑度拉到了1,然后就成了这样。其实这里加上天空球也还是黑的,说明天空球没起到作用,也就是这里的环境光反射的强度系数写成了0的原因.

这里还有问题,就是我们有两个探针,把上边的intensity multiplier改的比较小的时候,比如一半 ,我们移动处在他们中间的一个球,当这个球移动到他俩overlap的地方的时候,亮度是突然变亮的了。这个问题也不知道为啥,可以通过把上边的intensity multiplier改的大一些,比如0.9多,1就好了。

更奇怪的是,当我们把intensity multiplier调成0 的时候,本来应该所有的东西都变黑了,但是处于交界地的居然还是亮的。服了。。。。

相关的blend设置。

混合完成之后,这里考虑到采样需要很多工作,而有时候根本不需要对第二张cubemap进行采样,所以在采样之间进行一个判断。别做无用功。

这里在对一些平台进行优化,有的平台没办法混合。

想要实现一个无限反射的效果,这里需要把地面的镜子改成静态的。

More Reflection

————————————————————————————————————————————————————————————————————————————————————

RENDERING 9

想要创建自定义的GUI,需要使用C#操作,大致的操作流程:

确保我们的类是继承于ShaderGUI的。

他是一个新版的GUI类。

当我们C#这边定制好了之后,拽到材质上,要想发挥作用还得shader声明一下:

这一句是在文末加上。

声明之后,剩下的就是重写函数,这个函数就决定了材质面板上是如何show 的。

这里要模仿标准的着色写法。

然后针对单个属性,首先要get到这个属性,让显示的东西和属性值挂钩。

然后针对文字或者tool tip这种,都是创建GUIContent。

针对颜色tint,这个和属性挂钩的,需要结合属性来创建

这个scale 和offset的比较特殊一些,不用单独搞一个变量出来,直接函数创建即可。

其实这里定义了三个东西在一行中,从函数接口上来看,这三个是毫无关联性的。

我们在面板中显示的大致就两类东西,一类是属性,一类是补充文字。

其实这里的格式是可以不写补充文字的。也就是说补充文字和属性之间没有任何关系。这里属性创建需要属性对象,然后unity会根据类型来创建相应的GUI。然后你通过在它旁边加一些文字作为补充。

对于offset那个特殊一些,算是属性,却又是依附于其他属性的属性,所以这里就有点特殊。

关于标签,这里也可以进行一个封装化简。只需要把属性传进去,这样内部根据属性自动获取display name,然后传进去tool tip就好了。

这里normal添加图片,label,bump scale这都是基本操作,属性和label现在都是调用函数,然后搞到一行就行了。

这里有一个需要说的是:standard的bump scale只有当normal map被正确赋值之后,才会显示出来bump scale,所以这里可以加一个判断。

这里有俩点:一个是这个在通过函数得到属性和label之后,添加到editor上的时候,它使用的函数变了。

其次是之前说label说明和属性是完全独立的,这个也不完全,这里的参数确实让指定label,但是像tint那个就不需要指定。

可能一行指定一个label吧??

然后这里通过求改indent level实现一个对齐的效果。

至此,第一套map就完成了,下面是第二套,玩法都是一样的。

这个是整体的代码结构,然后Domain和DoSecondary里面自己

这里其实就是考虑一个关于金属度的问题,因为我们的metallic属性是直接应用于整个模型的,也就是说整个模型表面所有的金属度都是一样的,这就有些影响材质的发挥了。

因此metallic map就出现了,针对每一个texel,设置特定的金属度。

这里这种noScaleOffset已经没用了,因为整个是给默认的ShaderGUI看的,而我们现在使用了自己定义的GUI。

这里添加金属度的贴图之后,我们金属度的计算方式就要改动一下,所以这里封装一个函数。

同时调整一下GUI。

这个是整体的代码结构,然后Domain和DoSecondary里面自己

这里其实就是考虑一个关于金属度的问题,因为我们的metallic属性是直接应用于整个模型的,也就是说整个模型表面所有的金属度都是一样的,这就有些影响材质的发挥了。

因此metallic map就出现了,针对每一个texel,设置特定的金属度。

这里这种noScaleOffset已经没用了,因为整个是给默认的ShaderGUI看的,而我们现在使用了自己定义的GUI。

这里添加金属度的贴图之后,我们金属度的计算方式就要改动一下,所以这里封装一个函数。

同时调整一下GUI。

这里GUI还有一个细节,这个正好和之前处理的bump scale相反,这里有了贴图就不需要数值了,没有贴图就使用数值。

猜你喜欢

转载自blog.csdn.net/yinianbaifaI/article/details/127607895