HMAC会导致性能的南桥过热会降低性能么

硬质石料、优质沥青有助于提高浸水条件下沥青混合料抗车辙性能。
In addition, the high-quality bitumen and hard aggregate can improve the rutting performance of the mixture in water-submerged conditions.
结果表明,多聚磷酸的加入能够提高沥青的黏度,改善沥青的高温抗车辙性能;
The results showed that the high-temperature furrow resistance and viscosity of asphalt were improved significantly with the addition of PPA.
它不但具有良好的抗车辙性能及耐久性,而且雨天抗滑性能较好,可降低车辆行驶的噪声等。
It has the advantage such as anti-rutting performance and durability and skid resistance during rainy days and reducing the traffic noise of vehicles.
使用少量交联剂可提高沥青的高温抗车辙性能,降低其黏度。
The use of a little crosslinker could improver high-temperature furrow resistance of asphalt and reduced its viscosity.
因此,选用合适的改性沥青、硬质石料和合理级配有助于提高中面层沥青混合料抗车辙性能。
The selection of modified asphalt, hard aggregate and a reasonable gradation are essential to the improvement of the rutting resistance of the mixtures used in the middle course.
高模量沥青混凝土(HMAC)具有优良的抗车辙性能,为解决车辙问题提供了一种新的途径。
Asphalt Concrete(HMAC) has the excellent antirutting performance, it provide a new way to solve the rutting problem.
室内车辙试验用压实度为100%的沥青混合料来评价实际沥青路面的高温稳定性,确实高估了沥青混合料的高温抗车辙性能。
The high-temperature stability of actual asphalt pavement is overrated by dynamic stability of the asphalt mixture under 100% compaction degree in laboratory.
此法设计出的沥青混合料较马歇尔法设计出的沥青混合料具有更好的高温抗车辙性能。
This method of the asphalt mixture design have better performance to resist high temperature rutting than the Marshall method.
试验结果表明,车辙板的试验条件对沥青混合料的高温抗车辙性能有很大的影响。
The results show that the test conditions have significant effect on HMA high temperature performance.
表明通过采用现场钻取的芯样试件做车辙试验来检测沥青面层的抗车辙性能的想法是可行的。
Resulted that use drilling core sample in the rutting test, can be used to detect the site asphalt pavement anti-rutting performance.
对改性沥青混合料进行高温车辙、低温弯曲、冻融劈裂和疲劳试验,表明其各项性能尤其是高温抗车辙性能均得到了较大的提高。
Through the high-temp running tests, low-temp bending tests, frost thawing split tests and fatigue tests, it indicates that the performance of …
抗车辙性能好,最终可降低保养成本。
So UINTAITE can reduce the maintaining cost in highway engineering.
结果表明:CA比对沥青混合料的空隙率、矿料间隙率、粗集料骨架的形成、抗车辙性能和压实性能具有显著影响;
The results show that CA ratio has a significant effect on percent air voids, VMA, formation of the coarse aggregate skeleton, rutting resistance and densification characteristics of asphalt mixture;
研究了扁平细长颗粒含量对不同级配类型沥青混合料抗车辙性能的影响,初步给出其界限值。
The influences of content of flat, long and thin particles on rutting resistance of hot mixed asphalt composed of different type gradation are studied, and their limit values are given elementarily.
结果表明,由GTM设计出的沥青混合料抗车辙及水稳性能较之大马歇尔设计方法有明显的提高。
As a result, the resisting rut performance and moisture susceptibility of asphalt admixture which is designed by GTM contain obvious exaltation than that is designed by marshall.
这种方法是基于沥青混合料路用性能的体积配比设计计算方法,经室内路用性能试验验证,用本方法设计的沥青混合料具有优良的抗滑性能、防水性能、抗车辙能力。
This method is one of the void design procedures based on the road performance. The test results show that the bituminous mixture designed by this method has a good road performance.
试验证明,粉煤灰能提高沥青混合料的抗车辙能力及其它路用性能。
The experiment proved that the flyash can improve the asphalt mixture"s ability of anti-rutting and other road performance."
通过对应力吸收层沥青混合料低温抗裂、高温车辙、水稳定性能及抗疲劳性能的试验研究,表明其具有良好的路用性能。
The good service performance of stress absorption interlayer, including cracking in low temperature, rutting in high temperature, stability in water and fatigue resistance, was tested.
经室内路用性能试验验证,用本方法设计的沥青混合料具有优良的抗滑、防渗、抗车辙以及耐低温和疲劳的性能。
Through evaluating the pavement performance of asphalt mixture in laboratory, the asphalt mixture designed by the method has a super pavement performance.
丁苯橡胶的加入提高了沥青的黏度和低温抗裂性能,但对沥青的高温抗车辙能力有一定的负面影响;
Although the use of SBR could improve low-temperature cracking resistance and viscosity of asphalt, it could cause negative effects on high-temperature performance.
采用车辙深度、横向裂缝长度和路面抗滑性能指数三指标,使用动态聚类法,划分预防性养护路段。
The preventive maintenance sections are divided by using dynamic cluster method and three indexes including rutting depth, transverse crack length and skidding resistance.
沥青混合料是沥青路面的主要组成材料,沥青混合料高温性能的好坏直接关系着沥青路面的高温抗车辙能力。
Asphalt pavement is mainly composed of asphalt mixture, the high temperature performance of which is directly connected with the high temperature rutting resistance of asphalt pavement.
开发抗剪强度高、抗高低温性能好的粘接材料,是解决在沥青面层车辙、拥包、推移等病害的关键。
Develop the binding material which resist high shearing strength, low and high temperature is the key to solve the disease of asphalt overlay.
高模量沥青混合料的设计及试验研究表明,通过改进沥青胶浆性能的途径可实现混合料的高模量,从而增强路面的抗车辙能力。
Design and test research of high modulus asphalt mixture show that improving the performance of asphalt mortar can heighten the modulus of mixture to strengthen the rut-resistance of pavement.
高模量沥青混合料的设计及试验研究表明,通过改进沥青胶浆性能的途径可实现混合料的高模量,从而增强路面的抗车辙能力。
A new way of anti-rutting was put forward by improving modulus of asphalt concrete and the effect of high modulus asphalt concrete(HMAT) on rutting was studied in view of mechanics.
高模量沥青混合料的设计及试验研究表明,通过改进沥青胶浆性能的途径可实现混合料的高模量,从而增强路面的抗车辙能力。
A new way of anti-rutting was put forward by improving modulus of asphalt concrete and the effect of high modulus asphalt concrete(HMAT) on rutting was studied in view of mechanics.
$firstVoiceSent
- 来自原声例句
请问您想要如何调整此模块?
感谢您的反馈,我们会尽快进行适当修改!
请问您想要如何调整此模块?
感谢您的反馈,我们会尽快进行适当修改!&p&系统设计的通常有这样一个现象,那就是一开始设计的时候,一个系统分划分成多个模块,各个模块之间有划分清晰的接口,除了接口之外互相之间是没有耦合的,但随着设计的完善,各个模块划分的过于清晰往往造成性能瓶颈,所以慢慢某些模块就放在一起了。放在一起的原因有好多种,有的是因为逻辑上的原因,有的则是物理上的原因。&/p&&p&&br&&/p&&p&系统设计中也有另一种现象,那就是一开始设计的时候,一个模块要完成的功能越来越多,它变得越来越复杂,慢慢的它就被划分成了多个模块,每个模块各自完成一个子功能,互相之间通过清晰的接口交互。&/p&&p&&br&&/p&&p&一个系统如果长时间演进,上述两种现象有可能交替出现。&/p&&p&&br&&/p&&h2&8086的内存控制器&/h2&&p&这个小节的标题纯粹是在瞎说,8086没有内存控制器,它只有访存总线,包括控制总线、数据总线和地址总线。比如一个load指令(8086的一个从内存读数据到寄存器的mov指令),它会在控制总线上把读/写控制位置为读状态,然后在地址总线上放上要读数据所在的地址,然后接在这个访存总线上的存储器件,比如说一个SRAM,就会在数据总线上放上数据(8086的地址总线与数据总线是部分复用的)。&/p&&figure&&img src=&https://pic2.zhimg.com/v2-5cd4c82ef53d8ebafd06aa2d4d145c9c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&720& data-rawheight=&444& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&https://pic2.zhimg.com/v2-5cd4c82ef53d8ebafd06aa2d4d145c9c_r.jpg&&&/figure&&p&在8086上,CPU与一个简单得还没有名字的内存控制器是集成在一起的。&/p&&h2&北桥上的内存控制器&/h2&&p&后来CPU把一部分功能分出去,成立了北桥。&/p&&p&北桥与CPU通过高速总线互连,完成了部分不属于CPU,但又与常规外设不同的工作。北桥上的设备与常规外设的不同之外主要就是速度快。&/p&&p&一般北桥上两个必须要的功能一个是显示,另一个就是内存控制器。&/p&&p&在北桥上的内存控制器接收从高速总线上发来的访存指令,转换为DDR总线上的DDR指令,完成访存动作。&/p&&p&从高速总线上下来的访存指令通常简明扼要,基本上就是两个句话:把某地址上的数据给我读过来,和把这个数据写在某个地址上。也就是对应RISC的load/store指令。其实也不完全对应,因为load/store指令要操作的数据通常是1,2,4,8个字节,而高速总线上的mem_&i&read/mem&/i&_write事务通常操作的数据是一个Cache line或两个Cache line,字节为单位的也可以有(通过mask掉一个cache line上其他的bytes),但不多。&/p&&p&一个mem_&i&read, memwrite很简单,但转换成DDR指令就比较复杂了。要考虑多种不同的情况,比如说open page policy情况下,row hit就不用发activate命令,直接发column就可以了,比如说两个地址连续mem_read命令,中间插有其他命令的时候是不是要乱序指行一下,地址转换要不要做等。&/i&&/p&&p&这时候,内存控制器实际上是两个总线之间的一个桥。&/p&&p&内存控制器涉及的更多的是电气上的技术,比如说DQS信号的校正等,但也有一些比较容易懂的算法在里面,比如说页管理策略、reorder buffer的设计、如何减小刷新占用的时间等。&/p&&p&&br&&/p&&h2&iMC&/h2&&p&大家都知道现在北桥没有了,又回到CPU里面去了,所以这个内存控制器也回到CPU里面去了,成为一个集成的模块,叫做iMC,即integrated Memory Controller。&/p&&p&它的功能没有大的变化,只是上游的总线协议变来变去。&/p&&p&&br&&/p&&h2&------------------------&/h2&&p&&br&&/p&&p&一时想不起来这块还有什么可以写的了,大家可以提醒一下。&/p&&p&想到的FB DIMM,但是感觉写着没啥 意思,想了解的自己搜资料看看吧,比如说:&/p&&a href=&https://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Fully_Buffered_DIMM& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic4.zhimg.com/v2-baa976ff3f_180x120.jpg& data-image-width=&1200& data-image-height=&971& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Fully Buffered DIMM&/a&&p&OJBK,先发吧,后面有时间聊聊新式存储介质。&/p&
系统设计的通常有这样一个现象,那就是一开始设计的时候,一个系统分划分成多个模块,各个模块之间有划分清晰的接口,除了接口之外互相之间是没有耦合的,但随着设计的完善,各个模块划分的过于清晰往往造成性能瓶颈,所以慢慢某些模块就放在一起了。放在一…
&figure&&img src=&https://pic2.zhimg.com/v2-c48b06d25bab73fc92d3_b.jpg& data-rawwidth=&1042& data-rawheight=&351& class=&origin_image zh-lightbox-thumb& width=&1042& data-original=&https://pic2.zhimg.com/v2-c48b06d25bab73fc92d3_r.jpg&&&/figure&&p&也不知道怎么搞的,PBR(Physicallly-Based-Rendering 基于物理渲染)突然成了一个……你会了就好像什么都会,不会就好像什么都不会的标尺了……&/p&&p&嘛,其实PBR也和其他渲染技术类似,虽然是比GPUSkinMesh之类“单纯”的技术要复杂,但也未见得比完整的FFT Ocean实现复杂度更高。如果只是想实现以及应用的话,其实也没有那么的难。&/p&&p&而我也不太理解,为何PBR相关的中文资料会那么的少,因为它基本已经可以认为是现代写实渲染的基本了,是一个必须了解的知识点。如果做现代写实风格的游戏,你不懂PBR,确实可以认为什么都不会。但同样也因为它是如此的基础,即使你完全不会,依靠引擎自带的功能也不怎么会影响到工作(Unity自带的Standard就是一个完整的PBR实现)&/p&&p&然而PBR不同于其他渲染技术,其实并没有太多可自定义扩展的地方。如果你需要对官方提供的PBR做修改,也就是一些性能调优,因为PBR的目标就是一致性,并不需要针对不同需求的灵活处理。所以在坐的各位,除非自己编写引擎,其实并不太需要知道PBR的具体实现方法,只需要知道PBR材质参数代表的物理意义,和美术一样知道如何使用即可。不过做一些扩展了解也没啥坏处,了解原理,至少可以在性能耗费上心里有个底。&/p&&p&&br&&/p&&a href=&https://link.zhihu.com/?target=https%3A//learnopengl-cn.github.io/07%2520PBR/01%2520Theory/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic1.zhimg.com/v2-cc9f9be10b1b3de06a3c0_180x120.jpg& data-image-width=&609& data-image-height=&298& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&理论 - LearnOpenGL CN&/a&&a href=&https://link.zhihu.com/?target=https%3A//learnopengl-cn.github.io/07%2520PBR/02%2520Lighting/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic3.zhimg.com/v2-8f9682acfd7a2ce440b690cf4e6ba606_180x120.jpg& data-image-width=&486& data-image-height=&274& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&光照 - LearnOpenGL CN&/a&&p&上面是篇相对比较简短,而且术语和公式较少(比较像人话)的PBR的基础教程翻译。我下面所写的内容,更多是对这篇文章内难点的解释和补充,所以希望大家不管看不看的懂,起码要先过一遍,然后进行结合阅读。&/p&&p&&br&&/p&&h2&基础概念:微平面和辐射度&/h2&&p&这是两个对于PBR非常重要的概念,和光线追踪一同,构成了PBR的物理基础。&/p&&p&然而,其实你并不一定非要去了解它们。因为它们的出现基本上只是为了证明:PBR里的“数学公式”,是符合物理的。&/p&&p&所以如果你不在乎这个“证明”,选择直接相信的话,就只需要记忆几个由微平面推导出的“结论公式”,而辐射度,也可以简单地理解成颜色值。&/p&&p&至于光线追踪……我们一般使用的BRDF模型并不需要涉及到&i&(但之后包含折射的BSDF,包含次表面反射的BSSRDF就必须使用光追了,而光追暂时是难以在当代硬件上广泛运用的)&/i&。&/p&&p&不过,如果不知道这些细节,许多公式的细节你是无法理解的,因为你甚至连它们的单位都不知道。虽然我很想从细处去说这个,但恐怕会违背这篇文章的主旨。个人建议你们还是去原文了解一下。&/p&&p&在这里我只补充几个容易迷惑的点:&/p&&ul&&li&光源的单位是辐射强度I(每单位角),但在不随距离衰减的直线光中,它与辐射度等价。&/li&&li&屏幕的最终颜色值是辐射度L(每单位角单位面积),这也被称为辐射率,或者辐射亮度。辐射度等价于以往的“颜色”。&/li&&li&辐射度是最常用的物理量,其他物理量更多情况下是作为公式中的中间值,或者输入参数存在。&/li&&li&微平面是微观而非宏观的,所以并不会和任何外部的宏观物理量产生交互,但微平面会导致一些宏观的统计结果(诸如散射)。这就和我们并不会真的去研究电子如何绕着原子核旋转一样,以这种方式理解微平面会比较妥当。&/li&&/ul&&p&&br&&/p&&h2&反射率方程&/h2&&p&&img src=&https://www.zhihu.com/equation?tex=L_%7Bo%7D%28p%2Cw_%7Bo%7D%29%3D%5Cint_%7B%5COmega%7D%28k_%7Bd%7D%5Cfrac%7Bc%7D%7B%5Cpi%7D%2B+k_%7Bs%7D+%5Cfrac%7BDGF%7D%7B4%28w_%7Bo%7D%5Ccdot+n%29%28w_%7Bi%7D%5Ccdot+n%29%7D%29L_%7Bi%7D%28p%2Cw_%7Bi%7D%29%28w_%7Bi%7D%5Ccdot+n%29dw_%7Bi%7D& alt=&L_{o}(p,w_{o})=\int_{\Omega}(k_{d}\frac{c}{\pi}+ k_{s} \frac{DGF}{4(w_{o}\cdot n)(w_{i}\cdot n)})L_{i}(p,w_{i})(w_{i}\cdot n)dw_{i}& eeimg=&1&&&/p&&p&这是PBR的核心,也是主要的劝退点。&/p&&p&翻译成自然语言,大概是这样的:&/p&&p&&img src=&https://www.zhihu.com/equation?tex=%E8%BE%93%E5%87%BA%E9%A2%9C%E8%89%B2%3D%5Cint_%7B%5COmega%7D%28%E6%BC%AB%E5%8F%8D%E5%B0%84%E6%AF%94%E4%BE%8B%5Cfrac%7B%E7%BA%B9%E7%90%86%E9%A2%9C%E8%89%B2%7D%7B%5Cpi%7D%2B+%E9%95%9C%E9%9D%A2%E5%8F%8D%E5%B0%84%E6%AF%94%E4%BE%8B+%5Cfrac%7B%E9%95%9C%E9%9D%A2%E9%AB%98%E5%85%89%5Ctimes+%E5%87%A0%E4%BD%95%E9%81%AE%E8%94%BD%5Ctimes+%E8%8F%B2%E6%B6%85%E5%B0%94%E6%95%88%E5%BA%94%7D%7B4%28viewDir%5Ccdot+normal%29%28lightDir%5Ccdot+normal%29%7D%29%E5%85%89%E6%BA%90%E9%A2%9C%E8%89%B2%28lightDir+%5Ccdot+normal%29+dw_%7Bi%7D& alt=&输出颜色=\int_{\Omega}(漫反射比例\frac{纹理颜色}{\pi}+ 镜面反射比例 \frac{镜面高光\times 几何遮蔽\times 菲涅尔效应}{4(viewDir\cdot normal)(lightDir\cdot normal)})光源颜色(lightDir \cdot normal) dw_{i}& eeimg=&1&&&/p&&p&先解释下这个公式遗留的部分。半球积分( &img src=&https://www.zhihu.com/equation?tex=%5Cint_%7B%5COmega%7D+%E2%80%A6%E2%80%A6%E2%80%A6%E2%80%A6+dw_%7Bi%7D& alt=&\int_{\Omega} ………… dw_{i}& eeimg=&1&&
),表示的是多光源下光照的叠加。之所以非要写成半球积分而不是 ∑,是为了兼容环境光照。如果你只考虑单个不衰减的直线光照的话,这部分其实可以直接去掉(并不是说数学上可以直接化简,而是因为这是一个特例)&/p&&p&&img src=&https://www.zhihu.com/equation?tex=%E8%BE%93%E5%87%BA%E9%A2%9C%E8%89%B2%3D%28%E6%BC%AB%E5%8F%8D%E5%B0%84%E6%AF%94%E4%BE%8B%5Cfrac%7B%E7%BA%B9%E7%90%86%E9%A2%9C%E8%89%B2%7D%7B%5Cpi%7D%2B+%E9%95%9C%E9%9D%A2%E5%8F%8D%E5%B0%84%E6%AF%94%E4%BE%8B+%5Cfrac%7B%E9%95%9C%E9%9D%A2%E9%AB%98%E5%85%89%5Ctimes+%E5%87%A0%E4%BD%95%E9%81%AE%E8%94%BD%5Ctimes+%E8%8F%B2%E6%B6%85%E5%B0%94%E6%95%88%E5%BA%94%7D%7B4%28viewDir%5Ccdot+normal%29%28lightDir%5Ccdot+normal%29%7D%29%E5%85%89%E6%BA%90%E9%A2%9C%E8%89%B2%28lightDir+%5Ccdot+normal%29+& alt=&输出颜色=(漫反射比例\frac{纹理颜色}{\pi}+ 镜面反射比例 \frac{镜面高光\times 几何遮蔽\times 菲涅尔效应}{4(viewDir\cdot normal)(lightDir\cdot normal)})光源颜色(lightDir \cdot normal) & eeimg=&1&&&/p&&p&看到这个lightDir o normal大家都应该很熟悉,如果将镜面反射系数设定为0,漫反射系数设定为1,公式就和单纯的Lambert漫反射基本一致:&/p&&p&&img src=&https://www.zhihu.com/equation?tex=%E8%BE%93%E5%87%BA%E9%A2%9C%E8%89%B2%3D%28%5Cfrac%7B%E7%BA%B9%E7%90%86%E9%A2%9C%E8%89%B2%7D%7B%5Cpi%7D%29%E5%85%89%E6%BA%90%E9%A2%9C%E8%89%B2%28lightDir+%5Ccdot+normal%29+& alt=&输出颜色=(\frac{纹理颜色}{\pi})光源颜色(lightDir \cdot normal) & eeimg=&1&&&/p&&p&不一致的部分是这个除π。因为它把亮度除低了,就只能相应调高光源的亮度补回来。看似别扭,但是回头一想,光源的亮度,难道不就应该比周围的物品高上很多吗?因为即使是直射,也还是会有很多光线被散射到其他方向,只有少部分才正常投射到了人眼中,漫反射的性质就是如此,之前不除π的做法其实才是错误的。&/p&&p&(至于为什么除的是π,是因为 &img src=&https://www.zhihu.com/equation?tex=%5Cint_%7B2%CF%80%7Dcos%CE%B8_%7Bo%7Dd%CF%89_%7Bo%7D%3D%CF%80& alt=&\int_{2π}cosθ_{o}dω_{o}=π& eeimg=&1&& ,如果散射的光线最后都能汇集到一点的话,积分的结果就是会再乘一个π。所以分散的时候就需要除π。)&/p&&p&&br&&/p&&p&另外还有一个地方容易让人迷惑,按说经过半球积分汇集了不同方向的光线后,返回的结果应该是辐照度E(每单位面积),而这个反射率公式左边却是L(每单位角单位面积),这在单位上就说不过去。&/p&&p&实际上,是因为这个公式经过了化简,把一些中间参数给约掉了,剩下的部分形成了这样的结构。这篇文章有推导过程:&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/jerrycg/p/4932031.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&PBR Step by Step(三)BRDFs&/a&&/p&&p&从“非数学”的角度考虑的话,也可以认为是这个单位面积汇集的不同方向的光线最后都融合并反射了出去,我们从中重新取了一条光线作为结果。&/p&&hr&&p&镜面反射部分( &img src=&https://www.zhihu.com/equation?tex=%5Cfrac%7B%E9%95%9C%E9%9D%A2%E9%AB%98%E5%85%89%5Ctimes+%E5%87%A0%E4%BD%95%E9%81%AE%E8%94%BD%5Ctimes+%E8%8F%B2%E6%B6%85%E5%B0%94%E6%95%88%E5%BA%94%7D%7B4%28viewDir%5Ccdot+normal%29%28lightDir%5Ccdot+normal%29%7D& alt=&\frac{镜面高光\times 几何遮蔽\times 菲涅尔效应}{4(viewDir\cdot normal)(lightDir\cdot normal)}& eeimg=&1&& ),这部分是个叫做Cook-Torrance的BRDF光照公式,分子上的三个系数含义如下:&/p&&p&&br&&/p&&p&&b&镜面高光:正态分布函数 Normal Distribution Function&/b&&/p&&p&&b&(参数:normal,viewDir,lightDir,粗糙度)&/b&&/p&&p&这里和传统的BlinnPhong高光模型一样,是用半角向量h,也就是viewdir和lightdir的中间向量h,和normal求点乘来决定高光亮度的。&/p&&p&了解的朋友都知道,BlinnPhong其实相对于它的前身Phong,并不是那么的“物理”(视线越接近水平和光线反射的物理原理越不一致),所以我看到PBR依然在使用BlinnPhong是有点意外的。&/p&&p&也就说明,两个都不完全“物理”的公式,还是看上去和物理效果更接近的,比实际“更物理”的吃香。经验公式最终获得了胜利(括弧笑)。&/p&&figure&&img src=&https://pic2.zhimg.com/v2-421db1ff5fa3509bcfb10510_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&523& data-rawheight=&208& class=&origin_image zh-lightbox-thumb& width=&523& data-original=&https://pic2.zhimg.com/v2-421db1ff5fa3509bcfb10510_r.jpg&&&/figure&&p&而综合了散射系数的具体的公式如下:&/p&&p&&img src=&https://www.zhihu.com/equation?tex=D+%3D%5Cfrac%7B%CE%B1%5E%7B2%7D%7D%7B%CF%80%28%28n%E2%8B%85h%29%5E%7B2%7D%28%CE%B1%5E%7B2%7D%E2%88%921%29%2B1%29%5E%7B2%7D%7D& alt=&D =\frac{α^{2}}{π((n?h)^{2}(α^{2}-1)+1)^{2}}& eeimg=&1&&&/p&&p&这个公式也是前人的劳动成果,我也不知道是物理推导的结果还是“看上去对就好”的经验公式。但在不同的粗糙度α取值下,它确实和BlinnPhong通过pow实现的效果方向一致,拥有类似的结果。但它的取值是0-1,效果变化也很平滑,比起Skininess那种没谱的参数更容易控制。&/p&&p&当然更重要的是不会辐射出多余的光,D不会大于1/π(除π的原因和上面漫反射部分一致)&/p&&p&当α非常接近0的时候,光照集中在一点,其他方向会完全看不到光线。这是符合现实的。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-9a491ddc22fdc810dfeca06_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&800& data-rawheight=&163& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic4.zhimg.com/v2-9a491ddc22fdc810dfeca06_r.jpg&&&/figure&&p&&b&几何遮蔽:几何函数 Geometry function&/b&&/p&&p&&b&(参数:normal,viewDir,lightDir,粗糙度)&/b&&/p&&p&这是一个其他传统光照模型不具有的特征,体现了光在物体粗糙面上反射时的损耗。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-97c81fc7cdeff19cb0f41df63ffb7202_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&574& data-rawheight=&181& class=&origin_image zh-lightbox-thumb& width=&574& data-original=&https://pic4.zhimg.com/v2-97c81fc7cdeff19cb0f41df63ffb7202_r.jpg&&&/figure&&figure&&img src=&https://pic1.zhimg.com/v2-b81716faccaffce748b77fd_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&800& data-rawheight=&163& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic1.zhimg.com/v2-b81716faccaffce748b77fd_r.jpg&&&/figure&&p&&img src=&https://www.zhihu.com/equation?tex=G+%3D%5Cfrac%7Bn%E2%8B%85l%7D%7Blerp%28n%E2%8B%85l%2C1%2Ck%29%7D%5Ctimes%5Cfrac%7Bn%E2%8B%85v%7D%7Blerp%28n%E2%8B%85v%2C1%2Ck%29%7D& alt=&G =\frac{n?l}{lerp(n?l,1,k)}\times\frac{n?v}{lerp(n?v,1,k)}& eeimg=&1&&&/p&&p&直接光照时: &img src=&https://www.zhihu.com/equation?tex=k+%3D+%5Cfrac%7B%28%CE%B1%2B1%29%5E%7B2%7D%7D%7B8%7D& alt=&k = \frac{(α+1)^{2}}{8}& eeimg=&1&& ,间接光照(IBL)时: &img src=&https://www.zhihu.com/equation?tex=k+%3D+%5Cfrac%7B%CE%B1%5E%7B2%7D%7D%7B2%7D& alt=&k = \frac{α^{2}}{2}& eeimg=&1&&&/p&&p&效果就是粗糙度越大,亮度越低。但视线和光线越接近垂直,受粗糙度的影响就越小,合情合理。&/p&&p&k的取值范围都在逐渐逼近1/2。而直接光和间接光的差别是,直接光至少有1/8的吸收系数保底,而间接光没有。这是为了让完全光滑的物体,也能至少吸收一些光线。完全不吸收光线的物体是不应该存在的。&/p&&p&&br&&/p&&p&&b&菲涅尔方程:Fresnel equation&/b&&/p&&p&&b&(参数:normal,viewDir,金属度)&/b&&/p&&p&菲涅尔方程以前一般是用在水体上的,因为水体粗糙度低反光能力强,却又不是金属,是菲涅尔效应最明显的现实物体。&/p&&p&&img src=&https://www.zhihu.com/equation?tex=F+%3D+lerp%28%281%E2%88%92%28n%E2%8B%85v%29%29%5E%7B5%7D%2C1%2CF_%7B0%7D%29& alt=&F = lerp((1-(n?v))^{5},1,F_{0})& eeimg=&1&&&/p&&p&注意:这个公式和光照方向无关。&/p&&p&法线和视线夹角越大(视线越接近水平),F的值也就越大,反射光的亮度也越高,这就是所有物体都具有的菲涅尔效应。即使不是金属物体,在这种情况下都会产生和金属物体类似的表现。而当物体本身就是金属的时候(F0接近1),不管视线是什么情况,F的值都会接近于1,那么菲涅尔效应也就看不出来了。&/p&&p&这看似是个无关紧要的特性——那只是我们大多没有意识到“物体应该如此”而已,但即使我们没注意到,我们的大脑却会依然会得出一个“不真实”的结论。其实菲涅尔效应的模拟比我们想象中要更重要,并不仅仅是在水体模拟这个情景下。&/p&&p&然而,对于金属物体而言,菲涅尔其实并不完全适用。他的F0参数对不同颜色值的反射率是不同的,而且还需要和表面颜色相乘,否则我们的大脑就会通知我们它“不像金属”,所以最终的做法是做这样一次处理:&/p&&p&F0 = mix(vec3(0.04), 表面颜色, 金属度);&/p&&p&这样代入公式的结果就比较符合金属的物理特征,而非金属由于F0值偏低,即使乘了表面颜色影响也不大。&/p&&p&注意这里的表面颜色仅仅是给金属物体用的,用于表现金属物体的特殊性质,高光部分本身并不需要和物体的表面颜色相乘。&/p&&p&&br&&/p&&p&&b&BRDF方程的配平系数:&/b&&/p&&p&&img src=&https://www.zhihu.com/equation?tex=%5Cfrac%7B%E2%80%A6%E2%80%A6%E2%80%A6%E2%80%A6%E2%80%A6%E2%80%A6%E2%80%A6%E2%80%A6%7D%7B4%28viewDir%5Ccdot+normal%29%28lightDir%5Ccdot+normal%29%7D& alt=&\frac{……………………}{4(viewDir\cdot normal)(lightDir\cdot normal)}& eeimg=&1&&&/p&&p&至于这个公式剩下的分母部分,在哪里都没有看到它们的解释,而且也想不出“除点乘”对应着何种物理特性,“4”这个迷之系数更是难以理解。大家都是把它当做一个配平系数直接用了,最后我也只知道这两个点乘是和微平面有关的。&/p&&p&我倒是觉得它们应该不是什么“经验公式”,应该有推导的方法,但这个问题我确实也没找到懂的人,所以这次也只能先放在一边了。&/p&&p&&br&&/p&&p&&b&最后看回这个公式:&/b&&/p&&p&&img src=&https://www.zhihu.com/equation?tex=L_%7Bo%7D%28p%2Cw_%7Bo%7D%29%3D%5Cint_%7B%5COmega%7D%28k_%7Bd%7D%5Cfrac%7Bc%7D%7B%5Cpi%7D%2B+k_%7Bs%7D+%5Cfrac%7BDGF%7D%7B4%28w_%7Bo%7D%5Ccdot+n%29%28w_%7Bi%7D%5Ccdot+n%29%7D%29L_%7Bi%7D%28p%2Cw_%7Bi%7D%29%28w_%7Bi%7D%5Ccdot+n%29dw_%7Bi%7D& alt=&L_{o}(p,w_{o})=\int_{\Omega}(k_{d}\frac{c}{\pi}+ k_{s} \frac{DGF}{4(w_{o}\cdot n)(w_{i}\cdot n)})L_{i}(p,w_{i})(w_{i}\cdot n)dw_{i}& eeimg=&1&&&/p&&p&最后还有两个参数没有解明,也就是Kd(漫反射比例)和Ks(镜面反射比例)。&/p&&p&Ks(镜面反射比例)实际上就是F。之前的公式其实并不妥当,因为Ks和F其实是重复的,只需要乘一次。所以应该是: &/p&&p&&img src=&https://www.zhihu.com/equation?tex=L_%7Bo%7D%28p%2Cw_%7Bo%7D%29%3D%5Cint_%7B%5COmega%7D%28k_%7Bd%7D%5Cfrac%7Bc%7D%7B%5Cpi%7D%2B+%5Cfrac%7BDGF%7D%7B4%28w_%7Bo%7D%5Ccdot+n%29%28w_%7Bi%7D%5Ccdot+n%29%7D%29L_%7Bi%7D%28p%2Cw_%7Bi%7D%29%28w_%7Bi%7D%5Ccdot+n%29dw_%7Bi%7D& alt=&L_{o}(p,w_{o})=\int_{\Omega}(k_{d}\frac{c}{\pi}+ \frac{DGF}{4(w_{o}\cdot n)(w_{i}\cdot n)})L_{i}(p,w_{i})(w_{i}\cdot n)dw_{i}& eeimg=&1&& 。&/p&&p&而Kd(漫反射比例),则是(1-F)(1-金属度),除了需要减掉F外,还要再乘一次(1-金属度)。这是因为金属会更多的吸收折射光线导致漫反射消失,这是金属物质的特殊物理性质。&/p&&p&&br&&/p&&p&其实,刚才说的这几个DGF公式都不是唯一的,因为这些公式即使是基于物理的,也还是会包含一些“只要和结果差不多就可以”的部分(比如那个1/8),因为严格的公式往往会为了不明显的细节而消耗大量计算时间,不值得。&/p&&p&所以,他们其实也都只是“并非那么拟合”的拟合公式。&/p&&p&而这几个公式,也有一些精度更低,但性能更好的拟合版本,诸如UE4的Paper里,菲涅尔部分使用的是这样一个神奇的公式:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-05a424d2dac6beb5d08cbc_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&497& data-rawheight=&64& class=&origin_image zh-lightbox-thumb& width=&497& data-original=&https://pic3.zhimg.com/v2-05a424d2dac6beb5d08cbc_r.jpg&&&/figure&&figure&&img src=&https://pic1.zhimg.com/v2-156aad94cc51e95ef3f8b91a35cef32c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&988& data-rawheight=&335& class=&origin_image zh-lightbox-thumb& width=&988& data-original=&https://pic1.zhimg.com/v2-156aad94cc51e95ef3f8b91a35cef32c_r.jpg&&&/figure&&p&这个公式是用曲线拟合方式对之前那个菲涅尔方程的近似,通过把pow函数换成exp2,得到了更好一点的性能。&/p&&p&(是的,exp2比pow快,因为&img src=&https://www.zhihu.com/equation?tex=x%5Ey+%3D+e%5E%7By+%5Cln+x%7D& alt=&x^y = e^{y \ln x}& eeimg=&1&&)&/p&&p&&br&&/p&&p&至此,PBR的直接光照部分就已经完成。&/p&&p&&br&&/p&&h2&IBL(Image-Based Lighting 基于纹理的光照)&/h2&&a href=&https://link.zhihu.com/?target=https%3A//learnopengl.com/PBR/IBL/Diffuse-irradiance& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic4.zhimg.com/v2-5ce5b37ac426bbd45c8f7_180x120.jpg& data-image-width=&350& data-image-height=&259& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&learnopengl.com/PBR/IBL&/span&&span class=&invisible&&/Diffuse-irradiance&/span&&span class=&ellipsis&&&/span&&/a&&p&&a href=&https://link.zhihu.com/?target=https%3A//learnopengl.com/PBR/IBL/Diffuse-irradiance& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Diffuse irradiance&/a&&/p&&a href=&https://link.zhihu.com/?target=https%3A//learnopengl.com/PBR/IBL/Diffuse-irradiance& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic4.zhimg.com/v2-5ce5b37ac426bbd45c8f7_180x120.jpg& data-image-width=&350& data-image-height=&259& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Diffuse irradiance&/a&&a href=&https://link.zhihu.com/?target=https%3A//learnopengl.com/PBR/IBL/Specular-IBL& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic3.zhimg.com/v2-3dcc43ddaf7a08c96af256_180x120.jpg& data-image-width=&800& data-image-height=&309& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&learnopengl.com/PBR/IBL&/span&&span class=&invisible&&/Specular-IBL&/span&&span class=&ellipsis&&&/span&&/a&&p&&a href=&https://link.zhihu.com/?target=https%3A//learnopengl.com/PBR/IBL/Specular-IBL& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&LearnOpenGL - Specular IBL&/a&&/p&&a href=&https://link.zhihu.com/?target=https%3A//learnopengl.com/PBR/IBL/Specular-IBL& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic3.zhimg.com/v2-3dcc43ddaf7a08c96af256_180x120.jpg& data-image-width=&800& data-image-height=&309& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&LearnOpenGL - Specular IBL&/a&&p&但是PBR并不只有直接光照。&/p&&p&如果只考虑直接光照的话,PBR渲染出来的画面,其实和以前并没有多少区别。PBR统一了光照的单位,保证了光能守恒,确实有它的积极意义。但是只说画面效果的话,确实没啥明显的进步。&/p&&p&让PBR表现出优于上一个世代的画面效果的,是它的环境光照部分。这部分则是由IBL实现的。实际上,他就是所谓的动态全局光照(Gl)的正体。&/p&&p&实现原理仅从它的名字(Image-Based)就可以猜出来,就是cubemap(环境贴图)。&/p&&p&实际上,它就是我们熟悉的环境反射贴图,只是采样点布点更加广泛,而且会在相近的采样点之间插值。对于Unity而言,就是Light Probe。&/p&&p&只不过,在PBR的IBL中,这张环境贴图并不会仅仅提供非常粗糙的几个光源的烘焙图。它会把周围环境的辐射度(也就是颜色)完整保存起来,而且精度很高,高到可以形成清晰的镜面倒影。&/p&&p&而PBR的材质则会把这种环境贴图当做光源来进行采样。如果是金属材质,且粗糙度低,就能够映射出周围的环境,甚至成为“镜子”。但不是金属的物体也会受此影响,不仅仅会被光源照亮,还会被周围这些“预烘焙成贴图”的物体略微照亮。&/p&&p&实现上确实并不复杂,和环境贴图的用法差不多,直接采样cubemap获得光照数据,然后再代入PBR的公式算出结果就行了。&/p&&p&这时候,大家应该回想起了之前那个讨厌的半球积分( &img src=&https://www.zhihu.com/equation?tex=%5Cint_%7B%5COmega%7D+& alt=&\int_{\Omega} & eeimg=&1&& ),那么,我们是否应该根据这个积分,采样整个半球的数据,然后再计算一次BRDF,最终合并出一个颜色值来呢?&/p&&p&这怎么可能算得动?有脑子的人,肯定都会直接把这个计算结果直接存在环境贴图里好吧?&/p&&p&漫反射部分不需要担心,这部分还真的就是最普通的环境贴图,因为并没有任何变量,直接搞出一张很糊的环境图,再通过normal从cubemap直接采样颜色值即可。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-151dca9845132ffffe22e9b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&800& data-rawheight=&300& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic4.zhimg.com/v2-151dca9845132ffffe22e9b_r.jpg&&&/figure&&p&而高光部分,则有粗糙度α这个变数,必须需要烘焙出多个粗糙度下的环境图。然而,不同α值下的烘焙出环境贴图,其实主要就是模糊程度的不同,所以生成这样一组图:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-fef9d0abbf1_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&800& data-rawheight=&309& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic1.zhimg.com/v2-fef9d0abbf1_r.jpg&&&/figure&&p&然后合并到一张cubemap的多个mipMap层级上,再利用cubeTexLod函数,根据其粗糙度选择特定层级的两个mipMap层级进行三线插值,就能得到需要的半球积分过的光照颜色值了(当然,是近似的)。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&float lod
= getMipLevelFromRoughness(roughness);
vec3 prefilteredColor = textureCubeLod(PrefilteredEnvMap, refVec, lod);
&/code&&/pre&&/div&&p&然后通过光照正常计算一次BRDF就好了。&/p&&p&这样各个不同粗糙度和金属度的材质就都能从同一张环境贴图里获得需要的数据,并完成各自的渲染。&/p&&p&&br&&/p&&p&&b&然而,IBL的难点并不在渲染部分。而是在预烘焙部分。&/b&&/p&&p&这些模糊的贴图,虽说也不是不能直接用高斯模糊一类的方法完成。但高斯模糊毕竟也只是一种近似,效果还是比不上真正的半球积分的。&/p&&p&我贴的两篇文章,其实大部分的内容都在讲怎么拆积分,通过拆解的积分写出一个4096次sample的随机采样函数,算出一个平均值来,存在纹理上,生成需要的烘焙纹理。&/p&&p&这部分内容实在太多,需要了解的就去看原文吧。不想了解的,也可以直接把它的烘焙部分代码抄走。&/p&&p&&br&&/p&&p&下面依然是对一些难点的解释:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-5a6e63a4deaf9cab51af98_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1033& data-rawheight=&616& class=&origin_image zh-lightbox-thumb& width=&1033& data-original=&https://pic3.zhimg.com/v2-5a6e63a4deaf9cab51af98_r.jpg&&&/figure&&p&在烘焙环境贴图的计算里,并没有取当前摄像机viewDir,而是让viewDir直接等于 &img src=&https://www.zhihu.com/equation?tex=w_%7Bo%7D%3D%E7%90%83%E9%9D%A2normal& alt=&w_{o}=球面normal& eeimg=&1&& 。&/p&&p&因为在生成cubemap的时候,viewDir本来也没有意义。所以只能让它一直朝向当前正在绘制的像素。之后使用这个cubemap,根据当前的viewDir重新计算的时候,因为两次的viewDir是不同的,积分合并后的结果当然也是错的。&/p&&p&但也没啥别的方法啊。&/p&&p&就图片里的结果,还算勉强可以接受吧。&/p&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&vec2 Xi = Hammersley(i, SAMPLE_COUNT);
= ImportanceSampleGGX(Xi, N, roughness);
&/code&&/pre&&/div&&p&Hammersley叫做低差异序列,是一种特殊的生成随机数的方法,可以生成一组“并不是那么随机的随机数”。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-85a7acf8b5d1ab2a25de4_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&700& data-rawheight=&368& class=&origin_image zh-lightbox-thumb& width=&700& data-original=&https://pic1.zhimg.com/v2-85a7acf8b5d1ab2a25de4_r.jpg&&&/figure&&p&随机数有两大要求:概率分布均匀,足够混乱。Hammersley就是一个概率分布均匀但是并不太混乱的随机数生成方法,作为一个随机数是很糟糕的,但是在随机收敛中使用它代替正常的随机数,反而可以获得更快的收敛速度,也就是在同样sample数量下获得更好的效果。&/p&&p&P.S. 其实这种方法也可以用到抽卡上,能够大幅减少非洲人和欧洲人的比例,在不增加保底的同时提高抽卡体验。&/p&&p&&br&&/p&&p&下面的ImportanceSampleGGX(重要性采样)其实很简单,就是“随机正态分布采样”,也就是需要实现一个正态分布的随机数生成器。&/p&&p&&a href=&https://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Box%25E2%Muller_transform& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&正态分布随机的生成方法&/a&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&z0 = sqrt(-2.0 * log(u1)) * cos(2 * pi * u2);
z1 = sqrt(-2.0 * log(u1)) * sin(2 * pi * u2);
(u1,u2是两个[0-1]的随机数)
&/code&&/pre&&/div&&p&和文中的重要性采样代码对比下就能发现他们的公式是多么的相似。&/p&&p&P.S. 其实也可以用到游戏逻辑中,比如角色长期静止时pose动作出现的时机。&/p&&hr&&figure&&img src=&https://pic1.zhimg.com/v2-fa94a620458eea780ef0a749c5461d7b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&400& data-rawheight=&400& class=&content_image& width=&400&&&/figure&&p&除了普通的辐射度烘焙外,它还将IBL的BRDF计算过程做了预计算,放入了一个LUT查找图里。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&vec2 envBRDF
= texture2D(BRDFIntegrationMap, vec2(NdotV, roughness)).
vec3 indirectSpecular = prefilteredColor * (F * envBRDF.x + envBRDF.y)
&/code&&/pre&&/div&&p&用NdotV,roughness作为参数就可以直接从图中获得计算结果,并得到处理了视角和高光的最终颜色值。虽然纹理随机采样会导致cache miss,但毕竟节约了大量的计算。&/p&&p&这张查找图的生成方法,还有那个拆积分的过程……很抱歉我实在没心情去看,实在是又臭又长。&/p&&p&——毕竟这个图其实是通用的啊,复制粘贴走就可以,连代码都不需要抄。&/p&&hr&&h2&结语:&/h2&&p&PBR这套东西,虽然实现一个其实并不算很难。&/p&&p&但是假如你非要去理解为什么它是这样,就确实比较费劲。而且还牵涉到了一些前置知识,不说的话也会难以前进,导致这篇文章特别的难写。&/p&&p&估计能完全看懂的人的不会太多,再说有些内容我自己也没搞懂。&/p&&p&不过,本来PBR这东西也不是非要看懂就是了,不求甚解,只是扒公式扒代码,一样能做出东西来。&/p&&p&写这篇文章的时候我倒是发现了很多自己以前对PBR的理解错误——然后修正过来了,也算有所收获吧。但这对做事方面并没有什么帮助。&/p&&p&&br&&/p&&p&本来想把这文章写的简单一点,但结果还是这样,也是没啥办法。&/p&&p&如果你们要问,要上PBR该怎么上?&/p&&p&如果你想上的是真正的PBR,而不是什么打着PBR幌子的劣化品(加了点法线高光就戛然而止),恐怕直接用unity的Standard就是现在最好的选择。因为直接光部分实在没啥可改的,而间接光部分,你要自己实现一套也实在太困难了,这可不是改个Shader这么简单的事情,怎么样都得依附Light ProbeGroup和配套的渲染管线。&/p&&p&之前Unity自己那个演示就是用的这套东西,看着也不赖不是么?效果上应该是合格的。&/p&&p&但是真正的PBR性能耗费肯定是比较高的。进入PS4时代后,游戏需求配置都在蹭蹭往上涨好吧,毕竟万物皆法线+高光+反射+菲涅尔。我其实很怀疑,到底有多少团队是真的需求PBR,而不是强行为了PBR而PBR。比如说,你游戏里半个光源都没有,还整天追求鲜艳的画面风格,而且没有法线没有高光……又或者有光源,但是并没有按自然光的方式打光,而是各种点光源补光,光源一点都不物理,那又何必去追求材质的物理正确呢?如果模型等等都非常简陋,一看就不像现实,那么材质贴近现实又什么意义?&/p&&p&用传统的材质Shader,效率自由度不是都更高吗?&/p&&p&——NPR也是极好的嘛。&/p&&hr&&h2&&i&Mark几篇相关文章避免以后找不到:&/i&&/h2&&p&BRDF分母系数4的来源:&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&基于物理着色:BRDF&/a&&/p&&p&一些推导:&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/jerrycg/p/4924761.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&PBR Step by Step(一)立体角&/a&&/p&
也不知道怎么搞的,PBR(Physicallly-Based-Rendering 基于物理渲染)突然成了一个……你会了就好像什么都会,不会就好像什么都不会的标尺了……嘛,其实PBR也和其他渲染技术类似,虽然是比GPUSkinMesh之类“单纯”的技术要复杂,但也未见得比完整的FFT Oce…
&figure&&img src=&https://pic3.zhimg.com/v2-db0eb68d69a9_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&https://pic3.zhimg.com/v2-db0eb68d69a9_r.jpg&&&/figure&&p&写好&b&产品需求文档(PRD)&/b&是产品经理的基本技能要求之一。有些同学可能对此嗤之以鼻,觉得写文档简直so easy,在学校里的课程设计,毕业设计经常写文档论文,产品经理关注的不应该是产品设计,业务模式等吗?确实如此,但实际工作发现,很多同学还真是写不好文档,描述不清自己的需求。在工作中对一些新同学的产品需求文档进行review时,经常出现批注的字数比原文档的字数还多的情况,或是整个文档要推翻重写。需求文档作为产品经理和设计、技术及测试沟通、传达需求的载体,完善的文档可以极大的降低团队的沟通成本,提升开发效率。项目规模越大,参与人数越多,价值体现的越明显。试想,一个产品经理+两三个技术的小团队,尚且可以通过简单的脑图、原型图+口头描述的形式沟通需求,如果面对的是人数众多的设计师,前端团队,后端团队,外部团队,测试团队等,沟通成本就会成倍增加。&/p&&p&&br&&/p&&p&过去几年的工作中,见过很多初创小团队不重视写需求文档,觉得太浪费时间,效率不够高,恨不得一个项目今天确定方案,明天就启动开发,具体需求开发过程中再定。但最终项目上线,纵观从需求到产品上线的完整过程,发现并不节省时间,因为前期节省的写文档的时间,都在开发、测试的过程中补回来了。需求文档不够完善,通常会导致以下几个问题:&/p&&p&&br&&/p&&ul&&li&&b&需求的工作量和技术方案难以评估&/b&:因为需求的不完善,导致启动开发前无法准确预估需求的工作量和确定技术实现方案,走一步看一步开发过程中,发现需求有坑,不断发现新的问题,有时因为一个简单的逻辑或设计不明确,在沟通明确后最终发现需要技术方案大调整,需求实际开发时间比预估的长很多,很多项目会变得失控甚至烂尾&/li&&li&&b&沟通成本高&/b&:在开发过程中,产品经理依然要经常与设计、技术和测试沟通需求逻辑,完善的需求文档无疑会降低沟通的成本&/li&&li&&b&技术脑补需求&/b&:有很多靠谱的技术同学,会帮助产品经理考虑逻辑和设计,如果需求没有明确描述,就按他自己的理解和想法实现了。遇到这样的技术同学,初看非常省事省心,产品简单描述下需求梗概,展示下原型图,东西就做出来了,但人和人的理解不同,实现的逻辑可能并不是产品期望的逻辑,到了测试环节,测试同学也有自己的理解,导致又要花时间沟通统一意见,或浪费时间返工修改&/li&&li&&b&产品经理失去对产品方案的掌控力&/b&:对于需求的很多细节逻辑产品经理自身都不清楚,遇事都得&b&问问技术&/b&,最懂产品逻辑的反而是技术同学,产品经理不是最了解产品逻辑的人,就会逐渐边缘化,只是简单描述要做什么,绘制原型图顺便讲讲交互的产品经理,实际更像是交互设计师&/li&&li&&b&产品逻辑难以后续追溯&/b&:产品不断的迭代更新,或是人员的交接,经常需要回溯之前的线上逻辑,需求文档的缺失或不完善,会导致线上逻辑不明确,甚至后续的产品需求设计的逻辑与线上矛盾或冲突,为项目的开发带来麻烦&/li&&/ul&&p&&br&&/p&&p&因此,建议刚入门的产品同学,一定要重视写好&b&严谨的&/b&需求文档,产品经理虽然是一个软实力岗位,但依然有这些基础技能的要求。首先就是要明确:&b&产品需求文档(PRD)是产品需求的说明书,不是产品需求的介绍材料&/b&。生活中我们购买电子电器等产品,会接触各种说明书(虽然现在的人都不太看了),我认为大致有以下几个特征:&b&一个是全&/b&,说明书覆盖了这个产品的每一个功能点,每一个按钮的具体操作和功能;&b&另一个是明确&/b&,没有等等,一个功能有几个模式会说几个模式,都会列出来依次描述;&b&还有一个是结构化&/b&,分章节很规整,有各个功能描述的部分,有名词解释的部分。相比之下,产品的介绍材料就简单多了,通常是产品的核心功能介绍,以及一些外观、操作界面的展示等,见过一些产品经理,仍然是以写介绍材料的风格写需求文档,读完需求文档感觉是看了一遍产品介绍,不够严谨没有细节。&/p&&p&&br&&/p&&p&基于以上的原则,在此谈谈写需求文档的几点经验:&/p&&p&&br&&/p&&blockquote&&b&需求有背景有目标&/b&&/blockquote&&p&&br&&/p&&p&很多产品需求文档模板中,开头都有需求背景,需求目标这样的章节,有些产品同学并不注重这些部分,不写或是简要略过,但我觉得这对于一个具体的需求项目非常重要。产品经理自身应该想清楚为什么要做这个需求,以及做这个需求期望达到怎样的结果,&b&先明确了目标就能以结果为导向,围绕提升目标效果深入思考找到最优解&/b&。这句话说来简单,实际很多人在产出需求时并没有仔细思考过,目标只局限在实现功能的层面即可。举个例子:&/p&&p&&br&&/p&&p&开发一个简单功能:用户个人信息增加身份证号录入,有些人设计,可能就只会简单的在个人信息页面增加一个身份证号码的输入框,用户提交个人信息,数据能成功保存即可,最省事的做法,可以连校验都不需要,认真一点的,加一个18位的校验,但这样就足够完善吗?如果明确了需求的背景和目标,期望的是用户录入的身份证号信息尽可能的准确,就会多花一些心思思考,例如,检查身份证号码中的生日位数与个人信息中的生日是否一致?再进一步了解身份证号码校验规则,会了解到身份证号的最后一位其实是校验位,可以通过其他的位数按固定的公示计算得出,这样可以更大的提升用户输入准确身份证号码的概率。&/p&&p&&br&&/p&&p&另一方面,明确需求的背景让参与这个需求的设计,技术,测试等同学,都能了解到为什么要做这个需求,做这个需求要达到的目标,让每个人感觉自己的工作是有意义的,每一个需求都是为了整个产品更好而添砖加瓦,这样团队的氛围也会更好。&/p&&p&&br&&/p&&blockquote&&b&同理心,代入技术、测试及其他角色&/b&&/blockquote&&p&&br&&/p&&p&工作中我经常建议产品同学写完需求文档后自己再读一遍,自己读一遍就能发现很多问题和漏洞。更重要的是,&b&要能代入看需求文档的人的角色中,以他们的视角来审阅需求&/b&。最简单的,我习惯于将文档中我认为重要的,担心他人阅读时会忽视的段落文字加下划线或背景色标识,或是特别注明(此处设计师请注意有多个状态)等。代入测试的角色,试想自己看着这份需求文档在写测试用例,通常会发现很多漏洞,举个例子:&/p&&p&&br&&/p&&p&很多线上SAAS产品都有一键导出页面表单数据这样的功能,很多产品经理在写需求时对这个操作按钮只有一句话的描述:点击『导出』按钮后,将表格中的数据导出为excel文档。如果以测试的角色审视这句话,会发现有很多不明确的点:&/p&&p&导出的文件格式是什么?xlsx?xls?还是csv?(这三种格式都很常见)&/p&&p&导出的表格是否区分sheet?sheet名称是什么?&/p&&p&导出的表格包含哪些字段?线上展示的表格中,如果还有图片(头像)等信息,肯定不可能被导出到excel中&/p&&p&导出的文件如何命名?&/p&&p&&br&&/p&&p&上述这些问题,如果在需求文档中不明确,在需求开发过程中通常会出现两种情况:要么是技术同学过来问产品经理如何定义(可能不止一次的沟通),要么是技术同学按自己的想法实现。前者增加了沟通成本,后续还是要花费时间完善文档或是再给测试同学讲需求,后者如果实现的方案在测试环节发现与产品或测试的想法不同,就需要返工再调整,两种情况无论怎样,都会浪费时间&/p&&p&&br&&/p&&blockquote&&b&先搭框架写目录&/b&&/blockquote&&p&&br&&/p&&p&我自己写需求文档的习惯是先搭框架,首先会把文档的每一个章节,包括大章节和小章节都罗列出来,其实就是先写目录。然后自己缕一遍想想两件事:一个是:结合上一点所说的同理心,一个产品功能的操作,涉及到多个页面或多个系统的状态变化,我这样的文档结构和顺序是不是足够清晰,看需求的人是否觉得容易理解,如果自己都觉得描述混乱,那就考虑换一个结构;另一个是大框架下的内容是不是有遗漏,有没有遗漏描述某一项功能逻辑。&/p&&p&&br&&/p&&p&通常完成了目录框架,自己对整个需求就很清晰明朗了,一种一切尽在掌控的感觉,接下来就是挨个补齐具体的章节的功能描述。&/p&&p&&br&&/p&&blockquote&&b&先整体后具体&/b&&/blockquote&&p&&br&&/p&&p&需求文档的第一个章节,应该先描述整体的逻辑,之后再分章节描述各个功能点。可以使用产品&b&功能结构图&/b&,&b&信息结构图&/b&,&b&流程图&/b&等形式,先从整体层面描述清楚本需求整个功能的操作和逻辑。这也是容易被忽视的问题,写需求的产品同学自己心里对于整个需求功能是有一个整体形象的,下笔写需求文档时,就开始按照功能流程描述ABCD各个界面或功能模块。导致实际阅读需求的人看完是一头雾水,读完整个需求,细节是清楚的,但就像是盲人摸象,不清楚各个功能模块或界面的关联是什么,整体的产品流程是什么。&/p&&p&&br&&/p&&blockquote&&b&结构化的描述功能&/b&&/blockquote&&p&&br&&/p&&p&见过不少产品同学都是以写小说的风格写需求文档,一大段一大段的描述,逻辑全靠『如果』『否则』等等连词组织在一起。对于具体的功能或界面的描述,应该尽量结构化,可以注意这么几个点:&/p&&p&&br&&/p&&ul&&li&明确原型图和所描述功能的对应关系,可以在原型图上标明界面元素ABCDE,再通过表格分别描述ABCDE的展示和操作逻辑,一些简单的逻辑也可以直接写在原型图上&/li&&li&能用表格的尽量用表格,区分展示、交互和逻辑&/li&&li&能用流程图的尽量用流程图&/li&&/ul&&p&&br&&/p&&p&结构化的描述使得文档更清晰可读性强,另一个重要作用是使得产品经理自身不容易遗漏需要描述的点,例如表格描述各个页面元素,区分了展示、交互和逻辑,就会提示自己依次要考虑这三部分,避免出现下面所说的只写前端展示不写后端逻辑的情况。&/p&&p&&br&&/p&&blockquote&&b&注意定义名词和状态&/b&&/blockquote&&p&&br&&/p&&p&这个也是很多产品同学在写需求时容易忽略的,要么是忘记了定义,要么是认为是共识都清楚不需要定义,对于后者,需要再深入想想到底&b&是不是真的清楚&/b&,通常会发现很多误以为是明确的名词或状态实际并不明确,特别是对于边缘状态。举个例子:&/p&&p&&br&&/p&&p&将优惠券定义为可用,已使用和已失效这三种状态,但在需求中并没有明确定义这三种状态,心想这应该是心知肚明有共识的吧,有效期之前的优惠券就是可用的,有效期之后的是已失效,操作了兑换的就是已使用呗,写需求时就这么过去了。但如果停下来,用文字描述下每个状态的定义,就会思考真的把条件想全面了吗?假如管理后台还有操作功能,那在管理后台操作失效的优惠券也是已失效的状态,以及,用有效期时间来区分可用和已失效,那在有效期deadline的那一秒,状态是可用还是已失效呢?这些都是有歧义的点&/p&&p&&br&&/p&&p&如果在需求中的多个位置出现这个名词或状态,可以在需求文档中专门起一个章节来描述定义,类似字典的作用&/p&&p&&br&&/p&&blockquote&&b&前端展示和后端逻辑同在&/b&&/blockquote&&p&&br&&/p&&p&我在很多新的产品同学所写的需求文档中都发现存在这个问题。特别是偏前端用户体验的产品经理,非技术出身的产品经理,经常习惯只描述前端展示而忽略了后端的逻辑。需求描述一个功能,用户在某个界面完成了某个操作,一定伴随着前端交互界面反馈给用户的变化(页面跳转、提示文案等等),以及更重要的:后端的逻辑,程序执行了怎样的操作,但写需求文档经常无意识而忽视了后者。举个例子:&/p&&p&&br&&/p&&p&前一阵看到一个同学写的通过H5营销活动页领取优惠券的需求,这种功能目前很普遍。因为领取优惠券的前端操作略复杂,涉及到帐号登录,产品同学在需求文档中把篇幅都用来写前端操作了,用户输入手机号码,格式校验,获取验证码,校验验证码是否正确等等,写完校验通过成功登录后,页面跳转展示成功获取到优惠券,继续开始描述成功获取优惠券页面。初看没什么问题,仔细想想会发现需求全部都在描述前端展示,然后这个功能最核心的并没有在需求中体现,即用户手机号登录成功后的逻辑:手机号未注册帐号如何自动注册帐号,已注册过帐号如何发放优惠券,此帐号已领取过优惠券如何处理等等,需求这一段只是从用户的视角描述了呈现给用户的前端展示变化,全部是写给前端技术看的,对于后端技术只能靠自己脑补逻辑了。&/p&&p&&br&&/p&&p&而偏后端的产品经理,文档又通常只描述业务逻辑而忽视前端界面展示的变化,但这个影响相对较小,很多纯后端需求并不涉及前端界面展示,即便设计到前端界面也是内部的管理系统。所以在需求文档中描述操作某个功能时,&b&一定要提醒自己是不是同时描述清楚了前端展示和后端逻辑&/b&。需求文档的结构化,强行要求自己分开写清楚前端展示和交互,以及后端的逻辑,可以有效的避免这个问题&/p&&p&&br&&/p&&blockquote&&b&警惕出现『等』&/b&&/blockquote&&p&&br&&/p&&p&需求文档中应警惕出现等这个字,除非是举例描述。对于状态或选项,一定要&b&穷举&/b&所有的情况&/p&&p&&br&&/p&&blockquote&&b&时刻考虑边缘状态和异常状态&/b&&/blockquote&&p&&br&&/p&&p&产品在需求文档中充分考虑到了边缘状态和异常状态的处理,可以有效的提升程序的鲁棒性,否则只能等技术同学在开发过程中,或是测试同学在测试过程中发现问题。这里其实有一些共通的经验:&/p&&p&&br&&/p&&p&对于功能有输入操作,一定要记住三个凡是,即:&/p&&ul&&li&凡是有输入,必须有限制&/li&&li&凡是有输入,必须考虑输出&/li&&li&凡是有输入,必须考虑失败&/li&&/ul&&p&&br&&/p&&p&对于列表页的展示,一定要描述列表为空的情况如何展示,这个是非常容易被忽视&/p&&p&&br&&/p&&p&关注未登录等情况的展示&/p&&p&……&/p&&p&&br&&/p&&p&暂时先想到了这些,而对于异常状态,通常不能面面俱到覆盖所有的情况,最好可以在需求中统一定义一种或几种给用户呈现的异常提示等,但不能没有。因为需求中没有定义,技术同学通常会按自己的实现有意识或无意识的把各种奇特状态提示呈现给用户。&/p&&p&&br&&/p&&blockquote&&b&另一个角色是项目经理&/b&&/blockquote&&p&&br&&/p&&p&在互联网公司,产品经理实际承担了很多项目经理的职责。一个需求文档对应一个项目,实际需求文档是控制产品迭代的有效手段,需求文档明确了本次需求要开发ABCD功能,如果明确这次D不上线,最好能更新需求文档标识或删去D的内容,在下一次另一个需求中再体现。避免出现&b&需求中有描述的不做,要做的却在文档中没有&/b&的情况,对于这个项目本身可能会导致需求不明确,例如测试同学在测试过程中不清楚哪些需求点要做哪些不做,而对于后续的迭代也容易搞混需求有没有开发、在哪个需求中开发了。同时,秉承以结果为导向,善于拆分需求,不追求一口吃成胖子,看看这个需求中是不是包含多个相对独立的功能可以拆开做,越细粒度越小的需求越容易精准的进行项目管理,也符合互联网产品小步快跑的节奏。&/p&&p&&br&&/p&&p&以上就是一些撰写需求文档的经验,时间紧写的比较潦草,有想到其他的以后再补充。&/p&&p&&br&&/p&&hr&&p&&b&欢迎关注我的公众号『aboutlzp』,分享我的一些产品工作心得,歌颂伟大事业等&/b&&/p&
写好产品需求文档(PRD)是产品经理的基本技能要求之一。有些同学可能对此嗤之以鼻,觉得写文档简直so easy,在学校里的课程设计,毕业设计经常写文档论文,产品经理关注的不应该是产品设计,业务模式等吗?确实如此,但实际工作发现,很多同学还真是写不好…
&figure&&img src=&https://pic4.zhimg.com/v2-cc65decc1459d8dbb6b4e_b.jpg& data-rawwidth=&1187& data-rawheight=&664& class=&origin_image zh-lightbox-thumb& width=&1187& data-original=&https://pic4.zhimg.com/v2-cc65decc1459d8dbb6b4e_r.jpg&&&/figure&&p&FlowMap其实算是一种UV动画, 这个技术的推广很大得益于Vlachos[1]的一篇技术分享. 由于当时文章里主要是用这种技术制作水面流动的效果,所以目前很多水面效果也是用这种方法来做,但是其实这个技术可以用在任何你希望看起来是流动的效果中,比如岩浆或者泥巴.&/p&&p&这个技术首先依赖的是UV的平移,也就是说第一步让贴图UV随着时间变换起来:&/p&&p&&img src=&http://www.zhihu.com/equation?tex=UV%7Bnew%7D+%3D+UV+%5Ctimes+t+%5C%5C& alt=&UV{new} = UV \times t \\& eeimg=&1&&&/p&&p&t是一个随时间变化的任意值,用这个新UV采样贴图那么贴图就会移动起来,在UE4的材质编辑器里是这样的:&/p&&figure&&img data-rawheight=&344& src=&https://pic4.zhimg.com/v2-3fbde631b3f_b.jpg& data-size=&normal& data-rawwidth=&514& class=&origin_image zh-lightbox-thumb& width=&514& data-original=&https://pic4.zhimg.com/v2-3fbde631b3f_r.jpg&&&/figure&&p&但是如果你预览会发现目前贴图只是随着一个方向不停的滚动,如果需要模拟水流的样子只平移是不够的, 受到了其他水分子的挤压,所以看起来有点扰动在里面才逼真。这个时候,Flow map登场了,通过给贴图的移动预先烘焙好一段移动的轨迹,那么水流看起来会栩栩如生许多:&/p&&figure&&img data-rawheight=&219& src=&https://pic3.zhimg.com/v2-04d5f093bf8f0cc59afd78_b.jpg& data-size=&normal& data-rawwidth=&481& data-thumbnail=&https://pic1.zhimg.com/v2-04d5f093bf8f0cc59afd78_b.jpg& class=&origin_image zh-lightbox-thumb& width=&481& data-original=&https://pic1.zhimg.com/v2-04d5f093bf8f0cc59afd78_r.jpg&&&figcaption&FlowMap 效果&/figcaption&&/figure&&br&&br&&p&FlowMap看起来是这样:&/p&&figure&&img data-rawheight=&403& src=&https://pic3.zhimg.com/v2-9adb77dd5eadce2621cad2bcfedd573a_b.jpg& data-size=&normal& data-rawwidth=&410& class=&content_image& width=&410&&&figcaption&FlowMap&/figcaption&&/figure&&p&因为我们主要encoding了水平方向的数据, 分别用r和g通道, 所以这样FlowMap看起来都是这个色调的样子. 这个数据可以用DCC工具bake, 不过作为学习和简化的方法, 我推荐你用&a href=&http://link.zhihu.com/?target=http%3A//teckartist.com/%3Fpage_id%3D107& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&FlowMap Painter&/a&, 一款免费并且简单易用的工具.&/p&&p&有了FlowMap, 我们只需要读取其中的数据分别作为原图的扰动分量即可实现让贴图&流动&起来, 这么说可能有点抽象, 所以必须自己手动做一遍感受下会比较好. 作为展示目的, 我在UE4中是用自定义节点做的:&/p&&figure&&img data-rawheight=&329& src=&https://pic1.zhimg.com/v2-b4f653da2adf634d4999dcc08b47bc78_b.jpg& data-size=&normal& data-rawwidth=&161& class=&content_image& width=&161&&&/figure&&p&代码如下:&/p&&div class=&highlight&&&pre&&code class=&language-cpp&&&span&&/span&&span class=&n&&float2&/span& &span class=&n&&AdjustUV&/span& &span class=&o&&=&/span& &span class=&n&&UV&/span& &span class=&o&&*&/span& &span class=&n&&Tiling&/span&&span class=&p&&;&/span&
&span class=&kt&&float&/span& &span class=&n&&HalfPeriod&/span& &span class=&o&&=&/span& &span class=&n&&PeriodSec&/span& &span class=&o&&*&/span& &span class=&mf&&0.5&/span&&span class=&p&&;&/span&
&span class=&n&&float2&/span& &span class=&n&&Flow&/span& &span class=&o&&=&/span& &span class=&n&&Texture2DSample&/span&&span class=&p&&(&/span&&span class=&n&&FlowMap&/span&&span class=&p&&,&/span& &span class=&n&&FlowMapSampler&/span&&span class=&p&&,&/span& &span class=&n&&AdjustUV&/span&&span class=&p&&).&/span&&span class=&n&&rg&/span&
&span class=&o&&*&/span& &span class=&mf&&0.5&/span& &span class=&o&&+&/span& &span class=&n&&float2&/span&&span class=&p&&(&/span&&span class=&mf&&0.5&/span&&span class=&p&&,&/span&&span class=&mf&&0.5&/span&&span class=&p&&);&/span&
&span class=&n&&float2&/span& &span class=&n&&Bias&/span& &span class=&o&&=&/span& &span class=&n&&fmod&/span&&span class=&p&&(&/span&&span class=&n&&View&/span&&span class=&p&&.&/span&&span class=&n&&RealTime&/span&&span class=&p&&,&/span&&span class=&n&&PeriodSec&/span&&span class=&p&&)&/span& &span class=&o&&*&/span& &span class=&n&&Flow&/span&&span class=&p&&;&/span&
&span class=&n&&float2&/span& &span class=&n&&NewUV&/span& &span class=&o&&=&/span& &span class=&n&&Bias&/span&&span class=&o&&*&/span& &span class=&n&&Speed&/span& &span class=&o&&+&/span& &span class=&n&&AdjustUV&/span&&span class=&p&&;&/span&
&span class=&n&&float4&/span& &span class=&n&&C1&/span& &span class=&o&&=&/span& &span class=&n&&Texture2DSample&/span&&span class=&p&&(&/span&&span class=&n&&Tex&/span&&span class=&p&&,&/span& &span class=&n&&TexSampler&/span&&span class=&p&&,&/span& &span class=&n&&NewUV&/span&&span class=&p&&);&/span&
&span class=&n&&Bias&/span& &span class=&o&&=&/span& &span class=&n&&fmod&/span&&span class=&p&&(&/span&&span class=&n&&View&/span&&span class=&p&&.&/span&&span class=&n&&RealTime&/span& &span class=&o&&+&/span& &span class=&n&&HalfPeriod&/span&&span class=&p&&,&/span&&span class=&n&&PeriodSec&/span&&span class=&p&&)&/span& &span class=&o&&*&/span& &span class=&n&&Flow&/span&&span class=&p&&;&/span&
&span class=&n&&NewUV&/span& &span class=&o&&=&/span& &span class=&n&&Bias&/span& &span class=&o&&*&/span& &span class=&n&&Speed&/span& &span class=&o&&+&/span& &span class=&n&&AdjustUV&/span&&span class=&p&&;&/span&
&span class=&n&&float4&/span& &span class=&n&&C2&/span& &span class=&o&&=&/span& &span class=&n&&Texture2DSample&/span&&span class=&p&&(&/span&&span class=&n&&Tex&/span&&span class=&p&&,&/span& &span class=&n&&TexSampler&/span&&span class=&p&&,&/span& &span class=&n&&NewUV&/span&&span class=&p&&);&/span&
&span class=&kt&&float&/span& &span class=&n&&a&/span& &span class=&o&&=&/span& &span class=&n&&abs&/span&&span class=&p&&(&/span&&span class=&n&&HalfPeriod&/span& &span class=&o&&-&/span& &span class=&n&&fmod&/span&&span class=&p&&(&/span&&span class=&n&&View&/span&&span class=&p&&.&/span&&span class=&n&&RealTime&/span&&span class=&p&&,&/span& &span class=&n&&PeriodSec&/span&&span class=&p&&))&/span& &span class=&o&&/&/span& &span class=&n&&HalfPeriod&/span&&span class=&p&&;&/span&
&span class=&k&&return&/span& &span class=&nf&&lerp&/span&&span class=&p&&(&/span&&span class=&n&&C1&/span&&span class=&p&&,&/span&&span class=&n&&C2&/span&&span class=&p&&,&/span& &span class=&n&&a&/span&&span class=&p&&);&/span&
&/code&&/pre&&/div&&p&比较重要的部分是C1和C2的混合,通过混合来掩盖单一贴图平移时候出现的闪烁,我觉得这也是这个算法里最核心和最美得部分,正是这种打时间差的配合让流动显得非常自然而且无尽无止。&/p&&p&使用后的效果:&/p&&figure&&img data-rawheight=&514& src=&https://pic1.zhimg.com/v2-15cd8d46d76d013ae42b1bdb12abab64_b.jpg& data-size=&normal& data-rawwidth=&534& class=&origin_image zh-lightbox-thumb& width=&534& data-original=&https://pic1.zhimg.com/v2-15cd8d46d76d013ae42b1bdb12abab64_r.jpg&&&/figure&&p&在UE4里,其实有一个官方预制的更复杂版本,但是其实本质算法是不变的,只是多了很多细节控制,甚至用不到的东西。&/p&&p&这只是模拟水面的一种方式,还有其他很多方法可以配合使用达到更多细节的拟真:&/p&&figure&&img data-rawheight=&226& src=&https://pic4.zhimg.com/v2-e0e5a9c1edc2e_b.jpg& data-size=&normal& data-rawwidth=&409& data-thumbnail=&https://pic3.zhimg.com/v2-e0e5a9c1edc2e_b.jpg& class=&content_image& width=&409&&&figcaption&水面流动(如果你把顶点动画和flowmap结合,可以达到神海的效果[2], 这是之前在UDK里做的效果)&/figcaption&&/figure&&br&&br&&p&&br&&/p&&hr&&p&[1]Alex Vlachos, Valve, Water Flow in PORTAL 2, 2010.&/p&&p&[2]Carlos Gonzalez-Ochoa, Naughty Dog, Water Technology of Uncharted, 2012.&/p&
FlowMap其实算是一种UV动画, 这个技术的推广很大得益于Vlachos[1]的一篇技术分享. 由于当时文章里主要是用这种技术制作水面流动的效果,所以目前很多水面效果也是用这种方法来做,但是其实这个技术可以用在任何你希望看起来是流动的效果中,比如岩浆或者泥巴.…
&figure&&img src=&https://pic2.zhimg.com/v2-1ee21ef61c88e737797dc_b.jpg& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&https://pic2.zhimg.com/v2-1ee21ef61c88e737797dc_r.jpg&&&/figure&&h2&&b&前言&/b&&/h2&&p&卡通渲染是图形学中一个有趣的话题,属于&b&非真实感计算机图形学(NPR)&/b&的范畴,在NPR领域中也最多地被应用到实际游戏中,近年来流行的《守望先锋》,《英雄联盟》,《DOTA2》,《崩坏3》等游戏中都或多或少地出现过卡通渲染的身影,恰好最近对这个领域的内容作了一些了解和探索,所以就对其中涉及的一些经典技术做一个概述。&/p&&h2&&b&卡通渲染的分类&/b&&/h2&&p&在具体讨论技术手段之前,先就卡通渲染做一个分类。卡通渲染最关键的特征包括不同于真实感渲染的&b&艺术化光影效果&/b&和&b&描边&/b&。以这两个关键的特征为卡通渲染分类的话,可以将近年来游戏中常用的卡通渲染分为&b&美式卡通风格&/b&和&b&日式卡通风格&/b&。美式卡通风格在色彩上比较连续,有渐变色,着色风格很大程度上依赖于艺术家定义的色调(tone),而在阴影和高光方面常常采取夸张和变形的做法,比较典型的是《军团要塞2》;日式卡通风格往往角色造型更写实,但在着色方面,则趋向于大片大片纯色色块,并有的明暗交界,例如《崩坏3》。虽然这样的分类并没有清晰界限,但易于描述,接下来我们就按照美式卡通和日式卡通的分类,从光影和描边两个维度上分别列举各类技术实现。&/p&&p&&figure&&img src=&https://pic4.zhimg.com/v2-55d6e225bd5cdad2fd23b0a_b.jpg& data-rawwidth=&1189& data-rawheight=&704& class=&origin_image zh-lightbox-thumb& width=&1189& data-original=&https://pic4.zhimg.com/v2-55d6e225bd5cdad2fd23b0a_r.jpg&&&/figure&军团要塞2的卡通渲染,人物造型夸张,但着色连续,接近真实感光照&/p&&p&&figure&&img src=&https://pic2.zhimg.com/v2-b39b32c0a115b416e438_b.jpg& data-rawwidth=&574& data-rawheight=&639& class=&origin_image zh-lightbox-thumb& width=&574& data-original=&https://pic2.zhimg.com/v2-b39b32c0a115b416e438_r.jpg&&&/figure&崩坏3游戏截图,着色以单色色块为主,有明显的明暗交界&/p&&h2&&b&描边&/b&&/h2&&p&描边是一个比较常用的技术,在《Real Time Rendering》中有相当篇幅的综述,大致来说包含了三类:&/p&&p&(1)&b&基于视角的勾边&/b&,这部分的计算依赖于我们的一个直觉观察:当我们的视线和某个表面相切时,这个表面上的像素点往往就是模型的边缘,基于这个观察,我们可以用&img src=&https://www.zhihu.com/equation?tex=dot%28viewDir%2C+normal%29%5E%7Bk%7D+& alt=&dot(viewDir, normal)^{k} & eeimg=&1&& 来估计一个像素的“边缘程度”,当然,这个值也可以用来作为纹理坐标去采样一张预定义的“轮廓纹理”&/p&&p&&figure&&img src=&https://pic2.zhimg.com/v2-c76d8febd2e33bb45c57_b.jpg& data-rawwidth=&626& data-rawheight=&595& class=&origin_image zh-lightbox-thumb& width=&626& data-original=&https://pic2.zhimg.com/v2-c76d8febd2e33bb45c57_r.jpg&&&/figure&基于视角的描边,最大的缺点是线宽粗细差别较大,不易控制&/p&&p&(2)&b&基于几何生成方法的描边&/b&,这类方法的特点是描边本身是一个单独的几何体,通过特殊的方法绘制出来,比较常见的做法是&b&shell method&/b&,原理和实现都比较简单:首先在绘制结束正常的模型后,将需要描边的物体&b&改用正面剔除&/b&再绘制一遍,在VS中将顶点沿着法线方向膨胀一定距离,然后在FS中将模型用纯色输出。另外一种叫做&b&z-bias&/b&的方法,也是绘制背面,但不膨胀,而是把背面顶点的Z值稍微向前偏移一点点,使得背面的些许部分显示出来形成描边效果。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-5c1e98261fac2ea11ce4fdb_b.jpg& data-rawwidth=&747& data-rawheight=&494& class=&origin_image zh-lightbox-thumb& width=&747& data-original=&https://pic4.zhimg.com/v2-5c1e98261fac2ea11ce4fdb_r.jpg&&&/figure&&p&基于shell method的绘制方法,实现简单,线宽较为均匀&/p&&p&(3)&b&基于图像处理的描边&/b&,这类方法的实现可以说更接近于“边缘”这一概念的本质定义,什么是“边缘”呢?&b&边缘就是在深度或者法线上不连续的位置&/b&。因此为了获取边缘,我们只需要在图片上找到深度或者法线不连续的位置即可,因此,我们需要将深度信息和法线信息以贴图的形式传入,运用边缘检测算法去寻找这些像素。这类方法的优点是描边的线宽一致,缺点是需要额外的法线和深度信息,当然,由于近年来流行的&b&延迟渲染&/b&框架,法线和深度本来就是G-Buffer的一部分,因此往往不需要额外绘制法线和深度的信息。&/p&&figure&&img src=&https://pic2.zhimg.com/v2-ef62abd9e04db2bc951e32dacac9e901_b.jpg& data-rawwidth=&481& data-rawheight=&691& class=&origin_image zh-lightbox-thumb& width=&481& data-original=&https://pic2.zhimg.com/v2-ef62abd9e04db2bc951e32dacac9e901_r.jpg&&&/figure&&p&基于边缘检测的描边方法,分别用深度信息和法线信息进行单独的边缘检测,而后合并起来成为最终的描边&/p&&p&&b&美式卡通中的做法&/b&&/p&&p&美式卡通中往往倾向于使用基于图像处理的描边方法来生成均匀一致的描边效果。在《英雄联盟》[1]中小兵和英雄的勾边效果就是&b&用Sobel算子对深度信息进行边缘检测来获得&/b&的。由于游戏中只需要针对小兵和英雄勾边而不需要对场景地图进行勾边,因此在LOL中,&b&勾边的计算并非全屏后处理,而是逐物体进行的&/b&,这样的好处是可以随意控制哪些物体描边,每个物体可以单独指定描边颜色,缺点是当物体较多时(尤其是skinned mesh较多时)计算量会增大。一个折衷的方案是,在进行正常绘制的阶段用stencil buffer标记出需要描边的物体,然后用一个全屏的后处理,对stencil buffer标记的像素进行边缘检测,当然这样的话,就很难给每个物体单独指定描边颜色了。&/p&&p&实际上,在LOL中有两种类型的描边,一种是小兵和英雄的固定描边,另一种是防御塔发出攻击警报或者某个单位被点选时才产生的红色描边,这两种描边在处理上略有差别,前者直接使用边缘检测的结果作为最终描边,而&b&后者则是对边缘检测结果再进行一次模糊&/b&,借此来扩大和柔化描边效果。&/p&&p&&figure&&img src=&https://pic3.zhimg.com/v2-608be38de54c5bb29c9e38_b.jpg& data-rawwidth=&425& data-rawheight=&407& class=&origin_image zh-lightbox-thumb& width=&425& data-original=&https://pic3.zhimg.com/v2-608be38de54c5bb29c9e38_r.jpg&&&/figure&&figure&&img src=&https://pic1.zhimg.com/v2-3f8a1a536a191b6b91b13640c2bfd6d1_b.jpg& data-rawwidth=&1200& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1200& data-original=&https://pic1.zhimg.com/v2-3f8a1a536a191b6b91b13640c2bfd6d1_r.jpg&&&/figure&LOL中两种类型的描边,可以看出第二类描边的线宽更宽,并且有明显的过度效果&/p&&p&&b&日式卡通的做法&/b&&/p&&p&日式卡通中往往倾向于使用基于几何体生成的方法去描边,这类描边方法相较于另两类方法的好处在于线宽更容易为美术所控制,而在日式卡通中,往往需要粗细有变化的描边去体现角色不同部位的特征,例如在《GUILTY GEAR Xrd》[2][3]中,角色的描边就是通过几何体生成的方法,结合了shell method和z-bias method,并引入了逐物体的顶点色来控制描边细节,同时也是为了保证描边粗细不会随着摄像机视距发生变化,具体来说,顶点色存储的信息包括:&/p&&ul&&li&R通道:控制toon shading的阈值,和描边无关,和着色有关,这个我们后面描述&/li&&li&G通道:控制顶点根据视距膨胀的强度(这个部分具体操作我也没有完全弄清楚,希望了解的朋友来补充)&/li&&li&B通道:控制描边的z-bias,越大则描边越不可见&/li&&li&A通道:控制描边的粗细&/li&&/ul&&br&上述做法中比较直观的理解是,通过引入逐顶点的线宽系数,使得整个描边的细节更易为美术控制,但是从我的理解来看,线宽控制只需要一个值即可,视距无关的粗细可以通过给偏移值offset.xy乘以当前顶点的z值来实现,似乎并不需要三个值来控制。&p&&figure&&img src=&https://pic1.zhimg.com/v2-d5ea50ce999c6ca22460_b.jpg& data-rawwidth=&615& data-rawheight=&500& class=&origin_image zh-lightbox-thumb& width=&615& data-original=&https://pic1.zhimg.com/v2-d5ea50ce999c6ca22460_r.jpg&&&/figure&没有vertex color,轮廓线宽没有粗细变化&/p&&p&&figure&&img src=&https://pic3.zhimg.com/v2-d00bfaf3_b.jpg& data-rawwidth=&615& data-rawheight=&500& class=&origin_image zh-lightbox-thumb& width=&615& data-original=&https://pic3.zhimg.com/v2-d00bfaf3_r.jpg&&&/figure&有vertex color, 轮廓线可以按照美术的需要去设定逐顶点粗细变化&/p&&h2&&b&着色&/b&&/h2&&p&&b&Cel Shading和Tone Based Shading &/b&&/p&&p&先来描述两种经典的NPR着色方法,分别是&b&Cel Shading&/b&[4]和&b&Tone Based Shading&/b&[5]。&/p&&p&&b&Cel Shading&/b&的基本思想是把色彩从多色阶降到低色阶,减少色阶的丰富程度,从而实现类似手工着色的效果,具体来说,可以用如下计算方法:&/p&&img src=&https://www.zhihu.com/equation?tex=celCoord+%3D+dot%28normal%2C+lightDir%29& alt=&celCoord = dot(normal, lightDir)& eeimg=&1&&&br&&img src=&https://www.zhihu.com/equation?tex=I+%3D+tex%28paletteTex%2C++celCoord%29.rgb+%2A+lightColor.rgb+%2A+k_%7Bd%7D+& alt=&I = tex(paletteTex,
celCoord).rgb * lightColor.rgb * k_{d} & eeimg=&1&&&p&其中,Kd表示模型自身的贴图颜色,celCoord表示法线和光照方向的点积,用作一维色彩表的查找坐标,而paletteTex则是由美术绘制的一维色阶表,一般来说是由几个纯色色块组成的,如下图:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-328ebfe55fd14144babce61_b.jpg& data-rawwidth=&4}

我要回帖

更多关于 苹果故意降低性能 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信