一、环境贴图
- 我们经常看到在一些网站当中会有全景(vr) 的效果,这里的效果使用threejs可以快速的实现。
-
- CubeTextureLoader加载立方体环境纹理
- RGBELoader环境纹理加载(推荐)
1. CubeTextureLoader加载立方体环境纹理
- 使用CubeTextureLoader 等同于我们把我们的空间当中一个盒子,然后我们身处在盒子当中,然后给这个盒子的上下左右前后6个面都贴上对应的环境图片,从而呈现出一个全景的效果。threejs会帮我们计算和渲染好衔接的各个图片现阶段部分。
- 创建盒装环境纹理贴图
要使用的6张图片threejs官方的例子的目录下有提供,可以直接使用
图片名称中的 neg 是 negative (反面)的简写
pos 是 positive (正面)的简写
const cubeTexture = new THREE.CubeTextureLoader()
.setPath('../examples/textures/cube/Park2/') // setPath可以设置贴图的文件放置目录
.load([ // 加载6个面对应的贴图材料 顺序不能乱改
'posx.jpg',
'negx.jpg',
'posy.jpg',
'negy.jpg',
'posz.jpg',
'negz.jpg',
]);const cubeTexture = new THREE.CubeTextureLoader()
.setPath('../examples/textures/cube/Park2/') // setPath可以设置贴图的文件放置目录
.load([ // 加载6个面对应的贴图材料 顺序不能乱改
'posx.jpg',
'negx.jpg',
'posy.jpg',
'negy.jpg',
'posz.jpg',
'negz.jpg',
]);
- 将盒装环境贴图添加给场景
scene.background = cubeTexture;scene.background = cubeTexture;
2. RGBELoader环境纹理加载(推荐)
-
cubeTexture 的实现往往需要6张图片来完成,而使用RGBELoader这个扩展我们可以仅仅加载一个hdr文件就可以完成等同的功能,而且这类的素材会更容易获取。
-
通过下面的网站可以获取到 hdris 纹理素材
-
- https://polyhaven.com/hdris
- 先引入 RGBELoader 扩展库
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'
- 新建 加载器
const loader = new RGBELoader(); // 创建一个 RGBE加载器 目的是为了能够加载hdr文件const loader = new RGBELoader(); // 创建一个 RGBE加载器 目的是为了能够加载hdr文件
- 加载hdr文件然后修改场景的背景
loader.loadAsync('../assets/belfast_farmhouse_4k.hdr').then(texture=>{
texture.mapping = THREE.EquirectangularReflectionMapping; // 将加载的材料给整体的背景进行贴合
scene.background = texture
})loader.loadAsync('../assets/belfast_farmhouse_4k.hdr').then(texture=>{
texture.mapping = THREE.EquirectangularReflectionMapping; // 将加载的材料给整体的背景进行贴合
scene.background = texture
})
二、PBR材质
- 在使用PBR材质之前我们创建的场景都称之为仿真场景。
- 经过了14节课的学习我们在3d场景当中我们加载了一个仿真的环境场景,而我们的3D模型放置在这样的环境当中如果需要呈现更接近于现实的场景的话就得使用PBR材质,PBR材质的概念是我们通过threejs构建出更符合物理特性(反光,折射)的材料。
- PBR 材质主要采用的是 MeshStandardMaterial 和 MeshPhysicalMaterial 来构建。我们通过使14节课的环境场景来学习PBR材质的使用
const geometry = new THREE.SphereGeometry( 1, 32, 16 ); const geometry = new THREE.SphereGeometry( 1, 32, 16 );
1. 金属材质
然后我们通过 MeshStandardMaterial 来构建一个PBR材质
metalness 金属度 取值范围 0-1 0 完全非金属 1完全的金属
roughness 材质表面的粗糙程度 0 完全光滑 1完全漫反射(极度不平整)
envMap 环境材料 ,取值为一个环境贴图,表示物体的表面的内容会结合当前的所在的周边环境(倒影反射等)
envMapIntensity: 材料跟环境的结合程度 1 完全贴合
const material = new THREE.MeshStandardMaterial({
metalness: 1.0, // 金属度
roughness: 0, // 粗糙程度 1 表示漫反射 0完全光滑(镜面效果更明显)
envMap: cubeTexture, //给材料也设置一个指定的环境贴图
envMapIntensity: 1
})const material = new THREE.MeshStandardMaterial({
metalness: 1.0, // 金属度
roughness: 0, // 粗糙程度 1 表示漫反射 0完全光滑(镜面效果更明显)
envMap: cubeTexture, //给材料也设置一个指定的环境贴图
envMapIntensity: 1
})
跟以往一样新建 网格模型并添加到场景当中
const ball = new THREE.Mesh( geometry, material );
scene.add( ball );const ball = new THREE.Mesh( geometry, material );
scene.add( ball );
2. 玻璃材质
能跟我们环境相关的材质处理金属以外,最常见的就还有玻璃。 我们使用MeshPhysicalMaterial来实现玻璃材质的效果。
对比金属材质,玻璃的效果需要多设置以下的两个属性
transmission 透光率
ior:折射率 不同的材质的折射率有所不同 ,可参考https://baike.baidu.com/item/%E5%B8%B8%E7%94%A8%E6%8A%98%E5%B0%84%E7%8E%87%E8%A1%A8/663686?fr=aladdin
const glassMaterial = new THREE.MeshPhysicalMaterial({
transmission:1, // 设置材质的透光率
ior: 1.5, // 材质的折射率 0 - 2.33
metalness: 0,
roughness: 0.1,
envMap: cubeTexture,
envMapIntensity: 1 // 环境贴图对于Mesh表面的影响程度
})
const ball2 = new THREE.Mesh(geometry,glassMaterial);
ball2.position.x = 3;
scene.add( ball2 );const glassMaterial = new THREE.MeshPhysicalMaterial({
transmission:1, // 设置材质的透光率
ior: 1.5, // 材质的折射率 0 - 2.33
metalness: 0,
roughness: 0.1,
envMap: cubeTexture,
envMapIntensity: 1 // 环境贴图对于Mesh表面的影响程度
})
const ball2 = new THREE.Mesh(geometry,glassMaterial);
ball2.position.x = 3;
scene.add( ball2 );
三、光和阴影
- 在学了环境贴图和几何体之后我们对于3d世界的效果要求就会越来越高,所以我们对于有光线的场景当中的阴影也会有一定的要求,这样做出的3d场景会更加的真实。
- 给渲染器开启阴影配置
// 开启渲染器的阴影渲染
renderer.shadowMap.enabled = true;// 开启渲染器的阴影渲染
renderer.shadowMap.enabled = true;
- 新建一个地板模型,我们会让光线照射几何体然后在地板上呈现出光影的效果
// 添加一个地板
const floorGeogemtry = new THREE.PlaneGeometry(30,30);
const material = new THREE.MeshLambertMaterial({
color: 0xffffff
})
const floor = new THREE.Mesh(floorGeogemtry, material )
floor.rotateX(-Math.PI/2); // 平放// 添加一个地板
const floorGeogemtry = new THREE.PlaneGeometry(30,30);
const material = new THREE.MeshLambertMaterial({
color: 0xffffff
})
const floor = new THREE.Mesh(floorGeogemtry, material )
floor.rotateX(-Math.PI/2); // 平放
- 阴影最终是落在地板上,所以地板模型需要开启接收阴影生成的配置
floor.receiveShadow = true;floor.receiveShadow = true;
- 创建一个几何体,几何的位置要在平板之上
const ballGeomerty = new THREE.SphereGeometry(1,30,16);
const ball = new THREE.Mesh( ballGeomerty , material);
ball.position.y = 2;const ballGeomerty = new THREE.SphereGeometry(1,30,16);
const ball = new THREE.Mesh( ballGeomerty , material);
ball.position.y = 2;
- 因为阴影是通过几何体生成的,所以需要给几何体设置阴影属性配置
ball.castShadow = true;ball.castShadow = true;
- 开始添加光源。最常见的能形成阴影的三种光源是
-
-
PointLight 点光源,由一个点开始沿着这个点的各个方向发散的光 ( 灯泡发出的光 )
-
DirectionalLight 平行光,只沿着一个方向照射不会发散的光源 ( 一般用来模拟太阳直射 )
-
SpotLightHelper 聚光源,有一个点沿着一个方向带有一定发散角度的光 ( 舞台的聚光灯)
-
// 点光源
const pointLight = new THREE.PointLight( 0xffffff, 1 );
pointLight.position.set(50, 50, 50);
scene.add( pointLight );
pointLight.castShadow = true;
// 默认的阴影效果有时候会比较差 我们可以通过修改阴影贴图的大小来让它的效果进行优化
// 通过修改阴影贴图的大小来优化 ( 默认是512*512 )
pointLight.shadow.mapSize.width = 1024;
pointLight.shadow.mapSize.height = 1024;
// 可以给阴影设置一个边缘模糊
pointLight.shadow.radius = 3;
// ---
// 平行光源一般是用来模拟大自然当中的 阳光直射的效果
const directLight=new THREE.DirectionalLight( 0xffffff, 0.5 );
// 光源的位置
directLight.position.set(50, 50, 50);
// 对于光线我们也要开启 castShadow 才能产生阴影效果
directLight.castShadow = true;
scene.add( directLight );
// ---
// 聚合光源
const spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set(50, 50, 50);
spotLight.castShadow = true;
scene.add( spotLight );// 点光源
const pointLight = new THREE.PointLight( 0xffffff, 1 );
pointLight.position.set(50, 50, 50);
scene.add( pointLight );
pointLight.castShadow = true;
// 默认的阴影效果有时候会比较差 我们可以通过修改阴影贴图的大小来让它的效果进行优化
// 通过修改阴影贴图的大小来优化 ( 默认是512*512 )
pointLight.shadow.mapSize.width = 1024;
pointLight.shadow.mapSize.height = 1024;
// 可以给阴影设置一个边缘模糊
pointLight.shadow.radius = 3;
// ---
// 平行光源一般是用来模拟大自然当中的 阳光直射的效果
const directLight=new THREE.DirectionalLight( 0xffffff, 0.5 );
// 光源的位置
directLight.position.set(50, 50, 50);
// 对于光线我们也要开启 castShadow 才能产生阴影效果
directLight.castShadow = true;
scene.add( directLight );
// ---
// 聚合光源
const spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set(50, 50, 50);
spotLight.castShadow = true;
scene.add( spotLight );
-
- 注意:光源对象也要开启阴影属性:
directLight.castShadow = true;
- 注意:光源对象也要开启阴影属性:
- 通过GUI去调试不同的位置的光源的效果
// 记得要先引入GUI:import { GUI } from 'jsm/libs/lil-gui.module.min.js';
const gui = new GUI();
gui.add(lightPos,'x',30,80).name('光源的x').onChange(val=>pointLight.position.x=val)
gui.add(lightPos,'y',30,80).name('光源的y').onChange(val=>pointLight.position.y=val)
gui.add(lightPos,'z',30,80).name('光源的z').onChange(val=>pointLight.position.z=val)// 记得要先引入GUI:import { GUI } from 'jsm/libs/lil-gui.module.min.js';
const gui = new GUI();
gui.add(lightPos,'x',30,80).name('光源的x').onChange(val=>pointLight.position.x=val)
gui.add(lightPos,'y',30,80).name('光源的y').onChange(val=>pointLight.position.y=val)
gui.add(lightPos,'z',30,80).name('光源的z').onChange(val=>pointLight.position.z=val)
- 通过光线辅助器,观察光线位置
// 平行光源辅助器
scene.add( new THREE.DirectionalLightHelper(directLight,5) )
// 点光源辅助器
scene.add( new THREE.PointLightHelper(pointLight,5))
// 聚合光源辅助器
scene.add( new THREE.SpotLightHelper(spotLight) )// 平行光源辅助器
scene.add( new THREE.DirectionalLightHelper(directLight,5) )
// 点光源辅助器
scene.add( new THREE.PointLightHelper(pointLight,5))
// 聚合光源辅助器
scene.add( new THREE.SpotLightHelper(spotLight) )
四、作业:
- 3D户型图
- 装修必备家具
potLightHelper(spotLight) )// 平行光源辅助器
scene.add( new THREE.DirectionalLightHelper(directLight,5) )
// 点光源辅助器
scene.add( new THREE.PointLightHelper(pointLight,5))
// 聚合光源辅助器
scene.add( new THREE.SpotLightHelper(spotLight) )
# 四、作业:
1. 3D户型图
[外链图片转存中...(img-dfXxevNt-1689732421438)]
- 装修必备家具
#
------
# 终---