Threejs教程三【揭秘3D貼圖魔法】

定義

貼圖(Texture)是 Three.js 中用于為物體表面添加紋理的一種技術(shù)。它可以將圖像、視頻或其他類型的媒體映射到物體的表面,使其看起來更加真實和生動。

基本原理

貼圖的基本原理是將圖像或視頻映射到物體的表面,使其看起來更加真實和生動。在 Three.js 中,貼圖是通過 Texture 對象來實現(xiàn)的。Texture 對象包含了圖像或視頻的數(shù)據(jù),以及一些用于控制貼圖行為的屬性和方法。

類型

在 Three.js 中,常用的貼圖類型包括:

  • 紋理貼圖(Texture): 紋理貼圖是最常見的貼圖類型,它可以將圖像映射到物體的表面。紋理貼圖可以通過 TextureLoader 加載圖像文件。
  • 視頻紋理(VideoTexture): 視頻紋理是一種特殊的貼圖類型,它可以將視頻映射到物體的表面。視頻紋理可以通過 VideoTextureLoader 加載視頻文件。
  • 立方紋理(CubeTexture): 立方紋理是一種特殊的貼圖類型,它可以將一個立方體的六個面分別映射到物體的表面。立方紋理可以通過 CubeTextureLoader 加載圖像文件。
  • ...

Texture

屬性

  • image: 紋理圖像的引用。可以通過設(shè)置該屬性來更新紋理圖像。
  • needsUpdate: 一個布爾值,表示紋理是否需要更新。當紋理圖像發(fā)生變化時,需要將該屬性設(shè)置為 true。
//可以鏈式調(diào)用
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load("path/to/texture.jpg");
const material = new THREE.MeshBasicMaterial({ map: texture });

TextureLoader

TextureLoader 構(gòu)造函數(shù)通過 load 加載圖片是一個異步操作,所以 load 還有其它參數(shù)

  • url: 紋理圖像的路徑。
  • onLoad: 加載完成后的回調(diào)函數(shù)。該函數(shù)會在加載完成后被調(diào)用,參數(shù)為加載完成的紋理對象。
  • onProgress: 加載進度的回調(diào)函數(shù)。該函數(shù)會在加載過程中被調(diào)用,參數(shù)為加載進度的對象。(暫不支持)
  • onError: 加載失敗的回調(diào)函數(shù)。該函數(shù)會在加載失敗后被調(diào)用,參數(shù)為加載失敗的錯誤對象。

這個只是最基本的貼圖效果,如果想做比較細節(jié)的貼圖,在材質(zhì)里面除了 map 這個屬性還有:

  • aoMap: 環(huán)境遮擋貼圖,用于模擬環(huán)境遮擋效果。
  • envMap: 環(huán)境貼圖,用于模擬環(huán)境反射效果。
  • lightMap: 光照貼圖,用于模擬光照效果。
  • specularMap: 高光貼圖,用于模擬高光效果。
  • alphaMap: 透明度貼圖,用于模擬物體表面的透明度效果。
  • displacementMap: 紋理位移貼圖,用于模擬物體表面的位移效果。
  • roughnessMap: 粗糙度貼圖,用于模擬物體表面的粗糙度效果。
  • normalMap: 法線貼圖,用于模擬物體表面的法線效果。
  • metalnessMap: 金屬度貼圖,用于模擬物體表面的金屬度效果。
  • emissiveMap: 自發(fā)光貼圖,用于模擬物體表面的自發(fā)光效果。
  • ...

示例

如果想實現(xiàn)更加逼真的效果,可以使用多個貼圖來模擬物體表面的不同特性。例如,可以使用環(huán)境貼圖來模擬環(huán)境反射效果,使用高光貼圖來模擬高光效果,使用法線貼圖來模擬物體表面的法線效果等等。

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// 創(chuàng)建場景
const scene = new THREE.Scene();

// 創(chuàng)建相機
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 20, 0);
camera.lookAt(0, 0, 0);

// 創(chuàng)建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

//添加燈光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
const directionLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionLight.position.set(3, 3, 3);
scene.add(ambientLight, directionLight);

//創(chuàng)建貼圖
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load("./texture/basecolor.png");

//創(chuàng)建一個平面
const geometry = new THREE.PlaneGeometry(20, 20);
const material = new THREE.MeshStandardMaterial({
  map: texture,
});
const plane = new THREE.Mesh(geometry, material);
plane.rotation.x = -Math.PI / 2;
scene.add(plane);

//創(chuàng)建控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 啟用阻尼效果
controls.enableDamping = true;

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

animate();

//監(jiān)聽窗口大小變化
window.addEventListener("resize", () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});
texture-init.png

這只是通過貼圖實現(xiàn)的效果,可以看出如果只是通過貼圖,并不能實現(xiàn)非常逼真的效果,所以接下來我們通過多種貼圖來實現(xiàn)更加逼真的效果。

會使用到環(huán)境光貼圖(aoMap)、法線貼圖(normalMap)、金屬度貼圖(metalnessMap)、粗糙度貼圖(roughnessMap)、自發(fā)光貼圖(emissiveMap)、紋理位移貼圖(displacementMap)。

// 省略...

//創(chuàng)建貼圖
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load("./texture/basecolor.png"); //基礎(chǔ)顏色貼圖
const aoTexture = textureLoader.load("./texture/ao.png"); //環(huán)境光貼圖
const normalTexture = textureLoader.load("./texture/normal.png"); //法線貼圖
const roughnessTexture = textureLoader.load("./texture/roughness.png"); //粗糙度貼圖
const heightTexture = textureLoader.load("./texture/height.png"); //紋理位移貼圖
const emissiveTexture = textureLoader.load("./texture/emissive.png"); //自發(fā)光貼圖
const metalnessTexture = textureLoader.load("./texture/metallic.png"); //金屬度貼圖

//創(chuàng)建一個平面
const geometry = new THREE.PlaneGeometry(20, 20);
const material = new THREE.MeshStandardMaterial({
  map: texture,
  aoMap: aoTexture,
  normalMap: normalTexture,
  roughnessMap: roughnessTexture,
  displacementMap: heightTexture,
  emissiveMap: emissiveTexture,
  metalnessMap: metalnessTexture,
});
const plane = new THREE.Mesh(geometry, material);
plane.rotation.x = -Math.PI / 2;
scene.add(plane);

//省略...

效果預(yù)覽

書洞筆記

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容