three.js learning notes - textures

What is texture Texture

Simply put, a texture is an image that covers the surface of geometry. Different texture types have different effects.

Texture loader TextureLoader

// Initialize a texture loader and load the texture map with. load()
const textureLoader = new THREE.TextureLoader()
const colorTexture = textureLoader.load('/textures/door/color.jpg')
// Then use textures to create materials
const material = new THREE.MeshBasicMaterial({ map:colorTexture  })

Note: a texture loader can load multiple textures

Three more callback functions can be added after the image path

const colorTexture = textureLoader.load(
    '/textures/door/color.jpg',
    ()=>{  //Called when the load is complete
         console.log('load');
     },
    ()=>{   //Call during loading (generally not used)
         console.log('progress');
     },
    ()=>{  //Called on error loading
         console.log('error');
     }
)

Load manager LoadingManager

Just now we used only one texture loader to load a texture, but if we load some other textures later, such as mobile phone texture, wall texture and so on, you may want to know the global loading progress of all these textures, or there will be a message when all textures are loaded, Therefore, you can use the loading manager to correlate these loading events

//Initialize load manager
const loadingManager = new THREE.LoadingManager()
loadingManager.onStart = () => {
    console.log('Started loading file');
}
loadingManager.onProgress = () =>{
    console.log('onProgress');
}
loadingManager.onLoad = () => {
    console.log('Loading complete!');
}
loadingManager.onError = () =>{
    console.log('onError');
}
// Use the loading manager loading manager to track the loading progress process of the TextureLoader
const textureLoader = new THREE.TextureLoader(loadingManager)
//Load texture maps with. load()
const colorTexture = textureLoader.load('/textures/door/color.jpg')
const checkerboard1024Texture = textureLoader.load('/textures/checkerboard-1024x1024.png')
const checkerboard8Texture = textureLoader.load('/textures/checkerboard-8x8.png')
const minecraftTexture = textureLoader.load('/textures/minecraft.png')

Observe the console output, indicating that there are four texture maps loaded

UV map unfold

When you switch the cubic buffer geometry to other types of geometry, you can see that the texture stretches or squeezes in different ways to cover the geometry, which is called UV map unfolding. Just like unfolding origami or candy wrapping paper to make it flat, each vertex has a two-dimensional coordinate (usually square) on the plane

const geometry = new THREE.TorusBufferGeometry(1, 0.35, 32,100)




You can view the 2D coordinates of geometry through geometry.attributes.uv

console.log(geometry.attributes.uv)

You can see the uv coordinate data array of cubic geometry, with a total of 2x4x6=48 data. Each of these data is a group, which constitutes the coordinate data of each point on each face. These coordinates will help us accurately cover the texture picture on the geometry.

Texture conversion

// How many times does the texture repeat on the surface
// The repeat attribute is just a Vector2 two-dimensional vector
colorTexture.repeat.x = 2
colorTexture.repeat.y = 3

You can see that the map changes to one-half of the original horizontally and one-third of the original vertically, but there is no repetition

This is because by default, the texture does not repeat and its last pixel is stretched. In this case, the above problem can be solved by setting the wrapS and wrapT attributes of the texture map, which define the wrapping mode of the texture in the horizontal and vertical directions respectively.

// If the repeat property in each direction is set to greater than 1
// Then the corresponding wrap parameter should also set the wrap mode to THREE.RepeatWrapping or THREE.MirroredRepeatWrapping to achieve the required tiling effect
colorTexture.wrapS = THREE.RepeatWrapping
colorTexture.wrapT = THREE.RepeatWrapping

//Offset of texture (same as Vector2 2D vector)
colorTexture.offset.x = 0.5
colorTexture.offset.y = 0.5

//Texture rotation angle
colorTexture.rotation = Math.PI / 4  //Rotate the texture map 45 degrees

The default center point is at the origin position and rotates around the origin

To change to rotate at the center of the map, you need to change the center point position with the following settings

//After rotation, you will find that the map rotates around the origin. To set it to rotate around the center of the map, you need to set the following settings
colorTexture.center.x = 0.5
colorTexture.center.y = 0.5

Filtering and Mip mapping

When we observe the top of the cubic geometry in the following figure, we can see that the texture becomes blurred, which is caused by FILTERING and mip mapping

mip mapping is a technique that involves creating half a smaller version of a texture again and again until you get a 1x1 texture.
All these texture changes are sent to the GPU, which will automatically select the most appropriate texture version. All of these have been processed by THREE.js and GPU, but we can choose different filtering algorithms

Minification Filters

The filter is triggered when the pixel of the texture is smaller than the rendered pixel, as shown in the following figure. The original texture map pixel is as large as the above picture, but when we move the camera back, we can see that the map is reduced and squeezed into a small rendering area, which will trigger the reduction filter. In other words, the original texture map is too large for the geometry surface, so the texture map used at this time may be a smaller version of texture, such as 64x64 and 32x32.

In the above case, we can change the reduction filter of the texture by setting any of the following values for the minFilter attribute of the texture. Here, we choose NearestFilter

// These constants are used for the minFilter attribute of the texture. They define the texture reduction function to be used when the textured pixel is mapped to an area greater than 1 texture element (texel).
THREE.NearestFilter
THREE.NearestMipmapNearestFilter
THREE.NearestMipmapLinearFilter
THREE.LinearFilter
THREE.LinearMipmapNearestFilter
THREE.LinearMipmapLinearFilter   //Default value
// NearestFilter returns the value of the texture element closest to the specified texture coordinates
colorTexture.minFilter = THREE.NearestFilter

As can be seen from the following figure, when the minFilter attribute of the texture is set to NearestFilter, the pixels are sharper and flicker

The effect of changing the texture map to a 1024x1024 is more obvious. This pattern is called Moire Pattern

Amplification filters

As opposed to reducing the filter. The filter is triggered when the pixels of the texture are larger than the rendered pixels. Let's change an 8x8 texture map

The original image size is like this. When rendering, the image becomes the image above because the pixels are stretched and mixed into one piece

In the above case, we can change the magnification filter of the texture by setting the magFilter attribute of the texture to NearestFilter. It can be seen that it becomes very sharp and the black-and-white junction is no longer mixed.

If you can get more satisfactory results by using NearestFilter, use it. When the texture's minFilter attribute uses NearestFilter, we no longer need mip mapping. We can disable mipmapping for the texture through the following code, so that the GPU no longer processes mip mapping

//If you don't care about the effects of distant objects, such as distortion, the minFilter attribute of the texture can disable mipmapping for better performance when using NearestFilter, depending on the actual project
colorTexture.generateMipmaps = false

Texture formatting and optimization

When looking for texture files from the Internet, you need to pay attention to three points

The size of the texture file

Select the correct texture file type.
jpg distortion compression but smaller, png lossless compression but larger

The size of the texture file

No matter how big the picture is, each pixel of the texture will be stored on the GPU. You can't send too many oversized textures to the GPU at once. You need to reduce the size of the texture as much as possible

Texture file data

Textures support transparency, but jpg files do not, so if you need transparent pictures, you'd better use png files.
If you use normal textures and want to get accurate values, you should not use lossy compressed files, or you'd better use png files
Sometimes we can combine different data into a texture by using red, green, blue and alpha channels respectively.

Texture resource website

https://www.poliigon.com/
https://3dtextures.me/
https://www.arroway-textures.ch/

Tags: Javascript Three.js

Posted on Sun, 28 Nov 2021 12:31:22 -0500 by lordgreg