Three.js 模型标签

发布于 2021-11-17 13:16:11 字数 3596 浏览 1463 评论 0

在很多的实际的项目中,你可能需要给一个 Three.js 的模型添加标签,标签可以通过一个包含文字图形信息的 HTML 元素或者一个 three.js 的精灵模型来表示。

层级模型

复杂的项目,一个three.js场景往往包含包含多个模型对象,模型对象也会有一些父对象,这样就会形成一个层级模型,从数据结构的角度来看就是树结构。

一个模型相对世界坐标系原点的位置是世界坐标,相对父对象的位置是局部坐标。

获取模型位置

你如果想给一个模型设置标签,首先需要获得模型在世界坐标系中所在的位置,如果你希望标注一个模型的某个局部位置,那就要获得该局部区域的一个顶点坐标。

  • .position 属性是一个模型的局部位置,相对父对象的位置,如果一个网格模型Mesh直接属于场景 Scene,没有除了 Scene 意外的父对象
  • .vertices 如果几何体是Geometry类型,可以通过 .vertices 属性访问顶点,通过下标可以访问具体的顶点位置坐标。
  • .attributes.position 如果几何体是 BufferGeometry 类型,可以通过 .attributes.position 属性访问顶点位置数据。
  • .getWorldPosition() 实际项目中一个模型对象可以有多个父对象,这个时候想获得该模型对象的世界坐标,就不能通过 .position 属性,应该通过 .getWorldPosition() 方法实现,该方法的使用参考基类 Object3D

实际项目中获得一个模型,可能是通过点击获得,或者遍历对象根据属性值找到某个或某些模型,等等这里不展开说,这不是本节课的重点,关于递归遍历模型或者鼠标点击选中某个模型可以关注课程的其它部分。

精灵模型 Sprite 作为标签

在使用精灵模型表示标签之前,你应该先了解精灵模型Sprite有什么特点。使用精灵模型表示一个模型对象的标签,那么精灵模型就要位于模型对象的附近。可以获得要标注模型的世界坐标,然后来设置精灵标签的位置,适当偏移一点就可以,当然也可以把精灵对象插入到模型对象的父对象中,和模型对象一样作为父对象的子对象,这样的话如果模型父对象的位置变化,精灵模型可以跟着一起变化。

标签的样式可以让美术设计好直接作为精灵的贴图就可以,如果标签不是特定的,比如用户输入文字,平台自动生成模型标签,可以通过程序自动化合成一个纹理作为精灵模型的贴图,关于如何自动合成纹理贴图这里不详细阐述。

/**
 * 创建点精灵模型
 */
// 创建精灵材质对象SpriteMaterial
var spriteMaterial = new THREE.SpriteMaterial({
  map:  new THREE.TextureLoader().load("立方体.png"), //设置精灵纹理贴图
  transparent: true,//开启透明(纹理图片png有透明信息)
});
// 创建精灵模型对象,不需要几何体geometry参数
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(30, 30, 1); //精灵大小
// 把精灵模型插入到模型对象的父对象下面
group.add( sprite);
// 父对象group位置变化,网格模型及其对象的标签同样发生变化
group.position.set(10, 0, -80);
// 表示标签信息的精灵模型对象相对父对象设置一定的偏移
sprite.translateY(30);

div 等 html 元素作为标签(世界坐标转屏幕坐标)

通过 html 元素表示标签相比较使用精灵来说比较麻烦,需要进行坐标变换,一个模型显示在 Canvas 画布上,经过了相机的视图、投影变换,如果想把一个 div 元素标注在一个模型附近,就需要计算模型渲染到画布上的具体位置,也就是所谓的屏幕坐标。使用 html 元素的好处是可以直接输入汉字,利用 Css 来设置一下标签的样式,当然也可以直接加载美术设计的标签。

世界坐标转 WebGL 标准设备坐标

  • 世界坐标:世界坐标简单说就是模型在three.js三维空间中的位置,但是注意不是局部位置属性.position,你可以通过.getWorldPosition()方法获得世界坐标,每个子对象都有一个相对父对象的位置,把一个对象的所有父对象相对Scene坐标原点的位置加起来就是一个模型的世界坐标
  • 屏幕坐标:你可以理解为Canvas画布上的位置,单位是像素px,这和HTML说的像素是一样的。
    //创建一个三维向量作为世界坐标
    var worldVector = new THREE.Vector3();
    //获取网格模型boxMesh的世界坐标,赋值给worldVector
    boxMesh.getWorldPosition(worldVector);
    //世界坐标转标准设备坐标,standardVector是WebGL设备坐标
    var standardVector = worldVector.project(camera);
    

    .project() 是向量 Vector3 的方法,一个表示位置的向量 Vector3 把相机作为参数执行该方法可以得到经过相机变换后的坐标。一般 threejs 渲染器渲染的时候,会自动从相机对象读取视图和投影矩阵对模型的顶点进行变换。

WebGL 标准设备坐标转屏幕坐标

Canvas 全屏显示的时候复合下面的计算规则,如果不是全屏要注意修改计算规则。如果不是全屏,计算a和b的值,不能使用 window.innerWidth,而应该使用 canvas 的具体宽高。如果 canvas 是局部显示相对 body 区域的左上角有偏移,那么div元素也要设置一定的偏移。

// 根据WebGL标准设备坐标standardVector计算div标签在浏览器页面的坐标
var a = window.innerWidth / 2;
var b = window.innerHeight / 2;
var x = Math.round(standardVector.x * a + a); //标准设备坐标转屏幕坐标
var y = Math.round(-standardVector.y * b + b); //标准设备坐标转屏幕坐标
/**
 * 设置标签元素的位置
 */
div.style.left = x + 'px';
//这里的130px主要是为了标签和模型有一定偏移,当然也可以不设置,两者叠加在一起
div.style.top = y - 130 + 'px';

Image text

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

虐人心

有一天你能到我的心里去,你会看到那里全是你给的伤悲。

0 文章
0 评论
24514 人气
更多

推荐作者

七秒鱼°

文章 0 评论 0

爱已欠费

文章 0 评论 0

ㄟ。诗瑗

文章 0 评论 0

小河采露

文章 0 评论 0

巅峰

文章 0 评论 0

gitee_v1qxdSBNo

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文