android - 在 GLSL 中混合不同大小/坐标的纹理

标签 android opengl-es opengl-es-2.0 blending

如果在 fragment 着色器中混合两个不同大小的纹理,是否可以将纹理映射到不同的坐标?

例如,如果混合来自以下两个图像的纹理:

black and white mask image Matterhorn image

使用以下着色器:

      // Vertex shader
      uniform mat4 uMVPMatrix;
      attribute vec4 vPosition;
      attribute vec2 aTexcoord;
      varying vec2 vTexcoord;
      void main() {
        gl_Position = uMVPMatrix * vPosition;
        vTexcoord = aTexcoord;
      }

      // Fragment shader
      uniform sampler2D uContTexSampler;
      uniform sampler2D uMaskTextSampler;
      varying vec2 vTexcoord;
      void main() {
        vec4 mask = texture2D(uMaskTextSampler, vTexcoord);
        vec4 text = texture2D(uContTexSampler, vTexcoord);
        gl_FragColor = vec4(text.r * mask.r), text.g * mask.r, text.b * mask.r, text.a * mask.r); 
      }

( fragment 着色器用第二个纹理替换黑白蒙版的空白区域)。

由于两个纹理使用相同的 gl_Position 和坐标(1.0f、1.0f、1.0f、0.0f、0.0f、1.0f、0.0f、0.0f),两个纹理在 View 中映射到相同的坐标:

enter image description here

不过,我的目标是保持原来的纹理比例:

enter image description here

我想在着色器中实现这一点,而不是 glBlendFuncglBlendFuncSeparate,以便我自己的混合值。

有没有办法在 GLSL 中实现这一点?我有一种感觉,我为不同位置坐标混合纹理顶点的方法被设计破坏了...

最佳答案

这确实是可能的,但你需要为蒙版纹理坐标获得一个 2D 比例向量。我建议您在 CPU 上计算它们并通过统一将它们发送到着色器,替代方法是按顶点甚至每个 fragment 计算它们,但您仍然需要将图像尺寸传递给着色器,所以只需在 CPU 上执行并添加制服。

要获得该比例矢量,您需要一些简单的数学知识。你想要做的是尊重蒙版比例但缩放它所以 2 个比例坐标之一是 1.0另一个是<=1.0 .这意味着您将看到整个 mask 的宽度或高度,而相反的尺寸将按比例缩小。例如,如果您有一个大小为 1.0x1.0 的图像和一个大小为 2.0x1.0 的 mask ,您的缩放向量将为 (.5, 1.0)。

使用这个scaleVector你只需要乘以纹理坐标:

vec4 mask = texture2D(uMaskTextSampler, vTexcoord* scaleVector);

要计算比例向量试试这个:

    float imageWidth;
    float imageHeight;
    float maskWidth;
    float maskHeight;

    float imageRatio = imageWidth/imageHeight;
    float maskRatio = maskWidth/maskHeight;

    float scaleX, scaleY;

    if(imageRatio/maskRatio > 1.0f) {
        //x will be 1.0
        scaleX = 1.0f;
        scaleY = 1.0f/(imageRatio/maskRatio);
    }
    else {
        //y will be 1.0
        scaleX = imageRatio/maskRatio;
        scaleY = 1.0f;
    }

请注意,我没有尝试过此代码,因此您可能需要尝试一下。

编辑:缩放纹理坐标修复

上面的纹理坐标比例使得 mask 纹理使用左上部分而不是中心部分。坐标必须围绕中心缩放。这意味着从中心获取原始向量 vTexcoord-vec2(.5,.5)然后缩放此向量并将其从中心添加回来:

vec2 fromCentre = vTexcoord-vec2(.5,.5);
vec2 scaledFromCenter = fromCenter*scaleVector;
vec2 resultCoordinate = vec2(.5,.5) + scaledFromCenter;

你可以把它放在一行中,甚至可以试着缩短一点(先在纸上做)。

关于android - 在 GLSL 中混合不同大小/坐标的纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24651369/

相关文章:

android - 如何在android中创建带有内容的角框?

android - 错误 :(24, 13) 无法解析 : com. android.support:appcompat-v7:20

android - 如何检查 SIM 卡是否处于 Activity 状态?

Android NDK SDL2 OpenGL ES 2 阴影映射(定向)- 可能吗?

android - 如何在 Android sqlite 中连接列

android - 在游戏引擎之上构建音乐制作应用程序是否有意义?

android - 在 Android 上创建比屏幕尺寸更小的后备缓冲区

templates - xcode 4.2 中的 OpenGL 游戏模板(这段代码发生了什么?!!)

android - irrlicht android on opengl es 2.0 驱动程序

javascript - WebGL 的 zBuffer 不起作用