Threejs:如何创建可缩放的自适应网格助手

时间:2019-06-20 15:44:09

标签: three.js 3d grid

我如何在threejs中制作 zoom自适应 网格帮助器,既不会变得过于密集以至于不能呈现为空白,也不会变得过于稀疏而无法完全呈现为未呈现?

function addGrid({scene}) {
    let gridSize = 200000;
    const grid = new THREE.GridHelper( gridSize, gridSize/100, 0x000000, 0x000000 );
    grid.name = 'gridHelper';
    grid.material.opacity = 0.2;
    grid.material.transparent = true;
    scene.add( grid );
}

我应该只使用控件的change侦听器并按照此answer中的建议对一堆值进行硬编码,以便在跨越这些值时重新呈现网格帮助程序,或者有一种简洁的数学方法可以一样吗?

此外,我找不到我可以更改的任何显式属性(例如grid.divisions),将对象移除并将其添加到场景中效率不高吗?

我该怎么做?

1 个答案:

答案 0 :(得分:0)

我将使用相同的网格并设置比例,也许是2个网格

        const gridLevel = Math.log10(zoom * zoomAdjust);
        const gridFract = THREE.Math.euclideanModulo(gridLevel, 1);
        const gridZoom = Math.pow(10, Math.floor(gridLevel));    

        grid1.scale.setScalar(gridZoom);
        grid1.material.opacity = Math.max((1 - gridFract) * 1);

        grid2.scale.setScalar(gridZoom * 10);
        grid2.material.opacity = Math.max(gridFract * 10) - 1;
        grid2.visible = grid2.material.opacity > 0;

'use strict';

/* global THREE */

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});
  const zoomAdjust = 5;  // change to adjust when things start/end. Try 5 or .5 for example
  const zoomElem = document.querySelector('#zoom');

  const fov = 75;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 1000;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.set(10, 10, 10);
  camera.lookAt(0, 0, 0);

  const scene = new THREE.Scene();
  
  function makeGrid() {
    const grid = new THREE.GridHelper(200, 200);
    grid.material.transparent = true;
    scene.add(grid);
    return grid;
  }
  const grid2 = makeGrid();
  const grid1 = makeGrid();

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  let zoom = 1;

  function render() {
    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }
    
    zoomElem.textContent = zoom.toFixed(4);
    
    camera.near = zoom / 100;
    camera.far = zoom * 100;
    camera.updateProjectionMatrix();
    
    camera.position.set(zoom * -10, zoom * 5, zoom * -10);
    
    const gridLevel = Math.log10(zoom * zoomAdjust);
    const gridFract = THREE.Math.euclideanModulo(gridLevel, 1);
    const gridZoom = Math.pow(10, Math.floor(gridLevel));    

    grid1.scale.setScalar(gridZoom);
    grid1.material.opacity = Math.max((1 - gridFract) * 1);
    
    grid2.scale.setScalar(gridZoom * 10);
    grid2.material.opacity = Math.max(gridFract * 10) - 1;
    grid2.visible = grid2.material.opacity > 0;

    renderer.render(scene, camera);
  }
  render();
  
  window.addEventListener('wheel', (e) => {
    e.preventDefault();
    const amount = e.deltaY;
    if (e.deltaY < 0) {
      zoom *= 1 - THREE.Math.clamp(e.deltaY / -500, 0, 1);
    } else {
      zoom *= 1 + THREE.Math.clamp(e.deltaY / 500, 0, 1);
    }
    zoom = THREE.Math.clamp(zoom, 0.0001, 10000);
    render();
  }, {passive: false});
  window.addEventListener('resize', render);

}

main();
body {
  margin: 0;
  color: white;
  font-family: monospace;
}
#c {
  width: 100vw;
  height: 100vh;
  display: block;
}
#hud {
  position: absolute;
  left: 1em;
  top: 1em;
}
<canvas id="c"></canvas>
<div id="hud">zoom: <span id="zoom"></span></div>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/three.min.js"></script>