前言
和各位前端神仙一起做项目,也一起磕磕碰碰出了爱与痛的领悟。小小总结,希望3D去往H5的道路天堑变通途。
Part 1 理论篇:主要让设计师了解计算机到底是如何理解和实时渲染我们设计的3D项目,以及three.js材质和预期材质的对应关系。
本文主要for刚接触3D图形学的设计师,仅截取了最常用的理论知识和大家一起学习。
其实无论H5开发用到的是哪种webGL,设计相关的材质制作基本还是基于PBR思路进行的,所以这边建议各位亲可以先去阅读一下Substance官方宝册《The PBR Guide》。
设计师在还原3D类型的互动H5项目的时候一定想过这个宇宙终极问题:为什么H5/Web实现的3D效果和C4D里渲染出来的差异那么大?
虽然UE5的实时渲染技术和硬件兼容性已经让大家大吃一惊,但在实际项目,尤其是需要兼容低端设备的H5来说,渲染能力还是相对有限的。二是对于游戏或H5互动网站实际应用来说,流畅的互动体验优先级往往高于画面精细度,所以牺牲视觉保性能也是常见情况。
nerror="javascript:errorimg.call(this);">
材质细节、全局光照及投影、以及抗锯齿表现差距明显
1. 着色器与着色算法差异(靴靴微硬核预警)
常用的着色器分为四种:像素/片元着色器(Pixel/Fragment Shader)、顶点着色器(Vertex Shader)、几何着色器(Geometry Shader)、细分曲面着色器(Tessellation Shader)。
着色器是怎么把顶点中所带有光照、纹理等信息转换并重建在二维图像的像素中呢?GPU中是透过不同的着色算法来实现的。
一般常见计算机图形着色算法有三类:Flat Shading、Gouraud Shading、Phong Shading。这些算法虽然看起来和我们设计师没啥关系,但事实上在后面了解three.js材质时,就会发现他们在呈现时的差异。
nerror="javascript:errorimg.call(this);">
1)平直着色法 Flat Shading
2)高洛德平滑着色法 Gouraud Shading
但是在渲染高光时,可能会因为无法获取精确的光照值而出现一些不自然的过渡(或T型连接容易被错误绘制),此时可以考虑对模型进行细分或使用漫反射材质。
与Gouraud Shading不同的是,它会对顶点的法线进行插值,并透过每个像素的法向量计算光照特性。这种做法能绘制出精致、精准的曲面,但是计算量较大。Blinn-Phong是Phong的进阶版,着色性能更好,且高光弥散更自然。
简单了解计算机如何绘制3D图形后,再来看看它要如何具体理解我们所设计的3D场景。
*请注意这里说的光照模型并不是指设计师理解的3D立体模型,而是指模型对象表面光照效果的数学计算模型。
传统光照模型都是对漫反射和镜面反射的理想化模拟,如果要还原基于真实物理世界的效果,光照模型需要遵循能量守恒定律:一个物体能反射的光必然少于它接受的光。在实践层面则表现为,一个漫反射更强且更粗糙的物体会反射更暗且范围更大的高光,反之亦反。
nerror="javascript:errorimg.call(this);">
光照模型与着色组合在不同的渲染需求下也会有不同的应用:
- 真实感渲染(Photorealistic Rendering):目的是基于真实物理世界对3D场景进行仿真还原。
- 非真实感渲染(Unphotorealistic Rendering):也被成为风格化渲染(Stylistic Rendering),会更抽象化地对模型进行重绘。
nerror="javascript:errorimg.call(this);">
1)真实感渲染 Photorealistic Rendering
Lambert 漫反射模型:
漫反射模型与其他光照模型对比 [ F4, (c)ViroCore ]
这是一种以实验及观察为合成基础的非物理模型。它的表面反射同时结合了粗糙表面漫反射和光滑表面镜面反射,但Phong模型在高光处的表现有过渡瑕疵。
nerror="javascript:errorimg.call(this);">
Blinn–Phong 模型:
Phong及Blinn-Phong镜面反射模型对比 [ F6 ]
如果你用过C4D的默认渲染器,那么一定在材质的反射通道设置中见过它俩。
Phong、Blinn-Phong与GGX镜面反射模型对比 [ F7, (c)ridgestd ]
终于有一个设计师们常见的概念了。次表面散射是指光穿透不透明物体时(皮肤、液体、毛玻璃等)的散射现象。现实生活中,大部分物体都是半透明的,光会先穿透物体表面,继而在物体内被吸收、多次反射、然后在不同的点穿出物体。以皮肤为例,只有大概6%的反射是直接反射,而94%的反射都是次表面散射。
Unity中模拟次表面散射光照模型效果 [ F8, (c)Alan Zucconi ]
也就是我们常说的3渲2,非写实渲染风格也是从人们对3D场景套以2D绘画或自然媒体材质需求而演化过来的。因此非写实渲染技术实际上是不同光照模型+不同着色处理共同作用的风格化输出,目前也被大量应用在动画及游戏中,像《英雄联盟:双城之战》《蜘蛛侠:平行宇宙》都是顶级三渲二大作。
nerror="javascript:errorimg.call(this);">
Cel Shading/Toon Shading:
Blender中不同类型的Toon Shader效果 [ F10, (c)Blendernpr]
Misaki Nakano的Toon Shader互动网站 [ F11, (c)Misaki Nakano]
目前越来越多渲染器可支持设计师及工程师根据项目需求对着色进行定制化处理,以产出更具风格化和艺术化的着色效果。例如工业界插画常用的冷暖着色(Gooch Shading),以及更具绘画质感的素描着色(Hatching)及油画水墨画等自然媒体着色,都已经深入到了我们日常的创作之中。
nerror="javascript:errorimg.call(this);">
3. Three.js 材质着色对比
和许多渲染引擎一样,除了原生材质外,webGL的材质和着色都是可以根据需求进行定制的,但这往往会也带来较高的开发成本及兼容性风险。考虑到H5项目的实际应用场景,下表罗列了Three.js原生材质的对比,包含了材质特性优势、贴图差异及适用场景,大家可以基于项目需求快速选择并混合使用:
nerror="javascript:errorimg.call(this);">
4. 色彩描述与管理 Color Space
真实世界中按照物理定律,如果光的强度增加一倍,那么亮度也会增加一倍,这是线性的关系。理想状态下,像素在显示屏上的亮度也应为线性关系,才能符合人眼对真实世界的观察效果(如图b:横坐标为像素的物理亮度,纵坐标为像素显示时的实际亮度)。
为了矫正显示器的非线性问题(从图c校正回图b),我们需要对它进行一个2.2次幂的逆运算(如图a),在数学上,这是一个约0.45的幂运算(Gamma0.45)。经过0.45幂运算,再由显示器经过2.2次幂输出,最后的颜色就和实际物理空间的一致了,这套校正的操作就是伽马校正(Gamma Correction)。
另一个校正原因是因为人眼在接受光线时的敏感度也不是线性的,人对于暗部的感知更敏感,对高亮区域感知较弱,而且人眼感知光强度与光的物理强度也刚好是对数关系。为了在暗部呈现更多人眼可感知的细节,Gamma0.45的色彩空间中(如图a),像素的实际亮度也会高于它的物理亮度。
nerror="javascript:errorimg.call(this);">
上面那一大段确实有点绕,但也就说回来为什么建议渲染时使用线性空间(Linear Space)了。因为在计算机图形中,着色器的运算基本上都是基于物理世界的光照模型来保证渲染真实性的,如果模型的纹理输入值是非线性的(sRGB),那么运算的前提就不统一,输出的结果自然就不那么真实了。
将所有贴图进行去Gamma化,统一为Linear空间后,再在渲染输出时由引擎统一进行Gamma校正,这个时候在显示屏里显示的就是接近真实世界的效果了。
https://docs.unity3d.com/Manual/LinearRendering-LinearOrGammaWorkflow.html
1)输入贴图数据 sRGB to Linear: 含色彩的贴图(基础材质、环境、发光)设编码为sRGB(texture.encoding = sRGBEncoding),或将渲染设置renderer.gammaInput设为True,可将原为sRGB的贴图转换为Linear,而原纯数值类贴图(法线、凹凸等)仍旧保持Linear;这一操作可保证贴图输入数据的正确性与统一性。
3)输出渲染 Linear to sRGB: 校正渲染输出值的Gamma:renderer.gammaOutput = true; renderer.gammaFactor = 2.2;以供显示屏正确显色。
《Part2-实践篇》会继续完善three.js场景、材质贴图的制作思路、以及gltf工作流,并动态讨论项目常常遇到的还原问题。
附录
① 像素着色器 Pixel Shader
但是在3D图像中,像素着色器可能无法实现一些复杂的效果,因为它只能控制独立的像素而并不含有场景中模型的顶点信息。不过,像素着色器拥有屏幕的坐标信息,可以依据屏幕或邻近像素的的材质进行采样并增强,例如,Cel Shader的边缘强化或一些后期的模糊效果。
是最常见的3D着色器,他记录了模型每个顶点的位置、纹理坐标、颜色等信息。它将每个顶点的3D位置信息转换成2D屏幕坐标。顶点着色器可以处理位置、颜色、纹理的坐标,但是无法增加新的顶点。
是最近新兴的着色器,在Direct3D 10 和Open GL3.2中被引用。这种着色器可以在图元外生成新的顶点,从而转换成新的图元(例如点、线、三角等),而优势也是在于可以直接在着色中增加模型细节,减低CPU负担。集合着色器的常用场景包括点精灵(Point Sprite)生成(粒子动画),细分曲面,体积阴影等。
在OpenGL4.0和 Direct3D 11中出现,它可以在图元内镶嵌更多三角体。为传统模型新增了两个着色步骤(一是细分控制着色,又称为Hull Shader,二是细分评估着色,又称为Domain Shader),两者结合可以让简单的模型快速获得细分曲面。(例如,含细分曲面效果的模型加上置换贴图就可以获得极其逼真细腻的模型)
GL:Graphics Library, 图形函数库。
Z-Buffering:
Rendering Pipeline:
渲染管道细节工作流 [ F12 ]
光栅化/点阵化/栅格化,就是将管线处理完的图元转换成一系列屏幕可视的像素,过程包括:图元拼装(Primitive assembly)-三角形遍历(Triangle Traversal)- Pixel Processing-Merging。
[1]Hearn, D. and Baker, M.P., 2004. Computer graphics with OpenGL, 计算机图形学第四版 . Upper Saddle River, NJ: Pearson Prentice Hall,.
[3]锐萌瑞, 经典光照模型(illumination model)
[4]Krishnaswamy, A; Baronoski, GVG (2004). “A Biophysically-based Spectral Model of Light Interaction with Human Skin” (PDF).
https://en.wikipedia.org/wiki/List_of_common_shading_algorithms
https://www.cnblogs.com/timlly/p/11098212.html
https://zhuanlan.zhihu.com/p/31194204
https://www.jianshu.com/p/96ca495669d6
https://blog.csdn.net/puppet_master/article/details/83582477
https://github.com/mrdoob/three.js/issues/11110
https://github.com/aframevr/aframe/issues/3509
[12] alteredq, Questions about the use of Gamma Correction in the WebGL Renderer #1488
[13] Friksel, What’s this about gammaFactor?
[14] PZZZB,Linear Space Lightning、Gamma、sRGB详情讲解:
[15] Learn OpenGL, Gamma Correction
[16] 柯灵杰,3D图形学基础:
[17] Klayge游戏引擎,关于D3D11你必须了解的几件事情(三)
[18] 拓荒犬, GPU渲染流水线简介
[19] Steve Baker, Learning to Love your Z-buffer.
[20] Steve Baker, Alpha-blending and the Z-buffer.
[21] Microsoft, Direct3D 11 Graphics-Tessellation Stages
[F1] Stefano Scheggi, Flat shading vs. Gouraud shading vs. Blinn-Phong shading
[F2] Joe Wilson, Physically-based Rendering, And You Can Too!
[F3] Autodesk, Apply Visual Effects
[F4] Virocore, Lighting and Materials
[F5] Wikipedia, Phong Reflection Model
[F6] Wikipedia, Blinn–Phong reflection model
[F7] Ridgestd,从Microfacet到GGX反射模型
[F8] Alan Zucconi, Fast Subsurface Scattering in Unity (Part 2)
[F9] Polygon Runway, Toon Shading Tutorial for Blender 2.8 with Commentary
[F10] Blendernpr, Basic Toon Shaders with Blender
[F11] 邓佳笛,在Unity进行水墨风3D渲染的尝试
[F12] Wikipedia, Graphics_pipeline
本文由 @腾讯ISUX 原创发布于人人都是产品经理。未经许可,禁止转载
题图来自Unsplash,基于CC0协议。
javascript手册下载(3D to H5工作流应用手册——理论篇)
