首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >将透视变换矩阵从GIMP应用到GLSL着色器

将透视变换矩阵从GIMP应用到GLSL着色器
EN

Stack Overflow用户
提问于 2018-05-25 08:13:28
回答 1查看 1.7K关注 0票数 3

因此,我尝试在顶点着色器中添加图像的旋转和透视效果。旋转效果很好,但我无法实现透视效果。我在做2D的工作。

旋转矩阵是从代码生成的,但透视矩阵是我使用透视工具从GIMP获得的一组硬编码值。

代码语言:javascript
复制
private final Matrix3 perspectiveTransform = new Matrix3(new float[] {
    0.58302f, -0.29001f, 103.0f,
    -0.00753f, 0.01827f, 203.0f,
    -0.00002f, -0.00115f, 1.0f
});

这个透视矩阵使用500x500的图像在GIMP中实现了我想要的结果。然后,我尝试在纹理坐标上应用相同的矩阵。这就是为什么我要先乘以500,然后再除以500。

代码语言:javascript
复制
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;

uniform mat4 u_projTrans;
uniform mat3 u_rotation;
uniform mat3 u_perspective;

varying vec4 v_color;
varying vec2 v_texCoords;

void main() {
    v_color = a_color;

    vec3 vec = vec3(a_texCoord0 * 500.0, 1.0);

    vec = vec * u_perspective;

    vec = vec3((vec.xy / vec.z) / 500.0, 0.0);

    vec -= vec3(0.5, 0.5, 0.0);
    vec = vec * u_rotation;
    v_texCoords = vec.xy + vec2(0.5);

    gl_Position = u_projTrans * a_position;
}

对于旋转,我偏移原点,使其围绕中心旋转,而不是左上角。

关于GIMP的透视工具,我所知道的大部分都来自http://www.math.ubc.ca/~cass/graphics/manual/pdf/ch10.ps,这表明我可以在读完它后重现GIMP所做的事情,但事实证明我做不到,结果显示什么都没有(没有像素),而删除透视部分则显示图像正确旋转。

正如链接中提到的,我除以vec.z将齐次坐标转换回2D点。我没有使用透视变换的原点移动,因为在链接中提到左上角被用作原点。第11页:

有一件事需要注意-- GIMP坐标的原点在左上角,y向下递增。

编辑

感谢@Rabbit76的回答,它现在显示了一些东西!然而,它不会像矩阵在GIMP上转换图像那样转换我的纹理。

我在GIMP上的转换矩阵应该做一些类似的事情:

但是,它看起来像这样:

这是我从实际结果中看到的想法:

https://imgur.com/X56rp8K (已使用Image)

(正如所指出的,它的纹理参数是夹子到边,而不是夹子到边界,但这不是重点)

看起来它做的和我想要的完全相反。在应用矩阵之前,我尝试将原点偏移到图像的中心和左下角,但没有成功。这是一个新的结果,但它仍然是同一个问题:如何将GIMP透视矩阵应用到GLSL着色器中?

EDIT2

通过更多的测试,我可以确认它正在做“相反”的事情。使用这个简单的小尺度变换矩阵:

代码语言:javascript
复制
private final Matrix3 perspectiveTransform = new Matrix3(new float[] {
        0.75f, 0f, 50f,
        0f, 0.75f, 50f,
        0f, 0f, 1.0f
});

结果是图像的放大版本:

如果我以编程方式反转矩阵,它适用于简单的缩放矩阵!但对于透视矩阵,它显示:

https://imgur.com/v3TLe2d

EDIT3

再次感谢@Rabbit76,它在透视矩阵完成旋转之后应用了旋转,我最终得到了这样的结果:https://imgur.com/n1vWq0M

就快到了!唯一的问题是图像被压得很紧。这就像透视矩阵被多次应用一样。但如果你仔细观察,你可以看到它在透视时旋转,就像我想要的那样。现在的问题是如何解压它以获得像我在GIMP中一样的结果。(根本问题仍然是,如何获取GIMP矩阵并将其应用于着色器)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-05-25 13:48:44

这个透视矩阵使用500x500的图像在

中实现了我想要的结果。然后,我尝试在纹理坐标上应用相同的矩阵。这就是为什么我要先乘以500,然后再除以500。

矩阵

代码语言:javascript
复制
 0.58302 -0.29001 103.0
-0.00753  0.01827 203.0
-0.00002 -0.00115 1.0f

是一个2D透视变换矩阵。它使用2D Homogeneous coordinate进行操作。

请参阅2D affine and perspective transformation matrices

由于GIMP中显示的矩阵是从透视图到正交视图的变换,因此必须使用逆矩阵进行变换。可以通过调用inv()来计算逆矩阵。

矩阵被设置为执行范围为0,500的Cartesian coordinate到范围为0,500的Homogeneous coordinates的运算。

您的假设是正确的,您必须将输入从范围0,1缩放到0,500,输出从0,500缩放到0,1。但是您必须缩放二维笛卡尔坐标

此外,您必须在透视投影和Perspective divide之后进行旋转。

可能有必要(取决于位图和纹理坐标属性),必须翻转纹理坐标的V坐标。

最重要的是,必须在片段着色器中对每个片段执行变换。请注意,由于此变换不是线性变换(它是透视变换),因此计算角点上的纹理坐标是不够的。

代码语言:javascript
复制
vec2 Project2D( in vec2 uv_coord )
{
    vec2 v_texCoords;

    const float scale = 500.0;

    // flip Y
    //vec2 uv = vec2(uv_coord.x, 1.0 - uv_coord.y);
    vec2 uv = uv_coord.xy;

    // uv_h: 3D homougenus in range [0, 500] 
    vec3 uv_h = vec3(uv * scale, 1.0) * u_perspective;

    // uv_h: perspective devide and downscale [0, 500] -> [0, 1]
    vec3 uv_p = vec3(uv_h.xy / uv_h.z / scale, 1.0);

    // rotate
    uv_p = vec3(uv_p.xy - vec2(0.5), 0.0) * u_rotation + vec3(0.5, 0.5, 0.0);

    return uv_p.xy; 
}

当然,你也可以在顶点着色器中进行变换。但是,您必须将2d同构坐标从顶点着色器传递到片段着色器,这类似于将剪辑空间坐标设置为gl_Position。不同的是,你有一个二维齐次坐标,而不是三维坐标。并且您必须在片段着色器中手动执行Perspective divide

顶点着色器:

代码语言:javascript
复制
attribute vec2 a_texCoord0;
varying   vec3 v_texCoords_h;

uniform mat3 u_perspective

vec3 Project2D( in vec2 uv_coord )
{
    vec2 v_texCoords;

    const float scale = 500.0;

    // flip Y
    //vec2 uv = vec2(uv_coord.x, 1.0 - uv_coord.y);
    vec2 uv = uv_coord.xy;

    // uv_h: 3D homougenus in range [0, 500] 
    vec3 uv_h = vec3(uv * scale, 1.0) * u_perspective;

    // downscale
    return vec3(uv_h.xy / scale, uv_h.z);
}

void main()
{
    v_texCoords_h = Project2D( a_texCoord0 );

    .....
}

片段着色器:

代码语言:javascript
复制
varying vec3 v_texCoords_h;

uniform mat3 u_rotation;

void main()
{
    // perspective divide
    vec2 uv = vertTex.xy / vertTex.z;

    // rotation
    uv = (vec3(uv.xy - vec2(0.5), 0.0) * u_rotation + vec3(0.5, 0.5, 0.0)).xy;

    .....
}

请参见预览,其中我使用了以下2D投影矩阵,它是GIMP中显示的矩阵的逆矩阵

代码语言:javascript
复制
2.452f,     2.6675f,    -388.0f,
0.0f,       7.7721f,    -138.0f,
0.00001f,   0.00968f,    1.0f

进一步注意,与u_projTrans相比,u_perspective是按行主顺序初始化的。

因此,您必须将向量从左到u_perspective相乘

代码语言:javascript
复制
vec_h = vec3(vec.xy * 500.0, 1.0) * u_perspective;

但是你必须将向量从右边乘以u_projTrans

代码语言:javascript
复制
gl_Position = u_projTrans * a_position;

请参阅GLSL Programming/Vector and Matrix Operations

Data Type (GLSL)

当然,如果在通过glUniformMatrix*设置矩阵时转置矩阵,这种情况可能会发生变化

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50519828

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档