调整画布/webgl 以适应屏幕宽度和高度

ui-*_*.uk 2 javascript canvas three.js responsive-design

嗨,我正在尝试让我的画布/webgl 将窗口的高度和宽度调整为 100% 我已经这样做了,但是如果我将窗口的大小从小到大调整,它不再“缩放/适合”窗口并且仍然很小想法?JSfiddle:http : //jsfiddle.net/jyr6y3fx/

代码:

var  scene, renderer;
    var glitchPass;

            init();
            animate();


            function init() {

        renderer = new THREE.WebGLRenderer( { alpha: true } );  

                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                document.body.appendChild( renderer.domElement );

                //

                camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
                camera.position.z = 400;

                scene = new THREE.Scene();



  // postprocessing

                composer = new THREE.EffectComposer( renderer );
                composer.addPass( new THREE.RenderPass( scene, camera ) );

                glitchPass = new THREE.GlitchPass();
                glitchPass.renderToScreen = true;
                composer.addPass( glitchPass );

            }



            function animate() {

                requestAnimationFrame( animate );


                composer.render();

                //renderer.render(scene, camera);

            }
Run Code Online (Sandbox Code Playgroud)

先感谢您

ɢʀᴜ*_*ᴜɴᴛ 5

这是因为,渲染器\xc2\xad \的宽度和高度始终是固定的,并且在调整浏览器窗口大小时不会改变。

\n\n

要解决此问题,您需要在窗口调整大小时重置 renderer\xc2\xad \ 的宽度和高度,您可以这样做......

\n\n
window.addEventListener(\'resize\', function() {\n   renderer.setSize(window.innerWidth, window.innerHeight);\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是工作中的 JSFiddle

\n


gma*_*man 5

其他的答案都很悲伤。他们都在与浏览器作斗争,而不是与它合作。

可以说,调整three.js 大小的最佳方法是对其进行编码,因此它只接受CSS 设置的画布大小。这样,无论您如何使用画布,您的代码都可以正常工作,无需针对不同情况进行更改。

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

// There's no reason to set the aspect here because we're going
// to set on resize anyway
const camera = new THREE.PerspectiveCamera(70, 1, 1, 1000);
Run Code Online (Sandbox Code Playgroud)

然后我们需要一些代码来调整画布的大小以匹配其显示大小

function resizeCanvasToDisplaySize(force) {
  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 (force || 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
  }
}
Run Code Online (Sandbox Code Playgroud)

在渲染循环中调用它,并在初始化时调用一次

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);
}

resizeCanvasToDisplaySize(true);
requestAnimationFrame(animate);
Run Code Online (Sandbox Code Playgroud)

对于全屏,这是所有需要的 css

body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
Run Code Online (Sandbox Code Playgroud)

这里有 4 个示例,示例之间的唯一区别是 CSS 以及是我们制作画布还是 Three.js 制作画布。没有其他代码更改。

示例 1:全屏,我们制作画布

// There's no reason to set the aspect here because we're going
// to set on resize anyway
const camera = new THREE.PerspectiveCamera(70, 1, 1, 1000);
Run Code Online (Sandbox Code Playgroud)
function resizeCanvasToDisplaySize(force) {
  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 (force || 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
  }
}
Run Code Online (Sandbox Code Playgroud)
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);
}

resizeCanvasToDisplaySize(true);
requestAnimationFrame(animate);
Run Code Online (Sandbox Code Playgroud)

示例2:全屏画布,three.js制作画布

body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
Run Code Online (Sandbox Code Playgroud)
"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 any
const  camera = new THREE.PerspectiveCamera(70, 1, 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(force) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (force || 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);
}

resizeCanvasToDisplaySize(true);
requestAnimationFrame(animate);
Run Code Online (Sandbox Code Playgroud)
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
Run Code Online (Sandbox Code Playgroud)

示例 3:内联画布

<canvas></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
"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 any
const  camera = new THREE.PerspectiveCamera(70, 1, 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(force) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (force || 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);
}

resizeCanvasToDisplaySize(true);
requestAnimationFrame(animate);
Run Code Online (Sandbox Code Playgroud)
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
Run Code Online (Sandbox Code Playgroud)

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

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
"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 any
const  camera = new THREE.PerspectiveCamera(70, 1, 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(force) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (force || 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);
}

resizeCanvasToDisplaySize(true);
requestAnimationFrame(animate);
Run Code Online (Sandbox Code Playgroud)
body { font-size: x-large; }
.diagram { width: 150px; height: 150px; float: left; margin: 1em; }
canvas { width: 100%; height: 100%; }
Run Code Online (Sandbox Code Playgroud)

注意window.innerWidth并且window.innerHeight在上面的代码中从未被引用过,但它适用于所有情况。

为什么不使用resize事件?因为在某些情况下,即使画布更改了大小,您也不会收到调整大小事件。例如,如果您正在制作一个 2 列编辑器,并且您可以在 2 列之间绘制分隔线。或者,如果您的画布根据附近的内容进行缩放。无论哪种情况,都不会resize发生事件。