Skip to content

纹理映射

此笔记记录于DISCOVER three.js,大多数为其中的摘要,少数为笔者自己的理解

基本知识

用最简单的术语来说,纹理映射意味着拿着图像并将其拉伸到3D对象的表面上。我们将以这种方式使用的图像称为纹理,我们可以使用纹理来表示颜色、粗糙度和不透明度等材料属性。例如,要更改几何区域的颜色,我们更改位于顶部的纹理区域的颜色,就像您在上图中看到的附加到面部模型的颜色纹理一样。

虽然获取2D纹理并将其拉伸到像立方体这样的规则形状上很容易,但对于像脸这样的不规则几何形状则要做到这一点要困难得多,而且多年来,已经开发了许多纹理映射技术。也许最简单的技术是 投影映射,它将纹理投影到一个对象(或场景)上,就好像它已经通过电影放映机照射了一样。想象一下,将您的手放在电影放映机前,并看到投影到您皮肤上的图像。

虽然投影映射和其他技术仍然广泛用于创建阴影(或模拟投影仪)等事情,但这不适用于将面部的颜色纹理附加到面部几何体。相反,我们使用一种称为 UV映射的技术,它允许我们在几何体上的点和脸上的点之间创建连接。

表示UV映射的数据存储在几何体上。像BoxBufferGeometry这样的three.js几何体已经设置了UV映射,并且在大多数情况下,当您加载在外部程序中创建的面部模型时,它也有已准备好的UV映射供使用。

纹理类型

uv-test-bw.png 是一个以PNG格式存储的普通2D图像文件,我们将使用TextureLoader加载它,这将返回 Texture类的一个实例。您可以以相同的方式使用浏览器支持的任何图像格式,例如PNG、JPG、GIF、BMP。这是我们将遇到的最常见和最简单的纹理类型:存储在简单2D图像文件中的数据。

还有一些专用图像格式的加载器,如HDR、EXR和TGA,它们具有相应的加载器,如 TGALoader。同样,一旦加载,我们将获得一个Texture实例,我们可以以与加载的PNG或JPG图像大致相同的方式使用它。

除此之外,three.js还支持许多其他类型的非简单2D图像的纹理,例如 视频纹理、 3D纹理、 画布纹理、 压缩纹理、 立方体纹理、 矩形纹理等等。

上图中,纹理的左上角已经映射到立方体角上的一个顶点坐标(−1,1,1):

(0,1)⟶(−1,1,1)

对立方体的其他五个面进行了类似的映射,从而在立方体的六个面上分别生成一个完整的纹理副本:

cube.js

js
import {
  BoxBufferGeometry,
  MathUtils,
  Mesh,
  MeshStandardMaterial,
  TextureLoader, 
} from 'three';

function createMaterial() { 
  // create a texture loader.
  const textureLoader = new TextureLoader(); 

  // load a texture
  const texture = textureLoader.load( 
    '/assets/textures/uv-test-bw.png', 
  ); 

  // create a "standard" material using
  // the texture we just loaded as a color map
  const material = new MeshStandardMaterial({ 
    map: texture, 
  }); 

  return material; 
} 

function createCube() {
  const geometry = new BoxBufferGeometry(2, 2, 2);
  const material = createMaterial(); 
  const cube = new Mesh(geometry, material);

  cube.rotation.set(-0.5, -0.1, 0.8);

  const radiansPerSecond = MathUtils.degToRad(30);

  cube.tick = (delta) => {
    // increase the cube's rotation each frame
    cube.rotation.z += delta * radiansPerSecond;
    cube.rotation.x += delta * radiansPerSecond;
    cube.rotation.y += delta * radiansPerSecond;
  };

  return cube;
}

export { createCube };