Three.js提供了一个特殊的渲染器examples/js/renderers/CSS2DRenderer,它允许在标准的WebGL渲染场景上使用html叠加(请参阅official demo, here。)
CSS2DRenderer通过CSS转换完成html项的定位。以下是渲染器如何将世界空间与屏幕空间联系起来:
vector.setFromMatrixPosition( object.matrixWorld );
vector.applyProjection( viewProjectionMatrix );
var element = object.element;
var style = 'translate(-50%,-50%) translate(' + ( vector.x * _widthHalf + _widthHalf ) + 'px,' + ( - vector.y * _heightHalf + _heightHalf ) + 'px)';
element.style.WebkitTransform = style;
element.style.MozTransform = style;
element.style.oTransform = style;
element.style.transform = style;
在下面的实时代码段中,我在网格旁边放置了几个文本元素,就像数据图中的轴标签一样。 我的问题是在three.js世界空间中为html标签选择一个位置来考虑它们的像素宽度。我用一个平面框住每个标签以显示到网格边缘的间隙 - 我需要消除这个差距!
var renderer, labelRenderer, scene, camera, controls, sprite, stats, rot, planes, ctx, fontFamily, fontSize;
rot = 0; // this drives load(?)
init();
//animate();
render();
function init() {
fontFamily = "monospace";
fontSize = "10px";
stats = new Stats();
stats.showPanel(1);
document.body.appendChild(stats.dom);
var canvas = document.createElement('canvas')
ctx = canvas.getContext('2d')
ctx.font = fontSize + " " + fontFamily;
// renderer
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
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);
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(20, 20, 20);
// controls
controls = new THREE.OrbitControls(camera);
// ambient
scene.add(new THREE.AmbientLight(0x222222));
// light
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(20, 20, 0);
scene.add(light);
// axes
scene.add(new THREE.AxisHelper(20));
var size = 5;
var step = 5;
var gridHelper = new THREE.GridHelper(size, step);
gridHelper.translateX(5);
gridHelper.translateZ(5);
scene.add(gridHelper);
var geometry, material, text, label;
planes = new Array(5);
var texts = ["one", "two", "three", "four", "five"];
for (var i = 0; i < 5; i++) {
geometry = new THREE.PlaneGeometry(2, 2);
material = new THREE.MeshBasicMaterial({
transparent: true,
opacity: 0
});
planes[i] = new THREE.Mesh(geometry, material);
planes[i].position.set(10 + 1, 1, i * 2 + 1)
planes[i].lookAt(camera.position)
scene.add(planes[i]);
scene.add(new THREE.EdgesHelper(planes[i]))
text = document.createElement('div');
text.className = 'label';
text.style.color = "white";
text.style["font-family"] = fontFamily;
text.style["font-size"] = fontSize;
text.textContent = texts[i];
var textWidth = ctx.measureText(texts[i]).width;
console.log("textWidth", textWidth);
label = new THREE.CSS2DObject(text);
label.position.copy(planes[i].position);
scene.add(label);
console.log("label", label);
}
}
function randomPos(scale) {
return scale * Math.random();
}
function render() {
renderer.render(scene, camera);
labelRenderer.render(scene, camera);
var x = camera.position.x;
var z = camera.position.z;
camera.position.x = x * Math.cos(rot) + z * Math.sin(rot);
camera.position.z = z * Math.cos(rot) - x * Math.sin(rot);
camera.lookAt(scene.position);
requestAnimationFrame(render);
planes.forEach(function(plane) {
plane.lookAt(camera.position);
});
stats.update();
}
function animate() {
requestAnimationFrame(animate);
//controls.update();
renderer.render(scene, camera);
stats.update();
}
&#13;
body {
background-color: #000;
margin: 0px;
overflow: hidden;
}
&#13;
<script src="https://rawgit.com/mrdoob/three.js/dev/build/three.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/controls/OrbitControls.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/renderers/CSS2DRenderer.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/libs/stats.min.js"></script>
&#13;
答案 0 :(得分:0)
像素宽度不是您的问题。它的起源。您正在抵消头寸(10 + 1,i,i * 2 + 1)... https://jsfiddle.net/7j4jypfL/1/
label = new THREE.CSS2DObject(text);
label.position.set(10+(0.5),0, (i * 2)+0.5);
scene.add(label);
你需要记住,在OpenGL中,广告牌之类的东西是以原点为中心的(即-1,-1到1,1),因此(0,0)将是中心。
你需要在比例尺1测量,当你进行缩放等时,由于透视数学,它会正确排列。看看我的小提琴,我将你的位置改为纯粹的(10,i,i * 2)并看看文本是如何排列的。如果你想从那里向下移动,(10 +(0.5),0,(i * 2)+0.5)