立方纹理(天空盒)和 标准网格材质进阶
学习ThreeJS的捷径
本段内容会写在0篇以外所有的,本人所编写的Threejs教程中
对,学习ThreeJS有捷径
当你有哪个函数不懂的时候,第一时间去翻一翻文档
当你有哪个效果不会做的时候,第一时间去翻一翻所有的案例,也许就能找到你想要的效果
最重要的一点,就是,绝对不要怕问问题,越怕找找别人问题,你的问题就会被拖的越久
如果你确定要走WebGL/ThreeJS的开发者路线的话,以下行为可以让你更快的学习ThreeJS
- 没事就把所有的文档翻一遍,哪怕看不懂,也要留个印象,至少要知道Threejs有什么
- 没事多看看案例效果,当你记忆的案例效果足够多时,下次再遇到相似问题时,你就有可能第一时间来找对应的案例,能更快解决你自己的问题
- 上述案例不只是官网的案例,郭隆邦技术博客,跃焱邵隼,暮志未晚等站点均有不少优质案例,记得一并收藏
http://www.yanhuangxueyuan.com/ 郭隆邦技术博客
https://www.wellyyss.cn/ 跃焱邵隼
http://www.wjceo.com/ 暮志未晚
这三个站点是我最常逛的站点,推荐各位有事没事逛一下,看看他们的案例和写法思路,绝对没坏处
立方纹理CubeTexture
立方纹理简介
在开这一篇之前,要先讲一讲立方纹理
上图是一个BoxGeometry的展开图,以及一张随手百度到的天空盒的图片
展开图有很多种,这里不是数学课就以这个为例
如上图的这样的纹理,被贴到盒子6个面的纹理,被称为 立方纹理CubeTexture
立方纹理及其简单,就是一套由6张图组成的图片包,这个纹理可以被贴到立方体的六个面,所以我们又有个说法叫它天空盒,而我们使用的图片组合,有时候也被称为全景图,threejs中给的比较官方的名称为立方纹理
立方纹理小案例
这里我们以官方的素材在这里开一个简单的案例
一般来说,我们要想让立方纹理完美拼合,threejs有如下加载规则
threeJS中天空盒加载顺序 px,nx,py,ny,pz,nz 或 left,right,top,bottom,front,back
一般提供全景图片全景照片的人,都会刻意标注出来每张图的位置
threejs加载这些图片也极其简单
我的文件结构如上
function addMesh(){
let loader = new THREE.CubeTextureLoader();
//设置加载图片组的路径
loader.setPath('./Park2/');
//threeJS中天空盒加载顺序 px,nx,py,ny,pz,nz 或 left,right,top,bottom,front,back
//一定要按顺序加载,否则会出现严重的拼合错误问题
loader.load([
"posx.jpg",
"negx.jpg",
"posy.jpg",
"negy.jpg",
"posz.jpg",
"negz.jpg",
],(texture)=>{
scene.background = texture;
});
}
案例效果
scene.background 可以允许使用立方纹理,这样我们生成的背景将具有很强的立体感
立方纹理常见错误
如果你的图片没有按顺序加载,大概率就会出现像下面这样的拼合错误问题,包括输出全景图的人命名不规范也会造成相关的问题
StandardMaterial常用属性
1. 环境贴图EnvMap
EnvMap官方解释
这里的环境贴图的属性,虽然要求是一个Texture,但是我们一般使用的时候,都尽量使用CubeTexture而非常规的Texutre
在文档中查看envMap的演示效果
在StandardMaterial官方文档中,我们看到其中有一个属性envMaps
但是设置它似乎没有什么作用,当我们把roughness拉到0,metalness拉到1时,出现了很明显的效果
这里面出现了镜面的效果吗?不是,这里仅仅反射的是 CubeTexture
这里使用的全景图,可以在这个案例中看到效果官方的CubeMap演示
然后我们把颜色拉到白色时,我们就能看到比较清晰的全景图
想要给你的材质添加这种反射效果,也很简单
案例代码
function addMesh(){
let loader = new THREE.CubeTextureLoader();
loader.setPath('./Park2/');
//threeJS中天空盒加载顺序 px,nx,py,ny,pz,nz 或 left,right,top,bottom,front,back
loader.load([
"posx.jpg",
"negx.jpg",
"posy.jpg",
"negy.jpg",
"posz.jpg",
"negz.jpg",
],(texture)=>{
let material = new THREE.MeshStandardMaterial({
roughness:0,
metalness:0.5,
envMap:texture //创建完立方纹理后,作为StandardMaterial的envMap来使用
});
let geometry = new THREE.BoxGeometry(100,1,1);
let mesh = new THREE.Mesh(geometry,material);
scene.add(mesh);
scene.background = texture;
});
}
案例效果
接下来就请各位自行研究,看看调整Roughness和Metalness对envMap的影响
2. 法线贴图NormalMap
法线贴图官方介绍
简单说,我们看到的很多效果,其实并不是建模的细节有多么精致,而是法线贴图在帮忙
法线贴图展示
我们以官方的这个案例为例https://threejs.org/examples/#webgl_nodes_materials_physical_clearcoat
尤其是左下角的这个白色的球,我们看到了很多很多的小坑,但是这些小坑并非是因为模型就是这样,因为法线贴图改变了它的光照
官方的案例源码指引了资源的位置
这个就是这个球体的法线贴图,有没有觉得单独看贴图都有不错的立体感呢?
如何获取法线贴图
一般来讲,法线贴图都是由建模师提供
关于法线贴图的具体制作方式,请自行决定是否要去了解与学习
笔者这里仅建议了解清楚法线贴图是什么用途即可
法线贴图案例
let scene,renderer,camera,orbitControls;
function init(){
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({
alpha:true,
antialias:true
});
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,0.01,50000);
camera.position.set(10,10,10);
orbitControls = new OrbitControls(camera,renderer.domElement);
//由于法线贴图是受光照影响的,所以我们这里需要添加相机灯
camera.add(new THREE.PointLight());
scene.add(camera);
let helper = new THREE.GridHelper(50,10);
scene.add(helper);
}
function addMesh(){
let textureLoader = new THREE.TextureLoader();
textureLoader.load('./golfball.jpg',(texture)=>{
let geometry = new THREE.SphereGeometry(5,32,32);
let material = new THREE.MeshStandardMaterial({
normalMap:texture
});
let mesh = new THREE.Mesh(geometry,material);
scene.add(mesh);
})
}
function render(){
renderer.render(scene,camera);
requestAnimationFrame(render);
}
代码和上面的envMap一样,特别简单,但是由于添加了法线贴图,使得球体的立体感直线上升
通过修改法线贴图强度来调整立体感
同时我们可以通过控制法线贴图的影响比例,来调整法线贴图的效果强度
注意,normalScale是一个vector2对象,也就是说我们需要同时设置x和y的值才能生效
let material = new THREE.MeshStandardMaterial({
normalMap:texture
});
//创建材质后,将法线贴图影响降低到0.1
material.normalScale.set(0.1,0.1);
修改结果
我们依然能看到一些细节,但是已经不如之前那么强烈了,更像是一个被磨平的球
3. 放射光Emissive
Emissive,自发光,放射光,发光效果的纠正
先纠正一点,Emissive也有翻译为自发光 ,但是自发光和发光效果是两码事,非常非常多的人把自发光理解为了发光效果,实际上我们常说的自发光,是指 放射光Emissive,而非发光效果
如上图这样的效果我们一般称为发光效果,所以在谈到自发光的时候,绝绝对对不要弄混了
放射光Emissive介绍
官方只是对这几个属性做了解释,根本没有讲清楚emissive和emissiveMap是干嘛的
我们在平时使用StandardMaterial的时候,需要使用光源,才能让材质达到一个最好的效果,因为StandardMaterial是对光源有反应的,如果我们本身让物体具有亮度呢?
emissive本质上是让这个材质本身具有发光的功能,使得我们不需要创建光源也能看到这个物体
放射光Emissive的简单案例
function addMesh(){
let geometry = new THREE.SphereGeometry(5,32,32);
let material = new THREE.MeshStandardMaterial({
emissive:"#ffffff",
emissiveIntensity:0.5,
});
let mesh = new THREE.Mesh(geometry,material);
scene.add(mesh);
}
这样创建的StandardMaterial,即使你的场景中没有光源,它依然能够被看到
emissive是它本身的光的颜色,一般默认是黑色,因为正常情况下我们使用StandardMaterial都是会添加光源的,所以这里必须为黑色,这里的颜色最终也会参与到颜色计算,一般我们都用白色或黑色
emissive可以理解为不需要光照的 color属性
emissiveMap是 放射光/自发光 贴图,这里的贴图可以理解为,不需要光照的map属性,属性值是一个常规Texture对象,基本上和map一样,不需要做像法线贴图那样的特殊处理
4. 其他贴图
关于Standard材质的文档中,还有好几个贴图笔者在这里就不做过多介绍了,很少有用到,如果你们合作的建模师是那种非常专业级的,那么很多的问题可以完全可以用贴图来解决
比如说:
处理透明度的alphaMap,
处理环境遮挡效果的aoMap,
创建凹凸效果的bumpMap
无需光源就能被看到的emissiveMap
无需光照就能反馈光照效果的lightMap
处理金属度的metalnessMap
处理粗糙度的roughnessMap
如果一个模型把上述的贴图全部都包含了,那么我们也无需对场景和模型做太多处理,全部直接导入就能看到比较好的效果了
关于 Standard材质与其他材质
Standard材质用途极其广泛
以笔者的经历来说,Standard材质可以说是Threejs的重中之重,几乎所有好看的效果,都是基于StandardMaterial,包括效果更好的MeshPhysicalMaterial,都是基于StandardMaterial的基础上开发的
建模软件里的标准材质,也基本都是对应Threejs中的StandardMaterial
Standard难在经验而非理解
这个材质其实属性就那么点,但是想用这个材质做出好看的效果,不仅需要你靠着大量的调整数据,增加贴图之类的操作积累经验,背后还需要有一个强力的美术工作者来提供好看的设计方案与贴图
其他材质的简单介绍
官方共计提供了18种材质,除去超类Material共计17种,这里对这些材质做简单介绍
Line材质
LineBasic和LineDashed在后面讲解线条的时候讲解,难度极低
Basic材质
Basic材质主要用于创建完全不受光照影响,然后又不需要好看的效果的物体,比如说指向用的箭头
Lambert材质
Lambert材质在做粗糙度物体上比较有优势,如果你的场景中元素特别多,而且都是粗糙的物体,需要从材质角度来优化的话,可以选择不用Standard材质,替换为Lambert材质
Normal材质
这个材质笔者仅在做案例时用过一次,除了做彩虹这种五颜六色的东西,笔者想不到有什么东西能用到这个材质
Phong材质
低配版的Standard材质,计算量要比Standard要低,理解和学习难度也比Standard材质要低
部分FBX格式的模型,导入到threejs中,会被创建为Phong材质,如果你的项目规定必须用FBX格式,可以自行了解一下这个材质
Physical材质
高配版的Standard材质,如果你需要你的项目效果更好,可以使用这个来替代Standard材质
Toon材质
卡通材质,感觉更像是官方开发着玩的材质,因为看起来非常有绘画和卡通的感觉
Points和Sprite材质
后续在讲到粒子效果和精灵时会着重讲解
Shadow材质
专门用于接收阴影的材质,不接收阴影时材质显示为纯透明,当你需要一个东西来接收阴影,但是你又不适合放一个实体的时候,可以使用这个材质
Shader材质和RawShader材质
这是整个Threejs最难的地方,Shader创建了threejs,threejs创建了ShaderMaterial来简化Shader的写法,已经对Shader做了简化,但是无法改变Shader本身难度过高的问题
Shader材质也是Threejs的重中之重,但是把它放到材质篇讲对于1~3年经验的threejs开发者来说又难度过高,笔者也只是刚刚入门的水平
所以关于这两种材质后续会有专门的文章着重讲解
其他材质
本文没有提到的材质,在笔者的3年经验中从未使用,不做讲解,有兴趣的可以自行学习和了解
下一篇预告
Standard材质简单应用