缩放后居中画布上下文

时间:2018-07-30 19:15:43

标签: javascript html5 canvas three.js

我一直试图在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>

应该将正方形缩放(仍为正方形)并居中

1 个答案:

答案 0 :(得分: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 会被拉伸到不自然的比例,并且纹理会对其进行校正。但是,您可能应该正常设置相机和网格,并确保相机做正确的事情并缩放到视口(就像.aspect上的PerspectiveCamera值将为您显示正确的视觉效果)< / p>

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>