我有一个现有的项目,一个太阳系的模型,其中的行星和卫星都标有文字。为了创建标签,我使用了精灵(SpriteMaterial
),并且效果很好。 (下面是结果-您可以放大以更仔细地查看标签)
如您所见,标签很好地呈现在其父级旁边,并且缩放比例也与其父级的缩放比例有关。
var camera, scene, renderer;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, .1, 2000);
camera.position.z = 3;
scene = new THREE.Scene();
var object;
var label;
var ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
scene.add(ambientLight);
var pointLight = new THREE.PointLight(0xffffff, 0.8);
camera.add(pointLight);
scene.add(camera);
var map = new THREE.TextureLoader().load('https://threejs.org/examples/textures/UV_Grid_Sm.jpg');
map.wrapS = map.wrapT = THREE.RepeatWrapping;
map.anisotropy = 16;
var material = new THREE.MeshPhongMaterial({
map: map,
side: THREE.DoubleSide
});
//
sun = new THREE.Mesh(new THREE.SphereBufferGeometry(1, 20, 10), material);
sun.position.set(0, 0, 0);
label = makeTextSprite("Sun");
sun.add(label)
scene.add(sun);
ratioOfJupiterToSun = 0.1
jupiter = new THREE.Mesh(new THREE.SphereBufferGeometry(1, 20, 10), material);
jupiter.position.set(1.5, 0, 0);
jupiter.scale.set(ratioOfJupiterToSun, ratioOfJupiterToSun, ratioOfJupiterToSun)
label = makeTextSprite("Jupiter");
jupiter.add(label)
sun.add(jupiter);
ratioOfGanymedeToJupiter = 0.1
ganymede = new THREE.Mesh(new THREE.SphereBufferGeometry(1, 20, 10), material);
ganymede.scale.set(ratioOfGanymedeToJupiter, ratioOfGanymedeToJupiter, ratioOfGanymedeToJupiter)
ganymede.position.set(4, 0, 0);
label = makeTextSprite("Ganymede");
ganymede.add(label)
jupiter.add(ganymede);
//
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.minDistance = 1.7
controls.maxDistance = 3
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
//
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
camera.lookAt(scene.position);
renderer.render(scene, camera);
}
function makeTextSprite(message, centerX = 1.5, centerY = 1.7) {
var canvas = document.createElement('canvas');
canvas.width = 256;
canvas.height = 256;
var ctx = canvas.getContext("2d");
ctx.font = "38pt Arial";
ctx.fillStyle = "white";
ctx.textAlign = "left";
ctx.fillText(message, 0, 38);
var tex = new THREE.Texture(canvas);
tex.needsUpdate = true;
var spriteMat = new THREE.SpriteMaterial({
map: tex
});
var sprite = new THREE.Sprite(spriteMat);
sprite.center.set(centerX, centerY);
return sprite;
}
body {
color: #eee;
font-family: Monospace;
font-size: 13px;
text-align: center;
background-color: #000;
margin: 0px;
padding: 0px;
overflow: hidden;
}
#info {
position: absolute;
top: 0px;
width: 100%;
padding: 5px;
}
a {
color: #0080ff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/renderers/CSS2DRenderer.js"></script>
精灵的问题在于它们使用栅格图形进行标注。有时质量不够。
这就是为什么我想用THREE.CSS2DRenderer
重现同样的效果。不幸的是,我获得的最佳近似值是
var camera, scene, renderer, labelRenderer;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, .1, 2000);
camera.position.z = 3;
scene = new THREE.Scene();
var object;
var label;
var ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
scene.add(ambientLight);
var pointLight = new THREE.PointLight(0xffffff, 0.8);
camera.add(pointLight);
scene.add(camera);
var map = new THREE.TextureLoader().load('https://threejs.org/examples/textures/UV_Grid_Sm.jpg');
map.wrapS = map.wrapT = THREE.RepeatWrapping;
map.anisotropy = 16;
var material = new THREE.MeshPhongMaterial({
map: map,
side: THREE.DoubleSide
});
//
sun = new THREE.Mesh(new THREE.SphereBufferGeometry(1, 20, 10), material);
sun.position.set(0, 0, 0);
label = makeTextLabel("Sun");
sun.add(label)
scene.add(sun);
ratioOfJupiterToSun = 0.1
jupiter = new THREE.Mesh(new THREE.SphereBufferGeometry(1, 20, 10), material);
jupiter.position.set(1.5, 0, 0);
jupiter.scale.set(ratioOfJupiterToSun, ratioOfJupiterToSun, ratioOfJupiterToSun)
label = makeTextLabel("Jupiter");
jupiter.add(label)
sun.add(jupiter);
ratioOfGanymedeToJupiter = 0.1
ganymede = new THREE.Mesh(new THREE.SphereBufferGeometry(1, 20, 10), material);
ganymede.scale.set(ratioOfGanymedeToJupiter, ratioOfGanymedeToJupiter, ratioOfGanymedeToJupiter)
ganymede.position.set(4, 0, 0);
label = makeTextLabel("Ganymede");
ganymede.add(label)
jupiter.add(ganymede);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.minDistance = 2
controls.maxDistance = 3
document.body.appendChild(renderer.domElement);
labelRenderer = new THREE.CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0';
labelRenderer.domElement.style.pointerEvents = 'none';
document.body.appendChild(labelRenderer.domElement);
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.setSize(window.innerWidth, window.innerHeight);
}
//
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
var timer = Date.now() * 0.0005;
// camera.position.x = Math.sin(timer) * 400;
// camera.position.z = Math.cos(timer) * 400;
camera.lookAt(scene.position);
scene.traverse(function(object) {
if (object.isMesh === true) {
//object.rotation.x = timer;
//object.rotation.z = timer;
}
});
renderer.render(scene, camera);
labelRenderer.render(scene, camera);
}
function makeTextLabel(label) {
var text = document.createElement('div');
text.style.color = 'rgb(255, 255, 255)';
text.style.marginTop = '1.7em';
text.style.marginLeft = '-4em';
text.className = 'label';
text.textContent = label;
return new THREE.CSS2DObject(text);
}
body {
color: #eee;
font-family: Monospace;
font-size: 13px;
text-align: center;
background-color: #000;
margin: 0px;
padding: 0px;
overflow: hidden;
}
a {
color: #0080ff;
}
.label {
color: #FFF;
font-family: sans-serif;
font-size: 44px;
padding: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/renderers/CSS2DRenderer.js"></script>
如您所见,它部分起作用:标签尊重父母的坐标系(世界矩阵)。这就是为什么他们的立场是相对的。但是规模不是。所有标签的尺寸都相同。
我还希望标签稍微移到左下角,就像我用Sprite一样。但是我能找到的最好方法是:
text.style.marginTop = '3em';
text.style.marginLeft = '-4em';
这显然也没有考虑到父母的规模。
您对如何使其与原版相似有任何想法吗?
jsfiddle中两个示例的代码:
r。 98
编辑:隐藏摘要以使帖子更具可读性
答案 0 :(得分:0)
报告不是错误。问题是您正在使用CSS2DRenderer
,但听起来您正在寻找CSS3DRenderer
提供的行为。您可以在动作in the examples section中看到它,以及放大/缩小时的行为。
您可以详细了解in the docs。请记住,您还必须创建CSS3DObject
而不是2D。然后,您可以将它们放置在所需的任何位置,就像其他3dObject:.position.set(x, y, z);
和scale.set(x, y, z);
如果必须使用CSS2D,则可以通过计算每个标签到相机的距离来执行自己的缩放。
// Create a Vec3 that holds the label's position
var start = new Vector3();
start.copy(label.position);
// Create a var that holds the distance to the camera
var dist = start.distanceTo(camera.position);
// Apply falloff, then turn that into the label's scale
var size = 1 / dist;
现在,您可以使用size
通过CSS transform: scale(x);
或其他方式缩放标签。