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

ılǝ*_*ılǝ 2 android blending opengl-es opengl-es-2.0

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

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

黑白面具图像 马特宏峰图像

使用以下着色器:

      // 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); 
      }
Run Code Online (Sandbox Code Playgroud)

(片段着色器用第二个纹理替换黑色和白色蒙版的白色空格).

由于两个纹理都使用相同的gl_Position和坐标(1.0f,1.0f,1.0f,0.0f,0.0f,1.0f,0.0f,0.0f),因此两个纹理都映射到视图中的相同坐标:

在此输入图像描述

但是,我的目标是保持原始纹理比例:

在此输入图像描述

我想着色器内实现这一目标,而不是glBlendFuncglBlendFuncSeparate,以我自己的值混合.

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

Mat*_*lak 6

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

要获得该比例矢量,您需要一些简单的数学运算.你想要做的是尊重掩模比例,但要缩放它,所以2个刻度坐标中的一个是,1.0而另一个是<=1.0.这意味着您将看到整个蒙版的宽度或高度,而相反的尺寸将缩小.例如,如果您的图像大小为1.0x1.0且掩码大小为2.0x1.0,则您的缩放矢量将为(.5,1.0).

要使用它,scaleVector您只需要乘以纹理坐标:

vec4 mask = texture2D(uMaskTextSampler, vTexcoord* scaleVector);
Run Code Online (Sandbox Code Playgroud)

要计算比例矢量,请尝试以下方法:

    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;
    }
Run Code Online (Sandbox Code Playgroud)

注意我没有尝试这个代码,所以你可能需要玩一下.

编辑:缩放纹理坐标修复

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

vec2 fromCentre = vTexcoord-vec2(.5,.5);
vec2 scaledFromCenter = fromCenter*scaleVector;
vec2 resultCoordinate = vec2(.5,.5) + scaledFromCenter;
Run Code Online (Sandbox Code Playgroud)

你可以将它放在一行中,甚至尝试缩短它(首先在纸上做).