shenshanyoumu / three.js-annotations

对Three 3D渲染库的代码注解

Home Page:https://threejs.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

threejs注解版

Three.js 是一款轻量级的3D 渲染库,提供了基于 Canvas、SVG、CSS3D 和 WebGL 等技术实现的渲染能力。

既然是一款商业级的渲染库,则一定包含完整的 3D 可视化要素,即包含 3D 场景、模型、相机、渲染器、坐标系、纹理/材质、着色和光照等。同时 Three.js 还提供了一系列加载器、动画效果和音效等,在代码结构中分目录整理方便开发者查阅。

题外话:threejs和D3.js都是采用rollup进行打包,但是D3.js采用lerna的多包单体管理,并且D3.js的代码量更多。D3的代码工程化**,以及处处体现的函数式编程方式值得借鉴;而three.js与echarts的实现风格更接近,都是采用OOP的**来模块化管理。

模块说明

core模块

(1) Object3D(核心模块,难度系数:3/5)
这个模块是threejs的核心模块,3D场景中几乎所有要素都继承自该模块。Object3D基类封装了事件分发、向量/矩阵计算,以及旋转位移变换相关(欧拉角、四元数和变换矩阵)的能力。

注意:Object3D基类包含图层属性Layers。图层对象Layers可以分为32个编号,图层对象layers可以控制场景中对象的可见性。场景中模型对象图层必须和相机对象的图层一样,才能被渲染出来。

(2) 事件总线(核心模块,难度系数:3/5)
Three.js实现了一个简单的事件分发模块,用于充当整个渲染系统的事件总线。

(3) Clock(辅助模块,难度系数:3/5)
在场景渲染中通过计时器模块来记录场景的渲染和逻辑计算耗时,帮助开发者发现渲染性能问题

(4) 各类Buffer对象(核心模块,难度系数:3.5/5)
Three.js是对WebGL的封装,其遵循WebGL的各种数据类型声明。三维场景中各种坐标都是TypedArray类型,并且除了很简单的应用可以直接硬编码顶点着色器坐标和颜色值;对于复杂的三维应用,场景中的数据都是通过外部数据源传入WebGL系统的内置BUFFER对象中进行属性绑定

(5) Geometry(核心模块,难度系数:4/5)
几何模型与Object3D不同在于,几何模型是一种数学抽象并不直接用于场景渲染。其提供了对场景中各种模型的几何计算能力,比如计算法向量、顶点坐标、顶点颜色,以及几何面。除此之外,几何模型还针对模型的形变处理、皮肤数据,以及包围盒/包围球进行数学计算。

(6) InterleavedBuffer(核心模块,难度系数:3.5/5)
根据WebGL的编程指南,传递给顶点着色器的多个数据集会被attribute修饰的多变量消费。为了简化编程复杂度和提高数据在CPU与GPU的传输效率,可以采用Interleaved方式来编制多种数据为同一个buffer对象中,WebGL系统通过offset+stride来拆分数据并消费

Math模块

(1) 数学基础工具(核心概念,难度系数:3.5/5)
二维向量、三维向量、四维向量在3D渲染系统主要用于对顶点坐标、颜色系统等表示;而33矩阵、44矩阵主要用于三维场景变换,以及从模型局部坐标空间过一系列矩阵变换得到屏幕显示的像素空间。矩阵的代数运算主要包括矩阵分解、矩阵乘除法,以及矩阵的特征值计算等;
四元数是对变换矩阵的空间压缩;欧拉角比四元数容易理解,但是需要注意万向节锁问题,即在旋转到特定角度会丢失模型的自由度。

(2) 坐标系(核心概念,难度系数:3/5)
平面坐标系:基于法向量和平面到原点的垂直距离来唯一确定一个平面;
球面坐标系:基于球心坐标、球面半径、球面半径与Y轴夹角,以及球面半径在XZ平面的投影与Z轴夹角来共同决定一个唯一的球面;
射线坐标系:基于射线原点和射线发出方向来唯一确定射线坐标系中的点
柱面坐标系:基于柱面在ZX屏幕上的截面半径、沿Y轴逆时针旋转弧度,以及柱面高度三个因子来决定柱面模型

(3) 基础图元(核心概念,难度系数:3.5/5)
射线:与射线坐标系的定义一样,因此射线坐标系可以不需要单独考虑;
三角形:三角形的法向量、面积计算、质心、重心、外心等;
平截头面Frustum:正交相机的视觉空间,ThreeJS在进行隐藏面消除时需要考虑给定片元是否在平截面内部;
包围盒:为了加快三维场景中模型的碰撞检测效率,抽象出包围盒概念。先对每个模型的包围盒进行相交检测,如果包围盒相交才进一步检测模型的碰撞 平面:平面的构造方程

(4) 相交检测算法(高级特性,难度系数:3.5/5)
三角形与包围盒的相交检测、与线段的相交检测、与射线的相交检测、与平面的相交检测;
球面图元与包围盒的相交检测、球面图元间的相交检测;
平截头面检测是否包含坐标点,以及与其他模型的相交检测,主要用于隐藏面消除逻辑;
平面与线段、球面、包围盒等模型对象的相交检测

(6) 插值算法(难度系数:4/5)
与D3.js大量的插值算法相比,Three.js的插值类型比较少,主要包括线性插值、三次曲线插值、离散采样插值等。在从顶点着色器通过varying修饰的变量将顶点颜色传递给片元着色器之前,webgl系统内部会自动进行一次颜色的线性插值来生成插值后的片元颜色缓冲

Scene模块(核心概念,难度系数:3/5)

三维场景对象就是宇宙,包罗万象唯独不包含camera对象。该模块下定义了雾化效果,以及scene作为容器对象继承自Object3D基类。
场景对象包含的属性包括背景图、雾化效果,以及材质特性来辅助场景中的光照模型

Camera模块(核心概念,难度系数:3.5/5)

相机模型继承自Object3D基类,因此具有事件分发、空间变换等能力,相机模型根据处理视场的形式分为透视相机(符合人类观察)、正交相交(设计领域)、立体相机(游戏场景)、阵列相机(多视角的图像合成)

Geometries模块(难度系数:4.5/5)

该目录定义了一系列常用的基础几何图形,包含线框图形、多面体、圆形、柱面体、球面、文本几何、管道图形、平面几何体,以及torus、Polyhedron、Lathe等复杂常见的图形。除了描述几何体的顶点及顶点索引,还可能顶点法向量列表、纹理的UV映射坐标

Lights模块(核心概念,难度系数:3.5/5)

计算机图形学的难点在于如何精细化描述光照对模型表面着色效果的影响。并且高级的光学理论和模型表面物理特性的计算过程往往过于复杂,因此需要一系列巧妙的算法来平衡渲染性能和渲染质量。
当然threejs系统暴露给开发者的光照API都比较简洁,通过简短的代码即可实现满足业务需求的光照。但是作为希望进入图形学领域的开发者来说,一定要记住光照过程是非常复杂的!!
(1)Light基类
Light基类同样继承自Object3D基类,定义了光学颜色属性、光照强度属性和对阴影的处理。模型表面的着色效果由光色、模型基底色,以及模型表面法向量和光线角度等因素共同决定

(2)LightShadow
光线与模型交互可在场景中形成阴影效果,LightShadow类的属性包括相机、视图变换矩阵等。很容易理解,虽然光线和模型交互可以产生阴影效果,但是观察者位置决定了阴影在裁剪空间的表现

(3)AmbientLight环境光照
环境光照等价于模型表面全方向均匀光照,因此环境光照的着色效果至于光照颜色和模型表面基底颜色相关

(4)DirectionalLight方向光
典型的方向光是太阳光,即太阳光作为平行光照射到模型表面。模型表面基底色、模型表面粗糙度、模型表面折射率,以及模型表面法向量和入射光夹角等共同作用影响最终着色

(5)PointLight点光源
实际应用中可以将室内白炽灯抽象为点光源,点光源与模型表面距离、光照强烈衰减率,光照夹角和模型表面法向量等因素共同决定模型表面着色效果

Textures纹理(核心概念,难度系数:3.5/5)

纹理贴图用于增强三维场景的表现力,纹理贴图对象原型继承自EventDispatch类,具有事件分发能力。因此在完成纹理贴图时可以触发场景更新逻辑,针对多样化的三维场景,纹理贴图从简单的ST贴图到复杂的各向异性贴图都有实现。

(1)VideoTexture
视频贴图,即将视频信息贴图到模型表面。在WebGL底层实际上是对视频帧贴图到模型表面并通过eventDispatch事件分发来触发场景渲染更新

(2)CubeTexture
立体贴图默认采用环境反射贴图,比如在场景中的镜面反射环境信息时的贴图。其实现方式是采用六个平面图像形成天空盒模型

(3)DataTexture
所谓数据贴图,依赖于数据类型和数据格式的贴图方式。如果数据类型为THREE.unsignedByteType,则使用uint8Array声明纹素数据

(4)CanvasTexture
所谓canvas贴图,即使用canvas对象绘制图像并作为纹理来源贴图到模型表面

materials材质(核心概念,难度系数:4/5)

材质概念其实是一种处理光照过程的抽象,three.js中的材质类包含大量的纹理模型、颜色混合模式、片元深度检测、阴影开启开关,以及模型皮肤形变过程等大量属性。

(1)LineBasicMaterial
最简单的材质类型,定义了线段的宽度、颜色、端点形态和线段连接方式

(2)LineDashedMaterial
虚线材质,必然需要定义虚实的比例。

(3)MeshBasicMaterial
在建模时经常使用线框模型,因此线框基础材质包括线框的连接形态、镜面反射材质、环境材质、alpha透明度材质、光照材质等属性

(4)MeshDepthMaterial
具有深度信息的线框材质,比基础版线框材质更加逼真

(5)MeshLambertMaterial
兰伯特材质是兰伯特光照模型的模拟,用于对粗糙表面的漫反射光照过程进行近似

(6)MeshNormalMaterial
基于模型片元法向量的光照着色,比Lambert着色效果更逼真

(7)MeshPhongMaterial
Phong冯式高光着色模型,可以根据光照入射角、观察者视角和片元法向量三者的关系来动态计算表面着色。在Phong光照模型中,引入了half-vector概念,便于加速着色过程

(8)PointsMaterial
在点云系统中,点材质可定义点对象的基底色、纹理对象、尺寸等属性

Renders渲染器(核心概念,难度系数:5/5)

three.js库是一个渲染库,即该库的核心能力是将几何模型通过渲染管线转换为屏幕上的图像。与图表库D3.js抽象了绘制API一样,three.js的渲染API也进行了屏蔽,一般采用canvas的绘制API,当然也支持CSSRender等

(1)shaders着色器目录
UniformsUtils: 顶点着色器和片元着色器通过uniform修饰的变量来传递参数。其中uniform可以修饰的变量类型包括matrix、vector、texture和color等。这个模块的作用就是提供对uniform修饰的变量的合并和复制操作

UniformsLibs: 定义了常用的贴图模型、光源类型,以及纹理映射坐标系统等

ShaderLib: 在ShaderLib目录下才是完整的可被编译使用的着色器,GLSL着色器使用C-like语言编写,通过#include语法引入ShaderChunk目录下的着色器片段代码

ShaderChunk: 定义了大量的three.js内部使用的着色器代码片段。注意里面BRDF-双向反射分布函数光照着色、各种纹理着色器的实现比较复杂

(2)webvr目录
该目录下只有一个文件WebVRManager,所谓VR的实现通过一组阵列相机和两台透视相机即可。同时需要VR硬件支持,VR硬件用于捕捉用户动作姿态并编码传入计算机应用,应用将动作姿态转换为一组变换矩阵来同步修改场景中模型坐标

(3)WebGLRender
WebGL渲染器用于渲染艺术级的三维场景,three.js库抽离了渲染器的实现细节,类似d3.js库对数据布局器和数据绘制进行分离一样,这样的软件设计思路便于扩展和迁移。
WebGLRender的渲染输出到canvas画布,而其他诸如CSS3DRender或者SVGRender则分别渲染输出到CSS样式对象和SVG元素

animation动效(核心概念,难度系数:4/5)

虽然three.js不是完整的游戏引擎,而主要作为渲染引擎使用,但是其内置了基本的动效模块来满足一般场景需求。动画的本质就是图片在时间维度的运动,在这里有个思考问题即电影放映只要满足24FPS则观影流畅,而计算机实时动画则需要60FPS左右才能感受到平滑,这里面涉及到电影拍摄中帧间关联性会写入帧数据中,而实时动画的每一帧独立并不存在过渡性

(1)KeyframeTrack
关键帧轨道控制关键帧的运动,一个完整的动画可能存在多个关键帧轨道来独立处理各自的关键帧变换。

(2)tracks目录
目录下存储了一系列关键帧轨道模块,所谓动画轨道其实是方便对动画的分组管理,即在动画中不同的轨道独立控制关键帧运动。

(3)AnimationUtils
动画系统的工具函数集,包含对TypedArray的操作

(4)PropertyMixer
所谓属性混合器,其实就是对属性进行插值混合处理。目前主要是线性插值和球面插值两种方式。

(5)AnimationClip
用于对多个keyframeTrack对象进行编排,表示一个动画过程。注意场景动画中可能存在多个AnimationClip,比如角色动画中一个AnimationClip控制行走,一个AnimationClip控制跳跃,另一个AnimationClip控制慢走等

(6)AnimationAction
用于对AnimationClip进行调度的控制对象,控制动画的循环模式、淡入/淡出等

(7)AnimationMixer
对三维场景中特定模型的动画播放对象,当场景中存在多个独立动画过程,则每个动画对象由各自的AnimationMixer控制。实际上AnimationMixer只有少量的属性和方法,因为AnimationMixer被AnimationAction控制。

Loader数字资产加载(难度系数:3.5/5)

three.js是一个三维场景渲染库,因此并不关注如何构建复杂的三维空间。但是在实际应用中,复杂的场景存在百万级的顶点数据、三角化后的表面成千上万,因此无法通过编程方式来绘制场景要素。three.js提供大量辅助模块来加载标准的工业级数字资产,并且还可以自定义数字资产格式,因此通过第三方设计软件比如Blender、3DMax、Maya等快速构建复杂的模块数据,供three.js进行解析和渲染

(1)LoadingManager
通过网络加载数字资产模块,加载过程中提供一系列钩子函数来辅助开发者进行增强处理。开发者可以基于LoadingManager进行自定义扩展,方便不同应用的使用

(2)FontLoader/FileLoader
字体加载器,专门用于加载字体库,其内部使用FIleLoader来加载文件资源。而FileLoader是一个比较低层次的加载器,其不需要考虑文件结构,响应报文格式包括文本、Blob、文档、JSON、arrayBuffer等。FileLoader使用XMLHTTPRequest规范,当然随着W3C的网络接口的丰富,甚至可以使用浏览器的Fetch规范实现

(3)ImageLoader/ImageBitmap
专门用于加载图像的加载器,被纹理加载器在内部使用。加载的图像可以写入canvas,或者作为帧缓冲对象的一部分。ImageBitmapLoader用于加载位图,用于图像坐标系和透视坐标系存在差异,因此加载器根据配置项进行处理

(4)TextureLoader/DataTextureLoader
纹理加载器在内部使用图像加载器来加载纹理图像,而数字纹理加载器用于加载通用的二进制纹理格式,比如RGBE、HDR等

(5)BufferGeometryLoader
专门用于加载BufferGeometry的模块,其内部实现使用FileLoader来加载文件,值得注意的是特化的加载器才有parse方法,用于解析具体的资产格式

(6)AnimationLoader
在three.js的动画系统中,keyFrameTrack对象在时间维度上对某个属性进行插值提取关键帧;而AnimationClip可以控制一组keyFrameTrack来作为动画帧基础,对于复杂的三维应用,三方设计软件会导出带动效的角色模型,因此该加载器的作用就是加载动画数据文件

(7)MaterialLoader
在计算机图形学中,材质是一个复杂概念,主要作用于模型表面的光照过程,材质加载器的实现基于FileLoader来加载材质文件。材质对象本身也会依赖纹理对象,纹理对象可以在模型光照过程中产生高效逼真的渲染效果

(8)ObjectLoader
第三方设计软件导出的数字资产可能是一个独立的JSON对象,因此通过对象加载器进行加载并解析出场景渲染所需的全部信息,比如几何数据、材质数据、动效数据、纹理数据、图像数据等。这是一个非常通用强大的加载器,可以解析计算机图形学中任何的结构性对象

audio音频动效(难度系数:3.5/5)

three.js库的音频系统遵循WebAudio规范,因此可以在支持WebAudio的浏览器端直接使用厂商实现。

(1)AudioContext
ctx对象控制音频的处理、播放和分析等,类似canvas的ctx对象。

(2)AudioAnalyser
音频分析器接受audioCtx上下文对象和FFT分析算法模型,分析音频数据的频域、时域信息

(3)PositionalAudio
空间音频是目前三维场景中的重要辅助要素,所谓空间音频就是声音源位于空间某处,向观察者传播中的衰减变换过程

(4)AudioListener
音频监听器,监听处理音频的增益、空间传播变化过程

About

对Three 3D渲染库的代码注解

https://threejs.org/


Languages

Language:JavaScript 92.0%Language:GLSL 8.0%