three.js - 如何使用 threejs 在 iPhone 上启用视网膜分辨率 render.

使用 threejs,可以将 Canvas 绘制成两倍大,但是如何使用 css 将它缩小,以便它以 iPhone 的正确分辨率显示。

renderer.setSize(window.innerWidth, window.innerHeight);

产生像素化图像,这有效:

renderer.setSize(window.innerWidth*2, window.innerHeight*2);

然后 Canvas 对于屏幕来说太大了,我似乎无法让 css 正确地缩小它。更不用说在配备 Retina 显示屏的笔记本电脑上执行此操作将是非常糟糕的。这是因为它使用 WebGL 绘制到屏幕吗?

如何在threejs中容纳这些不同的像素密度?

最佳答案

如果是我,我会让 CSS 设置 Canvas 的大小。然后我会询问浏览器 Canvas 的大小

const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;

并适本地设置 Canvas 绘图缓冲区的大小

renderer.setSize(desiredWidth, desiredHeight, false);

在最后传递 false 很重要,这样 three.js 就不会搞砸 CSS

此外,我永远不会使用 setPixelRatio,因为它只会导致错误和歧义。相反,我会计算我想要的大小并使用该大小。示例

const pixelRatio = window.devicePixelRatio;
const desiredWidth = canvas.clientWidth * pixelRatio | 0;
const desiredHeight = canvas.clientHeight * pixelRatio | 0;
renderer.setSize(desiredWidth, desiredHeight, false);

为什么要使用 CSS 并查找尺寸?

通过使用 CSS,您的代码在所有情况下都能正常工作。如果您希望 Canvas 全屏显示,或者您希望 Canvas 成为段落中的图表,或者您希望 Canvas 在 flexbox 或网格中可拉伸(stretch),无论您如何操作,您都可以获得正确的尺寸。

为什么不使用setPixelRatio

当您使用 setPixelRatio 时,您现在拥有一个与您指定的大小不同的 Canvas 绘图缓冲区。在许多情况下,您需要知道实际大小。这包括使用某些类型的效果、为 GPU 拾取读取像素、可能截取屏幕截图、用点绘图等......当您使用 setPixelRatio 时,您真的不知道 Canvas 绘图缓冲区的大小将结束向上。是的,您相信代码只会乘以设备像素比,但它会四舍五入吗?四舍五入?明天会改变吗?你不知道。因此,通过不使用它,您知道 Canvas 的大小。它始终是您调用 setSize 时指定的大小。这意味着您可以在任何地方使用该尺寸。您不必猜测何时适合使用指定的大小以及何时必须进行不同的数学计算。请注意,如果您计算错误,则您的应用程序可能在像素比为 1 的设备上正常运行,但在像素比为其他像素比的设备上可能会失败。通过不使用 setPixelRatio,这些错误将变得不可能。

您可能根本不想设置像素比例

如果像素比为 2,则设备需要绘制 4 倍的像素,就像像素比为 1 时那样。如果像素比为 3,则设备需要绘制 9 倍的像素。有些设备甚至具有 3.5 或 4 的设备像素比,即 16 倍像素。这会使您的页面运行非常缓慢。仅仅因为设备具有高像素比而盲目设置像素比是导致页面缓慢的秘诀。很少有原生游戏会这样做,因为它们运行得太慢了。通常不设置它是合适的。

例子:

html, body {
  margin: 0;
  height: 100%;
}
#c {
  width: 100%;
  height: 100%;
  display: block;
}
<canvas id="c"></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r113/build/three.module.js';

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});

  const fov = 75;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 5;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 2;

  const scene = new THREE.Scene();

  {
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(-1, 2, 4);
    scene.add(light);
  }

  const boxWidth = 1;
  const boxHeight = 1;
  const boxDepth = 1;
  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);

  function makeInstance(geometry, color, x) {
    const material = new THREE.MeshPhongMaterial({color});

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

    cube.position.x = x;

    return cube;
  }

  const cubes = [
    makeInstance(geometry, 0x44aa88,  0),
    makeInstance(geometry, 0x8844aa, -2),
    makeInstance(geometry, 0xaa8844,  2),
  ];

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

  function render(time) {
    time *= 0.001;

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }

    cubes.forEach((cube, ndx) => {
      const speed = 1 + ndx * .1;
      const rot = time * speed;
      cube.rotation.x = rot;
      cube.rotation.y = rot;
    });

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
}

main();
</script>

关于three.js - 如何使用 threejs 在 iPhone 上启用视网膜分辨率 render.setSize,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60500710/

相关文章:

javascript - 显示到小数点后两位 - React.Js

c++ - 如何解决 C++ std::string_view 超出范围的问题?

amazon-web-services - 使用 axios 和 aws4 向 aws 进行身份验证

swiftui - 使用 SwiftUI 实现 PencilKit 撤消功能

python - 在python中将类返回给自身

python - 按升序对月份名称字符串列表进行排序

c# - 获取错误 System.IO.IOException : 'The process can

visual-studio-code - 有一种方法可以在 vscode 中的 ` `(重音符)内语

javascript - 运算符 '<' 不能应用于类型 'Date' 和 'number' .ts

c++ - 如何正确删除C++中的指针?