threejs:两点坐标绘制贝赛尔曲线遇到的坑

飞机从武汉飞往背景,根据起点和终点,需要绘制飞机航线,网上搜来的通用代码运行后一直找不到copy属性。

坑1:

ray的at方法参数变更:

仔细排查发现,是ray的at方法修改了,现在必须要两个参数了,只需要增加一个临时变量来充当at方法的target 参数,只需要修改一点点就可以了。

坑2:

并非所有的起点和终点都可以绘制贝塞尔曲线:

代码跑通后,我随便设置了如下图的一组起点和终点,结果绘制的是一条直线。

v0和v3设置成下图,甚至还报NAN的错!

 直到我把v0和v3设置得更加随机一些,才终于出现了曲线!

 

总结一下两点绘制贝塞尔曲线的方法:

创建一条平滑的三维 三次贝塞尔曲线, 由起点、终点和两个控制点所定义。

但是基于我们日常的需求,比如飞机航线,我们只知道起点和终点,也就是v0和v3,所以我们需要通过一系列算法,得到中间的两个控制点,也就是v1和v2,但是v0和v3需要符合一定条件,目前我通过经验,只能找到两个反例:

1、 v0和v3不可以是原点,也就是坐标不能为(0,0,0),否则绘制出来的将是一条直线。

2、v0和v3组成的直线,不可以贴在一条轴线上,比如(-5,0,0)和(5,0,0),就是一条贴在x轴的直线,这样我们的算法会报NaN的错。

既然如此,那就让v0和v3随机一点吧。

修改后的js代码如下:

import * as THREE from 'three'
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';
import { Line2 } from 'three/examples/jsm/lines/Line2.js';
export function createFlyLine( v0, v3 ) {
	
		// 夹角
		var angle = ( v0.angleTo( v3 ) * 1.8 ) / Math.PI / 0.1; // 0 ~ Math.PI
		var aLen = angle * 0.4, hLen = angle * angle * 12;
		var p0 = new THREE.Vector3( 0, 0, 0 );
		// 法线向量
		var rayLine = new THREE.Ray( p0, getVCenter( v0.clone(), v3.clone() ) );
		// ray的at方法现在必须要两个参数才能执行,所以需要加入临时变量temp
		var temp = new THREE.Vector3();
		// 顶点坐标
		var vtop = rayLine.at( hLen / rayLine.at( 1,temp).distanceTo( p0 ),temp);
		// 控制点坐标
		var v1 = getLenVcetor( v0.clone(), vtop, aLen );
		var v2 = getLenVcetor( v3.clone(), vtop, aLen );
		// 绘制三维三次贝赛尔曲线
		var curve = new THREE.CubicBezierCurve3( v0, v1, v2, v3 );
		var geometry = new LineGeometry();
		var points = curve.getSpacedPoints( 5000 );
		var positions = [];
		var colors = [];
		var color = new THREE.Color();
		/**
		 * HSL中使用渐变
		 * h — hue value between 0.0 and 1.0
		 * s — 饱和度 between 0.0 and 1.0
		 * l — 亮度 between 0.0 and 1.0
		 */
		for (var j = 0; j < points.length; j ++) {
			// color.setHSL( .31666+j*0.005,0.7, 0.7); //绿色
			color.setHSL( .81666+j,0.88, 0.715+j*0.0025); //粉色
			colors.push( color.r, color.g, color.b );
			positions.push( points[j].x, points[j].y, points[j].z );
		}
		geometry.setPositions( positions );
		geometry.setColors( colors );
		var matLine = new LineMaterial( {
			linewidth: 0.0006,
			vertexColors: true,
			dashed: false
		} );
		var lineMesh = new Line2( geometry, matLine );
		return lineMesh;
}
// 计算v1,v2 的中点
	function getVCenter( v1, v2 ) {
		const v = v1.add( v2 );
		return v.divideScalar( 2 );
	}

	// 计算V1,V2向量固定长度的点
	function getLenVcetor( v1, v2, len ) {
		const v1v2Len = v1.distanceTo( v2 );
		return v1.lerp( v2, len / v1v2Len );
	}

 vue代码如下:

<template>
	<div>
		<!-- 本案例演示两点绘制贝塞尔曲线-->
		<div id="container"></div>
	</div>

</template>

<script>
	import * as THREE from 'three'
	// 注意OrbitControls要加{},注意路径是jsm
	import {
		OrbitControls
	} from 'three/examples/jsm/controls/OrbitControls.js';
	import {
		createFlyLine,timerFlyLine
	} from './flyLine.js';

	export default {
		name: "hello",
		props: {

		},
		components: {

		},
		data() {
			return {
				scene: null,
				renderer: null,
				camera: null,
				orbitControls: null
			}
		},
		created() {},
		mounted() {
			this.init();
			this.animate();

		},
		//后续还要在beforeDestory中进行销毁
		beforeDestroy() {
			this.scene = null;
			this.renderer = null;
			this.camera = null;
			this.orbitControls = null;
			clearInterval(timerFlyLine);
		},
		methods: {
			// 场景初始化
			init() {
				let container = document.getElementById('container');
				this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
				// 特别注意,相机的位置要大于几何体的尺寸
				this.camera.position.x = 10;
				this.camera.position.y = 10;
				this.camera.position.z = 10;
				this.scene = new THREE.Scene();
				this.renderer = new THREE.WebGLRenderer({
					// alpha: true, // canvas是否包含alpha (透明度) 默认为 false
					antialias: true,
					// precision: 'highp',
				})
				// this.renderer.setClearAlpha(0.0); // 设置alpha,合法参数是一个 0.0 到 1.0 之间的浮点数
				// 设置背景色
				this.renderer.setSize(window.innerWidth, window.innerHeight);
				container.appendChild(this.renderer.domElement);
				// 添加三维坐标轴
				// 红色代表x轴,绿色代表y轴,蓝色代表z轴
				// let axesHelper = new THREE.AxesHelper(30);
				// this.scene.add(axesHelper);

				// 环境光不能用来投射阴影,因为它没有方向。
				var ambienLight = new THREE.AmbientLight(0xcccccc);
				this.scene.add(ambienLight);
				// 初始化轨道控制器
				// 还需要配合animate,不断循环渲染,达到用鼠标旋转物体的作用。
				this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement);
				// 窗口大小自适应
				window.addEventListener('resize', this.onWindowResize, false);
				this.addObjects();
			},
			// 添加物体
			addObjects(){
				 // var v0 = new THREE.Vector3(-3, 4, 0);
				 // var v3 = new THREE.Vector3(3, 4, 0);
				 var v0 = new THREE.Vector3(- 1.7049594735603837, 3.208354470512221, - 3.4350509144786985);
				 var v3 = new THREE.Vector3(0.5738958419746141, - 0.44114968930852216, 4.9473255920938985);
				var sphere = createFlyLine(v0,v3);
				this.scene.add(sphere);
			},
			animate() {
				requestAnimationFrame(this.animate);
				this.renderer.render(this.scene, this.camera);
			},
			onWindowResize() {
				this.camera.aspect = window.innerWidth / window.innerHeight;
				this.camera.updateProjectionMatrix();
				this.renderer.setSize(window.innerWidth, window.innerHeight);
			}
		}
	}
</script>

<style scoped>
	#container {
		width: 100%;
		height: 600px;
		outline: none;
		/* background-image: linear-gradient(rgb(255, 255, 255), rgb(119, 119, 237)); */
	}
</style>

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在OpenCV中,可以使用 `cv::polylines` 函数绘制贝塞尔曲线。具体步骤如下: 1. 定义控制点。贝塞尔曲线需要通过一系列控制点来定义其形状。在OpenCV中,可以使用 `cv::Point` 类型的向量来存储控制点。 2. 使用 `cv::approxPolyDP` 函数来拟合贝塞尔曲线。该函数可以根据一组点的形状,自动确定最适合的贝塞尔曲线。 3. 使用 `cv::polylines` 函数绘制贝塞尔曲线。该函数接受一个包含所有点的向量,并将其连成平滑的曲线。 下面是一个简单的代码示例: ```c++ #include <opencv2/opencv.hpp> using namespace cv; using namespace std; int main() { // 定义控制点 vector<Point> controlPoints = {Point(50, 50), Point(100, 100), Point(150, 50)}; // 拟合贝塞尔曲线 vector<Point> curvePoints; approxPolyDP(controlPoints, curvePoints, 1.0, true); // 绘制贝塞尔曲线 Mat image(200, 200, CV_8UC3, Scalar(255, 255, 255)); polylines(image, curvePoints, false, Scalar(0, 0, 255), 2, LINE_AA); imshow("Bezier Curve", image); waitKey(0); return 0; } ``` 在上面的代码中,我们定义了三个控制点,然后使用 `approxPolyDP` 函数拟合贝塞尔曲线。最后,使用 `polylines` 函数将拟合后的曲线绘制到图像上,并显示出来。 注意,`approxPolyDP` 函数的第三个参数表示拟合精度,可以根据需要进行调整。此外,`polylines` 函数的第四个参数表示曲线颜色,第五个参数表示曲线粗细。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值