Three.js 调整画布大小

Posted

技术标签:

【中文标题】Three.js 调整画布大小【英文标题】:Three.js Resizing Canvas 【发布时间】:2013-12-15 22:10:58 【问题描述】:

我一直在做一个 3D 项目,我们使用 Three.js 库在网络浏览器中显示 3D 对象。

问题是:

1st 模型显示在一个小的 dom 元素中或当浏览器窗口本身很小时。 然后当窗口(或 dom 元素调整大小)时,模型变得像素化

以下是一些截图:

调整大小前:

调整大小后:

调整大小后应该如何:

这是设置模型尺寸(高度和宽度)的代码部分,如果触发了调整大小事件,则会调用此函数:

console.log("domChanged fired")

instance.domBoundingBox = instance.dom.getBoundingClientRect();
instance.domCenterPos.x = instance.domBoundingBox.width / 2 + instance.domBoundingBox.left;
instance.domCenterPos.y = instance.domBoundingBox.height / 2 + instance.domBoundingBox.top;

var width = instance.dom.clientWidth, height = instance.dom.clientHeight;
instance.domWidthHalf = width / 2, instance.domHeightHalf = height / 2;

// TODO: fire event to expose it to site developers

// here we should update several values regarding width,height,position
if(instance.cameraReal) 
    instance.cameraReal.aspect = instance.dom.clientWidth / instance.dom.clientHeight;
    instance.cameraReal.updateProjectionMatrix();


if(instance.renderer3D)
    instance.renderer3D.setSize(instance.dom.clientWidth, instance.dom.clientHeight);

谁能给我一个提示?我已经研究了几天了,但目前还没有任何线索

【问题讨论】:

AFAIK setSize 为您更改画布 width/height(渲染分辨率)并为 glViewport 使用新尺寸。你能仔细检查instance.dom.clientWidth/Height 是否真的在改变?看起来画布正在改变大小而不是其内部分辨率。 【参考方案1】:

因此,canvas 元素可以像其他所有元素一样调整大小。您要做的是告诉渲染器和相机也调整画布内容的大小。

window.addEventListener( 'resize', onWindowResize, false );

function onWindowResize()

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

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


【讨论】:

它已经完成了,你可以在我分享的代码片段中看到它 只是想将答案与可能有此问题的其他任何人分开。顺便说一句,很酷的建筑。 好的,谢谢帮助:),其实问题现在已经解决了,我会争取找时间写一个答案 初学者不要在这里使用window,你可能正在使用自己的容器作为渲染器,用那个容器代替window【参考方案2】:

问题终于解决了,实际问题出在因为应用程序使用THREE.EffectComposer对象,在类构造函数中创建了一个composer对象,如下所示:

this.composer = new THREE.EffectComposer(this.renderer3D);

所以对于渲染器,作曲家需要在事件处理函数之后更新大小,如下所示:

if(instance.renderer3D)
    instance.renderer3D.setSize(instance.dom.clientWidth, instance.dom.clientHeight);
if(instance.composer)
    instance.composer.setSize(instance.dom.clientWidth, instance.dom.clientHeight);

这完美地解决了这个问题:)

【讨论】:

【参考方案3】:

我通过 React JS 应用了 Shawn Whinnery 的回答来满足我的需求:

在Mount上启动监听器:

componentDidMount() 
  window.addEventListener('resize', this.handleResize, false)

移除监听 onUnmount(因为我们喜欢垃圾回收):

componentWillUnmount() 
  window.removeEventListener('resize', this.handleResize, false)

安装处理函数:

handleResize = () => 
  this.camera.aspect = window.innerWidth / window.innerHeight
  this.camera.updateProjectionMatrix()
  this.renderer.setSize(window.innerWidth, window.innerHeight)

胖箭头语法用于避免绑定this。如果你有这个代码将不起作用:handleResize() ... ,但当然,如果你将它添加到你的构造函数中它会起作用:

this.handleResize = this.handleResize.bind(this)

最后说明:确认你的相机是this.camera,你的渲染器是this.renderer。除此之外,你应该可以把它全部粘贴进去。

【讨论】:

【参考方案4】:

对于那些在谷歌上搜索的人,如果您想快速开始使用可以为您调整大小的帮助工具,请查看此 github:https://github.com/jeromeetienne/threex.windowresize

您唯一需要做的就是通过bower 安装并初始化它:

new THREEx.WindowResize(renderer, camera)

【讨论】:

这种方法最简单。只需包含 js 文件并初始化大小调整器。完美运行。【参考方案5】:

这很简单。即使调整浏览器窗口大小,这三个.js 代码也不会改变。

代码:

//Simple Cube Example
var scene = new THREE.Scene();
			var camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 1000 );
			var renderer = new THREE.WebGLRenderer();
			renderer.setSize( window.innerWidth, window.innerHeight );
			document.body.appendChild( renderer.domElement );

			var geometry = new THREE.BoxGeometry( 1, 1, 1 );
			var material = new THREE.MeshBasicMaterial(  color: "rgb(255, 0, 0)"  );
			var cube = new THREE.Mesh( geometry, material );
			scene.add( cube );
			camera.position.z = 5;
			var edges = new THREE.EdgesHelper( cube, "rgb(0, 0, 0)" );
			edges.material.linewidth = 5;
			scene.add( edges );

			function animate()
				requestAnimationFrame( animate );
				cube.rotation.x += 0.01;
				cube.rotation.y += 0.01;
				renderer.render( scene, camera );
			
			animate();
			function rot()
				requestAnimationFrame( rot );
				edges.rotation.x += 0.01;
				edges.rotation.y += 0.01;
			
			rot();
      //this will not change it's size when browser is resized, but use css and correct it.
//this is the code. it does not work use a div and use the javascript
.code
  float: left;
  width: 100vw; /*fullscreen*/
  height: 100vh;
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="robots" content="index, follow" />
<link rel="canonical" href="http://" />
<meta name="author" content="">
<meta name="google-site-verification" content="">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Hammersmith+One|Lato" rel="stylesheet">
<title></title>
<link rel="stylesheet" href="style.css">
</head>

<body>
		<script src="https://threejs.org/build/three.js"></script>
</body>
</html>

【讨论】:

【参考方案6】:

尝试使用抗锯齿属性将像素化问题解决 50 - 70%

例如:var renderer = new THREE.WebGLRenderer(antialias:true);

【讨论】:

这里的“像素化”是由于二次采样,因为渲染器没有放大到新的窗口大小,而不是由于锯齿。

以上是关于Three.js 调整画布大小的主要内容,如果未能解决你的问题,请参考以下文章

Three.js 画布纹理幂为 2 但被裁剪

将 three.js 生成的画布保存到服务器 - 没有文件被保存

如何从 Three.js 画布中保存图像?

Three.js 检测 webgl 支持并回退到常规画布

WebGL 多画布three.js 示例

three.js中drawtext的字不能改吗