我想在 Three.js 中创建一个相机正在移动的场景。每帧中有 4 个可见点,形成一个四边形。随后,我想通过将这 4 个点扭曲到画布边缘来处理每一帧,使它们形成一个与画布大小相同的矩形。理想情况下,我会通过创建着色器并将其传递给 ShaderPass() 类,使用 Three.js 的后处理解决方案来完成此操作,但我很感谢任何其他解决方案。
我读过有关透视变换的内容,并看到这篇文章:将四边形变换为矩形?。我了解如何创建变换矩阵,但我对如何将其应用于 2d 图像帧的后处理有点困惑,因为我只阅读了有关将变换矩阵应用于 3d 对象的内容。
我附上了一张显示后处理步骤之前画布输出的图像。我想将红色四边形的 4 个角扭曲到画布边缘。我通过使用 Three.js 的 .project() 方法知道它们在 3D 世界空间和 2D 屏幕空间中的坐标。
我在一个带有 p5.js 和 opencv.js 的项目中尝试使用 opencv 的 warpPerspective() 函数进行后处理,它有点有效,但由于不同的原因我想切换到 Three.js。
非常感谢任何帮助或指向相关主题的指示!
谢谢,卢卡
经过几个小时的困惑,我终于解决了问题,并为 Three.js 创建了一个可以进行透视变形的着色器。我使用“dltjs”库(https://github.com/charlee/dltjs)来计算单应性矩阵。在片段着色器中的 warpPoint() 函数中,矩阵乘以坐标,然后去均匀化以计算变换后的坐标。
这是 WarpShader 代码。 p0 包含矩形点,p1 包含四边形点。 M 是单应性矩阵,然后将其作为统一传递给着色器。
import * as THREE from 'three';
import dlt from 'dltjs';
let p0 = [[0, 0], [0, 1], [1, 0], [1, 1]];
let p1 = [[0.3, 0.3], [0.1, 0.9], [0.9, 0.1], [0.9, 0.9]];
let M = dlt.dlt2d(p0, p1);
const WarpShader = {
uniforms: {
tDiffuse: null,
transformMat: {
value: new THREE.Matrix3(
M[0][0], M[0][1], M[0][2],
M[1][0], M[1][1], M[1][2],
M[2][0], M[2][1], M[2][2]
)
}
},
vertexShader: /* glsl */`
varying vec2 vUv;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
vUv = uv;
}
`,
fragmentShader: /* glsl */`
uniform sampler2D tDiffuse;
varying vec2 vUv;
uniform mat3 transformMat;
vec2 warpPoint(mat3 transformMat, vec2 p) {
vec3 result = transformMat * vec3(p, 1.0); // transformation
return vec2(result.x / result.z, result.y / result.z); // dehomogenization
}
void main() {
vec2 coords = warpPoint(transformMat, vUv);
gl_FragColor = texture2D(tDiffuse, coords);
}`
};
export { WarpShader };