three.js物体按照轨迹行走并显示轨迹

2,739 阅读3分钟

three.js物体按照轨迹行走并显示轨迹

人物按照指定个轨迹行走 在这里插入图片描述

显示人物行走的轨迹 在这里插入图片描述


核心代码

时间有限,核心代码如下,没时间解释,敬请原谅。

var curve = new THREE.CatmullRomCurve3([
	new THREE.Vector3(-6, 0, -5),
	new THREE.Vector3(-6, 0, -10),
	new THREE.Vector3(10, 0, -5),

	new THREE.Vector3(0, 0, 0),
	new THREE.Vector3(-6, 0, -3),
	new THREE.Vector3(-3, 0, -7),
	new THREE.Vector3(10, 0, -5)

], false/*是否闭合*/);


var tubeGeometry = new THREE.TubeGeometry(curve, 100, 0.1, 50, false);
var tubeMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: false })
var tube = new THREE.Mesh(tubeGeometry, tubeMaterial);


var points = curve.getPoints(3000);

var _material = new THREE.LineBasicMaterial({
          color: 0xff0000
      });
      var _geometry = new THREE.BufferGeometry();
      var _pointsBuf = [
          // 10,0,0,
          // 0,0,10,
      ]
var _vertices = new Float32Array(_pointsBuf);
_geometry.addAttribute('position', new THREE.BufferAttribute(_vertices, 3));
      var _lineA = new THREE.Line(_geometry, _material);
      scene.add(_lineA);

let _i = 0;;
setTimeout(() => {
	setInterval(() => {
		_pointsBuf.push(points[_i].x, points[_i].y, points[_i].z)
              _vertices = new Float32Array(_pointsBuf)
              _geometry.addAttribute('position', new THREE.BufferAttribute(_vertices, 3));
		
		renwu.position.set(points[_i].x, points[_i].y, points[_i].z);
		renwu.lookAt(points[_i+1].x, points[_i+1].y, points[_i+1].z)
		_i++;
		if(_i>3000-1) _i=0
	}, 10);
}, 3000);

人物模型

哎,还有人要模型,模型在下面连接,自己下载。 walkingman.fbx

全部代码

还有人非得要全部代码,也是醉了。 下面就是

<!DOCTYPE html>
<html>

<head lang="en">
	<meta charset="UTF-8">
	<title></title>
	<script src="JS/three.js"></script>
	<script src="js/WebGL.js"></script>
	<script src="JS/MTLLoader.js"></script>
	<script src="JS/OBJLoader.js"></script>
	<script src="JS/OrbitControls.js"></script>
	<script src="JS/Tween.js"></script>
	<script src="JS/inflate.min.js"></script>
	<script src="JS/FBXLoader.js"></script>
	<script src="JS/CSS2DRenderer.js"></script>

</head>

<body>
	<script>

		if (WEBGL.isWebGLAvailable() === false) {

			document.body.appendChild(WEBGL.getWebGLErrorMessage());

		}
		//创建场景,相机,渲染器,网格
		var scene, camera, renderer, controls, tween, mesh, mixer;
		var meshfloor;
		var keyboard = {};
		var player = { height: 1.8, speed: 0.2, turnSpeed: Math.PI * 0.05 };
		var renwu;
		var flag = false;
		scene = new THREE.Scene();
		camera = new THREE.PerspectiveCamera(90, 1280 / 720, 0.1, 100);
		var clock = new THREE.Clock();
		
		var target;
		var spherical = new THREE.Spherical();
		var rotationMatrix = new THREE.Matrix4();
		var targetRotation = new THREE.Quaternion();
		// var clock = new THREE.Clock();
		var speed = 2;

		//红点
		var targetGeometry = new THREE.SphereBufferGeometry(0.5);
		var targetMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
		target = new THREE.Mesh(targetGeometry, targetMaterial);
		scene.add(target);



		meshfloor = new THREE.Mesh(
			new THREE.PlaneGeometry(20, 20, 10, 10),
			new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: false })
		)

		var geometry = new THREE.PlaneGeometry(20, 20, 10, 10);//矩形平面
		var texture = new THREE.ImageUtils.loadTexture("floor.jpg");//加载纹理贴图
		texture.wrapS = texture.wrapT = THREE.RepeatWrapping; //重复包装
		texture.repeat.set(20, 20);//重复个数
		var material = new THREE.MeshLambertMaterial({
			map: texture,//给纹理属性map赋值
			side: THREE.DoubleSide//两面可见
		});//材质对象


		meshfloor = new THREE.Mesh(geometry, material);//纹理贴图网格模型对象


		meshfloor.rotation.x -= Math.PI / 2;


		// scene.add(mesh);
		scene.add(meshfloor);


		var models = [];


		var loader = new THREE.FBXLoader();
		loader.load("walkingman.fbx", function (object) {
			mixer = new THREE.AnimationMixer(object);
			var action = mixer.clipAction(object.animations[0]);
			action.play();
			object.traverse(function (child) {
				if (child.isMesh) {
					child.castShadow = true;
					child.receiveShadow = true;
				}
			});


			object.rotation.y = 1.57;
			// object.rotation.x = -1.57;

			
			renwu = new THREE.Group();
			renwu.add(object)
			scene.add(renwu);


			console.log(renwu);
		});



		//辅助线
		var axes = new THREE.AxisHelper(20);
		scene.add(axes);


		var curve = new THREE.CatmullRomCurve3([
			new THREE.Vector3(-6, 0, -5),
			new THREE.Vector3(-6, 0, -10),
			new THREE.Vector3(10, 0, -5),

			new THREE.Vector3(0, 0, 0),
			new THREE.Vector3(-6, 0, -3),
			new THREE.Vector3(-3, 0, -7),
			new THREE.Vector3(10, 0, -5)

		], false/*是否闭合*/);



		var tubeGeometry = new THREE.TubeGeometry(curve, 100, 0.1, 50, false);
		var tubeMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: false })
		var tube = new THREE.Mesh(tubeGeometry, tubeMaterial);
		// scene.add(tube)

		var points = curve.getPoints(3000);
		
		var _material = new THREE.LineBasicMaterial({
            color: 0xff0000
        });
        var _geometry = new THREE.BufferGeometry();
        var _pointsBuf = [
            // 10,0,0,
            // 0,0,10,
        ]
		var _vertices = new Float32Array(_pointsBuf);
		_geometry.addAttribute('position', new THREE.BufferAttribute(_vertices, 3));
        var _lineA = new THREE.Line(_geometry, _material);
        scene.add(_lineA);

		let _i = 0;
		console.log('renwu :', renwu);
		setTimeout(() => {
			console.log('renwu :', renwu);
			setInterval(() => {
				_pointsBuf.push(points[_i].x, points[_i].y, points[_i].z)
                _vertices = new Float32Array(_pointsBuf)
                _geometry.addAttribute('position', new THREE.BufferAttribute(_vertices, 3));
				
				renwu.position.set(points[_i].x, points[_i].y, points[_i].z);
				renwu.lookAt(points[_i+1].x, points[_i+1].y, points[_i+1].z)
				_i++;
				if(_i>3000-1) _i=0
			}, 10);

		}, 3000);

		//环境光
		ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
		scene.add(ambientLight);
		//点光
		light = new THREE.PointLight(0xffffff, 0.9, 250);
		light.position.set(0, 20, -10);
		light.castShadow = true;

		light.shadow.camera.near = 0.1;
		light.shadow.camera.far = 25;

		scene.add(light);



		camera.position.set(0, player.height, -5);
		camera.lookAt(new THREE.Vector3(0, player.height, 0));
		renderer = new THREE.WebGLRenderer({ antialias: true });
		renderer.setClearColor(0x4682B4, 1.0);
		renderer.setSize(1280, 720);



		createHtml("img", "person.png", "person", "点击就能成神", 20);
		createHtml("img", "fps.png", "fps", "点击就能成神", -10);
		createHtml("img", "reset.png", "reset", "点击就能成神", -40);


		function createHtml(img, src, className, text, extend) {
			var laberDiv = document.createElement("img");
			laberDiv.src = src;
			laberDiv.onclick = function () { bnt1(className); };
			laberDiv.className = className;
			laberDiv.textContent = text;
			laberDiv.setAttribute('align', 'center');
			laberDiv.style.marginTop = '-1em';
			var pointLabel = new THREE.CSS2DObject(laberDiv);
			pointLabel.position.set(0, extend, 50);
			scene.add(pointLabel);
		}
		labelRenderer = new THREE.CSS2DRenderer(); //新建CSS2DRenderer 
		labelRenderer.setSize(40, 120);
		labelRenderer.domElement.style.position = 'absolute';
		labelRenderer.domElement.style.margin = '10px';


		labelRenderer.domElement.style.background = '#FFFFFF';
		console.log(labelRenderer.domElement.style);
		document.body.appendChild(labelRenderer.domElement);
		renderer.render(scene, camera);
		labelRenderer.render(scene, camera);//渲染

		function bnt1(className) {
			if (className === 'person') {
				if (flag === false) {

					mixer._actions[0].play();
					flag = true;

				}
				else {

					flag = false;
					mixer._actions[0].stop();
				}

			}
		}


		//把画面插入HTML中的body标签下显示
		document.body.appendChild(renderer.domElement);
		initControls();
		animate();



		var progress = 0;

		function animate() {
			requestAnimationFrame(animate);
			// mesh.rotation.x+=0.01;
			// mesh.rotation.y+=0.02;
			controls.update();
			TWEEN.update();
			var delta = clock.getDelta();

			if (mixer) mixer.update(delta);


			renderer.render(scene, camera);

		}

		function keyDown(event) {
			keyboard[event.keyCode] = true;
		}

		function keyUp(event) {
			keyboard[event.keyCode] = false;
		}

		function initControls() {

			controls = new THREE.OrbitControls(camera, renderer.domElement);
		
			controls.enableDamping = true;
			
			controls.enableZoom = true;
			
			controls.autoRotate = false;
			controls.autoRotateSpeed = 0.5;
		
			controls.minDistance = 1;
			
			controls.maxDistance = 2000;
		
			controls.enablePan = true;
		}


		function generateTarget() {

			

			spherical.theta = Math.random() * Math.PI * 2;
			spherical.phi = Math.acos((2 * Math.random()) - 1);
			spherical.radius = 2;


			target.position.setFromSpherical(spherical);

			// compute target rotation
			//计算目标旋转

			rotationMatrix.lookAt(target.position, renwu.position, renwu.up);
			targetRotation.setFromRotationMatrix(rotationMatrix);

			setTimeout(generateTarget, 3000);

		}

		window.addEventListener('keydown', keyDown);
		window.addEventListener(('keyup'), keyUp);
	</script>
</body>

</html>

CatmullRomCurve3

是 Three.js 中的一种曲线类型,用于创建 Catmull-Rom 样条曲线。Catmull-Rom 样条曲线是一种平滑的曲线,它通过一组控制点来定义曲线的形状。与贝塞尔曲线不同,Catmull-Rom 曲线可以通过控制点的位置和切线来精确控制曲线的形状。

在 Three.js 中创建 CatmullRomCurve3 很简单,只需要创建一个 CatmullRomCurve3 类的实例,并将控制点添加到曲线中即可。例如:

var curve = new THREE.CatmullRomCurve3([
  new THREE.Vector3(-10, 0, 10),
  new THREE.Vector3(-5, 5, 5),
  new THREE.Vector3(0, 0, 0),
  new THREE.Vector3(5, -5, 5),
  new THREE.Vector3(10, 0, 10)
]);

在上述代码中,我们创建了一个 CatmullRomCurve3 曲线,其中包含了五个控制点。这些控制点用于定义曲线的形状。

除了控制点之外,CatmullRomCurve3 还有一些其他的属性和方法,可以用于控制曲线的细节。例如:

  • curve.points:获取或设置曲线的控制点数组。
  • curve.closed:获取或设置曲线是否闭合。
  • curve.getPoint(t):获取曲线上 t 位置处的点坐标。
  • curve.getTangent(t):获取曲线上 t 位置处的切向量。
  • curve.getLength():获取曲线的长度。

通过这些属性和方法,我们可以更加精确地控制 Catmull-Rom 曲线的形状和行为。

TubeGeometry

TubeGeometry 是 Three.js 中的一种几何体类型,用于创建管道状几何体。TubeGeometry 的构造函数接受两个参数:一个路径和一个半径。路径是一个 Curve 类型的对象,用于定义管道的路径;半径是一个数值类型的值,用于定义管道的半径。

在 Three.js 中创建 TubeGeometry 很简单,只需要创建一个 TubeGeometry 类的实例,并将路径和半径作为参数传入即可。例如:

var path = new THREE.CatmullRomCurve3([
  new THREE.Vector3(-10, 0, 0),
  new THREE.Vector3(-5, 5, 5),
  new THREE.Vector3(0, 0, 10),
  new THREE.Vector3(5, -5, 5),
  new THREE.Vector3(10, 0, 0)
]);

var radius = 1;

var tubeGeometry = new THREE.TubeGeometry(path, 64, radius, 16, false);

在上述代码中,我们创建了一个路径对象和一个半径值,并将它们作为参数传入 TubeGeometry 的构造函数中。我们还设置了一些其他的参数,例如管道的分段数、半径的分段数以及是否闭合管道等。

除了上述参数之外,TubeGeometry 还有一些其他的属性和方法,可以用于控制管道的细节。例如:

  • tubeGeometry.parameters.path:获取管道的路径对象。
  • tubeGeometry.parameters.radius:获取管道的半径。
  • tubeGeometry.getPoint(t):获取管道上 t 位置处的点坐标。
  • tubeGeometry.getTangent(t):获取管道上 t 位置处的切向量。

通过这些属性和方法,我们可以更加精确地控制 TubeGeometry 的形状和行为。


文章首发:webgl.blog.csdn.net/article/det…