本文主要是介绍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.PIvar 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方法现在必须要两个参数才能执行,所以需要加入临时变量tempvar 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要加{},注意路径是jsmimport {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 (透明度) 默认为 falseantialias: 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>
这篇关于threejs:两点坐标绘制贝赛尔曲线遇到的坑的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!