Three.js:更改精灵的枢轴点

问题描述 投票:0回答:4

我创建了一张 3D 地图,并通过 Sprites 在这张地图上标记点。除了精灵标签的定位之外,这本身工作得很好。

因为我正在创建地图,所以相机可以从 0 度倾斜到 90 度,而理想情况下,标签始终与屏幕上标记的项目正上方保持一定距离。但不幸的是,由于精灵始终以它们的原点为中心并且与项目重叠,因此我必须在 Y 世界轴上向上移动精灵,并且随着相机倾斜,精灵的中心位置也会发生变化。如果所看到的项目偏离中心,这看起来很奇怪,并且当相机垂直向下看时效果不太好。

没有方便的 jsfiddle,但我在 http://leeft.eu/starcitizen/ 的申请应该会给人留下很好的印象。

THREE.SpritePlugin 的代码向我建议应该可以使用“matrixWorld”在渲染时将精灵在屏幕的 Y 轴上向上移动一段距离,但我不知道如何使用它,我也不完全知道当然这就是我首先需要使用的。

是否可以在渲染时将精灵在屏幕上向上移动,或者更改它们的原点?或者还有其他方法可以达到同样的效果吗?

Three.js r.67

three.js
4个回答
2
投票

按照 WestLangley 的建议,我通过根据视角更改精灵位置来创建了一个可行的解决方案,尽管我花了几个小时才算出数学运算所需的几行代码。我也更新了我的应用程序,所以请观看现场演示。

使用

phi
中的相机计算出的倾斜角
theta
和航向角
OrbitControls.js
,以下代码计算出的精灵偏移量完全符合我的要求:

// Given:
// phi = tilt; 0 = top down view, 1.48 = 85 degrees (almost head on)
// theta = heading; 0 = north, < 0 looking east, > 0 looking west

// Compute an "opposite" angle; note the 'YXZ' axis order is important
var euler = new THREE.Euler( phi + Math.PI / 2, theta, 0, 'YXZ' );
// Labels are positioned 5.5 units up the Y axis relative to its parent
var spriteOffset = new THREE.Vector3( 0, -5.5, 0 );
// Rotate the offset vector to be opposite to the camera
spriteOffset.applyMatrix4( new THREE.Matrix4().makeRotationFromEuler( euler ) );

scene.traverse( function ( object ) {
   if ( ( object instanceof THREE.Sprite ) && object.userData.isLabel ) {
      object.position.copy( spriteOffset );
   }
} );

使用此代码的任何人请注意:精灵标签是它们所引用的对象组的子对象,这仅设置距该父对象的本地偏移量。


0
投票

我也有类似的问题,但是是平面精灵;我将树木放在地图上,并希望它们以围绕其底座而不是中心旋转的方式旋转。为此,我只需将树木的图像文件编辑为两倍高,底部只是透明的:

https://i.sstatic.net/HMuA5.jpg

如果将第一张图像变成精灵,当相机旋转时它会围绕树的中心旋转。当相机旋转时,第二棵树将绕其底座旋转。

对于您的应用程序,如果您调整文本框的大小,使其中心与星星重合;也许通过添加一些换行符或编辑精灵的高度


0
投票

这在很大程度上是一种黑客行为,但如果您仅以这种方式使用精灵,并且可以容忍精灵渲染方式的全局更改,您可以在编译的

three.js
脚本中更改以下行:

找到(ctrl+F)

THREE.SpritePlugin = function
,你会看到:

this.init = function ( renderer ) {

    _gl = renderer.context;
    _renderer = renderer;

    vertices = new Float32Array( [
        - 0.5, - 0.5, 0, 0, 
          0.5, - 0.5, 1, 0,
          0.5,   0.5, 1, 1,
        - 0.5,   0.5, 0, 1
    ] );

我将数组的定义更改为以下内容:

    var vertices = new Float32Array( [
        - 0.5, - 0.0,  0, 0,
          0.5, - 0.0,  1, 0,
          0.5,   1.0,  1, 1,
        - 0.5,   1.0,  0, 1 
    ] );

现在我所有的精灵都以底部的旋转原点进行渲染。

如果您使用缩小版本,请搜索

THREE.SpritePlugin=function
并向右移动光标,直到找到定义的 Float32Array,然后进行相同的更改。

注意:这仅改变使用 WebGL 时的渲染方式。对于画布渲染器,您必须在 renderSprite() 中运行一个名为

THREE.CanvasRenderer
的函数。我怀疑玩这些线就可以了:

var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite _elemBox.min.set( v1.x - dist, v1.y - dist ); _elemBox.max.set( v1.x + dist, v1.y + dist );

这个函数在缩小版本中也将更难找到,因为
renderSprite()

不是一个向外的函数,它可能会被重命名为一些晦涩而小的东西。


注2

:我确实尝试使用“polyfills”进行这些修改(或者更确切地说,在定义了三个之后重新定义SpritePlugin),但是由于某种原因,它导致了一些没有正确定义的重大问题。范围界定也是“polyfill”方法的一个问题。

注3

:我的 Three.js 版本是 r69。所以上面可能会有差异。


0
投票

如果我们需要在对象顶部放置标签,则 y 应该为负数,例如下面屏幕截图中的 -0.35 至 -1:

sprite.center.set( 0, -1 );

enter image description here 适用于 r146(也可能是其他版本)

© www.soinside.com 2019 - 2024. All rights reserved.