SOURCE

console 命令行工具 X clear

                    
>
console
<div id="container"></div>
<script type="module">
	 
			import { TrackballControls } from 'https://threejs.org/examples/jsm/controls/TrackballControls.js';
			import { CSS2DRenderer, CSS2DObject } from 'https://threejs.org/examples/jsm/renderers/CSS2DRenderer.js';

			let camera, scene, renderer, labelRenderer;
			let controls;
			
			let root;

			const offset = new THREE.Vector3(); // pdb 原子的 

			const menu = document.getElementById( 'menu' );

			init();
			animate();

			function init() {

				scene = new THREE.Scene();
				scene.background = new THREE.Color( 0xffffff ); // 场景背景色

				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 2000 );
				camera.position.z = 1500;
				camera.position.x = 1700;
				camera.position.y = 1200;
				scene.add( camera );

				const light1 = new THREE.DirectionalLight( 0xffffff, 0.8 );
				light1.position.set( 1, 1, 1 );
				scene.add( light1 );

				const light2 = new THREE.DirectionalLight( 0xffffff, 0.5 );
				light2.position.set( - 1, - 1, 1 );
				scene.add( light2 );

				root = new THREE.Group();
				scene.add( root );


				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				document.getElementById( 'container' ).appendChild( renderer.domElement );

				labelRenderer = new CSS2DRenderer();
				labelRenderer.setSize( window.innerWidth, window.innerHeight );
				labelRenderer.domElement.style.position = 'absolute';
				labelRenderer.domElement.style.top = '0px';
				labelRenderer.domElement.style.pointerEvents = 'none';
				document.getElementById( 'container' ).appendChild( labelRenderer.domElement );

				//
				controls = new TrackballControls( camera, renderer.domElement );
				controls.minDistance = 500;
				controls.maxDistance = 1000;
 

				var geometry = new THREE.BufferGeometry();
				var band = [
					379.6613, 0.0045 ,-159.5722,
					-67.0589,373.6930,-159.5719,
					-1.6247, -1.9418 ,527.6072,
					// 442.1,0,0,
					// 0,442,0,
					// 0,0,291
				], vertices = [],
				xline = [], yline = [], zline = [],
				xPointV3='', yPointV3='', zPointV3='', originPointV3='',
				ori = [0,0,0];
				originPointV3 = new THREE.Vector3(0,0,0);

				for(let i = 0; i < 3; i++) {
					let se = [band[i*3],band[i*3+1],band[i*3+2]];
					if(i == 0){
						xline = [...ori, ...se];
						vertices = vertices.concat(xline);
						xPointV3 = new THREE.Vector3(se[0],se[1],se[2]);
					}
					if(i == 1){
						yline = [...ori, ...se];
						yPointV3 = new THREE.Vector3(se[0],se[1],se[2]);
					}
					if(i == 2){
						zline = [...ori, ...se];
						vertices = vertices.concat(zline);
						zPointV3 = new THREE.Vector3(se[0],se[1],se[2]);
					}
				}
				// 三个方向的长度
				var lengthX = xPointV3.length(), lengthY = yPointV3.length(), lengthZ =zPointV3.length();

				
				var material = new THREE.PointsMaterial( { 
					color: 0xff0ff0,
					size:20 } );
				var group1 = new THREE.Group();
				var group2 = new THREE.Group();
 
				var x1 = new THREE.BufferGeometry();
				x1.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array(xline), 3 ));
				var x1L = new THREE.Line( x1, material );
				group2.add(x1L); // 添加 X轴1号线

				var x2L = x1L.clone();
				zPointV3.normalize();
				x2L.translateOnAxis(zPointV3, lengthZ);

				var x3L = x1L.clone();
				yPointV3.normalize();
				x3L.translateOnAxis(yPointV3, lengthY);
    		group2.add(x3L);

				var y1 = new THREE.BufferGeometry();
				y1.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array(yline), 3 ));
				var y1L = new THREE.Line( y1, material );
				group1.add(y1L);


				var y2L = y1L.clone();
				xPointV3.normalize();
				y2L.translateOnAxis(xPointV3, lengthX);
				group2.add(y2L);

				var y3L = y1L.clone();
				y3L.translateOnAxis(zPointV3, lengthZ);
				group1.add(y3L)

				var z1 = new THREE.BufferGeometry();
				z1.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array(zline), 3 ));
				var z1L = new THREE.Line( z1, material );
				group1.add(z1L)

				var z3L = z1L.clone();
				z3L.translateOnAxis(yPointV3, lengthY);
				group1.add(z3L)
				scene.add(group1);
				scene.add(group2);

				var group3 = group1.clone();
				group3.translateOnAxis(xPointV3, lengthX);
    		scene.add(group3); // 添加上面面的线

				var group4 = group2.clone();
				group4.translateOnAxis(zPointV3, lengthZ);
    		scene.add(group4); // 添加上面面的线


				// 三个箭头和标识
				var dirlength = 150, labelren=[]; // 箭头长度
				let dirs = [{
					name:'a',
					color:'red',
					angTxt: '��',
					line: yPointV3,
					toCurve:xPointV3,
					length: lengthY,
				}, {
					name:'b',
					color:'green',
					angTxt: '��',
					line: xPointV3,
					toCurve:zPointV3,
					length: lengthX
				},{
					name:'c',
					color:'blue',
					angTxt: '��',
					line:zPointV3,
					toCurve:yPointV3,
					length: lengthZ
				},];
				dirs.forEach((item, i)=> {
					// 箭头
					let arrow = new THREE.ArrowHelper( item.line, originPointV3, item.length+dirlength, item.color);
					scene.add( arrow); 
					// 文字
					let text = document.createElement( 'div' );
					text.className = 'label';
					text.style.color = item.color;
					text.textContent = item.name;
					let label = new CSS2DObject( text );
					label.translateOnAxis( item.line , Math.ceil(item.length*2/3));
					scene.add( label ); //方向轴上面的文字

					let dirco = arrow.line.clone();
					dirco.translateOnAxis( item.line , Math.ceil(item.length/3));
					
					labelren.push({
						line: dirco,
						length:item.length,
						angTxt:  item.angTxt,
					});
				
				});

				labelren.forEach((htem,h) => {
					let end = labelren[h+1]?labelren[h+1].line : labelren[0].line;
					let li = addLines(htem.line.position,end.position, originPointV3, htem.angTxt);
					
					scene.add( li.lineMesh); // 角度的线
 

				})

				window.addEventListener( 'resize', onWindowResize );

			}

			function addLines(v0, v3, point, txt) {
					// 计算向量夹角
					// let angle = v0.angleTo(v3) * 270 / Math.PI / 10; // 0 ~ Math.PI
					// let aLen = angle * 50,	hLen = angle * angle * 120;
					// angleTo返回该向量与向量v之间的角度
					let angle = v0.angleTo(v3)*(180/Math.PI); // 0 ~ Math.PI
					let aLen = angle * 1,	hLen = 1;

					let p0 = new THREE.Vector3(0, 0, 0);

					// 法线向量,垂直于平面的直线(叫法线)所表示的向量为该平面的法向量
					// let rayLine = new THREE.Ray(p0, getVCenter(v0.clone(), v3.clone()));

					// // 顶点坐标
					// // rayLine.at(1) 获得这一Ray上给定距离处的Vector3。
					// // distanceTo 计算该向量到所传入的点 间的距离。
					// let vtop = rayLine.at(rayLine.at(1).distanceTo(p0));

					// 法线向量,垂直于平面的直线(叫法线)所表示的向量为该平面的法向量
					let rayLine = new THREE.Ray(p0, getVCenter(v0.clone(), p0));
					let rayLine2 = new THREE.Ray(p0, getVCenter(v3.clone(), p0));

					// 顶点坐标
					// rayLine.at(1) 获得这一Ray上给定距离处的Vector3。
					// distanceTo 计算该向量到所传入的点 间的距离。
					let vtop = rayLine.at(rayLine.at(1).distanceTo(p0));
					let vtop2 = rayLine2.at(rayLine.at(1).distanceTo(p0));

					// 控制点坐标
					let v1 = getLenVcetor(v0.clone(), vtop2, aLen);
					let v2 = getLenVcetor(v3.clone(), vtop, aLen);

					// 绘制贝塞尔曲线
					let curve = new THREE.CubicBezierCurve3(v0, v1, v2, v3);
					let geo = new THREE.BufferGeometry().setFromPoints(  curve.getPoints(50) );
					let mat = new THREE.LineDashedMaterial({
						color: 0x000000,
						dashSize: 10,//短划线的大小
       			gapSize: 6,//短划线之间的距离
					});

					// var curve = new THREE.CatmullRomCurve3(
					// 	// -Math.ceil(item.length/2), 
					// 	// Math.ceil(end/2),
					// 		label.position,
					// 		originPointV3,
					// 		end

					// 	);
					let line = new THREE.Line(geo, mat); 
					line.computeLineDistances();//不可或缺的,若无,则线段不能显示为虚线

					let text2 = document.createElement( 'div' );
					text2.className = 'label';
					// text2.style.color = item.color;
					text2.textContent = txt;
					let label2 = new CSS2DObject( text2 );
					debugger;
					label2.translateOnAxis( v1 , 1);
					scene.add( label2 ); //方向轴上面的文字

					return {
							curve: curve,
							lineMesh: line
					};
			}

			// 计算v1,v2 的中点
			function getVCenter(v1, v2) {
					let v = v1.add(v2); // 向量相加
					return v.divideScalar(2); // 向量除以标量等于k,相当于以因子k来缩放向量的长度
			}

			// 计算V1,V2向量固定长度的点
			// lerp 朝着进行插值,两点间的缓冲效果
			function getLenVcetor(v1, v2, len) {
					let v1v2Len = v1.distanceTo(v2);
					return v1.lerp(v2, len / v1v2Len); 
			}
		  
			function onWindowResize() {

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

				renderer.setSize( window.innerWidth, window.innerHeight );
				labelRenderer.setSize( window.innerWidth, window.innerHeight );

				render();

			}

			function animate() {

				requestAnimationFrame( animate );
				controls.update();

				render();

			}

			function render() {

				renderer.render( scene, camera );
				labelRenderer.render( scene, camera );

			}

		</script>

本项目引用的自定义外部资源