文章目录
- Three.js 纹理贴图
- 纹理贴图 map属性
- 纹理贴图的映射方式 texture.Mapping
- 纹理加载器 THREE.TextureLoader
- 监听单个材质
- 监听多个材质 - LoadingManager类
- 1. 颜色贴图与材质的颜色
- 2.渲染效果:UV坐标 - 描述纹理贴图的坐标
- 自定义顶点UV`geometry.attributes.uv`
- 纹理对象Texture阵列 - texture.wrapS、texture.wrapT与texture.repeat
- 案例:矩形Mesh+背景透明png贴图
- 案例:uv动画 - 纹理对象的偏移属性offset
- 纹理贴图阵列 + UV动画
- 环境贴图
- 添加环境贴图 mesh材质的envMap属性
- 使用立方体纹理加载器CubeTextureLoader加载环境贴图
- 透明贴图 mesh的alphaMap属性 / 高光贴图 mesh的specularMap属性/光照贴图 mesh的lightMap属性/环境遮挡贴图 mesh的aoMap属性
Three.js 纹理贴图
- 纹理贴图加载器
TextureLoader
的.load()
方法加载一张图片,返回一个纹理对象Texture
。 - 立方体纹理加载器
CubeTextureLoader
的.load()
方法加载6张图片,返回一个立方体纹理对象CubeTexture
。立方体纹理对象CubeTexture的父类是纹理对象Texture。
网格材质 Mesh的贴图属性
属性 | 描述 | 其他 |
---|---|---|
map:Texture | 材质的颜色贴图 | 使用范围:除MeshPhysicalMaterial |
envMap : Texture | 环境贴图 | |
alphaMap: | 透明贴图 alpha贴图是一张灰度纹理,用于控制整个表面的透明度。 | 需要开启材质的透明度属性 |
specularMap : Texture | 高光贴图用于控制对象表面的高光反射强度和位置,通常使用灰度图像来表示不同的反射强度值。 | 可以通过reflectivity属性设置反射强度 |
纹理贴图 map属性
纹理贴图的映射方式 texture.Mapping
属性默认值:texture.Mapping = THREE.UVMapping
属性含义:如何将纹理题图应用到几何体表面
mapping
是一种将纹理贴到几何体表面上的技术cube mapping
则是一种将纹理贴到立方体表面上的技术。
属性值 | 描述 | 使用 |
---|---|---|
THREE.UVMapping UV贴图 | 将二维纹理映射到三维物体表面的过程。在 Three.js 中,每个几何体都有一个 UV 坐标系,和几何体表面上的三角形网格一一对应。UV 坐标系中的每个点都映射到纹理图像上的一个像素,用来确定几何体表面的纹理贴图。 | U,V 坐标用来应用映射,要求是单个纹理。 一般与网格材质的map属性配合使用。 |
THREE.CubeReflectionMapping 立方体反射映射 | 该映射模式将环境贴图作为一个立方体贴图,将六个面分别映射到对应的立方体面上,以模拟立方体环境映射和反射效果。 | cubeTexture.mapping的默认值 |
THREE.CubeRefractionMapping 立方体折射映射 | 使用一个立方体贴图来表示环境光的折射,可以用来模拟环境光和镜面反射等效果 | 该映射模式与 THREE.CubeReflectionMapping 类似,但是它模拟的是折射效果,环境贴图中的物体看作透明的,经过物体的折射后反射到表面上。 |
THREE.EquirectangularReflectionMapping 圆柱反射映射 | 将环境贴图作为一个全景图片,将图片映射到球体或半球体上,以模拟球形环境映射和反射效果。 | 类似cube mapping,只不过不是用立方体贴图,而是使用单个贴图? 可以配合材质的envMap属性使用 |
THREE.EquirectangularRefractionMapping 圆柱折射映射 | 该映射模式与 THREE.EquirectangularReflectionMapping 类似,但是模拟的是折射效果,即将环境贴图中的物体看作透明的,经过物体的折射后反射到表面上。 | 可以配合材质的envMap属性使用 |
纹理加载器 THREE.TextureLoader
纹理加载器:new THREE.TextureLoader( manager : LoadingManager )
参数:加载器使用的 loadingManager
,默认值为THREE.DefaultLoadingManager
继承链:Loader → TextureLoader
返回值:返回创建的纹理加载器TextureLoader
.
纹理对象的属性和方法
属性名和方法名 | 描述 |
---|---|
texture.offset:Vector2 | 贴图单次重复中的起始偏移量(偏移贴图在Mesh上位置),分别表示U和V。 |
加载纹理- 得到纹理对象
textureLoader.load ( url : String, onLoad : (texture)=>{}, onProgress : Function, onError : Function ) : Texture
返回值:新的纹理对象texture
,该纹理对象可以用于材质创建
注意点:异步加载,第三个参数在后续版本好像被遗弃了可以用undefined
暂时占位
监听单个材质
import tile from "./assets/tile.jpg";
// 初始化一个加载器
const loader = new THREE.TextureLoader();
// 加载一个资源
loader.load(
// 【参数1】资源URL
tile,
// 【参数2】onLoad回调
function ( texture ) {
// 【才材质加载成功后执行】
const material = new THREE.MeshBasicMaterial( {
map: texture
} );
},
// 【参数3】目前暂不支持onProgress的回调
undefined,
// 【参数4】onError回调,
function ( err ) {
console.error( '材质加载失败' );
}
)
监听多个材质 - LoadingManager类
语法:LoadingManager(onLoad:Function,onProgress:Function,, onError:Function,)
说明:处理并跟踪已加载和待处理的数据。
参数
onLoad:所有加载器加载完成后,将调用此函数。
onProgress: 当每个项目完成后,将调用此函数。
onError: 当一个加载器遇到错误时,将调用此函数。
// 设置加载管理器
const loadingManager = new THREE.LoadingManager(
function() {
console.log('图片加载完成')
},
function(url, loaded, total) {
console.log(`图片加载中,本次加载的材质${url},第 ${loaded}/${total} 个材质`)
},
function(err) {
console.log('图片加载失败', err)
}
)
// Three提供的纹理加载器
const textureLoader = new THREE.TextureLoader(loadingManager)
// 导入纹理贴图基础贴图
const imgTexture1 = textureLoader.load('../assets/images/140.jpg')
const imgTexture2 = textureLoader.load('../assets/images/141.jpg')
执行输出
图片加载中,本次加载的材质../assets/images/140.jpg,第 1/2 个材质
图片加载中,本次加载的材质../assets/images/141.jpg,第 2/2 个材质
图片加载完成
1. 颜色贴图与材质的颜色
在vur中的引入方式
方式1.先import引入然后作为参数传递给load
方式2.将图片存储在public
公共文件夹下
// 方式1
import map from "./assets/map.jpg";
const texLoader = new THREE.TextureLoader();
const texture = texLoader.load(map)
// 方式2
import panda from "/panda.png";
const material = new THREE.MeshLambertMaterial({
map:texLoader.load( panda),
});
// 这种写法也可以
const material = new THREE.MeshLambertMaterial({
map:texLoader.load('../public/panda.png'),
});
// 加载失败会报错,这里参数只是字符串
const texture = texLoader.load('./assets/map.jpg')
public里的文件不会处理,直接复制到打包文件。文件中的绝对地址也不会解析所以可以将图片放到public中。
.
开头的地址会被理解为相对地址,webpack会解析地址加载图片,这里不知道是不是load的参数没有被理解为相对地址去解析,所以才会报错?
vue中引入图片失败的原因及解决办法
材质的颜色贴图属性.map
设置后,模型会从纹理贴图上采集像素值,这时候一般来说不需要再设置材质颜色.color
。
颜色贴图map
和color
属性颜色值会混合。如果没有特殊需要,设置了颜色贴图.map
就不用设置·color
2.渲染效果:UV坐标 - 描述纹理贴图的坐标
是什么:顶点UV坐标可以在0~1.0之间任意取值,纹理贴图左下角对应的UV坐标是(0,0),右上角对应的坐标(1,1)。
作用:从纹理贴图上提取UV坐标范围的像素映射到网格模型Mesh的几何体表面上。
// 默认情况会自动提取
import panda from "../public/panda.png";
const geometry = new THREE.BoxGeometry(100, 100,100);
const texLoader = new THREE.TextureLoader();
const texture = texLoader.load(panda )
const material = new THREE.MeshLambertMaterial({
map:texture,
});
const mesh = new THREE.Mesh(geometry, material);
console.log(geometry.attributes.uv)
自定义顶点UVgeometry.attributes.uv
geometry.attributes.position
描述几何体的顶点坐标
geometry.attributes.uv
描述纹理贴图的坐标
位置关系是一一对应的,每一个顶点位置对应一个纹理贴图的位置
根据纹理坐标将纹理贴图的对应位置裁剪映射到几何体的表面上。
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
0, 0, 0, //顶点1坐标
100, 0, 0, //顶点2坐标
0, 100, 0, //顶点3坐标
]);
geometry.attributes.position = new THREE.BufferAttribute(vertices, 3);
const uv = new Float32Array([
0, 0, //顶点1对应位置的纹理坐标uv
1, 0, //顶点2对应位置的纹理坐标uv
0, 1, //顶点3对应位置的纹理坐标uv
]);
geometry.attributes.uv = new THREE.BufferAttribute(uv, 2);
纹理对象Texture阵列 - texture.wrapS、texture.wrapT与texture.repeat
阵列就是不断的重复,如果使用一个规则的图形,load只需要加载一小部分,然后通过阵列完全显示,加快贴图加载的速度。
属性名 | 描述 | 参考值 |
---|---|---|
texture.wrapS:number | 定义了纹理贴图在水平方向上将如何包裹,在UV映射中对应于U | 可选纹理常量中的包裹模式三个选项,默认是THREE.ClampToEdgeWrapping |
texture.wrapT :number | 纹理贴图在垂直方向上将如何包裹,在UV映射中对应于V | 同 |
texture.repeat:Vector2 | 决定纹理在表面的重复次数,两个方向分别表示U和V | - |
包裹模式的可选值
包裹模式 | 描述 |
---|---|
THREE.RepeatWrapping | 纹理将简单地重复到无穷大 |
THREE.ClampToEdgeWrapping | 纹理中的最后一个像素将延伸到网格的边缘 |
THREE.MirroredRepeatWrapping | 在每次重复时将进行镜像 |
import tile from "./assets/tile.jpg";
// 1.创建地面
const geometry = new THREE.PlaneGeometry(300, 250);
// 2.加载纹理对象
const texLoader = new THREE.TextureLoader();
const texture = texLoader.load(tile)
//3.开启阵列,设置阵列模式
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
// uv两个方向纹理重复数量
texture.repeat.set(8,8);
const material = new THREE.MeshLambertMaterial({
map:texture,
});
案例:矩形Mesh+背景透明png贴图
想要png
贴图完全透明的部分不显示,需要将材质的transparent
属性打开。
// 矩形平面网格模型设置背景透明的png贴图
import direction from "./assets/direction .jpg";
const geometry = new THREE.PlaneGeometry(60, 60); //默认在XOY平面上
const textureLoader = new THREE.TextureLoader();
const material = new THREE.MeshBasicMaterial({
map: textureLoader.load(direction ),
transparent: true, //使用背景透明的png贴图,注意开启透明计算
});
const mesh = new THREE.Mesh(geometry, material);
mesh.rotateX(-Math.PI / 2);
案例:uv动画 - 纹理对象的偏移属性offset
偏移之后的左边部分被截掉,右边的剩余部分为图片最后1px无限重复
// 渲染循环
function render() {
texture.offset.x +=0.001;//设置纹理动画:偏移量根据纹理和动画需要,设置合适的值
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
纹理贴图阵列 + UV动画
开启阵列之后,左边偏移消失的地方会拼接到右边偏移之后多出来的地方(首尾相连)
import * as THREE from "three";
import panda from "/panda.png";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
1,
8000
);
camera.position.set(300,300,300)
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
const geometry = new THREE.PlaneGeometry(200, 200);
const loader = new THREE.TextureLoader();
const texture = loader.load(panda)
// 设置U方向阵列模式
texture.wrapS = THREE.RepeatWrapping;
// u方向纹理重复数量
texture.repeat.x=2;
const material = new THREE.MeshBasicMaterial( {
map: texture
} );
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
const ambient = new THREE.AmbientLight(0xffffff,3)
scene.add(ambient);
document.body.appendChild(renderer.domElement);
// 渲染循环
function render() {
texture.offset.x +=0.1;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
环境贴图
环境贴图是一类用于模拟环境反射光照的一种 3D 技术
为什么叫天空盒
OpenGL中天空盒的思想就是绘制一个大的立方体,然后将观察者放在立方体的中心,当相机移动时,这个立方体也跟着相机一起移动,这样相机就永远不会运动到场景的边缘。
添加环境贴图 mesh材质的envMap属性
给模型设置环境贴图后,可以将将光反射的环境部分映射到模型上(类似镜子将人反射在镜子上面)。
使用下图作为环境贴图
这里一定要将设置envMap.mapping
,不然模型就是一片黑色,这里设置成THREE.EquirectangularReflectionMapping
和THREE.EquirectangularRefractionMapping
都可以。
// 这里的图片都在public文件夹下
const geometry = new THREE.PlaneGeometry(200, 200);
const loader = new THREE.TextureLoader();
const texture = loader.load("/assets/door.png")
const material = new THREE.MeshBasicMaterial({
map: texture,
});
loader.load("/assets/test.jpg",(envMap)=>{
envMap.mapping = THREE.EquirectangularReflectionMapping;
material.envMap = envMap;
})
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
使用一个全景图作为环境贴图
loader.load("/assets/test.jpg",(envMap)=>{
envMap.mapping = THREE.EquirectangularReflectionMapping;
scene.background = envMap; // 将全景图设置为scen的背景
scene.environment = envMap;
material.envMap = envMap; // 设置为环境贴图后,可以在模型上看见光反射的环境
})
使用立方体纹理加载器CubeTextureLoader加载环境贴图
语法:new CubeTextureLoader( manager : LoadingManager )
参数:加载器使用的 loadingManager
,默认值为THREE.DefaultLoadingManager
继承链:Loader → CubeTextureLoader
返回值:返回创建的立方体纹理加载器CubeTextureLoader
.
描述:立方体纹理加载器CubeTextureLoader
的.load()
方法加载6张图片,返回一个立方体纹理对象CubeTexture
。
loader.setPath
设置基础路径
// 加载环境贴图
// 加载周围环境6个方向贴图
// 上下左右前后6张贴图构成一个立方体空间
const loader = new THREE.TextureLoader();
const texture = loader.load("/assets/door1.png")
const alphaMap = loader.load("/assets/mask.png")
const urls = [
'/assets/tile.jpg', x轴正方向 p:正positive n:负negative
'/assets/tile.jpg', x轴负方向 p:正positive n:负negative
'/assets/tile.jpg', y轴正方向
'/assets/tile.jpg', y轴负方向
'/assets/tile.jpg', z轴正方向
'/assets/tile.jpg', z轴负方向
]
let textureCube = new THREE.CubeTextureLoader().load(urls);
scene.background = textureCube;
const material = new THREE.MeshBasicMaterial({
map: texture,
envMap:textureCube,
});
透明贴图 mesh的alphaMap属性 / 高光贴图 mesh的specularMap属性/光照贴图 mesh的lightMap属性/环境遮挡贴图 mesh的aoMap属性
- 透明贴图:alpha贴图是一张灰度纹理,用于控制整个表面的透明度。
- 高光贴图:用于控制对象表面的高光反射强度和位置,通常使用灰度图像来表示不同的反射强度值。
- 光照贴图:用于控制对象表面的光照强度和位置,通常使用灰度图像来表示不同的光照强度值。光照贴图可以让对象表面看起来更加真实,增强细节和立体感。
- 环境光遮蔽贴图(AO贴图):用于控制对象表面在环境光下的遮蔽程度,通常使用灰度图像来表示不同的遮蔽程度值。
贴图类型 | 黑色 | 白色 | 灰色 |
---|---|---|---|
透明贴图alphaMap | 不透明区域 | 完全透明 | 不同程度的半透明 |
高光贴图specularMap | 不反射区域 | 最大反射强度区域 | 不同程度反射强度区域 |
光照贴图lightMap | 无光照 | 五颜六色的光 | |
环境遮蔽贴图aoMap | 完全被遮蔽 | 没有遮蔽 | 不同程度的遮蔽 |
案例代码
代码只显示某一贴图,测试时可以修改为不同贴图的设置属性,使用下图测试效果。
const texture = loader.load("/assets/door.png")
const alphaMap = loader.load("/assets/transparent.png")
let planeMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff,
map: texture,
transparent: true, // 允许透明
// 透明度贴图
alphaMap: alphaMap,
reflectivity: 0.5, //设置反射强度
});