-
Environment Map
- as a background
- as reflection
- as lighting
-
Set up
<script setup>
import * as THREE from 'three'
import {OrbitControls} from 'three/addons/controls/OrbitControls.js'
import GUI from 'lil-gui'
/**
* scene
*/
const scene = new THREE.Scene()
/**
* torus knot
*/
const torusKnot = new THREE.Mesh(
new THREE.TorusKnotGeometry(1, 0.4, 100, 16),
new THREE.MeshBasicMaterial()
)
torusKnot.position.y = 4
scene.add(torusKnot)
/**
* camera
*/
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
100)
camera.position.set(4, 5, 4)
scene.add(camera)
/**
* renderer
*/
const renderer = new THREE.WebGLRenderer({})
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
document.body.appendChild(renderer.domElement)
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})
/**
* control
*/
const controls = new OrbitControls(camera, renderer.domElement)
controls.target.y = 3.5
controls.enableDamping = true
/**
* tick
*/
const tick = () => {
controls.update()
renderer.render(scene, camera)
requestAnimationFrame(tick)
}
tick()
/**
* gui
*/
const gui = new GUI()
</script>

Set up.png
-
Model
- 添加model后向下移动camera就能看见了
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; /** * loaders */ const gltfLoader = new GLTFLoader() ... ... /** * models */ gltfLoader.load( '../public/models/environment-map/models/FlightHelmet/glTF/FlightHelmet.gltf', (gltf) => { // console.log((gltf)); scene.add(gltf.scene) } )model.png- the model is too small and it's black, because its materials are
MeshStandardMaterialand those need light - cube texture environment map, load the textures in this order: positive x, negative x, positive y, negative y, positive z, negative z
/** * loaders */ ... const cubeTextureLoader = new THREE.CubeTextureLoader() /** * environment map */ // LDR cube texture const environmentMap = cubeTextureLoader.load([ '../public/models/environment-map/environmentMaps/0/px.png', '../public/models/environment-map/environmentMaps/0/nx.png', '../public/models/environment-map/environmentMaps/0/py.png', '../public/models/environment-map/environmentMaps/0/ny.png', '../public/models/environment-map/environmentMaps/0/pz.png', '../public/models/environment-map/environmentMaps/0/nz.png' ]) scene.background = environmentMap- move the torus knot to the side and change its material to
MeshStandardMaterial
/** * torus knot */ const torusKnot = new THREE.Mesh( new THREE.TorusKnotGeometry(1, 0.4, 100, 16), new THREE.MeshStandardMaterial({ roughness: 0.3, metalness: 1, color: 0xaaaaaa }) ) torusKnot.position.x = -4 ...model.png- use the environment map to light up the model, 也可以在单个model的material上设置
envMap属性,但我们import的model层级结构比较复杂,不方便遍历添加,所以我们使用以下方法
/** * environment map */ // LDR cube texture ... scene.environment = environmentMap // to the hold scene scene.background = environmentMapenvironment.png- control the environment map's intensity, it has to be done on each material, we're going to touch the hole scene using
traverse(), this method is available on object3D, we'll do it in a separated function and call it once is loaded - we only want to apply the environment map to the
Meshesthat have aMeshStandardMaterial
/** * update all materials */ const updateAllMaterials = () => { scene.traverse(child => { // console.log(child) // mesh, group, perspectiveCamera... // child instanceof THREE.Mesh && child.material instanceof THREE.MeshStandardMaterial if(child.isMesh && child.material.isMeshStandardMaterial) { // console.log(child); child.material.envMapIntensity = 3 // 增强环境贴图的反射强度 } }) }/** * models */ gltfLoader.load( '../public/models/environment-map/models/FlightHelmet/glTF/FlightHelmet.gltf', (gltf) => { ... updateAllMaterials() } )envMapIntensity.png- control the
envMapIntensityby using theDat.gui
/** * gui */ const gui = new GUI() const global = { envMapIntensity: 1 } gui .add(global, 'envMapIntensity') .min(0) .max(10) .step(0.001) .onChange(updateAllMaterials)/** * update all materials */ const updateAllMaterials = () => { scene.traverse(child => { ... child.material.envMapIntensity = global.envMapIntensity // 调整环境贴图的反射强度 } }) } -
Background blurriness and intensity 模糊度、强度
scene.backgroundBlurriness = 0
scene.backgroundIntensity = 1
gui
.add(scene, 'backgroundBlurriness')
.min(0)
.max(1)
.step(0.001)
gui
.add(scene, 'backgroundIntensity')
.min(0)
.max(10)
.step(0.001)
-
HDRI - Equirectangular Environment Map 等距矩形环境贴图
-
HDR Files: File extension is
.hdr, high dynamic range 高动态范围 - HDRI: color values stored have a much higher range than a traditional image
- Equirectangular: only one picture containing kind of a 360° view of the surrounding
- comment the environment map(keep the
backgroundBlurrinessandbackgroundIntensity)
/** * environment map */ // LDR cube texture // const environmentMap = cubeTextureLoader.load([ // '../public/models/environment-map/environmentMaps/0/px.png', // '../public/models/environment-map/environmentMaps/0/nx.png', // '../public/models/environment-map/environmentMaps/0/py.png', // '../public/models/environment-map/environmentMaps/0/ny.png', // '../public/models/environment-map/environmentMaps/0/pz.png', // '../public/models/environment-map/environmentMaps/0/nz.png' // ]) // scene.environment = environmentMap // to the hold scene // scene.background = environmentMap scene.backgroundBlurriness = 0 scene.backgroundIntensity = 1- load and use the HDRI, we need to use the RGBELoader, RGBE stands for Red Blue Green Exponent, the exponent means stores the brightness, 使用
RGBELoader加载的背景看起来要更亮,因为存储在文件中的值更多、范围更大
import {RGBELoader} from 'three/addons/loaders/RGBELoader.js' /** * loaders */ ... const rgbeLoader = new RGBELoader()/** * environment map */ ... ... // HDR (RGBE) equirectangular rgbeLoader.load('../public/models/environment-map/environmentMaps/0/2k.hdr', (environmentMap) => { environmentMap.mapping = THREE.EquirectangularReflectionMapping scene.environment = environmentMap scene.background = environmentMap }) scene.backgroundBlurriness = 0 scene.backgroundIntensity = 1hdr.png-
这里我们展示一些通过blender创建的不同类型的HDR背景图所呈现的效果
image.png
image.png
-
HDR Files: File extension is
-
AI generated environment using NVIDIA Canvas
- the software is in beta and only works on windows
- the extension is
.exr, our exported file is also an HDR, but EXR can also store layer - import the
EXRLoader
...
import { EXRLoader } from 'three/addons/loaders/EXRLoader.js';
/**
* loaders
*/
...
const exrLoader = new EXRLoader()
// HDR (RGBE) equirectangular
// rgbeLoader.load('../public/environment-map/environmentMaps/blender-2k-1.hdr', environmentMap => {
// environmentMap.mapping = THREE.EquirectangularReflectionMapping
// scene.environment = environmentMap
// scene.background = environmentMap
// })
// HDR (EXR) equirectangular
exrLoader.load('../public/environment-map/environmentMaps/nvidia-canvas-4k.exr', environmentMap => {
environmentMap.mapping = THREE.EquirectangularReflectionMapping
scene.environment = environmentMap
scene.background = environmentMap
})

nvidia-canvas.png
-
AI generated environment map using BlockadeLabs
/**
* loaders
*/
...
const textureLoader = new THREE.TextureLoader()
// HDR (RGBE) equirectangular
// rgbeLoader.load('../public/environment-map/environmentMaps/blender-2k-1.hdr', environmentMap => {
// environmentMap.mapping = THREE.EquirectangularReflectionMapping
// scene.environment = environmentMap
// scene.background = environmentMap
// })
// HDR (EXR) equirectangular
// exrLoader.load('../public/environment-map/environmentMaps/nvidia-canvas-4k.exr', environmentMap => {
// environmentMap.mapping = THREE.EquirectangularReflectionMapping
// scene.environment = environmentMap
// scene.background = environmentMap
// })
// scene.backgroundBlurriness = 0
// scene.backgroundIntensity = 1
// LDR equirectangular
const environmentMap = textureLoader.load('../public/environment-map/environmentMaps/blockadesLabsSkybox/anime_art_style_japan_streets_with_cherry_blossom_.jpg')
environmentMap.mapping = THREE.EquirectangularReflectionMapping
environmentMap.colorSpace = THREE.SRGBColorSpace
scene.environment = environmentMap
scene.background = environmentMap

BlockadeLabs.png
-
Ground Projected Environment Map
- when using the environment map as background, the objects look like are flying
- to use on of the HDR environment maps, only as the
environment
-
RealTime EnvironmentMap
/** * real time environment map */ const environmentMap = textureLoader.load('../public/environment-map/environmentMaps/blockadesLabsSkybox/interior_views_cozy_wood_cabin_with_cauldron_and_p.jpg') environmentMap.mapping = THREE.EquirectangularReflectionMapping environmentMap.colorSpace = THREE.SRGBColorSpace scene.background = environmentMap- we're going to create a torus or a donut surrounding the scene and try to make the donut illuminate and reflect on the surface of our objects
/** * holy donut */ const holyDonut = new THREE.Mesh( new THREE.TorusGeometry(8, 0.5), new THREE.MeshBasicMaterial({color: 'white'}) ) holyDonut.position.y = 3.5 scene.add(holyDonut)- we're going to render the scene inside our own environment map texture and it's going to be a cube texture
- 创建立方体纹理:we need to use WebGLCubeRenderTarget, we need to create textures on each frame
/** * cube render target */ const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 256, // 分辨率 { type: THREE.HalfFloatType } ) scene.environment = cubeRenderTarget.texture- we need to use CubeCamera, because we need to render 6 texture for each face
// cube camera const cubeCamera = new THREE.CubeCamera(0.1, 100, cubeRenderTarget) // near, far/** * tick */ const clock = new THREE.Clock() const tick = () => { const elapsedTime = clock.getElapsedTime() if(holyDonut) { holyDonut.rotation.x = Math.sin(elapsedTime) * 2 cubeCamera.update(renderer, scene) } controls.update() renderer.render(scene, camera) requestAnimationFrame(tick) } tick()image.png- we can make the cube color go beyond the 0 to 1 range
/** * holy donut */ const holyDonut = new THREE.Mesh( ... new THREE.MeshBasicMaterial({color: new THREE.Color(10, 4, 2)}) ) ...image.png








