【问题标题】:How to express pixel width in Three.js world space?如何在 Three.js 世界空间中表示像素宽度?
【发布时间】:2016-11-30 11:55:55
【问题描述】:

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;

在下面的实时 sn-p 中,我在网格旁边放置了几个文本元素,就像数据图中的轴标签一样。 我的问题是在 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();

}
body {
  background-color: #000;
  margin: 0px;
  overflow: hidden;
}
<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>

【问题讨论】:

    标签: three.js


    【解决方案1】:

    像素宽度不是您的问题。是起源。您正在偏移位置 (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)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-17
      • 2018-11-03
      • 2013-04-22
      • 2013-12-16
      • 2016-04-26
      • 1970-01-01
      相关资源
      最近更新 更多