我的图像宽*高= 1442 * 1303, 我能够通过webgl的texture2D读取它们并成功渲染到画布。
在客户端,我有一个数组缓冲区,可以获取大小=宽*高* 4的图像数据。
那么,当我的画布宽度和高度为window.innerWidth * 0.90和window.innerHeight * 0.90时,如何保持图像的纵横比。
另外,我必须通过WEBGL 2dTexture使用arraybuffer直接渲染,所以,我不能使用任何2d canvs API,如drawImage。请提出建议。
答案 0 :(得分:1)
这个问题确实有一百万个答案。
首先是图像的大小,然后是您决定绘制它的大小,以及画布的大小,然后是画布显示的大小。你使用的顶点的位置也可以是任何东西。
See this article on WebGL指出WebGL使用剪辑空间坐标(-1到+1)和this article points out that the size a canvas is displayed is separate from its resolution。
假设您想要尽可能大地绘制图像并使其适合画布。
首先让我们查看画布显示的大小
var canvasDisplayWidth = gl.canvas.clientWidth;
var canvasDisplayHeight = gl.canvas.clientHeight;
让我们假设我们想要尽可能大地绘制图像 首先尝试将宽度拟合到画布
var imageDisplayWidth = canvasDisplayWidth;
var imageDisplayHeight = img.height * imageDisplayWidth / img.width;
现在让我们检查它是否合适?如果不是,让我们使用高度
if (imageDrawHeight > canvasDisplayHeight) {
imageDisplayHeight = canvasDisplayHeight;
imageDisplayWidth = img.width * imageDisplayHeight / img.height;
}
现在我们需要将imageDisplayWidth
和imageDisplayHeight
转换为画布中像素的大小。注意:如果画布显示的大小相同
作为其分辨率,您可以跳过此步骤,因为显示尺寸和绘图尺寸将相同。
// make our image take into account the pixel aspect
var canvasPixelsAcrossPerDisplayPixel = gl.canvas.width / canvasDisplayWidth;
var canvasPixelsDownPerDisplayPixel = gl.canvas.height / canvasDisplayHeight;
var imageDrawWidth = imageDisplayWidth * canvasPixelsAcrossPerDisplayPixel;
var imageDrawHeight = imageDisplayHeight * canvasPixelsDownPerDisplayPixel;
现在我们需要将其转换为剪辑空间
var clipWidth = imageDrawWidth / canvas.width;
var clipHeight = imageDrawHeight / canvas.height;
现在,给定一个单位四元组,我们可以缩放它以适应那个大小。
var m = m4.identity();
// convert our square unit quad match the size we want
m4.scale(m, [clipWidth, clipHeight, 1], m);
// move our unit square from 0,0 (the center) to the bottom, top corner
m4.translate(m, [-1, 1, 0], m);
// scale our unit sqaure to cover the clip space
m4.scale(m, [2, -2, 1], m);
现在可以用该矩阵和我们的单位四维绘制
var m4 = twgl.m4;
var gl = twgl.getWebGLContext(document.getElementById("c"));
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
var arrays = {
position: {
numComponents: 2,
data: [
0, 0,
1, 0,
0, 1,
0, 1,
1, 0,
1, 1,
],
},
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
// Lets make a texture using a 2d canvas
// There's a circle in the middle. If our
// code is correct it will be a circle when
// drawn (not an oval or ellipse)
var ctx = document.createElement("canvas").getContext("2d");
ctx.canvas.width = 100;
ctx.canvas.height = 75;
ctx.fillStyle = "red";
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.fillStyle = "blue";
ctx.fillRect(10, 10, ctx.canvas.width - 20, ctx.canvas.height - 20);
ctx.strokeStyle = "yellow";
ctx.lineWidth = 20;
ctx.beginPath();
ctx.arc(
ctx.canvas.width / 2, ctx.canvas.height / 2,
Math.min(ctx.canvas.width, ctx.canvas.height) / 2 - 20,
0, Math.PI * 2, false);
ctx.stroke();
var img = ctx.canvas;
var tex = twgl.createTexture(gl, {
src: img,
});
var canvasDisplayWidth = gl.canvas.clientWidth;
var canvasDisplayHeight = gl.canvas.clientHeight;
// Let's assume we want to draw the image as large as possible so
// first try fitting the width to the canvas
var imageDisplayWidth = canvasDisplayWidth;
var imageDisplayHeight = img.height * imageDisplayWidth / img.width;
// Now let's check if it fit? If not let's use the height
if (imageDisplayHeight > canvasDisplayHeight) {
imageDisplayHeight = canvasDisplayHeight;
imageDisplayWidth = img.width * imageDisplayHeight / img.height;
}
// Now we need to convert `imageDisplayWidth` and `imageDisplayHeight` to the size of pixels
// in the canvas. Note: If the canvas is being displayed the same size
// as the its resolution you can skip this step
var canvasPixelsAcrossPerDisplayPixel = gl.canvas.width / canvasDisplayWidth;
var canvasPixelsDownPerDisplayPixel = gl.canvas.height / canvasDisplayHeight;
var imageDrawWidth = imageDisplayWidth * canvasPixelsAcrossPerDisplayPixel;
var imageDrawHeight = imageDisplayHeight * canvasPixelsDownPerDisplayPixel;
// Now we need to convert that to clip space
var clipWidth = imageDrawWidth / gl.canvas.width;
var clipHeight = imageDrawHeight / gl.canvas.height;
// Now, given a unit quad we can just scale it to fit that size.
var m = m4.identity();
// convert our square unit quad to something to match the image's aspect
m4.scale(m, [clipWidth, clipHeight, 1], m);
// move our unit square from 0,0 (the center) to the bottom, left corner
m4.translate(m, [-1, 1, 0], m);
// scale our unit square to cover the clip space
m4.scale(m, [2, -2, 1], m);
var uniforms = {
texture: tex,
matrix: m,
};
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, gl.TRIANGLES, bufferInfo);
<script id="vs" type="notjs">
attribute vec4 position;
uniform mat4 matrix;
varying vec2 v_texcoord;
void main() {
gl_Position = matrix * position;
// using position since we know it's a unit quad
v_texcoord = position.xy;
}
</script>
<script id="fs" type="notjs">
precision mediump float;
uniform sampler2D texture;
varying vec2 v_texcoord;
void main() {
gl_FragColor = texture2D(texture, v_texcoord);
}
</script>
<script src="https://twgljs.org/dist/twgl-full.min.js"></script>
<canvas id="c" width="50" height="100" style="width: 300px; height: 150px; border: 1px solid black;"></canvas>