我创建了一张 3D 地图,并通过 Sprites 在这张地图上标记点。除了精灵标签的定位之外,这本身工作得很好。
因为我正在创建地图,所以相机可以从 0 度倾斜到 90 度,而理想情况下,标签始终与屏幕上标记的项目正上方保持一定距离。但不幸的是,由于精灵始终以它们的原点为中心并且与项目重叠,因此我必须在 Y 世界轴上向上移动精灵,并且随着相机倾斜,精灵的中心位置也会发生变化。如果所看到的项目偏离中心,这看起来很奇怪,并且当相机垂直向下看时效果不太好。
没有方便的 jsfiddle,但我在 http://leeft.eu/starcitizen/ 的申请应该会给人留下很好的印象。
THREE.SpritePlugin 的代码向我建议应该可以使用“matrixWorld”在渲染时将精灵在屏幕的 Y 轴上向上移动一段距离,但我不知道如何使用它,我也不完全知道当然这就是我首先需要使用的。
是否可以在渲染时将精灵在屏幕上向上移动,或者更改它们的原点?或者还有其他方法可以达到同样的效果吗?
Three.js r.67
按照 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 );
}
} );
使用此代码的任何人请注意:精灵标签是它们所引用的对象组的子对象,这仅设置距该父对象的本地偏移量。
我也有类似的问题,但是是平面精灵;我将树木放在地图上,并希望它们以围绕其底座而不是中心旋转的方式旋转。为此,我只需将树木的图像文件编辑为两倍高,底部只是透明的:
https://i.sstatic.net/HMuA5.jpg
如果将第一张图像变成精灵,当相机旋转时它会围绕树的中心旋转。当相机旋转时,第二棵树将绕其底座旋转。
对于您的应用程序,如果您调整文本框的大小,使其中心与星星重合;也许通过添加一些换行符或编辑精灵的高度
这在很大程度上是一种黑客行为,但如果您仅以这种方式使用精灵,并且可以容忍精灵渲染方式的全局更改,您可以在编译的
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。所以上面可能会有差异。