Three.js Journey (notes2)

ref

Three.js中文网

Three.js Journey — Learn WebGL with Three.js

Part 1 Fullscreen and resizing

When the double click happens, we will toggle the fullscreen —meaning that if the window is not in fullscreen, a double-click will enable fullscreen mode, and if the window is already in fullscreen, a double-click will exit fullscreen mode.

To make the canvas fit perfectly in the viewport, instead of using fixed numbers in the sizes variable, use the window.innerWidth and window.innerHeight:

// Sizes
const sizes = {width: window.innerWidth,height: window.innerHeight
}

Handle resize 

window.addEventListener('resize', () =>
{// Update sizessizes.width = window.innerWidthsizes.height = window.innerHeight
})

 Handle fullscreen

To know if we are already in fullscreen or not, we can use document.fullscreenElement:

window.addEventListener('dblclick', () =>
{if(!document.fullscreenElement){canvas.requestFullscreen()}else{document.exitFullscreen()}
})

Part 2 Geometries

What is a geometry?

In Three.js, geometries are composed of vertices (point coordinates in 3D spaces) and faces (triangles that join those vertices to create a surface).

We use geometries to create meshes, but you can also use geometries to form particles. Each vertex (singular of vertices) will correspond to a particle, but this is for a future lesson.

We can store more data than the position in the vertices. A good example would be to talk about the UV coordinates or the normals.

The different built-in geometries

Three.js has many built-in geometries. While you don't need to know precisely how to instantiate each one, it is good to know that they exist.

All the built-in geometries we are going to see inherit from the BufferGeometry class. This class has many built in methods like translate(...)rotateX(...)normalize(), etc. but we are not going to use them in this lesson.

Most of the geometries documentation pages have examples.

  • BoxGeometry To create a box.
  • PlaneGeometry To create a rectangle plane.
  • CircleGeometry To create a disc or a portion of a disc (like a pie chart).
  • ConeGeometry To create a cone or a portion of a cone. You can open or close the base of the cone.
  • CylinderGeometry To create a cylinder. You can open or close the ends of the cylinder and you can change the radius of each end.
  • RingGeometry To create a flat ring or portion of a flat circle.
  • TorusGeometry To create a ring that has a thickness (like a donut) or portion of a ring.
  • TorusKnotGeometry To create some sort of knot geometry.
  • DodecahedronGeometry To create a 12 faces sphere. You can add details for a rounder sphere.
  • OctahedronGeometry To create a 8 faces sphere. You can add details for a rounder sphere.
  • TetrahedronGeometry To create a 4 faces sphere (it won't be much of a sphere if you don't increase details). You can add details for a rounder sphere.
  • IcosahedronGeometry To create a sphere composed of triangles that have roughly the same size.
  • SphereGeometry To create the most popular type of sphere where faces looks like quads (quads are just a combination of two triangles).
  • ShapeGeometry To create a shape based on a path.
  • TubeGeometry To create a tube following a path.
  • ExtrudeGeometry To create an extrusion based on a path. You can add and control the bevel.
  • LatheGeometry To create a vase or portion of a vase (more like a revolution).
  • TextGeometry To create a 3D text. You'll have to provide the font in typeface json format.

If you need a particular geometry that is not supported by Three.js, you can create your own geometry in JavaScript, or you can make it in a 3D software, export it and import it into your project. We will learn more about that later.

Box example

const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)
const material = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true })

 Creating your own buffer geometry

To create your own buffer geometry, start by instantiating an empty BufferGeometry. We will create a simple triangle.

To add vertices to a BufferGeometry you must start with a Float32Array.

Float32Array are native JavaScript typed array. You can only store floats inside, and the length of that array is fixed.

To create a Float32Array, you can specify its length and then fill it later:

// Create an empty BufferGeometry
const geometry = new THREE.BufferGeometry()// Create a Float32Array containing the vertices position (3 by 3)
const positionsArray = new Float32Array([0, 0, 0, // First vertex0, 1, 0, // Second vertex1, 0, 0  // Third vertex
])// Create the attribute and name it 'position'
/*
The first parameter corresponds to your typed array and 
the second parameter corresponds to how much values make one vertex attribute. 
As we saw earlier, to read this array, 
we have to go 3 by 3 because a vertex position is composed of 3 values (x, y and z):
*/
const positionsAttribute = new THREE.BufferAttribute(positionsArray, 3)
geometry.setAttribute('position', positionsAttribute)

We can also create a bunch of random triangles:

// Create an empty BufferGeometry
const geometry = new THREE.BufferGeometry()// Create 50 triangles (450 values)
const count = 50
const positionsArray = new Float32Array(count * 3 * 3)
for(let i = 0; i < count * 3 * 3; i++)
{positionsArray[i] = (Math.random() - 0.5) * 4
}// Create the attribute and name it 'position'
const positionsAttribute = new THREE.BufferAttribute(positionsArray, 3)
geometry.setAttribute('position', positionsAttribute)

Part 3  Debug UI

While you can create your own debug UI using HTML / CSS / JS, there are already multiple libraries:

  • dat.GUI
  • lil-gui
  • control-panel
  • ControlKit
  • Uil
  • Tweakpane
  • Guify
  • Oui

All of these can do what we want, but we will use lil-gui because it’s popular, maintained, and easy to use.

Instantiating lil-gui

To add lil-gui to our project, we can use the dependency manager provided with Node.js called NPM (just like we did for GSAP in a previous lesson).

In your terminal (while the server is not running or by using another terminal window in the same folder) run npm install lil-gui

lil-gui is now available in the node_modules/ folder and we can import it into our script.js. Don't forget to relaunch the server:

import GUI from 'lil-gui'

 You can now instantiate lil-gui in a gui variable and we can do that at the very beginning, right after the imports:

/*** Debug*/
const gui = new GUI()

The different types of tweaks 

On the top right corner of the experience, you can see an empty panel. There are different types of tweaks you can add to that panel:

  • Range —for numbers with minimum and maximum value
  • Color —for colors with various formats
  • Text —for simple texts
  • Checkbox —for booleans (true or false)
  • Select —for a choice from a list of values
  • Button —to trigger functions

Range

The first tweak we are going to add is the range.

Most of the tweaks can be added using gui.add(...). The first parameter is the object and the second parameter is the property of that object you want to tweak.

You need to add the gui.add(...) after you’ve created the object and its property. Otherwise, you will ask lil-gui to tweak something that doesn’t exist yet.

Let’s try with the mesh.position.y:

const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)gui.add(mesh.position, 'y', - 3, 3, 0.01)

If you don’t like to have that many parameters, you can use the methods min(...)max(...), and step(...) by chaining directly after the add(...) method:

gui.add(mesh.position, 'y').min(- 3).max(3).step(0.01)
 Tweaks for non-properties

One important thing to note here is that lil-gui can only modify properties.you can use some tricks to do so, such as creating an object whose purpose is to hold properties for lil-gui to be used on the object:

//If you want to update a variable, you can’t:
let myVariable = 1337
gui.add(myVariable, '???')//But you can use some tricks to do soconst myObject = {myVariable: 1337
}
gui.add(myObject, 'myVariable')

Checkbox 

lil-gui will automatically detect what kind of property you want to tweak and use the corresponding interface. A good example is the visible property of Object3D. It is a boolean that, if false, will hide the object:

gui.add(mesh, 'visible')
gui.add(material, 'wireframe')

 Colors 

Handling colors is a little harder. Let’s try modifying the color property of the material.

First, we need to use addColor(...) instead of add(...) because the color property is not a string, a boolean, or a number. It’s an object with various properties because it’s an instance of the Three.js Color class. Among those properties are rg and b , which lil-gui can use to display a nice tweak:

gui.addColor(material, 'color')

Next, we need to access the Color instance and we can use the classic material.color or we can retrieve a value directly as a parameter of the function:

gui.addColor(material, 'color').onChange((value) =>{console.log(material.color)console.log(value)})

Function / Button

Sometimes, we just want to trigger instructions on demand. Right now, we want to make the cube perform a little spin animation when we click somewhere in our debug UI.

const myFunction = () => {console.log('do something')
}
gui.add(myFunction, '???')

 Folders

Let’s imagine that we have a lot more tweaks and the debug UI starts to get crowded. We can separate them into folders by using the addFolder() method.

To create a folder, call addFolder() and send the name you want for it as the parameter. Make sure to do it before the tweaks and save it as cubeTweaks:

const cubeTweaks = gui.addFolder('Awesome cube')

GUI setup 

const gui = new GUI({width: 300,title: 'Nice debug UI',closeFolders: false,
})
// gui.close()
gui.hide()

 Part 4 Textures

PBR 

Those textures (especially the metalness and the roughness) follow what we call PBR principles. PBR stands for Physically Based Rendering. It regroups many techniques that tend to follow real-life directions to get realistic results.

While there are many other techniques, PBR is becoming the standard for realistic renders, and many software, engines, and libraries are using it.

For now, we will simply focus on how to load textures, how to use them, what transformations we can apply, and how to optimize them. We will see more about PBR in later lessons, but if you're curious, you can learn more about it here:

  • https://marmoset.co/posts/basic-theory-of-physically-based-rendering/
  • https://marmoset.co/posts/physically-based-rendering-and-you-can-too/

How to load textures

1.Getting the URL of the image

//You can put the image texture in the /src/ folder and 
//import it like you would import a JavaScript dependency
import imageSource from './image.png'console.log(imageSource)//Or you can put that image in the /static/ folder 
//and access it just by adding the path of the image (without /static) to the URL:const imageSource = '/image.png'console.log(imageSource)

 2.Loading the image

①Using native JavaScript

With native JavaScript, first, you must create an Image instance, listen to the load event, and then change its src property to start loading the image:

const image = new Image()
image.onload = () =>
{console.log('image loaded')
}
image.src = '/textures/door/color.jpg'

Unfortunately, the texture variable has been declared in a function and we can not access it outside of this function. This is a JavaScript limitation called scope.

We could create the mesh inside the function, but there is a better solution consisting on creating the texture outside of the function and then updating it once the image is loaded by setting the texture needsUpdate property to true:

const image = new Image()
const texture = new THREE.Texture(image)
image.addEventListener('load', () =>
{texture.needsUpdate = true
})
image.src = '/textures/door/color.jpg'

To see the texture on the cube, replace the color property by map and use the texture as value:

const material = new THREE.MeshBasicMaterial({ map: texture })

You should see the door texture on each side of your cube. but, the texture looks oddly greyish.

It’s because the image has been encoded using the sRGB color space but Three.js isn’t aware of this.

To fix that, you need to set their colorSpace to THREE.sRGBColorSpace:

const texture = new THREE.Texture(image)
texture.colorSpace = THREE.SRGBColorSpace

The general idea is that textures that are used on the map or matcap (that you’ll see later) properties of a material are supposed to be encoded in sRGB and we need to set the colorSpace to THREE.sRGBColorSpace but only for those.

②Using TextureLoader

Instantiate a variable using the TextureLoader class and use its .load(...) method to create a texture.

You can send 3 functions after the path. They will be called for the following events:

  • load when the image loaded successfully
  • progress when the loading is progressing
  • error if something went wrong
const textureLoader = new THREE.TextureLoader()
const texture = textureLoader.load('/textures/door/color.jpg',() =>{console.log('loading finished')},() =>{console.log('loading progressing')},() =>{console.log('loading error')}
)
texture.colorSpace = THREE.SRGBColorSpace
 ③Using the LoadingManager
const loadingManager = new THREE.LoadingManager()
loadingManager.onStart = () =>
{console.log('loading started')
}
loadingManager.onLoad = () =>
{console.log('loading finished')
}
loadingManager.onProgress = () =>
{console.log('loading progressing')
}
loadingManager.onError = () =>
{console.log('loading error')
}const textureLoader = new THREE.TextureLoader(loadingManager)// ...const colorTexture = textureLoader.load('/textures/door/color.jpg')
colorTexture.colorSpace = THREE.SRGBColorSpace
const alphaTexture = textureLoader.load('/textures/door/alpha.jpg')
const heightTexture = textureLoader.load('/textures/door/height.jpg')
const normalTexture = textureLoader.load('/textures/door/normal.jpg')
const ambientOcclusionTexture = textureLoader.load('/textures/door/ambientOcclusion.jpg')
const metalnessTexture = textureLoader.load('/textures/door/metalness.jpg')
const roughnessTexture = textureLoader.load('/textures/door/roughness.jpg')

As you can see here, we renamed the texture variable colorTexture so don't forget to change it in the material too:

const material = new THREE.MeshBasicMaterial({ map: colorTexture })

 UV unwrapping

You can actually see those UV 2D coordinates in the geometry.attributes.uv property:

console.log(geometry.attributes.uv)

Transforming the texture

Repeat

you have to update the wrapS and wrapT properties using the THREE.RepeatWrapping constant.

  • wrapS is for the x axis
  • wrapT is for the y axis
const colorTexture = textureLoader.load('/textures/door/color.jpg')
colorTexture.colorSpace = THREE.SRGBColorSpace
colorTexture.wrapS = THREE.RepeatWrapping
colorTexture.wrapT = THREE.RepeatWrapping

 You can also alternate the direction with THREE.MirroredRepeatWrapping:

colorTexture.wrapS = THREE.MirroredRepeatWrapping
colorTexture.wrapT = THREE.MirroredRepeatWrapping

 Offset

You can offset the texture using the offset property that is also a Vector2 with x and y properties. Changing these will simply offset the UV coordinates:

colorTexture.offset.x = 0.5
colorTexture.offset.y = 0.5

Rotation 

You can rotate the texture using the rotation property, which is a simple number corresponding to the angle in radians:

colorTexture.rotation = Math.PI * 0.25

That is, in fact, the 0, 0 UV coordinates. If you want to change the pivot of that rotation, you can do it using the center property which is also a Vector2:

colorTexture.rotation = Math.PI * 0.25
colorTexture.center.x = 0.5
colorTexture.center.y = 0.5

Part 5 Materials

Materials are used to put a color on each visible pixel of the geometries.

The algorithms that decide on the color of each pixel are written in programs called shaders. Writing shaders is one of the most challenging parts of WebGL and Three.js, but don't worry; Three.js has many built-in materials with pre-made shaders.

// MeshBasicMaterial
const material = new THREE.MeshBasicMaterial()const sphere = new THREE.Mesh(new THREE.SphereGeometry(0.5, 16, 16),material
)

We can now rotate our objects on our tick function, as we did in the Animation lesson:

/*** Animate*/
const clock = new THREE.Clock()const tick = () =>
{const elapsedTime = clock.getElapsedTime()// Update objectssphere.rotation.y = 0.1 * elapsedTimeplane.rotation.y = 0.1 * elapsedTimetorus.rotation.y = 0.1 * elapsedTimesphere.rotation.x = 0.15 * elapsedTimeplane.rotation.x = 0.15 * elapsedTimetorus.rotation.x = 0.15 * elapsedTime// ...
}tick()

All the texture images are located in the static/textures/ folder. For now, we will load all the door textures located in the static/textures/door/ folder, the first matcap texture located in the static/textures/matcaps/ folder, and the first gradient texture located in the static/textures/gradients/ folder.

Make sure to do that before instantiating the material:

/*** Textures*/
const textureLoader = new THREE.TextureLoader()const doorColorTexture = textureLoader.load('./textures/door/color.jpg')
const doorAlphaTexture = textureLoader.load('./textures/door/alpha.jpg')
const doorAmbientOcclusionTexture = textureLoader.load('./textures/door/ambientOcclusion.jpg')
const doorHeightTexture = textureLoader.load('./textures/door/height.jpg')
const doorNormalTexture = textureLoader.load('./textures/door/normal.jpg')
const doorMetalnessTexture = textureLoader.load('./textures/door/metalness.jpg')
const doorRoughnessTexture = textureLoader.load('./textures/door/roughness.jpg')
const matcapTexture = textureLoader.load('./textures/matcaps/1.png')
const gradientTexture = textureLoader.load('./textures/gradients/3.jpg')

 As we’ve seen previously, textures used as map and matcap are supposed to be encoded in sRGB and we need to inform Three.js of this by setting their colorSpace to THREE.SRGBColorSpace:

doorColorTexture.colorSpace = THREE.SRGBColorSpace
matcapTexture.colorSpace = THREE.SRGBColorSpace

To ensure that all the textures are well loaded, you can use them on your material with the map property, as we saw in the Textures lesson.

const material = new THREE.MeshBasicMaterial({ map: doorColorTexture })

MeshBasicMaterial

MeshBasicMaterial is probably the most "basic" material... But there are multiple properties that we haven't covered yet.

You can set most of those properties while instancing the material in the object we send as a parameter, but you can also change those properties in the instance directly:

const material = new THREE.MeshBasicMaterial({map: doorColorTexture
})// Equivalent
const material = new THREE.MeshBasicMaterial()
material.map = doorColorTexture

 Map 

The map property will apply a texture on the surface of the geometry:

material.map = doorColorTexture

Color 

The color property will apply a uniform color on the surface of the geometry. When you are changing the color property directly, you must instantiate a Color class. You can use many different formats.

Try commenting on the map first and test those color formats:

// material.map = doorColorTexture
material.color = new THREE.Color('#ff0000')
material.color = new THREE.Color('#f00')
material.color = new THREE.Color('red')
material.color = new THREE.Color('rgb(255, 0, 0)')
material.color = new THREE.Color(0xff0000)

Combining color and map will tint the texture with the color:

material.map = doorColorTexture
material.color = new THREE.Color('#ff0000')

Wireframe

// material.map = doorColorTexture
// material.color = new THREE.Color('#ff0000')
material.wireframe = true

Opacity

 The opacity property controls the transparency but, to work, you need to set the transparent property to true in order to inform Three.js that this material now supports transparency.

// material.map = doorColorTexture
// material.color = new THREE.Color('#ff0000')
// material.wireframe = true
material.transparent = true
material.opacity = 0.5

 AlphaMap

Now that the transparency is working, we can use the alphaMap property to control the transparency with a texture:

// material.map = doorColorTexture
// material.color = new THREE.Color('#ff0000')
// material.wireframe = true
material.transparent = true
// material.opacity = 0.5
material.alphaMap = doorAlphaTexture

Side

 The side property lets you decide which side of the faces is visible. By default, the front side is visible (THREE.FrontSide), but you can show the backside instead (THREE.BackSide) or both (THREE.DoubleSide):

// material.map = doorColorTexture
// material.color = new THREE.Color('#ff0000')
// material.wireframe = true
// material.transparent = true
// material.opacity = 0.5
// material.alphaMap = doorAlphaTexture
material.side = THREE.DoubleSide

You should see both the front and the back of the plane.

Try to avoid using THREE.DoubleSide whenever possible because it actually requires more resources when rendering, even though the side isn’t visible.

Some of these properties like wireframe or opacity can be used with most following materials. We won't repeat those every time.

MeshNormalMaterial

Normals are information encoded in each vertex that contains the direction of the outside of the face. If you displayed those normals as arrows, you would get straight lines coming out of each vertex that compose your geometry.

// MeshNormalMaterial
const material = new THREE.MeshNormalMaterial()

 You can use Normals for many things like calculating how to illuminate the face or how the environment should reflect or refract on the geometries' surface.

When using the MeshNormalMaterial, the color will just display the normal orientation relative to the camera. If you rotate around the sphere, you'll see that the color is always the same, regardless of which part of the sphere you're looking at.

While you can use some of the properties we discovered with the MeshBasicMaterial like wireframetransparentopacity, and side, there is also a new property that you can use, which is called flatShading:

material.flatShading = true

 flatShading will flatten the faces, meaning that the normals won't be interpolated between the vertices.

MeshNormalMaterial can be useful to debug the normals, but it also looks great, and you can use it just the way it is, similar to what ilithya did on her portfolio https://www.ilithya.rocks.

MeshDepthMaterial 

The MeshDepthMaterial will simply color the geometry in white if it's close to the camera's near value and in black if it's close to the far value of the camera:

// MeshDepthMaterial
const material = new THREE.MeshDepthMaterial()

Adding a few lights

We are going to add two simple lights to our scene but we are not going to dive too deep into the topic because there is a whole lesson dedicated to lights.

/*** Lights*/
const ambientLight = new THREE.AmbientLight(0xffffff, 1)
scene.add(ambientLight)// ...const pointLight = new THREE.PointLight(0xffffff, 30)
pointLight.position.x = 2
pointLight.position.y = 3
pointLight.position.z = 4
scene.add(pointLight)

 MeshPhongMaterial

The MeshPhongMaterial is very similar to the MeshLambertMaterial, but the strange patterns are less visible, and you can also see the light reflection on the surface of the geometry:

// // MeshLambertMaterial
// const material = new THREE.MeshLambertMaterial()// MeshPhongMaterial
const material = new THREE.MeshPhongMaterial()

MeshPhongMaterial is less performant than MeshLambertMaterial. However, it doesn't really matter at this level.

You can control the light reflection with the shininess property. The higher the value, the shinier the surface. You can also change the color of the reflection by using the specular property:

material.shininess = 100
material.specular = new THREE.Color(0x1188ff)

Fortunately, we can control how the GPU handles such texture thanks to the minFiltermagFilter, similar to what we saw in the Textures lesson when talking about mipmapping.

Change the minFilter and magFilter to THREE.NearestFilter.

// MeshToonMaterial
const material = new THREE.MeshToonMaterial()
gradientTexture.minFilter = THREE.NearestFilter
gradientTexture.magFilter = THREE.NearestFilter
material.gradientMap = gradientTexture

You should now see the cartoon effect with an intermediate step.

And because the THREE.NearestFilter isn’t actually using any mipmap versions of the texture, we can deactivate the generation of the mipmaps in order to free some memory by setting gradientTexture.generateMipmaps to alse:

gradientTexture.minFilter = THREE.NearestFilter
gradientTexture.magFilter = THREE.NearestFilter
gradientTexture.generateMipmaps = false

 You can try out even more steps by using the image located in static/textures/gradients.5.jpg:

const gradientTexture = textureLoader.load('/textures/gradients/5.jpg')

 MeshStandardMaterial

The MeshStandardMaterial uses physically based rendering principles. Yes, we are talking about the PBR we saw in the Textures lesson. Like the MeshLambertMaterial and the MeshPhongMaterial, it supports lights but with a more realistic algorithm and better parameters like roughness and metalness.

It's called "standard" because the PBR has become the standard in many software, engines, and libraries. The idea is to have a realistic result with realistic parameters, and you should have a very similar result, regardless of the technology you are using:

// // MeshToonMaterial
// const material = new THREE.MeshToonMaterial()
// gradientTexture.minFilter = THREE.NearestFilter
// gradientTexture.magFilter = THREE.NearestFilter
// gradientTexture.generateMipmaps = false
// material.gradientMap = gradientTexture// MeshStandardMaterial
const material = new THREE.MeshStandardMaterial()
material.metalness = 0.45
material.roughness = 0.65

Add a debug UI

Now would be an excellent time to add a debug UI. This will be very useful to test the different properties.

First, we must add the lil-gui dependency to our project. In the terminal, in the project folder (where the server should be currently running), use the following command:

/*** Debug*/
const gui = new GUI()
const material = new THREE.MeshStandardMaterial()
material.metalness = 0.45
material.roughness = 0.65gui.add(material, 'metalness').min(0).max(1).step(0.0001)
gui.add(material, 'roughness').min(0).max(1).step(0.0001)

 Adding an environment map

We are not done with the MeshStandardMaterial, but before going any further, we are going to add an additional feature called environment map.

The environment map is like an image of what's surrounding the scene and you can find it in /static/textures/environmentMap/2k.hdr. You might be able to preview it if your OS supports it. If not, don’t worry, as it’s not important and Three.js will be able to handle it.

You can use it to add reflection, refraction but also lighting to your objects, in addition to the current DirectionalLight and AmbientLight.

Just like for the lights, we are not going to cover this in detail because there is a lesson dedicated to it in which you’ll also learn a bunch of ways to create your own environment maps.

Let's start by changing the metalness and the roughness of MeshStandardMaterial so that we can appreciate the upcoming environment map:

const material = new THREE.MeshStandardMaterial()
material.metalness = 0.7
material.roughness = 0.2

 To load the previously mentioned environment map file, we need to use the RGBELoader. Import RGBELoader from three/examples/jsm/loaders/RGBELoader.js:

import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'

 Next, we need to instantiate it as rgbeLoader and use its load() method to load the ./textures/environmentMap/2k.hdr file:

/*** Environment map*/
const rgbeLoader = new RGBELoader()
rgbeLoader.load('./textures/environmentMap/2k.hdr', (environmentMap) =>
{console.log(environmentMap)
})

 Unlike the textureLoader, we need to send a callback function as the second parameter. We can retrieve the loaded environment map as the parameter of that function.

To apply it to our scene, we need to change its mapping property to THREE.EquirectangularReflectionMapping and then assign it to the background and environment properties of the scene:

rgbeLoader.load('/environmentMaps/0/2k.hdr', (environmentMap) =>
{environmentMap.mapping = THREE.EquirectangularReflectionMappingscene.background = environmentMapscene.environment = environmentMap
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/65891.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入理解Python中的常用数据格式(如csv、json、pickle、npz、h5等):存储机制与性能解析

在数据科学与工程领域&#xff0c;数据的存储与读取是日常工作中不可或缺的一部分。选择合适的数据格式不仅影响数据处理的效率&#xff0c;还关系到存储空间的利用与后续分析的便捷性。本文将以通俗易懂的方式&#xff0c;深入探讨Python中几种常用的数据读写格式&#xff08;…

Ubuntu开机The root filesystem on /dev/sdbx requires a manual fsck 问题

出现“Manual fsck”错误可能由以下几种原因引起&#xff1a; 不正常关机&#xff1a;如果系统意外断电或被强制重启&#xff0c;文件系统可能未能正确卸载&#xff0c;导致文件系统损坏。磁盘故障&#xff1a;硬盘的物理损坏可能会引发文件系统错误。文件系统配置问题&#x…

黑马Java面试教程_P10_设计模式

系列博客目录 文章目录 系列博客目录前言1. 工厂方法模式1.1 概述1.2 简单工厂模式1.2.1 结构1.2.2 实现1.2.3 优缺点 1.3 工厂方法模式1.3.1 概念1.3.2 结构1.3.3 实现1.3.4 优缺点 1.4 抽象工厂模式1.4.1 概念1.4.2 结构1.4.3 实现1.4.4 优缺点1.4.5 使用场景 总结&#xff0…

Science Robotics让软机器人“活”得更久的3D打印!

软机器人硬件在医疗、探索无结构环境等领域有广泛应用&#xff0c;但其生命周期有限&#xff0c;导致资源浪费和可持续性差。软机器人结合软硬组件&#xff0c;复杂组装和拆卸流程使其难以维修和升级。因此&#xff0c;如何延长软机器人的生命周期并提高其可持续性成为亟待解决…

Vue3实战教程》24:Vue3自定义指令

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》 自定义指令​ 介绍​ 除了 Vue 内置的一系列指令 (比如 v-model 或 v-show) 之外&#xff0c;Vue 还允许你注册自定义的指令 (Custom Directives)。 我们已经介绍了两种在 Vue 中重用代码的方式&#xff1a;组件和组…

Speech Recognition vs. Voice Recognition | 语音识别工作原理 | 模型训练 | 应用

注&#xff1a;Speech Recognition 与 Voice Recognition 机翻混淆&#xff0c;未校。 Speech Recognition vs. Voice Recognition: In Depth Comparison 语音识别与语音识别&#xff1a;深度比较 Calendar12 July 2023 Have you ever stopped to think about how your voice…

[ubuntu-22.04]ubuntu不识别rtl8153 usb转网口

问题描述 ubuntu22.04插入rtl8153 usb转网口不识别 解决方案 安装依赖包 sudo apt-get install libelf-dev build-essential linux-headers-uname -r sudo apt-get install gcc-12 下载源码 Realtek USB FE / GBE / 2.5G / 5G Ethernet Family Controller Softwarehttps:/…

USB 控制传输的 PID 序列

文章目录 USB 控制传输的 PID 序列PID 序列setup 设置阶段data 数据阶段status 状态阶段setup + in data + out statussetupin dataout statussetup + in statussetupin statussetup + out data + in statussetupout datain status为什么需要了解 PID 序列状态转换总结参考USB …

前端-动画库Lottie 3分钟学会使用

目录 1. Lottie地址 2. 使用html实操 3. 也可以选择其他的语言 1. Lottie地址 LottieFiles: Download Free lightweight animations for website & apps.Effortlessly bring the smallest, free, ready-to-use motion graphics for the web, app, social, and designs.…

在Ubuntu 18.04.6 LTS安装OpenFace流程

一、修改配置:将gcc8&#xff0c;g8作为默认选项 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 100 sudo update-alternatives --config gcc 选择版本&#xff0c;再查看gcc --version sudo update-alternatives --install /usr/bin/g g /usr/bin/g-…

Flink源码解析之:如何根据JobGraph生成ExecutionGraph

Flink源码解析之&#xff1a;如何根据JobGraph生成ExecutionGraph 在上一篇Flink源码解析中&#xff0c;我们介绍了Flink如何根据StreamGraph生成JobGraph的流程&#xff0c;并着重分析了其算子链的合并过程和JobGraph的构造流程。 对于StreamGraph和JobGraph的生成来说&…

生成式AI与RAG架构:如何选择合适的向量数据库?

大规模语言模型和情境感知的AI应用程序推动了检索增强生成&#xff08;RAG&#xff09;架构的发展&#xff0c;使其成为关注的焦点。RAG将生成模型的力量与外部知识相结合&#xff0c;允许系统生成更加具体且与情境相关的回应。 向量数据库构成了RAG系统的基石。选择正确的向量…

电脑找不到mfc110.dll文件要如何解决?Windows缺失mfc110.dll文件快速解决方法

一、mfc110.dll文件的重要性 mfc110.dll&#xff0c;全称Microsoft Foundation Class Library 110&#xff0c;是Microsoft Visual C Redistributable for Visual Studio 2012的一部分。这个动态链接库&#xff08;DLL&#xff09;文件对于支持基于MFC&#xff08;Microsoft F…

大模型Weekly 03|OpenAI o3发布;DeepSeek-V3上线即开源!

大模型Weekly 03&#xff5c;OpenAI o3发布&#xff1b;DeepSeek-V3上线即开源&#xff01;DeepSeek-V3上线即开源&#xff1b;OpenAI 发布高级推理模型 o3https://mp.weixin.qq.com/s/9qU_zzIv9ibFdJZ5cTocOw?token47960959&langzh_CN 「青稞大模型Weekly」&#xff0c;持…

4、上一个接口返回值,作为下一个方法(接口)的变量

import requestsclass TestCase:# 设置1个类变量B "初始值"def test1(self):url "**这里是接口url**"params {"type": "json"}resp1 requests.get(urlurl, paramsparams)# .json()用于将服务器返回的 JSON 格式的响应内容解析为 P…

USB 中断传输的 PID 序列

中断传输的 PID 序列 端点在初始化后&#xff0c;从 DATA0 开始&#xff0c;每成功执行一个事务&#xff0c;数据包序列翻转一次&#xff08;从 DATA0 变为DATA1 或从 DATA1 变为 DATA0)。 数据翻转和传输的个数没有直接关系&#xff0c;只由端点在初始化后处理的总数决定。 …

SAP财务凭证的更改、冲销的方式

文章目录 一、财务凭证更改二、财务凭证冲销 【SAP系统研究】 #SAP #FICO #SAP财务 一、财务凭证更改 &#xff08;1&#xff09;已经过账的财务凭证 FB02&#xff1a;过完帐的允许更改的地方有限&#xff0c;只有凭证抬头文本、参照、分配、文本、原因代码等。 &#xff0…

OpenCV的人脸检测模型FaceDetectorYN

OpenCV的人脸检测模型FaceDetectorYN 1. 官网地址2. 如何使用2.1.到opencv_zoo下载模型文件和代码2.2. 下载文件展示2.3. 修改了demo支持读取视频文件&#xff0c;默认是图片和摄像头## 2.4 效果展示 1. 官网地址 https://docs.opencv.org/4.x/df/d20/classcv_1_1FaceDetector…

vue使用el-select下拉框自定义复选框

在 Vue 开发中&#xff0c;高效且美观的组件能极大地提升用户体验和开发效率。在vue中使用elementplus 的 el-select下拉框实现了一个自定义的多选下拉框组件。 一、代码功能概述 这段代码创建了一个可多选的下拉框组件&#xff0c;通过el-select和el-checkbox-group结合的方…

01-英语准备

首先是自我介绍&#xff0c;中英文都可以&#xff0c;建议提前打好草稿然后开始背&#xff0c;模板网上有很多&#xff0c;可以自行查找&#xff0c;主要就是个人的一些基本情况&#xff0c;竞赛获奖经历&#xff0c;感兴趣的方向等等。接下来就是老师问的一些问题了。 做个英文…