当前位置: 首页 > 工具软件 > Buster.JS > 使用案例 >

Threejs-自定义多边形并贴uv图

邵星光
2023-12-01

知识点

  • threejs自定义多边形
  • earcut切割多边形为三角面
  • 模型坐标与uv坐标

资源

threejs历史版本.


OrbitControls-百度云链接.
提取码:ob5n


Earcut

切割多边形三角剖分算法的实现。
earcut-百度云链接.
提取码:i91m


直接上代码:

注释写得很清楚

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<title>WebGL三维场景</title>
		<style>
			body {
				margin: 0;
				overflow: hidden;
				/* 隐藏body窗口区域滚动条 */
			}
		</style>
		<!--引入three.js三维引擎-->
		<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script>
		<script src="./OrbitControls.js"></script>
		<script src="./earcut.js"></script>
		<!-- <script src="./three.js"></script> -->
		<!-- <script src="http://www.yanhuangxueyuan.com/threejs/build/three.js"></script> -->
	</head>

	<body>
		<script>
			//创建一个renderer ,
			var renderer = new THREE.WebGLRenderer({ antialias: true });
			//设置清空颜色,每秒会渲染60次,渲染的时候会使用此颜色先清空
			renderer.setClearColor(new THREE.Color(0xeeeeee, 1.0));
			//设置渲染尺寸
			renderer.setSize(window.innerWidth, window.innerHeight);
			//设置阴影允许
			renderer.shadowMapEnabled = true;
			//将webgl元素添加到body中
			document.body.appendChild(renderer.domElement);

			//创建场景
			var scene = new THREE.Scene();

			//创建一个透视相机,45是相机的视角  , 宽高比是屏幕的宽高比 , 最近能看到0.1 , 最远能看到10000
			var camera = new THREE.PerspectiveCamera(
				45,
				window.innerWidth / window.innerHeight,
				0.1,
				10000
			);
			//将相机放到x:1000 , y:1000 , z:1000的位置
			camera.position.set(1000, 1000, 1000);
			//设置相机的朝向,可以认为与相机镜头垂直的轴线应该和哪一个轴相交
			camera.up.set(0, 1, 0);
			//将相机的镜头对准x:0 , y:0 , z:0的位置 经过这个设置相机就被固定住了
			camera.lookAt({ x: 0, y: 0, z: 0 });
			//将相机添加到场景中
			scene.add(camera);

			//创建一个自然光,自然光无处不在
			var light1 = new THREE.AmbientLight(0xffffff);
			//设置灯光的位置
			light1.position.set(1000, 1000, 1000);
			//将灯光加入场景
			scene.add(light1);

			//创建一个长宽高600的立方体
			// var geometry = new THREE.CubeGeometry(600, 600, 600);
			// var geometry = new THREE.PlaneGeometry(204, 102);
			var geometry = new THREE.Geometry(); //创建一个空几何体对象
			/**顶点坐标(纹理映射位置)*/
			var p1 = new THREE.Vector3(0, 0, 0); //顶点1坐标
			var p2 = new THREE.Vector3(160, 0, 0); //顶点2坐标
			var p3 = new THREE.Vector3(160, 80, 0); //顶点3坐标
			var p4 = new THREE.Vector3(0, 80, 0); //顶点4坐标
			geometry.vertices.push(p1, p2, p3, p4); //顶点坐标添加到geometry对象
			/**
			*利用earcut切分平面为三角面
			*方法
				.triangulate ( data, holeIndices, dim ) : Array
					data -- 一个顶点坐标的平面数组。
					holeIndices -- 空洞索引的数组(如果有的话)。
					dim -- 输入数组中每个顶点的坐标数。
			*/
			var plans = THREE.Earcut.triangulate(
				[0, 0, 0, 160, 0, 0, 160, 80, 0, 0, 80, 0],
				[],
				3
			);
			//console.log(plans);
			/** 三角面1、三角面2*/
			var normal = new THREE.Vector3(0, 0, 1); //三角面法向量
			var face0 = new THREE.Face3(plans[0], plans[1], plans[2], normal); //三角面1
			var face1 = new THREE.Face3(plans[3], plans[4], plans[5], normal); //三角面1
			// var face1 = new THREE.Face3(0, 2, 3, normal); //三角面2
			geometry.faces.push(face0, face1); //三角面1、2添加到几何体
			/**纹理坐标*/

			//创建一个phone材质并且用图片作为纹理
			var material = new THREE.MeshPhongMaterial({
				map: THREE.ImageUtils.loadTexture("./earth.jpg"),
			});
			
			//注意!uv坐标为图片左上角是(0,0)。需要对应到threejs坐标系中
			var bricks = [
				new THREE.Vector2(0, 1),//uv图左下角
				new THREE.Vector2(1, 1),//uv图右下角
				new THREE.Vector2(1, 0),//uv图右上角
				new THREE.Vector2(0, 0),//uv图左上角
			];

			// 清除现有的UV映射,geometry对象的faceVertexUvs属性包含该geometry各个面的坐标映射。
			geometry.faceVertexUvs[0] = [];

			// 立方体的每个面实际上是由2个三角形组成的。所以我们必须单独映射每个三角形
			// 个面的顶点坐标的定义顺序必须遵循逆时针方向。为了映射底部三角形,我们需要使用的顶点指数0,1和3,
			// 而要映射顶部三角形,我们需要使用索引1,2,和顶点的3。
			geometry.faceVertexUvs[0][0] = [bricks[0], bricks[1], bricks[2]];
			geometry.faceVertexUvs[0][1] = [bricks[2], bricks[3], bricks[0]];

			

			mesh = new THREE.Mesh(geometry, material);

			scene.add(mesh);

			var orbitCtl = new THREE.OrbitControls(camera);
			orbitCtl.autoRotate = false;

			var clock = new THREE.Clock();

			function threeStart() {
				var delta = clock.getDelta();
				orbitCtl.update(delta);

				renderer.clear();
				renderer.render(scene, camera);
				requestAnimationFrame(threeStart);
			}

			threeStart();
		</script>
	</body>
</html>

 类似资料: