我正在开发一个网络应用程序,它将能够进行一些图像转换,其中之一是图像旋转,问题是:只要画布是正方形(宽度=高度),一切都可以,但除此之外,图像像所附的屏幕截图一样变得倾斜。 我尝试使用这些方程根据旋转角度改变缩放比例
const scalingY = 1 + (aspectRatio - 1) * Math.pow(Math.sin(angelInRadian/2), 1);
const scalingX = (1/aspectRatio) + (1-(1/aspectRatio)) * Math.pow(Math.cos(angelInRadian), 1);
但是图像在旋转过程中仍然倾斜
const scalingY = 1 + (aspectRatio - 1) * Math.pow(Math.sin(angelInRadian/2), 1);
const scalingX = (1/aspectRatio) + (1-(1/aspectRatio)) * Math.pow(Math.cos(angelInRadian), 1)
const aspectRatioCompensation = new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
]);
//const aspectRatioCompensation = new Float32Array([
scalingX, 0, 0, 0,
0, scalingY, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
]);
const cosTheta = Math.cos(angelInRadian);
const sinTheta = Math.sin(angelInRadian);
const rotationMatrix = new Float32Array([
cosTheta, -sinTheta, 0, 0,
sinTheta, cosTheta, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
]);
// Combine the aspect ratio adjustment and rotation
const combinedMatrix = mat4.create();
mat4.multiply(combinedMatrix, aspectRatioCompensation, rotationMatrix );
顶点着色器:
attribute vec4 a_position;
attribute vec2 a_texCoord;
varying vec2 v_position;
varying vec2 v_texCoord;
void main() {
gl_Position = a_position;
v_position = a_position.xy;
v_texCoord = a_texCoord;
}
片段着色器:
precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D u_texture;
uniform vec4 u_color;
uniform int u_renderMode; // 0 for texture, 1 for shape
void main() {
if (u_renderMode == 0) {
gl_FragColor = texture2D(u_texture, v_texCoord);
} else if (u_renderMode == 1) {
gl_FragColor = u_color;
}
}
gl 设置(此函数是负责屏幕更新的类的一部分):
updateScreen() {
const { gl, program, positionBuffer, texCoordBuffer } = this;
gl.useProgram(program);
// Bind the position buffer for this layer
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positionLocation = gl.getAttribLocation(program!, 'a_position');
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
// Bind the texCoord buffer for this layer
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
const texCoordLocation = gl.getAttribLocation(program!, 'a_texCoord');
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
const error = gl.getError();
if (error !== gl.NO_ERROR) {
console.error('WebGL error:', error);
}
// Enable blending
//TODO: need more understanding of the blending functions
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
const hitTestLayer = globalState.get('hitTestLayer');
this.model?.documents.activeDocument!.layers.forEach((layer: any) => {
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, layer.positionCoordArray, gl.STATIC_DRAW);
gl.bindTexture(gl.TEXTURE_2D, layer.texture);
const textureLocation = gl.getUniformLocation(program!, 'u_texture');
gl.uniform1i(textureLocation, 0);
layer.shapes.performDrawingCalls(gl, program!, 0)
const pixels = new Uint8Array(4);
gl.readPixels(5, 5, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
})
gl.useProgram(null);
}
问题在于,与沿 Y 轴选择 NDC 中的任何坐标相比,沿 X 轴选择 NDC 中的任何坐标都会导致距原点的距离不同。出现这种差异的原因是,无论轴的实际长度如何,NDC 的范围都是从 -1 到 1。为了解决这个问题,我决定将 X 轴缩小 1/aspectRatio
,然后旋转,最后按aspectRatio放大X轴。这种方法对我有用。
mat4.scale(finalTransformationMatrix, initialTransformationMatrix, [1/aspectRatio, 1, 1])
mat4.rotateZ(finalTransformationMatrix, finalTransformationMatrix, -angelInRadian)
mat4.scale(finalTransformationMatrix, finalTransformationMatrix, [ aspectRatio, 1, 1])