Three.js开发必备:几何顶点UV坐标、纹理贴图详解含素材

Three.js开发必备:几何顶点UV坐标、纹理贴图详解

创建纹理贴图

通过纹理贴图加载器TextureLoaderload()方法加载一张图片可以返回一个纹理对象Texture,纹理对象Texture可以作为模型材质颜色贴图.map属性的值。

javascript 复制代码
// 创建一个纹理加载器对象
const loadTex = new THREE.TextureLoader();
// 加载图片返回一个纹理对象
const texture = loadTex.load('../src/assets/earth.jpg');
const material = new THREE.MeshBasicMaterial({
    map: texture
});

测试不同几何体添加纹理贴图的效果

可以尝试把颜色纹理贴图映射到不同的几何体上面查看渲染效果,映射效果的不同其实和UV坐标相关;

平面
javascript 复制代码
import * as THREE from 'three'

const geometry = new THREE.PlaneGeometry(200, 100);
// 创建一个纹理加载器对象
const loadTex = new THREE.TextureLoader();
// 加载图片返回一个纹理对象
const texture = loadTex.load('../src/assets/earth.jpg');
const material = new THREE.MeshBasicMaterial({
    map: texture
});
const mesh = new THREE.Mesh(geometry, material);

export default mesh;
球体
javascript 复制代码
import * as THREE from 'three'

const geometry = new THREE.SphereGeometry(50);
// 创建一个纹理加载器对象
const loadTex = new THREE.TextureLoader();
// 加载图片返回一个纹理对象
const texture = loadTex.load('../src/assets/earth.jpg');
const material = new THREE.MeshBasicMaterial({
    map: texture
});
const mesh = new THREE.Mesh(geometry, material);

export default mesh;
长方体
javascript 复制代码
import * as THREE from 'three'

const geometry = new THREE.BoxGeometry(100, 100, 100);
// 创建一个纹理加载器对象
const loadTex = new THREE.TextureLoader();
// 加载图片返回一个纹理对象
const texture = loadTex.load('../src/assets/earth.jpg');
const material = new THREE.MeshBasicMaterial({
    map: texture
});
const mesh = new THREE.Mesh(geometry, material);

export default mesh;

测试不同几何体添加纹理贴图的效果

也可以通过颜色贴图属性.map直接设置纹理贴图,和材质的参数设置一样。

javascript 复制代码
	mesh.material.map = texture;

自定义顶点UV坐标

纹理贴图UV坐标范围

顶点UV坐标可以在0~1.0之间任意取值,纹理贴图左下角对应的UV坐标是(0,0),右上角对应的坐标(1,1)

自定义顶点UV、geometry.attributes.uv

顶点UV坐标geometry.attributes.uv和顶点位置坐标geometry.attributes.position是一一对应的,UV顶点坐标你可以根据需要在0~1之间任意设置,具体怎么设置要看想把图片那部分映射到mesh的几何体表面上面。

javascript 复制代码
import * as THREE from 'three';

const geometry = new THREE.BoxGeometry(); //创建一个几何体对象
//类型数组创建顶点数据
const vertices = new Float32Array([
    0, 0, 0, //顶点1坐标
    160, 0, 0, //顶点2坐标
    160, 80, 0, //顶点3坐标
    0, 80, 0, //顶点4坐标
]);
// 创建属性缓冲区对象
const attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组,表示一个顶点的xyz坐标
// 设置几何体attributes属性的位置属性
geometry.attributes.position = attribue;

// Uint16Array类型数组创建顶点索引数据
const indexes = new Uint16Array([
    0, 1, 2, 0, 2, 3,
])
// 索引数据赋值给几何体的index属性
geometry.index = new THREE.BufferAttribute(indexes, 1); //1个为一组

/**纹理坐标0~1之间随意定义*/
const uvs = new Float32Array([
    0, 0, //图片左下角
    1, 0, //图片右下角
    1, 1, //图片右上角
    0, 1, //图片左上角
]);
// 设置几何体attributes属性的位置normal属性
geometry.attributes.uv = new THREE.BufferAttribute(uvs, 2); //2个为一组,表示一个顶点的纹理坐标

//纹理贴图加载器TextureLoader
const texLoader = new THREE.TextureLoader();
const texture = texLoader.load('../src/assets/earth.jpg');
const material = new THREE.MeshBasicMaterial({
    map: texture, //map表示材质的颜色贴图属性
    color: 0xfff0ff,
});
const mesh = new THREE.Mesh(geometry, material);

export default mesh;

使用UV坐标映射纹理贴图1/4

javascript 复制代码
import * as THREE from 'three';

const geometry = new THREE.BoxGeometry(); //创建一个几何体对象
//类型数组创建顶点数据
const vertices = new Float32Array([
    0, 0, 0, //顶点1坐标
    160, 0, 0, //顶点2坐标
    160, 80, 0, //顶点3坐标
    0, 80, 0, //顶点4坐标
]);
// 创建属性缓冲区对象
const attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组,表示一个顶点的xyz坐标
// 设置几何体attributes属性的位置属性
geometry.attributes.position = attribue;

// Uint16Array类型数组创建顶点索引数据
const indexes = new Uint16Array([
    0, 1, 2, 0, 2, 3,
])
// 索引数据赋值给几何体的index属性
geometry.index = new THREE.BufferAttribute(indexes, 1); //1个为一组

// 获取纹理贴图左下角四分之一部分的像素值
const uvs = new Float32Array([
    0, 0,
    0.5, 0,
    0.5, 0.5,
    0, 0.5,
]);
// 设置几何体attributes属性的位置normal属性
geometry.attributes.uv = new THREE.BufferAttribute(uvs, 2); //2个为一组,表示一个顶点的纹理坐标


//纹理贴图加载器TextureLoader
const texLoader = new THREE.TextureLoader();
const texture = texLoader.load('../src/assets/earth.jpg');
const material = new THREE.MeshBasicMaterial({
    map: texture, //map表示材质的颜色贴图属性
    color: 0xfff0ff,
});
const mesh = new THREE.Mesh(geometry, material);

export default mesh;

圆形平面CircleGeometry设置纹理贴图

通过圆形几何体CircleGeometry创建一个网格模型Mesh,把一张图片作为圆形Mesh材质的颜色贴图,这样就可以把一张方形图片剪裁渲染为圆形的效果。 CircleGeometryUV坐标会对颜色纹理贴图.map进行提取,CircleGeometryUV坐标默认提取的就是一个圆形轮廓。

javascript 复制代码
import * as THREE from 'three';
const geometry = new THREE.CircleGeometry(50, 100);
const texLoader = new THREE.TextureLoader();
const material = new THREE.MeshBasicMaterial({
    map: texLoader.load('../src/assets/texture.jpg'),
});
const mesh = new THREE.Mesh(geometry, material);
export default mesh;

纹理对象Texture阵列( 瓷砖地面案例 )

使用three.JS纹理对象Texture的阵列功能+矩形平面几何题PlaneGeometry实现一个地面瓷砖效果。

javascript 复制代码
import * as THREE from 'three';

const geometry = new THREE.PlaneGeometry(2000, 2000);

const texLoader = new THREE.TextureLoader();
const texture = texLoader.load('../src/assets/瓷砖.jpg')
// 允许阵列模式
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
// uv两个方向纹理重复数量,阵列多少个
texture.repeat.set(30, 30);
const material = new THREE.MeshBasicMaterial({
    map: texture,
    side: THREE.DoubleSide
});
const mesh = new THREE.Mesh(geometry, material);
mesh.rotateX(-Math.PI / 2)

export default mesh;

矩形Mesh加背景透明png贴图(场景标注)

three.js项目开发中,把一个背景透明的.png图像作为平面矩形网格模型Mesh的颜色贴图是一个非常实用的功能,通过这个功能可以对three.js三维场景进行标注。 思路:创建一个矩形平面,设置颜色贴图.map,注意选择背景透明的.png图像作为颜色贴图,同时材质transparent:true,这样png图片背景完全透明的部分不显示。

设置网格地面GridHelper

javascript 复制代码
// 创建一个辅助地面
const gridHelper = new THREE.GridHelper(500, 50, 0x00ffff, 0x004444);
scene.add(gridHelper);

矩形平面PlaneGeometry设置颜色贴纸

javascript 复制代码
import * as THREE from 'three';

const geometry = new THREE.PlaneGeometry(60, 60); // 默认在XOY平面上
const textureLoader = new THREE.TextureLoader();
const material = new THREE.MeshBasicMaterial({
    map: textureLoader.load('../src/assets/转弯.png'),
    transparent: true,
    side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(geometry, material);

mesh.position.y = 2.5;
mesh.rotateX(-Math.PI / 2);
export default mesh;

UV动画(偏移属性.offset)

通过纹理对象的偏移属性.offset实现一个UV动画效果。

纹理对象.offset属性

纹理对象Textyre的.offset的功能是偏移贴图在Mesh上位置,本质上相当于修改了UV顶点坐标。

偏移前
javascript 复制代码
import * as THREE from 'three';

const geometry = new THREE.PlaneGeometry(200, 20); // 默认在XOY平面上
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('../src/assets/纹理1.jpg')
const material = new THREE.MeshBasicMaterial({
    map: texture,
    transparent: true,
    side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(geometry, material);

mesh.position.y = 2.5;
mesh.rotateX(-Math.PI / 2);
export default mesh;
偏移后
javascript 复制代码
texture.offset.x += 0.5;

纹理对象.wrapS或.wrapT与.offset组合使用

可以通过.offset设置纹理映射片以后,是否把.wrapS或.wrappT设置为重复映射模式THREE.RepeatWrapping,两种情况的渲染效果差异。

javascript 复制代码
texture.offset.x += 0.5;
texture.wrapS = THREE.RepeatWrapping;  // 对应offset.x偏移
texture.offset.y += 0.5;
texture.wrapT = THREE.RepeatWrapping; // 对应offset.y偏移

传送带效果实现,方式1、大贴图

javascript 复制代码
import * as THREE from 'three';

const geometry = new THREE.PlaneGeometry(200, 20); // 默认在XOY平面上
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('../src/assets/wl2.jpg')
texture.offset.x += 0.5;
texture.wrapS = THREE.RepeatWrapping;  // 对应offset.x偏移
texture.offset.y += 0.5;
texture.wrapT = THREE.RepeatWrapping; // 对应offset.y偏移
const material = new THREE.MeshBasicMaterial({
    map: texture,
    transparent: true,
    side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(geometry, material);

mesh.position.y = 2.5;
mesh.rotateX(-Math.PI / 2);
export { mesh, texture };

每次渲染都+0.001

javascript 复制代码
// 渲染循环
function render() {
    texture.offset.x += 0.001;//设置纹理动画
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}
render();

传送带效果实现,方式2、小贴图+重复阵列

javascript 复制代码
import * as THREE from 'three';

const geometry = new THREE.PlaneGeometry(200, 20); // 默认在XOY平面上
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('../src/assets/wl3.jpg')

texture.wrapS = THREE.RepeatWrapping;  // 对应offset.x偏移
texture.repeat.x = 30;

const material = new THREE.MeshBasicMaterial({
    map: texture,
    transparent: true,
    side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = 2.5;
mesh.rotateX(-Math.PI / 2);
export { mesh, texture };

完结

素材

相关推荐
中微子7 分钟前
React状态管理最佳实践
前端
烛阴17 分钟前
void 0 的奥秘:解锁 JavaScript 中 undefined 的正确打开方式
前端·javascript
中微子24 分钟前
JavaScript 事件与 React 合成事件完全指南:从入门到精通
前端
Hexene...33 分钟前
【前端Vue】如何实现echarts图表根据父元素宽度自适应大小
前端·vue.js·echarts
天天扭码1 小时前
《很全面的前端面试题》——HTML篇
前端·面试·html
xw51 小时前
我犯了错,我于是为我的uni-app项目引入环境标志
前端·uni-app
!win !1 小时前
被老板怼后,我为uni-app项目引入环境标志
前端·小程序·uni-app
Burt1 小时前
tsdown vs tsup, 豆包回答一坨屎,还是google AI厉害
前端
群联云防护小杜2 小时前
构建分布式高防架构实现业务零中断
前端·网络·分布式·tcp/ip·安全·游戏·架构
ohMyGod_1233 小时前
React16,17,18,19新特性更新对比
前端·javascript·react.js