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

时间:2014-07-15 11:42:35

标签: three.js

我已经创建了一个3D地图,我通过Sprites在这张地图上标记点。除了精灵标签的定位外,这本身就可以正常工作。

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

没有jsfiddle方便,但我在http://leeft.eu/starcitizen/的申请应该给出一个好看的样子。

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

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

Three.js r.67

3 个答案:

答案 0 :(得分: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 );
   }
} );

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

答案 1 :(得分:0)

我有类似的问题,但有精灵;我把树放在地图上,希望它们以这样的方式旋转,即它们围绕它们的基座而不是它们的中心旋转。要做到这一点,我只是将树的图像文件编辑为两倍高,底部只是透明度:

http://imgur.com/ogFxyFw

如果您将第一张图像转换为精灵,它会在相机旋转时围绕树的中心旋转。当相机旋转时,第二棵树将围绕它旋转。

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

答案 2 :(得分:0)

这非常糟糕,但是如果你只是以这种方式使用sprite,并且可以容忍对sprite的呈现方式进行全局更改,那么你可以在编译的three.js脚本中更改以下行:< / p>

查找(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”进行这些修改(或者更确切地说,在定义了Three之后重新定义SpritePlugin),但是由于某种原因导致了未正确定义的事情导致了重大问题。范围界定也是“polyfill”方法的一个问题。

注3 :我的three.js版本是r69。所以上面可能存在差异。