three.js教程5-几何体顶点UV坐标、纹理贴图TextureLoader
1、纹理贴图
纹理贴图,是给MeshLambertMaterial等材质一些纹理图片,以达到更好的视觉效果。
使用方法:通过纹理贴图加载器TextureLoader
的load()
方法加载一张图片可以返回一个纹理对象Texture
,纹理对象Texture
可以作为模型材质颜色贴图.map
属性的值。
const geometry = new THREE.PlaneGeometry(200, 100); //纹理贴图加载器TextureLoader const texLoader = new THREE.TextureLoader(); // .load()方法加载图像,返回一个纹理对象Texture const texture = texLoader.load('./earth.jpg'); const material = new THREE.MeshLambertMaterial({ // color: 0x00ffff,color和map颜色值会混合,因此设置map后color一般不用设置 // 设置纹理贴图:Texture对象作为材质map属性的属性值 map: texture,//map表示材质的颜色贴图属性 });
color和map颜色值会混合,因此设置map后color一般不用设置
2、顶点uv坐标
顶点uv坐标,是二维顶点坐标,顶点UV坐标geometry.attributes.uv
和顶点位置坐标geometry.attributes.position
是一一对应的。
作用:纹理贴图上提取像素映射到网格模型Mesh的几何体表面上。
顶点UV坐标,可以在0~1.0之间任意取值(是百分比值,比如0.3,对应是30%的位置),纹理贴图左下角对应的UV坐标是(0,0)
,右上角对应的坐标(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个为一组,表示一个顶点的纹理坐标
获取纹理贴图左下角四分之一部分:
const uvs = new Float32Array([ 0, 0, 0.5, 0, 0.5, 0.5, 0, 0.5, ]);
3、实现瓷砖地面效果
// .load()方法加载图像,返回一个纹理对象Texture const texture = texLoader.load('./瓷砖.jpg'); // 设置阵列包裹模式,S对应U,T对应V texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; // uv两个方向纹理重复数量 texture.repeat.set(12,12);//注意选择合适的阵列数量
4、背景透明的png图片贴图-transparent
如果不做处理,直接贴图,透明部分会有颜色填充,因此要设置transparent: true解决
const material = new THREE.MeshBasicMaterial({ map: textureLoader.load('./指南针.png'), transparent: true, //使用背景透明的png贴图,注意开启透明计算 });
5、创建uv动画(利用offset属性)
通过纹理对象的偏移属性.offset
实现一个UV动画效果。offset是Vector2对象。
texture.offset.x +=0.5;//纹理U方向偏移 // 设置.wrapS也就是U方向,纹理映射模式(包裹模式) texture.wrapS = THREE.RepeatWrapping;//对应offste.x偏移 texture.offset.y +=0.5;//纹理V方向偏移 // 设置.wrapT也就是V方向,纹理映射模式 texture.wrapT = THREE.RepeatWrapping;//对应offste.y偏移
把上面代码放到渲染循环函数中执行即可实现动画。
记住对应关系:X:S:U这3个对应,Y:T:V这3个对应。
下面展示一个示例:
实例完整代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Three.js中文网:www.webgl3d.cn</title> <style> body{ overflow: hidden; margin: 0px; } </style> </head> <body> <!-- type="importmap"功能:.html文件中也能和nodejs开发环境中一样方式,引入npm安装的js库 --> <script type="importmap"> { "imports": { "three": "../../../three.js/build/three.module.js", "three/addons/": "../../../three.js/examples/jsm/" } } </script> <script type="module"> import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; // 一个矩形平面几何体用来表示传送带 const geometry = new THREE.PlaneGeometry(200, 20); //纹理贴图加载器TextureLoader const texLoader = new THREE.TextureLoader(); // .load()方法加载图像,返回一个纹理对象Texture const texture = texLoader.load('./纹理3.jpg'); const material = new THREE.MeshLambertMaterial({ map: texture,//map表示材质的颜色贴图属性 }); const mesh = new THREE.Mesh(geometry, material); mesh.rotateX(-Math.PI/2); // 设置阵列 texture.wrapS = THREE.RepeatWrapping; // uv两个方向纹理重复数量 texture.repeat.x=50;//注意选择合适的阵列数量 //场景 const scene = new THREE.Scene(); scene.add(mesh); //模型对象添加到场景中 //辅助观察的坐标系 const axesHelper = new THREE.AxesHelper(100); scene.add(axesHelper); //光源设置 const directionalLight = new THREE.DirectionalLight(0xffffff, 1); directionalLight.position.set(100, 60, 50); scene.add(directionalLight); const ambient = new THREE.AmbientLight(0xffffff, 0.4); scene.add(ambient); //渲染器和相机 const width = window.innerWidth; const height = window.innerHeight; const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000); camera.position.set(292, 223, 185); camera.lookAt(0, 0, 0); const renderer = new THREE.WebGLRenderer(); renderer.setSize(width, height); document.body.appendChild(renderer.domElement); // 渲染循环 function render() { texture.offset.x +=0.1;//设置纹理动画 renderer.render(scene, camera); requestAnimationFrame(render); } render(); const controls = new OrbitControls(camera, renderer.domElement); // 画布跟随窗口变化 window.onresize = function () { renderer.setSize(window.innerWidth, window.innerHeight); camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); }; </script> </body> </html>
文章中部分素材选取自Threejs中文网:http://www.webgl3d.cn/