需要在3d模型上实现标注的功能,一开始是直接通过添加一个普通的mesh来实现的,但是这样就会有一个问题-当视图缩放的时候,标注也会跟着一起放大缩小,影响视觉效果,因此需要实现一个不会随着视图一起放大或者缩小的mesh
-
根据需求,可以知道我们其实需要实现的就是更改模型渲染的默认方式,而模型的渲染是由模型的
MVP
三个矩阵来决定的
-
再进一步分析
MVP
三个矩阵,
Model
矩阵决定模型的旋转、缩放和位移,
View
决定相机的变换,
Projection
决定模型最终到屏幕的输出。根据需求,我们只需要修改Model矩阵当中的缩放就可以了。
-
查看threejs的源码可知,
scene
中的
Mesh
都是继承自
Object3D
这个基类的,其中的
matrixWorld
属性就对应着我们上面提到的
Model
矩阵,因此只要我们能正确的更改这个矩阵应该就能实现我们想要的效果了。
-
那么如何更改这个
matrixWorld
呢?那就是
updateMatrixWorld
这个方法了。我们只需要在这个方法里面提取出
Model
矩阵中的缩放因子并去除就可以了
-
因为涉及到了更改
Object3D
源码,因此我们可以实现一个新的类
Mark
,让它继承自
Object3D
,再改写其中的一些方法就可以了
-
代码—
import { Mesh, Object3D, Quaternion, Vector3 } from 'three';
class Mark extends Object3D {
constructor(camera, position) {
super();
this.type = 'Mark';
this.camera = camera;
this._position = position || new Vector3();
this.size = 1;
this.worldPosition = new Vector3();
this._worldQuaternion = new Quaternion();
this._worldScale = new Vector3();
this.cameraPosition = new Vector3();
this._cameraQuaternion = new Quaternion();
this._cameraScale = new Vector3();
this.add(this.setupBall())
setupBall() {
const group = new THREE.Group();
const bar = new Mesh(
new THREE.CylinderGeometry(0.1, 0, 2, 20, 4),
new THREE.MeshBasicMaterial({color: 'red'})
bar.position.setY(1)
const ball = new Mesh(
new THREE.SphereBufferGeometry(0.6, 20, 20),
new THREE.MeshBasicMaterial({color: 'red'})
ball.position.setY(2)
group.add(bar)
group.add(ball)
return group
updateMatrixWorld( force ) {
this.matrixWorld.decompose( this.worldPosition, this._worldQuaternion, this._worldScale );
this.camera.updateMatrixWorld();
this.camera.matrixWorld.decompose( this.cameraPosition, this._cameraQuaternion, this._cameraScale );
const factor = this.worldPosition.distanceTo( this.cameraPosition ) * Math.min( 1.9 * Math.tan( Math.PI * this.camera.fov / 360 ) / this.camera.zoom, 10 );
this.scale.set( 1, 1, 1 ).multiplyScalar( factor * this.size / 40);
super.updateMatrixWorld( this );
Mark.prototype.isMark = true;
export { Mark };
function addMark(direction, position, parent) {
const axis = new THREE.Vector3(0, 1, 0);
const mark = new Mark(camera, position);
const positionLocal = parent.worldToLocal(position);
mark.quaternion.setFromUnitVectors(axis, direction.clone().normalize());
mark.position.copy(positionLocal);
parent.add(mark);
需求背景需要在3d模型上实现标注的功能,一开始是直接通过添加一个普通的mesh来实现的,但是这样就会有一个问题-当视图缩放的时候,标注也会跟着一起放大缩小,影响视觉效果,因此需要实现一个不会随着视图一起放大或者缩小的mesh实现思路明确方向根据需求,可以知道我们其实需要实现的就是更改模型渲染的默认方式,而模型的渲染是由模型的MVP三个矩阵来决定的再进一步分析MVP三个矩阵,Model矩阵决定模型的旋转、缩放和位移,View决定相机的变换, Projection决定模型最终到屏幕的输出。根据需求
Three.js是JavaScript编写的WebGL第三方库。提供了非常多的3D显示功能。运行在浏览器中的 3D 引擎,你可以用它创建各种三维场景,包括了摄影机、光影、材质等各种对象。你可以在它的主页上看到许多精彩的演示。不过,这款引擎还处在比较不成熟的开发阶段,其不够丰富的 API 以及匮乏的文档增加了初学者的学习难度(尤其是文档的匮乏)three.js的代码托管在github上面。
一些有用的链接
Three.js的基本概念:https://
<template>
<div class="search">
<el-select v-model="input" filterable clearable placeholder="请输入项目名" @change="change">
<el-option
v-for="(item, index) in ..
精灵平面(Sprite)
精灵平面(Sprite)是一个在3D场景中总是面对着相机的平面。也就是无论你怎么旋转,你会发现他都朝向你哟,是不是很厉害的样子~
好的,现在开始给模型增加sprite:
(1)利用canvas绘制文字,作为sprite的材质
var canvas = document.createElement(...
在three.js中给标点添加弹窗可以通过以下步骤实现:
1. 首先,需要在页面中导入three.js库,并创建一个场景(scene)、一个相机(camera)和一个渲染器(renderer)。
2. 创建一个标点(Particle)或粒子系统(Particle System),用于表示需要添加弹窗的标点。可以使用three.js提供的内置几何体如Sphere或Cube,也可以自定义几何体。
3. 创建一个HTML元素作为弹窗的内容,可以是一段文本、图片、视频等。
4. 使用CSS将弹窗内容进行样式设置,使其呈现所需的外观和布局。
5. 监听鼠标事件,当鼠标悬停在标点上时触发。可以使用Raycaster进行鼠标拾取操作,判断鼠标是否与标点相交。
6. 当鼠标与标点相交时,根据需要的效果,可以通过显示/隐藏CSS设置弹窗内容,或者使用JavaScript动态创建弹窗元素并添加到页面上。
7. 在弹窗元素中显示所需的内容。
8. 根据需要,可以实现其他交互效果,如拖动弹窗、关闭弹窗等。
需要注意的是,three.js是一个基于WebGL的3D库,弹窗的具体实现可能需要结合HTML、CSS和JavaScript等技术。以上步骤提供了一个基本的思路,具体实现方式可以根据需求和场景进行调整。