【问题标题】:Centering canvas context after scaling缩放后居中画布上下文
【发布时间】:2019-01-07 02:37:57
【问题描述】:

我一直在尝试在 three.js 中使用画布作为纹理。由于 three.js 要求纹理是 2 的幂,因此画布的宽度和高度设置为 [512, 512] 但是我希望输出画布是非 2 的幂。为了保持缩放,我将高度按纵横比放大,这会使绘制的对象的中心向下移动。我试图通过一些任意数字(即ctx.transform(0, -height/ (1 -(height/width))))将高度转换回来,但无法找到最佳位置。有谁知道如何处理这个问题?

var camera, scene, renderer, mesh, material, ctx, texture, canvas, dimensions;
init();
animate();

function init() {
    canvas = document.createElement("canvas")
    canvas.width = 512;
    canvas.height = 512;
    ctx = canvas.getContext("2d");
    texture = new THREE.CanvasTexture(canvas)
    
    
    renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth,window.innerHeight);
    document.body.appendChild(renderer.domElement);

    camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
    scene = new THREE.Scene();
    material = new THREE.MeshBasicMaterial({map: texture});
    
    var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
    mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);
    dimensions = renderer.getSize()
}

function animate() {
		
    ctx.save()
    ctx.scale(1, dimensions.width / dimensions.height)
    // ctx.translate(0, -height * ??);
    ctx.fillStyle = "#FF0000"
    ctx.fillRect((canvas.width / 2) - 25, (canvas.height / 2) - 25, 50, 50);
    ctx.restore()
    
    texture.needsUpdate = true;
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/94/three.min.js"></script>

正方形应该被缩放(仍然是正方形)并居中

【问题讨论】:

  • 一个更安全的方法是使用第二个画布,您可以在上面绘制任何您想要的大小的精灵。所以从技术上讲,一个正方形texture canvas 和一个任意形状sprite canvas。然后只需将您的画布混搭到另一个画布上,并在此过程中调整其大小。老实说,我在你的 sn-p 中看不到一个正方形,所以我看不到你想要完成什么。
  • 您好,感谢您的回复。 stackoverflow 显示在问题中没有正确显示,所以我把它放在这里:jsfiddle.net/m0pnj6de/4。我想缩放它以保持原来的形状和位置,所以我希望正方形居中,嗯,一个正方形。精灵的想法可能会奏效,但如果可能的话,我宁愿减少绘制调用的数量

标签: javascript html canvas three.js


【解决方案1】:

我们可以通过移动到中心并在每次绘制时调整渲染器的大小来解决您的问题,这样您就可以看到剩余的正方形,并在每次绘制时清除您的画布,这样多次绘制就不会停留在混淆正方形的位置。

function init() {
	
    canvas = document.createElement( 'canvas' );
    ctx = canvas.getContext( '2d' );
    
    renderer = new THREE.WebGLRenderer;
    renderer.setSize( innerWidth, innerHeight);
	
	texture = new THREE.Texture( canvas );
    camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 );
    scene = new THREE.Scene;
    
    scene.add( new THREE.Mesh(
    	new THREE.PlaneBufferGeometry( 2, 2 ),
    	new THREE.MeshBasicMaterial({ map: texture })
    ) );
    
    document.body.appendChild( renderer.domElement );
    
}
function animate() {
	
	// Always update your renderer size.
	// This might be better off in the window.onresize event.
    renderer.setSize( innerWidth, innerHeight );
    
    // This will clear all draw data from your canvas, so we can draw on an empty canvas
    canvas.width = 512;
    canvas.height = 512;
    
	ctx.save();
    // Move the origin to the center of the canvas
    ctx.translate( canvas.width / 2, canvas.height / 2 );
    // Scale the canvas like you did, except we know the size as we just set it.
    ctx.scale( 1, innerWidth / innerHeight );
    ctx.fillStyle = "#FF0000";
    // Draw the rectangle as if you want its center at the origin
    ctx.fillRect( -25, -25, 50, 50 );
    ctx.restore();
    
    texture.needsUpdate = true;
    requestAnimationFrame( animate );
    renderer.render( scene, camera );
    
}

// I have removed some of the globals we don't need
// as the animate() function only needs access to some.
// I mostly do this because it clarifies what the functions share of resources.
	
var renderer, scene, camera, texture, canvas, ctx;

init();
animate();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.min.js"></script>

老实说,这似乎与您尝试了解的内容相反,因为 OrthographicCamera 的工作原理。最好将相机设置为缩放到视口而不是您的纹理(我理解,出于此目的,这是检查缩放能力的一种不错的方法)。在这种情况下,您的 mesh 被拉伸到不自然的比例,并且您的纹理会纠正它。但是,您可能应该正常设置您的相机和网格,并确保您的相机做正确的事情并缩放到您的视口(就像 PerspectiveCamera 上的 .aspect 值会显示正确的视觉效果)

function dispatch_draw( time ){
  
  window.dispatchEvent( new CustomEvent( 'draw' ) );
	
	window.requestAnimationFrame( dispatch_draw );
	
}
function event_draw(){

	renderer.render( scene, camera );
	
}
function event_resize(){
	
	dimensions.set( innerWidth, innerHeight );
	renderer.setSize( dimensions.x, dimensions.y );
	
	camera.left = -dimensions.x / 2;
	camera.right = dimensions.x / 2;
	camera.top = dimensions.y / 2;
	camera.bottom = -dimensions.y / 2;
	camera.near = -1;
	camera.far = 1;
	camera.updateProjectionMatrix();

}

const renderer = new THREE.WebGLRenderer;
const camera = new THREE.OrthographicCamera;
const scene = new THREE.Scene;
const mesh = new THREE.Mesh(
	new THREE.PlaneGeometry( 200, 200 ),
	new THREE.MeshBasicMaterial({ color: 0x00ff00 })
);
const dimensions = new THREE.Vector2( innerWidth, innerHeight );

scene.add( mesh );

window.addEventListener( 'resize', event_resize );
window.addEventListener( 'draw', event_draw );

event_resize();
dispatch_draw();

document.body.appendChild( renderer.domElement );
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.min.js"></script>

【讨论】:

  • 抱歉回复晚了,谢谢你的回答,里面有很多很好的信息
猜你喜欢
  • 2021-07-23
  • 2023-02-11
  • 1970-01-01
  • 2018-03-04
  • 1970-01-01
  • 2011-05-29
  • 1970-01-01
  • 2015-05-05
  • 2016-08-26
相关资源
最近更新 更多