Если бы это был я, я бы позволил CSS установить размер холста. Затем я спросил бы браузер, какой размер холста
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
, и соответственно установил бы размер буфера рисования холста, используя
renderer.setSize(desiredWidth, desiredHeight, false);
. В конце важно передать false
так что три. 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 ваш код работает во всех случаях. Если вы хотите, чтобы ваш холст работал в полноэкранном режиме, или вы хотите, чтобы ваш холст представлял собой диаграмму в абзаце, или вы хотите, чтобы ваш холст можно было растягивать во flexbox или сетке, независимо от того, как вы это делаете, вы получите правильный размер.
Почему бы не использовать setPixelRatio
?
Когда вы используете setPixelRatio, у вас теперь есть буфер рисования холста, размер которого отличается от указанного вами. Есть много ситуаций, когда вам нужно знать фактический размер. Это включает в себя использование определенных видов эффектов, считывание пикселей для выбора графического процессора, возможно создание снимков экрана, рисование с точками и т. Д. c ... Когда вы используете setPixelRatio
, вы действительно не знаете, какого размера окажется буфер рисования холста. Да, вы считаете, код будет просто умножаться на соотношение пикселей устройства, но округляется ли он? округлить вниз? Это изменится завтра? Ты понятия не имеешь. Таким образом, не используя его, вы знаете, какой размер холста. Это всегда тот размер, который вы указали при вызове setSize
. Это означает, что вы можете использовать этот размер везде. Вам не нужно угадывать, когда уместно использовать указанный размер и когда вам нужно делать другую математику. Обратите внимание, что если вы ошиблись в математике, ваше приложение может работать на устройстве с соотношением пикселей 1, но не работать на устройстве с другим соотношением пикселей. Если не использовать setPixelRatio
, то эти ошибки становятся невозможными.
Возможно, вы вообще не захотите устанавливать соотношение пикселей
Если соотношение пикселей равно 2, устройству необходимо отрисовать пиксели в 4 раза больше, чем с Пиксельное соотношение 1. Если пиксельное отношение равно 3, это dr aws 9x пикселей. Некоторые устройства даже имеют пиксель устройства rat ios, равный 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>