- 三.js教程
- Three.js - 主页
- Three.js - 简介
- Three.js - 安装
- Three.js - Hello Cube 应用程序
- Three.js - 渲染器和响应能力
- Three.js - 响应式设计
- Three.js - 调试和统计
- Three.js - 相机
- Three.js - 控件
- Three.js - 光与影
- Three.js - 几何
- Three.js - 材料
- Three.js - 纹理
- Three.js - 画线
- Three.js - 动画
- Three.js - 创建文本
- Three.js - 加载 3D 模型
- Three.js - 库和插件
- Three.js 有用资源
- Three.js - 快速指南
- Three.js - 有用的资源
- Three.js - 讨论
Three.js - 纹理
纹理是添加到材质中以提供更多细节或美感的图像或颜色。纹理是 Three.js 中的一个重要主题。在本节中,我们将了解如何将基本纹理应用于我们的材质。
基本纹理
首先,您应该创建一个加载程序。Three.js 有一个内置函数TextureLoader(),用于将纹理加载到您的 Three.js 项目中。然后,您可以通过在 load() 函数中指定其路径来加载任何纹理或图像。
const loader = new THREE.TextureLoader() texture.load('/path/to/the/image')
然后,将材质的贴图属性设置为此纹理。就是这样; 您将纹理应用到平面几何体。
纹理具有重复、偏移和旋转纹理的设置。默认情况下, Three.js 中的纹理不重复。有两个属性,wrapS 用于水平环绕,wrapT 用于垂直环绕,用于设置纹理是否重复。并将重复模式设置为THREE.ReaptWrapping。
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)
例子
查看以下示例。
纹理.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
您可以使用凹凸贴图、法线贴图或距离贴图添加深度效果。
凹凸贴图
凹凸贴图是灰度图像,其中每个像素的强度决定高度。您只需将材质凹凸贴图属性设置为纹理即可。它为纹理添加了精美的细节。
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
例子
现在,查看以下示例
纹理贴图.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>
输出
还有一些其他地图可用于在计算机图形学中创建真实世界模型。您可以在这里了解更多信息。