2016-03-07 2 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, и ожидал, что за его пределами альфа-текстура должна выглядеть как 0.0? Как я могу исправить свой шейдерный код для достижения желаемого поведения? Или мне нужно изменить мой графический конвейер?

EDIT Vertex шейдеров ценам ниже

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); 

исправлена ​​проблема.

Также, как упоминалось @Reto, я изменил свой шейдер фрагмента, чтобы использовать векторные операции для оптимизации.

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

Я ожидал, что за ее пределами, альфа текселя должно появиться 0,0

Как вы выборки текстур за пределами его границы? При отборе проб текстуры, координаты уф должен находиться в диапазоне от 0 до 1. Если координаты находятся за пределами этого диапазона, то одна из двух вещей будет:

  • Если GL_CLAMP_TO_EDGE установлен, то cooridnate будет прижата к (0, 1) в диапазоне, и вы будете пробовать краевой пиксель
  • Если GL_REPEAT установлен, то дробная часть координаты будет принято, и вы будете пробовать где-то в середине текстуры

См. the docs на glTexParameter для получения более подробной информации.

Если ваш случай использования - это просто накладываемые изображения, возможно, вам стоит попробовать написать pixel shader.

  • Установите видовое окно на размеры базового изображения и нарисуйте квад из (-1, 1).
  • Теперь ваш шейдер фрагмента будет работать на каждом пикселе, известном как тексель. Получите тексель с gl_FragCoord
  • Образец основания и наложения текселем, например. используя 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

Что произойдет, если вы образец вне диапазона текстуры контролируется значение, которое вы установили для GL_TEXTURE_WRAP_S и GL_TEXTURE_WRAP_T, используя glTexParameteri().

В полном OpenGL вы можете установить значение GL_CLAMP_TO_BORDER, установить цвет границы на значение с альфа-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); 

По сравнению с исходным кодом, а также обратите внимание на использовании векторных операций. Всякий раз, когда есть хороший способ работы с векторами, он сделает код более простым. Это также облегчит работу оптимизатора для графических процессоров с векторными операциями.

Смежные вопросы