使用Three.js创建相对于视口大小的BoxGeometry 16x16网格

时间:2019-07-02 09:25:10

标签: javascript canvas three.js

问题尽可能地简单,标题几乎描述了我正在尝试做的事情。

我是Three.js和WebGL的新手,我或多或少了解创建多维数据集的基础知识,但是当涉及到我要尝试做的事情时,我很茫然。

在学习的过程中,我基本上是以这支笔为参考的:https://codepen.io/jackrugile/pen/vOEKzw可以满足我的要求,而与屏幕尺寸无关

var tick = 0,
  smallestDimension = Math.min(window.innerWidth, window.innerHeight),
  viewportWidth = smallestDimension,
  viewportHeight = smallestDimension,
  worldWidth = 100,
  worldHeight = 100,
  rows = 30,
  cols = 30,
  tileWidth = worldWidth / cols,
  tileHeight = worldHeight / rows,
  FOV = 90,
  scene = new THREE.Scene(),
  camera = new THREE.PerspectiveCamera(
    FOV,
    viewportWidth / viewportHeight,
    0.1,
    1000
  ),
  renderer = new THREE.WebGLRenderer({
    antialias: true
  }),
  plane = new THREE.Mesh(
    new THREE.PlaneBufferGeometry(worldWidth, worldHeight, 1),
    new THREE.MeshPhongMaterial({
      color: 0x222222
    })
  ),
  cubes = new THREE.Object3D(),
  spotLight = new THREE.SpotLight(0xffffff),
  ambientLight = new THREE.AmbientLight(0x666666);

renderer.setSize(viewportWidth, viewportHeight);
renderer.shadowMapEnabled = true;
renderer.shadowMapType = THREE.PCFSoftShadowMap;

scene.add(plane);
scene.add(cubes);
scene.add(spotLight);
scene.add(ambientLight);

for (var x = 0; x < cols; x++) {
  for (var y = 0; y < rows; y++) {
    var width = tileWidth,
      height = tileHeight,
      dx = (cols / 2 - x),
      dy = (rows / 2 - y),
      depth = 1 + (20 - Math.sqrt(dx * dx + dy * dy)) / 4,
      xBase = -worldWidth / 2 + x * tileWidth + tileWidth / 2,
      yBase = -worldHeight / 2 + y * tileHeight + tileHeight / 2,
      zBase = depth / 2,
      cube = new THREE.Mesh(
        new THREE.BoxGeometry(width, height, depth),
        new THREE.MeshPhongMaterial({
          color: 'rgb(' + ~~((y / rows) * 255) + ', ' + ~~((x / cols) * 255) + ', 255)',
          shininess: 50
        })
      );
    cube.position.set(
      xBase,
      yBase,
      zBase
    );
    cube.castShadow = true;
    cube.receiveShadow = true;
    cube.zBase = zBase;
    cube.zScaleTarget = 1;
    cubes.add(cube);
  }
}

plane.position.set(0, 0, 0);
plane.castShadow = false;
plane.receiveShadow = true;

camera.position.set(0, 0, 100);

spotLight.position.set(0, 0, 100);
spotLight.castShadow = true;
spotLight.shadowCameraNear = 0.1;
spotLight.shadowMapWidth = 2048;
spotLight.shadowMapHeight = 2048;
spotLight.shadowDarkness = 0.1;

function step() {
  spotLight.position.x = Math.sin(tick / 100) * (worldWidth / 2);
  spotLight.position.y = Math.cos(tick / 100) * (worldHeight / 2);

  cubes.traverse(function(cube) {
    if (cube instanceof THREE.Mesh) {
      if (Math.abs(cube.scale.z - cube.zScaleTarget) > 0.001) {
        cube.scale.z += (cube.zScaleTarget - cube.scale.z) * 0.05;
      } else {
        cube.zScaleTarget = 1 + Math.random() * 10;
      }
      cube.position.z = cube.geometry.parameters.depth / 2 * cube.scale.z;
    }
  });

  tick++;
}

function render() {
  renderer.render(scene, camera);
}

function loop() {
  requestAnimationFrame(loop);
  step();
  render();
}

loop();

document.body.appendChild(renderer.domElement);
body {
  background: #000;
  overflow: hidden;
}

canvas {
  bottom: 0;
  display: block;
  left: 0;
  margin: auto;
  position: absolute;
  right: 0;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>

worldWidth = 100,
worldHeight = 100,
rows = 30,
cols = 30,
tileWidth = worldWidth / cols,
tileHeight = worldHeight / rows,

我看到它使用它来设置他后期在循环中使用的图块的大小:

...
var width = tileWidth,
    height = tileHeight,
    dx = ( cols / 2 - x ),
    dy = ( rows / 2 - y ),
    depth = 1 + ( 20 - Math.sqrt( dx * dx + dy * dy ) ) / 4,
    xBase = -worldWidth / 2 + x * tileWidth + tileWidth / 2,
    yBase = -worldHeight / 2 + y * tileHeight + tileHeight / 2,
...

我将如何在整个视口上绘制这些图块,使其类似于:

enter image description here

谢谢!

1 个答案:

答案 0 :(得分:0)

然后使用Math.min在第2行smallestDimension = Math.max( window.innerWidth, window.innerHeight )中使用它 它会自动覆盖您的屏幕尺寸。 如果需要,您可以更改rows = 10col = 10