Three.js - 紋理



紋理是新增到材質上的影像或顏色,以提供更多細節或美感。紋理是Three.js中的一個重要主題。在本節中,我們將瞭解如何將基本紋理應用於我們的材質。

基本紋理

首先,您應該建立一個載入器。Three.js有一個內建函式`TextureLoader()`用於將紋理載入到您的Three.js專案中。然後,您可以透過在`load()`函式中指定其路徑來載入任何紋理或影像。

const loader = new THREE.TextureLoader()
texture.load('/path/to/the/image')

然後,將材質的`map`屬性設定為此紋理。就是這樣;您已將紋理應用於平面幾何體。

紋理具有用於重複、偏移和旋轉紋理的設定。預設情況下,three.js中的紋理不會重複。有兩個屬性,`wrapS`用於水平環繞,`wrapT`用於垂直環繞,用於設定紋理是否重複。並將重複模式設定為`THREE.RepeatWrapping`。

texture.wrapS = THREE.RepeatWrapping
texture.wrapT = THREE.RepeatWrapping
texture.magFilter = THREE.NearestFilter

在Three.js中,您可以選擇在紋理繪製尺寸大於其原始尺寸時以及在紋理繪製尺寸小於其原始尺寸時發生的情況。

對於設定過濾器,當紋理大於其原始尺寸時,您可以將`texture.magFilter`屬性設定為`THREE.NearestFilter`或`THREE.LinearFilter`。

  • NearestFilter - 此過濾器使用它可以找到的最近紋理畫素的顏色。

  • LinearFilter - 此過濾器更高階,它使用四個相鄰紋理畫素的顏色值來確定正確的顏色。

而且,您可以新增紋理重複的次數。

const timesToRepeatHorizontally = 4
const timesToRepeatVertically = 2
texture.repeat.set(timesToRepeatHorizontally, timesToRepeatVertically)

示例

檢視以下示例。

texture.html

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8" />
      <meta http-equiv="X-UA-Compatible" content="ie=edge" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Three.js - Checker Board</title>
      <style>
         * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: -applesystem, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
            Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
         }
         html,
         body {
            height: 100vh;
            width: 100vw;
         }
         #threejs-container {
            position: block;
            width: 100%;
            height: 100%;
         }
      </style>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script>
   </head>
   <body>
      <div id="threejs-container"></div>
      <script type="module">
         // Creating a checker-board using Textures
         // applying the texture to 2d plane geometry
         // GUI
         const gui = new dat.GUI()
         // sizes
         let width = window.innerWidth
         let height = window.innerHeight
         // scene
         const scene = new THREE.Scene()
         scene.background = new THREE.Color(0x262626)
         // camera
         const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 100)
         camera.position.set(0, 0, 10)
         const camFolder = gui.addFolder('Camera')
         camFolder.add(camera.position, 'z').min(10).max(60).step(10)
         camFolder.open()
         // Light
         const ambientLight = new THREE.AmbientLight(0xffffff, 1)
         scene.add(ambientLight)
         // texture
         const planeSize = 10
         const loader = new THREE.TextureLoader()
         const texture = loader.load(' https://cloud-nfpbfxp6x-hack-clubbot.vercel.app/0height.png ')
         texture.wrapS = THREE.RepeatWrapping
         texture.wrapT = THREE.RepeatWrapping
         texture.magFilter = THREE.NearestFilter
         const repeats = planeSize / 2
         texture.repeat.set(repeats, repeats)
         class StringToNumberHelper {
            constructor(obj, prop) {
               this.obj = obj
               this.prop = prop
            }
            get value() {
               return this.obj[this.prop]
            }
            set value(v) {
               this.obj[this.prop] = parseFloat(v)
            }
         }
         const wrapModes = {
            ClampToEdgeWrapping: THREE.ClampToEdgeWrapping,
            RepeatWrapping: THREE.RepeatWrapping,
            MirroredRepeatWrapping: THREE.MirroredRepeatWrapping
         }
         function updateTexture() {
            texture.needsUpdate = true
         }
         gui
            .add(new StringToNumberHelper(texture, 'wrapS'), 'value', wrapModes)
            .name('texture.wrapS')
            .onChange(updateTexture)
         gui
            .add(new StringToNumberHelper(texture, 'wrapT'), 'value', wrapModes)
            .name('texture.wrapT')
            .onChange(updateTexture)
         gui.add(texture.repeat, 'x', 0, 5, 0.01).name('texture.repeat.x')
         gui.add(texture.repeat, 'y', 0, 5, 0.01).name('texture.repeat.y')
         // plane for board
         const geometry = new THREE.PlaneGeometry(planeSize, planeSize)
         const material = new THREE.MeshPhongMaterial({
            map: texture,
            side: THREE.DoubleSide
         })
         const board = new THREE.Mesh(geometry, material)
         board.position.set(0, 0, 0)
         scene.add(board)
         // responsiveness
         window.addEventListener('resize', () => {
            width = window.innerWidth
            height = window.innerHeight
            camera.aspect = width / height
            camera.updateProjectionMatrix()
            renderer.setSize(window.innerWidth, window.innerHeight)
            renderer.render(scene, camera)
         })
         // renderer
         const renderer = new THREE.WebGL1Renderer()
         renderer.setSize(width, height)
         renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
         // animation
         function animate() {
            requestAnimationFrame(animate)
            renderer.render(scene, camera)
         }
         // rendering the scene
         const container = document.querySelector('#threejs-container')
         container.append(renderer.domElement)
         renderer.render(scene, camera)
         console.log(scene.children)
         animate()
      </script>
   </body>
</html>

輸出

紋理對映

基礎顏色貼圖

這是您新增到物件的紋理的基本彩色影像。使用基礎顏色貼圖,我們向表面新增顏色。

const textureMap = new THREE.TextureLoader().load('/path/to/texture-map')
material.map = textureMap

您可以使用凹凸貼圖、法線貼圖或距離貼圖來新增深度的效果。

凹凸貼圖

凹凸貼圖是一個灰度影像,其中每個畫素的強度決定了高度。您可以只將材質的`bumpMap`屬性設定為紋理。它為紋理添加了精細的細節。

const textureBumpMap = new THREE.TextureLoader().load('/path/to/bump-map')
material.bumpMap = textureBumpMap

法線貼圖

法線貼圖描述每個畫素的法線向量,這應該用於計算光線如何影響幾何體中使用的材質。它為平面表面創造了深度的錯覺。

const textureNormalMap = new THREE.TextureLoader().load('/path/to/normal-map')
material.normalMap = textureNormalMap

置換貼圖

雖然法線貼圖提供了深度的錯覺,但我們根據紋理中的資訊改變了模型的形狀,使用了置換貼圖。

const textureDisplacementMap = new THREE.TextureLoader().load(
   '/path/to/displacement-map'
)
material.displacemetMap = textureDisplacementMap

粗糙度貼圖

粗糙度貼圖定義了哪些區域是粗糙的,這會影響表面的反射銳度。

const textureRoughnessMap = new THREE.TextureLoader().load(
   '/path/to/roughness-map'
)
material.roughnessMap = textureRoughnessMap

環境光遮蔽貼圖

它突出顯示物件的陰影區域。它需要第二組UV。

const textureAmbientOcclusionMap = new THREE.TextureLoader().load(
   '/path/to/AmbientOcclusion-map'
)
material.aoMap = textureAmbientOcclusionMap
// second UV
mesh.geometry.attributes.uv2 = mesh.geometry.attributes.uv

如果您比較具有粗糙度貼圖和環境光遮蔽貼圖的物件,您可以觀察到使用aoMap後陰影更加突出。

金屬度貼圖

它定義了材質有多少像金屬。

const textureMetalnessMap = new THREE.TextureLoader().load(
   '/path/to/metalness-map'
)
material.metalnessMap = textureMetalnessMap

示例

現在,檢視以下示例

texture-maps.html

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8" />
      <meta http-equiv="X-UA-Compatible" content="ie=edge" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Three.js - Texture Mapping</title>
      <style>
         * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: -applesystem, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
            Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
         }
         html,
         body {
            height: 100vh;
            width: 100vw;
         }
         #threejs-container {
            position: block;
            width: 100%;
            height: 100%;
         }
      </style>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script>
   </head>
   <body>
      <div id="threejs-container"></div>
      <script type="module">
         // Using different types of texture maps
         import { OrbitControls } from "https://threejs.org/examples/jsm/controls/OrbitControls.js"

         // sizes
         let width = window.innerWidth
         let height = window.innerHeight
         // scene
         const scene = new THREE.Scene()
         scene.background = new THREE.Color(0xffffff)
         // lights
         const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
         scene.add(ambientLight)
         const light = new THREE.DirectionalLight(0xffffff, 4.0)
         light.position.set(0, 10, 20)
         light.castShadow = true
         light.shadow.mapSize.width = 512
         light.shadow.mapSize.height = 512
         light.shadow.camera.near = 0.5
         light.shadow.camera.far = 100
         scene.add(light)
         // camera
         const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100)
         camera.position.set(0, 0, 10)
         // textures
         const loader = new THREE.TextureLoader()
         const texture = loader.load('https://cloud-nfpbfxp6x-hack-clubbot.vercel.app/5basecolor.jpg')
         const normalmap = loader.load('https://cloud-nfpbfxp6x-hack-clubbot.vercel.app/2normal.jpg')
         const heightmap = loader.load('https://cloud-nfpbfxp6x-hack-clubbot.vercel.app/0height.png')
         const roughmap = loader.load('https://cloud-nfpbfxp6x-hack-clubbot.vercel.app/3roughness.jpg')
         const ambientOcclusionmap = loader.load('https://cloud-nfpbfxp6x-hackclub-bot.vercel.app/4ambientocclusion.jpg')
         const metallicmap = loader.load('https://cloud-nfpbfxp6x-hack-clubbot.vercel.app/1metallic.jpg')
         // plane
         const planeGeometry = new THREE.PlaneGeometry(100, 100)
         const plane = new THREE.Mesh(
            planeGeometry,
            new THREE.MeshPhongMaterial({ color: 0xffffff, side: THREE.DoubleSide })
         )
         plane.rotateX(-Math.PI / 2)
         plane.position.y = -2.75
         plane.receiveShadow = true
         scene.add(plane)
         // object
         const geometry = new THREE.SphereGeometry(1, 64, 64)
         const material1 = new THREE.MeshStandardMaterial({
            map: texture,
            side: THREE.DoubleSide
         })
         const object1 = new THREE.Mesh(geometry, material1)
         object1.position.set(-2.5, 1.5, 0)
         object1.castShadow = true
         scene.add(object1)
         // normal map
         const material2 = new THREE.MeshStandardMaterial({
            color: 0xffffff,
            map: texture,
            side: THREE.DoubleSide,
            normalMap: normalmap
         })
         const object2 = new THREE.Mesh(geometry, material2)
         object2.position.set(0, 1.5, 0)
         object2.castShadow = true
         scene.add(object2)
         // displacement map
         const material3 = new THREE.MeshStandardMaterial({
            color: 0xffffff,
            map: texture,
            side: THREE.DoubleSide,
            normalMap: normalmap,
            displacementMap: heightmap,
            displacementScale: 0.05
         })
         const object3 = new THREE.Mesh(geometry, material3)
         object3.position.set(2.5, 1.5, 0)
         object3.castShadow = true
         scene.add(object3)
         console.log(object3)
         // roughness map
         const material4 = new THREE.MeshStandardMaterial({
            color: 0xffffff,
            map: texture,
            side: THREE.DoubleSide,
            normalMap: normalmap,
            displacementMap: heightmap,
            displacementScale: 0.05,
            roughnessMap: roughmap,
            roughness: 0.5
         })
         const object4 = new THREE.Mesh(geometry, material4)
         object4.position.set(-2.5, -1.5, 0)
         object4.castShadow = true
         scene.add(object4)
         console.log(object4)
         // ambient occlusion map
         const material5 = new THREE.MeshStandardMaterial({
            color: 0xffffff,
            map: texture,
            side: THREE.DoubleSide,
            normalMap: normalmap,
            displacementMap: heightmap,
            displacementScale: 0.05,
            roughnessMap: roughmap,
            roughness: 0.1,
            aoMap: ambientOcclusionmap
         })
         const object5 = new THREE.Mesh(geometry, material5)
         object5.position.set(0, -1.5, 0)
         object5.geometry.attributes.uv2 = object5.geometry.attributes.uv
         object5.castShadow = true
         scene.add(object5)
         console.log(object5)
         // for env maps
         const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(128, {
            format: THREE.RGBFormat,
            generateMipMaps: true,
            minFilter: THREE.LinearMipmapLinearFilter,
            encoding: THREE.sRGBEncoding
         })
         const cubeCamera = new THREE.CubeCamera(1, 10000, cubeRenderTarget)
         cubeCamera.position.set(0, 100, 0)
         scene.add(cubeCamera)
         // metallic map
         const material6 = new THREE.MeshStandardMaterial({
            color: 0xffffff,
            map: texture,
            side: THREE.DoubleSide,
            normalMap: normalmap,
            displacementMap: heightmap,
            displacementScale: 0.15,
            roughnessMap: roughmap,
            roughness: 0.1,
            aoMap: ambientOcclusionmap,
            metalnessMap: metallicmap,
            metalness: 1,
            envMap: cubeRenderTarget.texture
         })
         const object6 = new THREE.Mesh(geometry, material6)
         object6.position.set(2.5, -1.5, 0)
         object6.geometry.attributes.uv2 = object6.geometry.attributes.uv
         object6.castShadow = true
         scene.add(object6)
         console.log(object6)
         cubeCamera.position.copy(object6.position)
         // responsiveness
         window.addEventListener('resize', () => {
            width = window.innerWidth
            height = window.innerHeight
            camera.aspect = width / height
            camera.updateProjectionMatrix()
            renderer.setSize(window.innerWidth, window.innerHeight)
            renderer.render(scene, camera)
         })
         // renderer - anti-aliasing
         const renderer = new THREE.WebGLRenderer({ antialias: true })
         renderer.physicallyCorrectLights = true
         renderer.setSize(width, height)
         renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
         const controls = new OrbitControls(camera, renderer.domElement)
         // animation
         function animate() {
            requestAnimationFrame(animate)
            let objects = [object1, object2, object3, object4, object5, object6]
            objects.forEach((i) => {
               //i.rotation.x += 0.005
               i.rotation.y += 0.01
            })
            controls.update()
            cubeCamera.update(renderer, scene)
            renderer.render(scene, camera)
         }
         // rendering the scene
         const container = document.querySelector('#threejs-container')
         container.append(renderer.domElement)
         renderer.render(scene, camera)
         animate()
      </script>
   </body>
</html>

輸出

Texture Maps

還有一些其他貼圖用於在計算機圖形學中建立真實世界的模型。您可以瞭解更多資訊 這裡

廣告
© . All rights reserved.