Three 之 three.js (webgl)简单实现根据点绘制线/弧线(基于LineGeometry / Line2 / LineMaterial,绘制两点基于圆心的弧线段)

Three 之 three.js (webgl)简单实现根据点绘制线/弧线(基于LineGeometry / Line2 / LineMaterial,绘制两点基于圆心的弧线段)

目录

Three 之 three.js (webgl)简单实现根据点绘制线/弧线(基于LineGeometry / Line2 / LineMaterial,绘制两点基于圆心的弧线段)

一、简单介绍

二、案例简单示意图

三、实现原理

四、注意事项

五、该案例的大概实现步骤

六、关键代码


 

一、简单介绍

Three js 开发的一些知识整理,方便后期遇到类似的问题,能够及时查阅使用。

扫描二维码关注公众号,回复: 13956588 查看本文章

本节介绍, three.js (webgl)中绘制线段的功能,主要根据 LineGeometry 进行点的设置,然后使用 Line2 进行绘制点组成的线段,绘制线实现方式很多,这里仅供思路提供,如果有不足之处,欢迎指出,或者你有更好的方法,欢迎留言。

二、案例简单示意图

三、实现原理

1、向量 angleTo 计算 A 向量与 B 向量之间的角度

2、然后根据sin(),cos() 方式获得弧线的点

3、把点给 LineGeometry,使用 Line2 结合材质把线段绘制出来

 
 

四、注意事项

1、这里是基于原点(0,0,0)的,如果圆点不在原点(0,0,0),在计算弧线点的时候添加上圆点位置;(一些思路提供)

2、这里是在  X  Y 平面绘制的圆弧,如果不是,可以根据计算一些角度(通过 z 点得到旋转角度),然后在 X  Y 平面绘制的圆弧 在根据得到的角度旋转即可;(一些思路提供)

3、绘制弧线分段精度可控,并且还可以设置弧线每个点的颜色

五、该案例的大概实现步骤

该案例基于Threejs   GitHub - mrdoob/three.js: JavaScript 3D Library.

工程框架创建实现的

1、创建脚本,引入 Three,创建基本的 Three 环境,添加场景,摄像机,光等

2、添加进行绘制弧线的演示的 3D 物体

3、根据一些点的向量得到对应的一些绘制角度

4、根据得到的角度,结合圆弧回执函数(sin/cos),生成圆弧位置点,最后,通过 LineGeometry 、Line2 绘制圆弧

5、在函数中调用对应函数,然后就可以在浏览器中查看效果了

六、关键代码

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>11TestCurveLine</title>
</head>
<body>
<script type="importmap">
			{
				"imports": {
					"three": "../../../build/three.module.js"
				}
			}

</script>

<script type="module">

	import * as THREE from 'three';

	import { OrbitControls } from '../../jsm/controls/OrbitControls.js';
	import Stats from '../../jsm/libs/stats.module.js';
	import { LineMaterial } from '../../jsm/lines/LineMaterial.js';
	import { LineGeometry } from '../../jsm/lines/LineGeometry.js';
	import { Line2 } from '../../jsm/lines/Line2.js';

	let scene, camera, renderer, stats;

	let POSITION_A;
	let POSITION_B;
	let POSITION_Center;
	let targetDegreeT1;
	let targetDegreeT2;
	const radius = 5;

	init();
	animate();

	function init() {

		// scene
		initScene();

		// camera
		initCamera();


		// light
		initLight();

		// renderer
		initRenderer();

		// OrbitControls
		initOrbitControls();

		stats = new Stats();
		document.body.appendChild( stats.dom );

		// onWindowResize
		window.addEventListener( 'resize', onWindowResize );


		axiesHelper();

		stats = new Stats();
		document.body.appendChild( stats.dom );

		// window.location.href = renderer.domElement.toDataURL( 'image/png' );

		addTestRoateLineObject();
	}

	function onWindowResize() {

		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();
		renderer.setSize( window.innerWidth, window.innerHeight );

	}

	function initScene() {

		scene = new THREE.Scene();

	}

	function initCamera() {

		camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 200 );
		camera.position.set( 0, 0, 25 );

	}

	function initLight() {

		const ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 );
		scene.add( ambientLight );

		const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.6 );
		directionalLight.position.set( - 1, 1, 100 );
		scene.add( directionalLight );

	}

	function initRenderer() {

		renderer = new THREE.WebGLRenderer( { antialias: true } );
		renderer.setSize( window.innerWidth, window.innerHeight );
		renderer.setPixelRatio( window.devicePixelRatio );
		renderer.setClearColor( 0xcccccc );
		document.body.appendChild( renderer.domElement );

	}

	function initOrbitControls() {

		const controls = new OrbitControls( camera, renderer.domElement );
		controls.minDistance = 5;
		controls.maxDistance = 50;
		controls.enablePan = false; // 移动 禁止

	}

	function animate() {

		requestAnimationFrame( animate );
		stats.update();
		render();


	}

	function axiesHelper() {

		var helper = new THREE.AxesHelper( 20 );
		scene.add( helper );

	}

	function render() {

		renderer.render( scene, camera );

	}


	function addTestRoateLineObject() {
		const Degree_A = Math.PI / 4 * 3;
		POSITION_A = new THREE.Vector3( radius * Math.cos( Degree_A ), radius * Math.sin( Degree_A ), 0 );

		const Degree_B = Math.PI / 8;
		POSITION_B = new THREE.Vector3( radius * Math.cos( Degree_B ), radius * Math.sin( Degree_B ), 0 );
		POSITION_Center = new THREE.Vector3( 0, 0, 0 );

		var geometry = new THREE.SphereGeometry( 4, 30 ); //矩形平面
		var material = new THREE.MeshPhongMaterial( {} );
		var spheremesh1 = new THREE.Mesh( geometry, material );
		spheremesh1.position.set( POSITION_Center.x, POSITION_Center.y, POSITION_Center.z );
		scene.add( spheremesh1 );

		var geometryA = new THREE.SphereGeometry( 1, 30 ); //矩形平面
		var materialA = new THREE.MeshPhongMaterial( {
			color: '#cc0000'
		} );
		var spheremeshA = new THREE.Mesh( geometryA, materialA );
		spheremeshA.position.set( POSITION_A.x, POSITION_A.y, POSITION_A.z );
		scene.add( spheremeshA );
		var geometryB = new THREE.SphereGeometry( 1, 30 ); //矩形平面
		var materialB = new THREE.MeshPhongMaterial( {
			color: '#cc00cc'
		} );
		var spheremeshB = new THREE.Mesh( geometryB, materialB );

		spheremeshB.position.set( POSITION_B.x, POSITION_B.y, POSITION_B.z );
		scene.add( spheremeshB );

		rotateLineDataT1T2();

	}

	function rotateLineDataT1T2() {

		const v1T1 = new THREE.Vector3( POSITION_A.x, POSITION_A.y, POSITION_A.z );
		const v2T1 = new THREE.Vector3( POSITION_B.x, POSITION_B.y, POSITION_B.z );
		targetDegreeT1 = v1T1.angleTo( v2T1 );
		console.log( 'targetDegreeT1 ' + targetDegreeT1 );
		const fromDegreeT1 = v2T1.angleTo( new THREE.Vector3( radius, 0, 0 ) );
		console.log( 'fromDegreeT1 ' + fromDegreeT1 );
		const toDegreeT1 = fromDegreeT1 + targetDegreeT1;

		const v1T2 = new THREE.Vector3( POSITION_A.x, POSITION_A.y, POSITION_A.z );
		const v2T2 = new THREE.Vector3( POSITION_B.x, POSITION_B.y, POSITION_B.z );
		targetDegreeT2 = v2T2.angleTo( v1T2 );
		console.log( 'targetDegreeT2 ' + targetDegreeT2 );
		const modifyDegree = Math.PI * 2 - targetDegreeT2;
		console.log( modifyDegree );
		const fromDegreeT2 = toDegreeT1;
		const toDegreeT2 = modifyDegree + fromDegreeT2;

		scene.add(drawCurveLine( radius, 50, fromDegreeT1, toDegreeT1, 1, 0, 0 ));

		scene.add(drawCurveLine( radius, 100, fromDegreeT2, toDegreeT2, 0, 1, 0 ));

	}

	function drawCurveLine( radius, segment, fromDegree, toDegree, colorR, colorG, colorB ) {

		var geometry = new LineGeometry(); //声明一个几何体对象Geometry
		var R = radius; // 圆弧半径
		var N = segment; // 分段数量
		const perAddDegree = ( toDegree - fromDegree ) / segment;
		console.log( 'perAddDegree ' + perAddDegree );
		const positionArray = [];
		const colors = [];

		// 批量生成圆弧上的顶点数据
		for ( let i = 0; i < N; i ++ ) {
			var angle = fromDegree + perAddDegree * i;
			var x = R * Math.cos( angle );
			var y = R * Math.sin( angle );
			var z = 0;
			positionArray.push( x, y, z );
			colors.push( colorR, colorG, colorB );

		}

		geometry.setPositions( positionArray );
		geometry.setColors( colors );

		const matLine = new LineMaterial( {

			color: 0xffffff,
			linewidth: 0.01, // in world units with size attenuation, pixels otherwise
			vertexColors: true,

			//resolution:  // to be set by renderer, eventually
			dashed: false,
			alphaToCoverage: true,

		} );

		const line = new Line2( geometry, matLine );

		return line;

	}


</script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/u014361280/article/details/124349641