2016-03-07 45 views
0

我写了这个简单的着色器纹理覆盖在另一个(基地)的质感 -如何叠加纹理而不裁剪基础纹理?

varying highp vec2 textureCoordinate; 
varying highp vec2 textureCoordinate2; 

uniform sampler2D inputImageTexture; 
uniform sampler2D inputImageTexture2; 

void main() 
{ 
    mediump vec4 base = texture2D(inputImageTexture, textureCoordinate); 
    mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2); 

    mediump float ra = (overlay.a) * overlay.r + (1.0 - overlay.a) * base.r; 
    mediump float ga = (overlay.a) * overlay.g + (1.0 - overlay.a) * base.g; 
    mediump float ba = (overlay.a) * overlay.b + (1.0 - overlay.a) * base.b; 

    gl_FragColor = vec4(ra, ga, ba, 1.0); 
} 

问题 - 这个工程除了一个问题。如果重叠图像小于基本图像,则重叠图像的外部区域给出α值为1.0,即overlay.a == 1.0。由于这个原因,基础图像被覆盖图像剪切。覆盖图之外的区域显示为黑色。

我是新来的opengl,并期待它的边界外,纹理的alpha应该显示为0.0?如何修复我的着色器代码以实现所需的行为?或者我需要修改我的图形管道?

编辑顶点着色器如下─

attribute vec4 inputTextureCoordinate2; 

varying vec2 textureCoordinate; 
varying vec2 textureCoordinate2; 

void main() 
{ 
    gl_Position = pos; 
    textureCoordinate = uv; 
    textureCoordinate2 = inputTextureCoordinate2.xy; 
} 
+0

你可以发布你的顶点着色器代码吗? – Swifter

+0

@Swifter:添加了顶点着色器 –

回答

0

我在我的代码中发现了这个问题。我有

GLES20.glClearColor(0, 0, 0, 1); 

在我的代码。更改为 -

GLES20.glClearColor(0, 0, 0, 0); 

修复了这个问题。

也正如@Reet提到的,我改变了我的片段着色器以使用矢量操作进行优化。

void main() 
{ 
    mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2); 

    mediump vec3 col = texture2D(inputImageTexture, textureCoordinate).xyz; 
    col = mix(col, overlay.xyz, overlay.a); 

    gl_FragColor = vec4(col, 1.0); 
} 
1

我期待它的边界之外,纹理的alpha应显示为0.0

你是如何取样纹理之外其界限?当采样纹理,UV坐标的范围从0到1,如果坐标在该范围之外,那么两件事情之一会发生:

  • 如果GL_CLAMP_TO_EDGE设置,那么cooridnate会固定(0,1)范围内,并且您将采样边缘像素
  • 如果设置了GL_REPEAT,则将采用坐标的小数部分,并且您将在纹理中间的某个位置采样

有关glTexParameter的更多详细信息,请参阅the docs

如果您的用例仅仅是覆盖图像,也许您应该尝试编写一个pixel shader

  • 将视口设置为基本图像尺寸并从(-1,1)中绘制一个四边形。
  • 您的片段着色器现在将在每个像素上操作,称为纹素。获取纹理与gl_FragCoord
  • 样本的基础和覆盖texel例如使用texelFetch
  • 如果纹理像素的覆盖之外,将叠加层的RGBA值设置为0

例如

//fragment shader 
uniform ivec2 overlayDim; 
uniform sampler2D baseTexture; 
uniform sampler2D overlayTexture; 

void main() { 
    vec2 texelf = floor(gl_FragCoord.xy); 
    ivec2 texel = (int(texelf.x), int(texelf.y)); 

    vec4 base = texelFetch(baseTexture, texel, 0); 
    vec4 overlay = texelFetch(overlayTexture, texel, 0); 

    float overlayIsValid = float(texel.x < overlayDim.x && texel.y < overlayDim.y); 

    overlay *= overlayIsValid; 

    //rest of code 
} 
1

,如果你品尝纹理的范围之外被控制,会发生什么您使用glTexParameteri()GL_TEXTURE_WRAP_SGL_TEXTURE_WRAP_T设置的值。

在完整的OpenGL中,您可以将值设置为GL_CLAMP_TO_BORDER,将边框颜色设置为alpha值为0.0的值,然后完成。但是纹理边框在OpenGL ES 2.0中不可用(该选项在ES 3.2中引入,但不在早期版本中引入)。

做不到这一点,我能想到的两个选项:

  • 如果你有过的纹理数据的控制,你可以一个一个像素的边框设置为透明值。 GL_CLAMP_TO_EDGE然后在范围之外采样时为您提供透明值。
  • 检查片段着色器中的范围。

第二种选择可能看起来像这样(未经测试),片段着色器代码:

mediump vec3 col = texture2D(inputImageTexture, textureCoordinate).xyz; 

if (all(greaterThan(textureCoordinate2, vec2(0.0))) && 
    all(lessThan(textureCoordinate2, vec2(1.0)))) 
{ 
    mediump vec3 overlay = texture2D(inputImageTexture2, textureCoordinate2).xyz; 
    col = mix(col, overlay, overlay.a); 
} 

gl_FragColor = vec4(col, 1.0); 

相比于原来的代码,还要注意使用矢量操作。每当有一种对矢量进行操作的好方法时,它会使代码更简单。这也将使GPU的矢量操作更容易优化器的工作。