Смешивание текстур разного размера/координат в GLSL

При смешивании двух текстур разного размера во фрагментном шейдере можно ли сопоставить текстуры с разными координатами?

Например, при смешивании текстур из следующих двух изображений:

черно-белое изображение маскиИзображение Маттерхорна

со следующими шейдерами:

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

(Фрагментный шейдер заменяет пробелы черно-белой маски второй текстурой).

Поскольку обе текстуры используют одни и те же gl_Position и координаты (1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f), обе текстуры сопоставляются с одними и теми же координатами в представлении:

введите здесь описание изображения

Однако моя цель — сохранить исходное соотношение текстур:

введите здесь описание изображения

Я хочу добиться этого в шейдере, а не в glBlendFunc и glBlendFuncSeparate, чтобы мои собственные значения для смешивания.

Есть ли способ добиться этого в GLSL? У меня такое ощущение, что мой подход к смешиванию вершин текстуры для разных координат положения нарушен дизайном...


person ılǝ    schedule 09.07.2014    source источник


Ответы (1)


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

Чтобы получить этот масштабный вектор, вам понадобится немного простой математики. То, что вы хотите сделать, это соблюдать соотношение маски, но масштабировать его так, чтобы одна из двух координат шкалы была 1.0, а другая - <=1.0. Это означает, что вы увидите всю ширину или высоту маски, в то время как противоположное измерение будет уменьшено. Например, если у вас есть изображение размером 1,0x1,0 и маска размером 2,0x1,0, ваш масштабный вектор будет (0,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;
    }

Примечание. Я не пробовал этот код, поэтому вам, возможно, придется немного поиграть.

EDIT: исправление масштабирования координат текстуры

Приведенная выше шкала координат текстуры заставляет текстуру маски использовать верхнюю левую часть вместо центральной части. Координаты должны быть отмасштабированы вокруг центра. Это означает, что нужно получить исходный вектор из центра, равный vTexcoord-vec2(.5,.5), затем масштабировать этот вектор и добавить его обратно из центра:

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

Вы можете поместить это в одну строку и даже попытаться немного сократить ее (сначала сделайте это на бумаге).

person Matic Oblak    schedule 09.07.2014
comment
Потрясающе, спасибо! Это навело меня на правильный путь — масштабирование получилось легким с переменной vec2, теперь я работаю над управлением положением маски. - person ılǝ; 10.07.2014
comment
Ах да, я забыл об этой части, теперь она у вас слева... Вам нужно нормализовать ее примерно на 0,5. Позвольте мне отредактировать. - person Matic Oblak; 10.07.2014
comment
Попробуйте это редактирование, я надеюсь, что оно правильное... И НЕ меняйте позиции, они должны быть такими же, как и цель. Также обратите внимание, что вы можете выполнить масштабирование в вершинном шейдере и добавить другую текстурную координату для маски во фрагментном шейдере. - person Matic Oblak; 10.07.2014
comment
@MaticOblak просто хотел сказать спасибо. Это самый полезный пост, который я нашел для работы с размером/положением во фрагментных шейдерах. Я работаю в системе, где у меня есть доступ только к фрагментам (без вершин или посторонних методов openGL), и эта информация спасла мне жизнь. - person Christopher Reid; 23.06.2016