Three.js画布大小基于容器

38

如何根据容器计算画布大小以避免滚动条出现?

如果我基于窗口设置大小,画布会太大。

8个回答

66

可以说,调整three.js大小的最佳方法是编写代码,使其只接受由CSS设置的画布大小。这样,无论如何使用画布,您的代码都将起作用,无需为不同情况更改它。

首先,在设置初始纵横比时,没有理由设置它,因为我们将根据画布大小的不同而设置它,所以设置两次只是浪费代码。

// There's no reason to set the aspect here because we're going
// to set it every frame anyway so we'll set it to 2 since 2
// is the the aspect for the canvas default size (300w/150h = 2)
const camera = new THREE.PerspectiveCamera(70, 2, 1, 1000);

然后我们需要一些代码来调整画布大小以匹配其显示大小。
function resizeCanvasToDisplaySize() {
  const canvas = renderer.domElement;
  // look up the size the canvas is being displayed
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;

  // adjust displayBuffer size to match
  if (canvas.width !== width || canvas.height !== height) {
    // you must pass false here or three.js sadly fights the browser
    renderer.setSize(width, height, false);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();

    // update any render target sizes here
  }
}

在渲染之前,在你的渲染循环中调用此函数。
function animate(time) {
  time *= 0.001;  // seconds

  resizeCanvasToDisplaySize();

  mesh.rotation.x = time * 0.5;
  mesh.rotation.y = time * 1;

  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

以下是3个示例,这3个示例唯一的区别在于CSS和是否我们创建canvas或three.js创建canvas

示例1:全屏,我们创建canvas

"use strict";

const  renderer = new THREE.WebGLRenderer({canvas: document.querySelector("canvas")});

// There's no reason to set the aspect here because we're going
// to set it every frame anyway so we'll set it to 2 since 2
// is the the aspect for the canvas default size (300w/150h = 2)
const  camera = new THREE.PerspectiveCamera(70, 2, 1, 1000);
camera.position.z = 400;

const scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(200, 200, 200);
const material = new THREE.MeshPhongMaterial({
  color: 0x555555,
  specular: 0xffffff,
  shininess: 50,
  shading: THREE.SmoothShading
});

const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

const light1 = new THREE.PointLight(0xff80C0, 2, 0);
light1.position.set(200, 100, 300);
scene.add(light1);

function resizeCanvasToDisplaySize() {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (canvas.width !== width ||canvas.height !== height) {
    // you must pass false here or three.js sadly fights the browser
    renderer.setSize(width, height, false);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();

    // set render target sizes here
  }
}

function animate(time) {
  time *= 0.001;  // seconds

  resizeCanvasToDisplaySize();

  mesh.rotation.x = time * 0.5;
  mesh.rotation.y = time * 1;

  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<canvas></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js"></script>

示例2:全屏画布,three.js创建画布。

"use strict";

const renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);

// There's no reason to set the aspect here because we're going
// to set it every frame anyway so we'll set it to 2 since 2
// is the the aspect for the canvas default size (300w/150h = 2)
const  camera = new THREE.PerspectiveCamera(70, 2, 1, 1000);
camera.position.z = 400;

const scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(200, 200, 200);
const material = new THREE.MeshPhongMaterial({
  color: 0x555555,
  specular: 0xffffff,
  shininess: 50,
  shading: THREE.SmoothShading
});

const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

const light1 = new THREE.PointLight(0xff80C0, 2, 0);
light1.position.set(200, 100, 300);
scene.add(light1);

function resizeCanvasToDisplaySize() {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (canvas.width !== width ||canvas.height !== height) {
    // you must pass false here or three.js sadly fights the browser
    renderer.setSize(width, height, false);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();

    // set render target sizes here
  }
}

function animate(time) {
  time *= 0.001;  // seconds

  resizeCanvasToDisplaySize();

  mesh.rotation.x = time * 0.5;
  mesh.rotation.y = time * 1;

  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js"></script>

示例3:内联画布

"use strict";

const  renderer = new THREE.WebGLRenderer({canvas: document.querySelector(".diagram canvas")});

// There's no reason to set the aspect here because we're going
// to set it every frame anyway so we'll set it to 2 since 2
// is the the aspect for the canvas default size (300w/150h = 2)
const  camera = new THREE.PerspectiveCamera(70, 2, 1, 1000);
camera.position.z = 400;

const scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(200, 200, 200);
const material = new THREE.MeshPhongMaterial({
  color: 0x555555,
  specular: 0xffffff,
  shininess: 50,
  shading: THREE.SmoothShading
});

const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

const light1 = new THREE.PointLight(0xff80C0, 2, 0);
light1.position.set(200, 100, 300);
scene.add(light1);

function resizeCanvasToDisplaySize() {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (canvas.width !== width ||canvas.height !== height) {
    // you must pass false here or three.js sadly fights the browser
    renderer.setSize(width, height, false);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();

    // set render target sizes here
  }
}

function animate(time) {
  time *= 0.001;  // seconds

  resizeCanvasToDisplaySize();

  mesh.rotation.x = time * 0.5;
  mesh.rotation.y = time * 1;

  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);
body { font-size: x-large; }
.diagram { width: 150px; height: 150px; float: left; margin: 1em; }
canvas { width: 100%; height: 100%; }
<p>
Pretend this is a diagram in a physics lesson and it's inline. Notice we didn't have to change the code to handle this case.
<span class="diagram"><canvas></canvas></span>
The same code that handles fullscreen handles this case as well. The only difference is the CSS and how we look up the canvas. Otherwise it just works. We didn't have to change the code because we cooperated with the browser instead of fighting it.
</p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js"></script>

示例4:50%宽度画布(类似于实时编辑器)

"use strict";

const  renderer = new THREE.WebGLRenderer({canvas: document.querySelector("canvas")});

// There's no reason to set the aspect here because we're going
// to set it every frame anyway so we'll set it to 2 since 2
// is the the aspect for the canvas default size (300w/150h = 2)
const  camera = new THREE.PerspectiveCamera(70, 2, 1, 1000);
camera.position.z = 400;

const scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(200, 200, 200);
const material = new THREE.MeshPhongMaterial({
  color: 0x555555,
  specular: 0xffffff,
  shininess: 50,
  shading: THREE.SmoothShading
});

const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

const light1 = new THREE.PointLight(0xff80C0, 2, 0);
light1.position.set(200, 100, 300);
scene.add(light1);

function resizeCanvasToDisplaySize() {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (canvas.width !== width ||canvas.height !== height) {
    // you must pass false here or three.js sadly fights the browser
    renderer.setSize(width, height, false);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();

    // set render target sizes here
  }
}

function animate(time) {
  time *= 0.001;  // seconds

  resizeCanvasToDisplaySize();

  mesh.rotation.x = time * 0.5;
  mesh.rotation.y = time * 1;

  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);
html {
  box-sizing: border-box;
}
*, *:before, *:after {
  box-sizing: inherit;
}
body { margin: 0; }
.outer {
}
.frame { 
  display: flex;
  width: 100vw;
  height: 100vh;
}
.frame>* {
  flex: 1 1 50%;
}
#editor {
  font-family: monospace;
  padding: .5em;
  background: #444;
  color: white;
}
canvas { 
  width: 100%;
  height: 100%;
}
<div class="frame">
  <div id="result">
    <canvas></canvas>
  </div>
  <div id="editor">
  explaintion of example on left or the code for it would go here
  </div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js"></script>

注意,上述代码中从未引用window.innerWidthwindow.innerHeight,但对于所有情况都有效。


更新:2021年,没有“最佳”方法,只有多种具有不同权衡的方法。

有些人似乎担心性能问题,好像检查2个值是否与另外2个值不匹配会对需要性能的任何程序产生可测量的性能影响。

无论如何,还有我之前发布的旧答案,它只检查容器的大小。有人建议使用window.addEventListener('resize', ...),但没有注意到它不能处理画布尺寸发生变化而窗口本身未发生变化的情况(例如上面的示例4)。

无论如何,在2021年,我们可以使用ResizeObserver代替window.addEventListener('resize', ...),对于那些认为每帧检查2个变量是性能开销的人来说。 ResizeObserver将在画布更改大小时触发,即使窗口本身没有更改大小也可能发生。

function resizeCanvasToDisplaySize() {
  const canvas = renderer.domElement;
  // look up the size the canvas is being displayed
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;

  // you must pass false here or three.js sadly fights the browser
  renderer.setSize(width, height, false);
  camera.aspect = width / height;
  camera.updateProjectionMatrix();

  // update any render target sizes here
}

const resizeObserver = new ResizeObserver(resizeCanvasToDisplaySize);
resizeObserver.observe(canvas, {box: 'content-box'});

示例1:全屏,我们将画布

body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<canvas></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r132/build/three.module.js';

const  renderer = new THREE.WebGLRenderer({canvas: document.querySelector("canvas")});

// There's no reason to set the aspect here because we're going
// to set it every frame anyway so we'll set it to 2 since 2
// is the the aspect for the canvas default size (300w/150h = 2)
const  camera = new THREE.PerspectiveCamera(70, 2, 1, 1000);
camera.position.z = 400;

const scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(200, 200, 200);
const material = new THREE.MeshPhongMaterial({
  color: 0x555555,
  specular: 0xffffff,
  shininess: 50,
  shading: THREE.SmoothShading
});

const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

const light1 = new THREE.PointLight(0xff80C0, 2, 0);
light1.position.set(200, 100, 300);
scene.add(light1);

function resizeCanvasToDisplaySize() {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;

  // you must pass false here or three.js sadly fights the browser
  renderer.setSize(width, height, false);
  camera.aspect = width / height;
  camera.updateProjectionMatrix();

  // set render target sizes here
}

function animate(time) {
  time *= 0.001;  // seconds

  mesh.rotation.x = time * 0.5;
  mesh.rotation.y = time * 1;

  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

const resizeObserver = new ResizeObserver(resizeCanvasToDisplaySize);
resizeObserver.observe(renderer.domElement, {box: 'content-box'});
</script>

示例4:50%宽度画布(类似实时编辑器)

html {
  box-sizing: border-box;
}
*, *:before, *:after {
  box-sizing: inherit;
}
body { margin: 0; }
.outer {
}
.frame { 
  display: flex;
  width: 100vw;
  height: 100vh;
}
.frame>* {
  flex: 1 1 50%;
}
#ui {
  position: absolute;
  right: 0;
  bottom: 0;
  padding: 0.5em;
}
#editor {
  font-family: monospace;
  padding: .5em;
  background: #444;
  color: white;
}
canvas { 
  width: 100%;
  height: 100%;
}
<div class="frame">
  <div id="result">
    <canvas></canvas>
  </div>
  <div id="editor">
    <p>no window resize</p>
    <p>For example level editor might have the level
    displayed on the left and a control panel on the right.</p>
    <p>Click the buttons below. The only thing changing is CSS. The window size is not changing so using <code>window.addEventListener('resize', ...)</code> would fail</p>
    <div id="ui">
      <button type="button" data-size="25%">small</button>
      <button type="button" data-size="50%">medium</button>
      <button type="button" data-size="75%">large</button>
    </div>
  </div>
</div>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r132/build/three.module.js';

const  renderer = new THREE.WebGLRenderer({canvas: document.querySelector("canvas")});

// There's no reason to set the aspect here because we're going
// to set it every frame anyway so we'll set it to 2 since 2
// is the the aspect for the canvas default size (300w/150h = 2)
const  camera = new THREE.PerspectiveCamera(70, 2, 1, 1000);
camera.position.z = 400;

const scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(200, 200, 200);
const material = new THREE.MeshPhongMaterial({
  color: 0x555555,
  specular: 0xffffff,
  shininess: 50,
  shading: THREE.SmoothShading
});

const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

const light1 = new THREE.PointLight(0xff80C0, 2, 0);
light1.position.set(200, 100, 300);
scene.add(light1);

function resizeCanvasToDisplaySize() {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;

  // you must pass false here or three.js sadly fights the browser
  renderer.setSize(width, height, false);
  camera.aspect = width / height;
  camera.updateProjectionMatrix();

  // set render target sizes here
}

function animate(time) {
  time *= 0.001;  // seconds

  mesh.rotation.x = time * 0.5;
  mesh.rotation.y = time * 1;

  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

const editorElem = document.querySelector("#editor");
document.querySelectorAll('button').forEach(elem => {
  elem.addEventListener('click', () => {
    editorElem.style.flexBasis = elem.dataset.size;
  });
});


const resizeObserver = new ResizeObserver(resizeCanvasToDisplaySize);
resizeObserver.observe(renderer.domElement, {box: 'content-box'});
</script>

为什么不使用ResizeObserver

  1. 如果你需要支持旧浏览器(如IE),ResizeObserver无法使用。

  2. 它不能保证更新速度。

    换句话说,通过rAF和每帧检查,理想情况下,你的内容将始终保持正确的大小,因为浏览器要求你准备好你的内容。相比之下,ResizeObserver只是表示最终会给你一个事件。这可能会在你的内容实际上需要调整大小的5-10帧之后才出现。

还有一件事是处理devicePixelRatio。这是一个太大的话题,超出了本答案的范围,但你可以在这里了解更多信息


1
在第二个例子中,为什么要为自动生成的画布元素设置CSS宽度/高度?自动画布具有宽度和高度的内联样式,因此您不需要覆盖它。 - zakdances
这不是“最佳方法”,因为在渲染循环中运行 resizeCanvasToDisplaySize 会浪费大量性能。最好和最安全的方法是在 window.addEventListener('resize', resizeCanvasToDisplaySize) 中运行它,这样只有在布局更改时才会进行渲染,而不是每一帧都进行渲染。 - TOPKAT
1
你对“大规模”的定义很有趣。 - gman
2
canvas.width !== width 应该改为 canvas.width !== width*window.devicePixelRatio 吗? - Alec Jacobson
没有所谓的“应该”。如果你想使用devicePixelRatio,就去用吧。但我几乎从不使用它。我真的不希望我的页面绘制9倍到16倍的像素,并且在具有3或4个dpr的慢速现代智能手机上运行缓慢。如果你决定使用devicePixelRatio,你需要对其进行ceil/floor/round处理,因为它可能是一个非整数,而canvas.width和canvas.height将始终是整数。请参见答案底部的链接。 - gman
显示剩余4条评论

10

那很简单,设置一下渲染的大小就可以了。

container = document.getElementById('container');
renderer.setSize($(container).width(), $(container).height());
container.appendChild(renderer.domElement);

这个处理视网膜显示、DPI缩放等吗? - jjxtra
2
好的回答,我不认为jQuery有什么用处。 - Aaron Matthews
@RenéK,你在说哪个答案? - Jay-R Joseph Gabunada

3

我认为最好的调整画布大小的方法不是上面接受的答案。每个animationframe @gman都会运行函数resizeCanvasToDisplaySize,进行多次计算。

我认为最好的方法是创建一个窗口事件监听器“resize”和一个布尔值,表示用户是否已经调整大小。在动画帧中,可以检查用户是否调整了大小。如果他调整了大小,您可以在动画帧中调整画布大小。

let resized = false

// resize event listener
window.addEventListener('resize', function() {
    resized = true
})

function animate(time) {
    time *= 0.001

    if (resized) resize()

    // rotate the cube
    cube.rotation.x += 0.01
    cube.rotation.y += 0.01

    // render the view
    renderer.render(scene, camera)

    // animate
    requestAnimationFrame(animate)
}

function resize() {
    resized = false

    // update the size
    renderer.setSize(window.innerWidth, window.innerHeight)

    // update the camera
    const canvas = renderer.domElement
    camera.aspect = canvas.clientWidth/canvas.clientHeight
    camera.updateProjectionMatrix()
}

1
这个问题涉及到一个更一般的“容器”,而不是窗口。您将如何调整您的答案来解决这个问题? - Mike Goodstadt
@MikeGoodstadt 一个选择是使用Resize Observer(对于旧浏览器需要使用polyfill),它可以监视元素的大小变化。但这对我来说仍然不够满意,因为我的画布容器的大小会根据抽屉的动画而改变。Resize Observer 似乎只在调整大小的开始和结束时触发,因此我的画布调整函数只在那时触发,而不是在容器动画期间触发。最终,我使用requestAnimationFrame手动同步JS中的容器和画布大小,并在基本函数中进行了动画处理。 - Kalnode
即使这个答案在每个循环中检查resized变量,你仍然可以在addEventListener中调用resize函数。 - Ömer Feyyaz Selçuk

2
也许我理解有误 - 但为什么现有的建议都涉及在动画循环内调整画布大小呢?
你希望你的动画循环尽可能做得少,因为它理想情况下会每秒重复30次以上,并且应该被优化以尽可能高效地运行 - 为最慢的系统提供最大的fps。
我认为从调整大小事件侦听器内调用resize函数没有害处 - 就像Meindert Stijfhals在下面建议的那样。
像这样:
var container = renderer.domElement.parentElement;
container.addEventListener('resize', onContainerResize);

function onContainerResize() {
    var box = container.getBoundingClientRect();
    renderer.setSize(box.width, box.height);

    camera.aspect = box.width/box.height
    camera.updateProjectionMatrix()
    // optional animate/renderloop call put here for render-on-changes
}

如果你设置了仅在变化时渲染,你可以在调整大小函数的结尾调用渲染函数。否则,下一次渲染循环触发时,它应该只使用新设置进行渲染。

0

当然,@gman提供的答案是完整的答案。但是,为了总结可能的情况,必须假设两种可能性,这就是答案差异巨大的原因。

第一种可能性是容器是全局(head)对象:window,或者可能是<body><frameset>,在这种情况下,最方便的方法是使用window.addEventListener('resize', onResize()) { ... }

第二种可能性是最初提出的问题:Three.js WebGL输出的容器应该具有响应性。在这种情况下,无论容器是canvas、section还是div,处理调整大小的最佳方法是针对DOM中的容器,并通过传递容器的clientWidthclientHeight来使用renderer.setsize()方法,然后在渲染循环函数中调用onResize()函数,其完整实现由@gman提供。在这种特殊情况下,不需要使用addEventListener


0
抱歉再次提起这个问题,但这是通过谷歌搜索得到的结果,所以我们继续说下去。 我需要的是一个始终适合屏幕的画布调整大小,现在可以仅通过CSS实现。

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>minimal threejs</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    #canvas-wrapper {
      background-color: grey;
      position: fixed;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    #main-canvas {
      border: 5px solid red;
      max-width: calc(100vh / 3 * 4);
      width: 100%;
      image-rendering: pixelated;
    }
  </style>

  <script type="importmap">
    {
        "imports": {
            "three": "https://unpkg.com/three@0.151.0/build/three.module.js"
        }
    }
</script>
</head>

<body>
  <div id="canvas-wrapper">
    <canvas id="main-canvas"></canvas>
  </div>

  <script type="module">
    import * as THREE from 'three';

    const main_canvas = document.getElementById("main-canvas");

    const n = 4
    let cwidth = 640 / n;
    let cheight = 480 / n;
    main_canvas.setAttribute("width", cwidth + "px");
    main_canvas.setAttribute("height", cheight + "px");

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, main_canvas.clientWidth / main_canvas.clientHeight, 0.1, 1000);

    const renderer = new THREE.WebGLRenderer({
      antialias: true,
      canvas: main_canvas,
    });

    const geometry = new THREE.BoxGeometry(1, 1, 1);
    const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);

    camera.position.z = 5;

    function animate() {
      requestAnimationFrame(animate);

      cube.rotation.x += 0.01;
      cube.rotation.y += 0.01;

      renderer.render(scene, camera);
    }

    animate();

  </script>
</body>

</html>


0
这是允许我掌握画布渲染大小的代码:
首先,场景在一个具有您选择的尺寸的 <div id="your_scene"> 中呈现:
<div class="relative h-512 w-512">
    <div id="your_scene"></div>
</div>

CSS:

.relative {
    position: relative;
}

h-512 {
    height: 51.2rem;
}

w-512 {
    width: 51.2rem;
}

#your_scene {
    overflow: hidden;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

然后,您获取其尺寸:

this.mount = document.querySelector('#your_scene');
this.width = document.querySelector('#your_scene').offsetWidth;
this.height = document.querySelector('#your_scene').offsetHeight;

然后,你(在我的情况下)将渲染器背景设置为透明,设置像素比,然后将容器的大小应用于渲染器。Three.js通过将your_scene容器附加到渲染器<canvas>元素上来工作,因此这里的最后一步是使用appendChild
this.renderer = new THREE.WebGLRenderer({ alpha: true });
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(this.width, this.height);
this.mount.appendChild(this.renderer.domElement);

这应该足以让某人对他们的场景进行取证。承担大部分工作的是setSize调用,但您需要具有正确的尺寸,并且此外,您的相机必须指向正确的位置。

如果您的代码与我的类似,但仍然无法正常工作,请查看您的相机视角,并确保您的场景对象实际上在视野中。


0

我不确定从上面的评论或API文档中是否对每个人都很明显,但以防其他人有我遇到的问题:请注意,渲染器的setSize()方法在设置画布大小时采用CSS像素,而不是实际设备像素。这意味着在高DPI屏幕上,它创建的实际像素数量似乎基于width * window.devicePixelRatioheight * window.devicePixelRatio。例如,在您尝试像我一样基于three.js帧捕获特定大小的GIF时,这很重要。最终我做了以下操作:

camera.aspect = gifWidth / gifHeight;
camera.updateProjectionMatrix();
var scale = window.devicePixelRatio;
renderer.setSize( gifWidth / scale, gifHeight / scale, true );

这可能不是处理它的理想方式,但对我来说有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接