- 三.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>
输出
还有一些其他地图可用于在计算机图形学中创建真实世界模型。您可以在这里了解更多信息。