在前文《ThreeJS:Geometry与顶点|索引|面》中,我们了解了与Geometry几何体相关的基础概念,也尝试了如何通过BufferGeometry自定义几何体。
常见Geometry几何体
ThreeJS内部也提供了诸多封装好的几何体,常见的Geometry几何体如下图所示,
基础材质入门
图形学中,模型/三维实体的外观是光照和材质共同作用的结果,而渲染方程中,由BRDF(Bidirectional Reflectance Distribution Function)双向反射分布函数来决定材质。所以,Material == BRDF。
什么是BRDF?
在计算机图形学中,BRDF代表双向反射分布函数(Bidirectional Reflectance Distribution Function)。BRDF用于描述材质表面对入射光的反射特性。它是一个函数,以入射光方向、观察者方向和表面法线为输入,给出了在给定方向上的反射光强度。
BRDF定义了光线从表面反射的方式,包括反射的光线强度、反射方向以及光的能量分布。它考虑了光线的入射角度、出射角度和表面法线方向对反射的影响。通过使用不同的BRDF模型,可以模拟不同类型的材质,如漫反射、镜面反射、透射等。 在渲染过程中,通过计算表面上每个点的BRDF,可以确定光线如何被反射和散射,从而呈现出真实的光照效果。BRDF在计算机图形学中是一个重要的概念,它对于渲染和可视化的真实感和逼真感起着至关重要的作用。
——摘自《ChatGPT回复---计算机图形学中,BRDF是什么?》
基础概念:材质|纹理|着色器
在WebGL三维应用开发中,经常听到“着色器”、“纹理贴图”、“材质”、“阴影”等相关术语,很多时候,我们会将其混为一谈,因为它们都是用于表达三维场景中的光影效果的。但是,这几者本质上还是有所区别的,如下表所示,
其中:
①Material材质:ThreeJS、CesiumJS等基于WebGL的JavaScript库中,都提供了Material材质相关的API接口,用于表现物体对光的交互,其底层是由纹理贴图mapping、光照算法algorithm以及Shader着色器程序配合实现的;
②Texture mapping纹理贴图:即通俗意义上的图片,可以视为一个存储了像素数据的二维数组,按照其具体用途,又可分为:漫反射/颜色贴图(Diffuse Map)、法线贴图(Normal Map)、高光贴图(Specular Map)、置换贴图(Displacement Map)、AO贴图(Ambient Occlusion map)、光泽贴图(Gloss Mapping)等。此外,还可以基于Shader着色器程序使用数学描述的方式,动态生成程序化纹理(Procedural Texture)。
③Shader着色器:即通常所说的由顶点着色器和片元着色器共同作用下构成的着色器程序;
④Shading着色:通过平行线或色块使插图或图表变暗或上色,对图形学来说,就是将材质应用到对物体表面的过程。在WebGL中,可以借助Material材质实现着色的目的。
在ThreeJS中,如下图所示,就是一个应用环境贴图到3D模型表面,最终生成的效果,
又如, 我们也可以手动编写Shader着色器程序,纯代码实现如下图所示的笑脸图案,
纹理映射与UV映射
什么是纹理映射呢?
纹理映射是将一张二维图像(纹理)映射到三维物体表面上的过程。这个过程通过将纹理坐标映射到物体表面的每个顶点上,再通过插值法在顶点之间进行纹理坐标的传递,最终在物体表面上生成纹理。这样可以为物体表面添加细节、颜色、图案等,使得渲染结果更加真实。
而UV映射是纹理映射的一种常用方法,它将物体的表面划分为一组二维坐标,通常用UV坐标表示。每个顶点都与一个UV坐标相关联,这些坐标定义了纹理图像中对应的位置。通过将纹理坐标与物体表面的几何信息相对应,可以实现将纹理正确地映射到物体表面的功能。
在WebGL中,将纹理贴图应用在三维物体表面时,通常使用UV映射(UV Mapping)的概念来描述。UV映射是一种将纹理坐标映射到三维物体表面的方法,它使得可以将纹理贴图正确地映射并渲染在物体表面上。通过为物体的每个顶点指定对应的UV坐标,可以将纹理的颜色和纹理坐标关联起来,从而实现纹理贴图的效果。
总的来讲:纹理贴图在WebGL三维应用开发中的应用,UV映射是关键的一环。
常用的纹理贴图
前面我们提到,Texture mapping纹理贴图:即通俗意义上的图片,可以视为一个存储了像素数据的二维数组,按照其具体用途,又可分为:漫反射/颜色贴图(Diffuse Map)、法线贴图(Normal Map)、高光贴图(Specular Map)、置换贴图(Displacement Map)、AO贴图(Ambient Occlusion map)、光泽贴图(Gloss Mapping)等。此外,还可以基于Shader着色器程序使用数学描述的方式,动态生成程序化纹理(Procedural Texture)。
颜色贴图Diffuse Map
Diffuse Map颜色贴图,顾名思义,就是用于:表示物体表面的颜色,即:rgba颜色分量的分布情况,
AO贴图Ambient Occlusion Map
Ambient Occlusion Map(环境遮挡贴图)简称AO贴图,是一张灰度图,用于模拟物体之间所产生的阴影,在不打光的时候可以用于增加体积感,它可以增加渲染的真实性,例如:上面的木板颜色贴图对应的Ao贴图如下,
置换贴图Displacement Map
Displacement Map置换贴图,可以改变模型对象的几何形状,因此在提供最真实的效果的同时也会大幅增加渲染性能的开销。置换贴图也常作为高度图来生成地形,并结合凹凸贴图实现丰富的地形效果。
高光贴图(Specular Map)
Specular Map,高光贴图,用来表现物体对光照反应的材质。 当光照到塑料,布料,金属上时,所展现出来的高光部分和高光表现是不一样的。 通过高光贴图上的颜色值来表现高光的强度,值越大表示高光反射越强。
高光贴图可以方便的控制物体各个布局区域的光照反射强度,即:灰度值越大表示高光反射越强(0不反射,255反射强度最大)。
法线贴图(Normal Map)
法线贴图包含角度信息而不包含任何高度信息,其R、G、B三个通道储存的信息表示了斜面的方向和陡峭程度。
详细可参见:游戏资源中常见的贴图类型 - 知乎。
ThreeJS:贴图的加载
TextureLoader纹理加载器
ThreeJS提供了纹理加载器,用于实现纹理贴图的加载操作,
使用方式如下,
const texture = new THREE.TextureLoader().load( 'textures/land_ocean_ice_cloud_2048.jpg' );// 立即使用纹理进行材质创建
const material = new THREE.MeshBasicMaterial( { map: texture } );
颜色贴图加载案例
ThreeJS的MeshBasicMaterial基础网格材质,提供了map颜色贴图、alphaMap透明度贴图、aoMap环境光遮挡贴图、lightMap光照贴图、.specularMap高光贴图、envMap环境贴图的属性。
通常的,颜色贴图用于设置物体表面的RGB颜色表现效果,AO贴图用户表现局部细节;alphaMap透明度贴图(灰度图)可用于控制物体表面的局部透明度效果。
例如,我们创建一个平面,然后为其设置颜色贴图,
//TOOD:纹理贴图加载器
const textureLoader = new THREE.TextureLoader();//TODO:创建平面
const planeGoemetry = new THREE.PlaneGeometry(1,1);
const planeMaterial = new THREE.MeshBasicMaterial({color:0xffffff,side:THREE.DoubleSide,//TODO:设置纹理贴图map:textureLoader.load('images/dry_riverbed_rock_diff_1k.jpg'),//颜色纹理transparent:true,alphaMap:textureLoader.load('images/dry_riverbed_rock_disp_1k.png'),//AO贴图
})
const planeMesh = new THREE.Mesh(planeGoemetry,planeMaterial);
scene.add(planeMesh)
环境贴图加载案例
环境贴图通常是使用HDR全景图作为资源,可从HDRI • Poly Haven进行下载,例如:我们下载一张如下所示的环境贴图,
ThreeJS加载环境贴图需要使用到对应的HDR加载器RGBELoader,
//TODO:HDR加载器
const hdrLoader = new RGBELoader();//TODO:加载环境贴图
const hdrTexture = hdrLoader.load('images/chapel_day_4k.hdr',function(envMap){//设置球形映射envMap.mapping = THREE.EquirectangularReflectionMapping; //设置环境贴图scene.background = envMap;
})
显示效果如下,
接下来,我们可以为前面创建的Plane平面设置环境贴图,在不同观察角度,就可以跟随环境变化,产生不同的光照反射的效果,