我正在使用three.js的太阳能系统,我很好奇是否有一种简单的方法可以让我所拥有的行星的标签显示相同的尺寸,无论它们离相机有多远?我似乎无法找到解决方案。我想你可以计算从每个标签到相机的距离,然后根据它得出某种比例因子。似乎有更简单的方法来实现这一目标?
谢谢!
更新了来自prisoner849的回复。效果很好!
答案 0 :(得分:15)
I figure you could calculate the distance from each label to the camera then come up with some sort of scaling factor based on that.
这很简单。比方说,THREE.Sprite()
对象(标签)是THREE.Mesh()
对象(行星)的子项,然后在动画循环中需要做
var scaleVector = new THREE.Vector3();
var scaleFactor = 4;
var sprite = planet.children[0];
var scale = scaleVector.subVectors(planet.position, camera.position).length() / scaleFactor;
sprite.scale.set(scale, scale, 1);
我使用这种技术制作了一个非常简单的example太阳系。
答案 1 :(得分:3)
最后我找到了你问题的答案:
首先,创建一个DOM元素:
<div class="element">Not Earth</div>
然后为它设置CSS样式:
.element {position: absolute; top:0; left:0; color: white}
// |-------------------------------| |-----------|
// make the element on top of canvas is
// the canvas black, so text
// must be white
之后,创建moveDom()
函数并在每次渲染场景时运行它requestAnimationFrame()
geometry
是网格的几何cube
是您要创建标签的网格var moveDom = function(){ vector = geometry.vertices[0].clone(); vector.applyMatrix4(cube.matrix); vector.project(camera); vector.x = (vector.x * innerWidth/2) + innerWidth/2; vector.y = -(vector.y * innerHeight/2) + innerHeight/2; //Get the DOM element and apply transforms on it document.querySelectorAll(".element")[0].style.webkitTransform = "translate("+vector.x+"px,"+vector.y+"px)"; document.querySelectorAll(".element")[0].style.transform = "translate("+vector.x+"px,"+vector.y+"px)"; };
您可以创建一个for
循环来为场景中的所有网格设置标签。
因为这个技巧只设置DOM元素的2D位置,即使你缩放(标签不是three.js
场景的一部分),标签的大小也是一样的。
完整的测试用例:https://jsfiddle.net/0L1rpayz/1/
var renderer, scene, camera, cube, vector, geometry;
var ww = window.innerWidth,
wh = window.innerHeight;
function init(){
renderer = new THREE.WebGLRenderer({canvas : document.getElementById('scene')});
renderer.setSize(ww,wh);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50,ww/wh, 0.1, 10000 );
camera.position.set(0,0,500);
scene.add(camera);
light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set( 0, 0, 500 );
scene.add(light);
//Vector use to get position of vertice
vector = new THREE.Vector3();
//Generate Not Earth
geometry = new THREE.BoxGeometry(50,50,50);
var material = new THREE.MeshLambertMaterial({color: 0x00ff00});
cube = new THREE.Mesh(geometry, material);
scene.add(cube);
//Render my scene
render();
}
var moveDom = function(){
vector = geometry.vertices[0].clone();
vector.applyMatrix4(cube.matrix);
vector.project(camera);
vector.x = (vector.x * ww/2) + ww/2;
vector.y = -(vector.y * wh/2) + wh/2;
//Get the DOM element and apply transforms on it
document.querySelectorAll(".element")[0].style.webkitTransform = "translate("+vector.x+"px,"+vector.y+"px)";
document.querySelectorAll(".element")[0].style.transform = "translate("+vector.x+"px,"+vector.y+"px)";
};
var counter = 0;
var render = function (a) {
requestAnimationFrame(render);
counter++;
//Move my cubes
cube.position.x = Math.cos((counter+1*150)/200)*(ww/6+1*80);
cube.position.y = Math.sin((counter+1*150)/200)*(70+1*80);
cube.rotation.x += .001*1+.002;
cube.rotation.y += .001*1+.02;
//Move my dom elements
moveDom();
renderer.render(scene, camera);
};
init();
body,html, canvas{width:100%;height:100%;padding:0;margin:0;overflow: hidden;}
.element{color:white;position:absolute;top:0;left:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.min.js"></script>
<!-- My scene -->
<canvas id="scene"></canvas>
<div class="element">
<h1>Not Earth</h1>
</div>
如果您对此进行了投票,请告诉我原因。我会尽力改善我的帖子。
答案 2 :(得分:2)
为了将来的访问者的利益,转换控件示例正是这样做的:
https://threejs.org/examples/misc_controls_transform.html
在示例代码中是这样完成的:
var factor;
if ( this.camera.isOrthographicCamera ) {
factor = ( this.camera.top - this.camera.bottom ) / this.camera.zoom;
} else {
factor = this.worldPosition.distanceTo( this.cameraPosition ) * Math.min( 1.9 * Math.tan( Math.PI * this.camera.fov / 360 ) / this.camera.zoom, 7 );
}
handle.scale.set( 1, 1, 1 ).multiplyScalar( factor * this.size / 7 );
答案 3 :(得分:0)
如果使用spriteMaterial呈现文本,则可以尝试将sizeAttenuation属性设置为false。
var spriteMaterial = new THREE.SpriteMaterial( { map: spriteMap, color: 0xffffff, sizeAttenuation:false } );
从此处查看更多信息: https://threejs.org/docs/index.html#api/en/materials/SpriteMaterial.sizeAttenuation