Проблема с исчезновением OpenGL

Вот что я делаю:

  • Визуализируйте первое изображение, используя цвет: glColor4f(1.0, 1.0, 1.0, 1.0);
  • Визуализируйте второе изображение, используя цвет: glColor4f(1.0, 1.0, 1.0, calc);. calc — это число, которое изменяется от 0,0 до 1,0 за секунду, и я могу убедиться, что оно действительно это делает.

Я ожидаю, что он будет переходить от одного изображения к другому, и он делает это, но на полпути он переходит в какой-то оттенок серого (кстати, черный цвет фона). О проблеме можно узнать здесь: http://www.youtube.com/watch?v=8dZXiYIM43s&feature=youtu.be .

Я просто хочу основное затухание, БЕЗ сероватого тона в середине затухания (который является самым сильным при непрозрачности 0,5). Я пытался сделать это с помощью GIMP, нижний слой непрозрачный, верхний слой имеет переменную непрозрачность, и он отлично работает, он делает точно то, что я хочу, я просто не знаю, почему мой код (или OpenGL) не будет делать то же самое. Видео, демонстрирующее, что я имею в виду: http://www.youtube.com/watch?v=Ym-VPu9hhjQ&feature=youtu.be

РЕДАКТИРОВАНИЕ: после небольшого эксперимента (изменение цвета фона на красный) при значении 0,5 он становится полупрозрачным, что обычно является желаемым эффектом, за исключением того, что ОБЕ текстура полупрозрачный (не только тот, что сверху). Почему это происходит??

Вот код:

void Sprite::render_single(Image* image, Pos2D pos, Angle angle) {
        int cx = image->width / 2;
        int cy = image->height / 2;
        glPushMatrix();
        glTranslatef(pos.x + cx, pos.y + cy, 0);
        glRotatef(angle.to_degrees(), 0.0, 0.0, 1.0);
        glTranslatef(-cx, -cy, 0);
        image->bind();
        glBegin(GL_QUADS);
                glTexCoord2f(0.0, 0.0);
                glVertex2f(0.0, 0.0);
                glTexCoord2f(1.0, 0.0);
                glVertex2f(image->width, 0.0);
                glTexCoord2f(1.0, 1.0);
                glVertex2f(image->width, image->height);
                glTexCoord2f(0.0, 1.0);
                glVertex2f(0.0, image->height);
        glEnd();
        image->unbind();
        glPopMatrix();
}

void Sprite::render(Pos2D pos, Angle angle) {
        Image* img = this->get_current_frame();
        if (this->images.size() == 1) {
                this->render_single(img, pos, angle);
                return;
        }
        double calc = (((double)this->current_frame_overflow) / this->frame_length);
        std::cout << calc << std::endl;
        glPushMatrix();
        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
        this->render_single(img, pos, angle);
        img = this->get_next_frame();
        glColor4f(1.0f, 1.0f, 1.0f, calc);
        this->render_single(img, pos, angle);
        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
        glPopMatrix();
}

Используемая функция смешивания: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Функция инициализации OpenGL:

/**
 * @brief Initializes OpenGL
 */
void Game::init_gl() {
        float width = this->display->w;
        float height = this->display->h;
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(0.0, width, height, 0.0);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glDisable(GL_DEPTH_TEST);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

Кроме того, вот весь исходный код основного цикла (который содержит большую часть материалов OpenGL): https://github.com/MiJyn/dbab/blob/master/src/game.cpp . И спрайт: https://github.com/MiJyn/dbab/blob/master/src/sprite.cpp .


person MiJyn    schedule 15.05.2013    source источник
comment
Видео помогает, но мы не знаем, что вы на самом деле пытаетесь сделать. Как это должно выглядеть?   -  person Trax    schedule 15.05.2013
comment
@Trax, спасибо, я знал, что-то забыл... Добавил в пост :)   -  person MiJyn    schedule 15.05.2013
comment
Вы пробовали смесь (ONE, ONE_MINUS_SRC_ALPHA)? Это то, что редактор изображений будет делать по умолчанию, то есть суммировать оба слоя (фон непрозрачный + верхний полупрозрачный).   -  person Trax    schedule 15.05.2013
comment
@Trax, да, но потом это начинает выглядеть действительно странно (во всей игре так, и хотя у меня нет проблемы, кажется, что она наслаивается или что-то в этом роде... это очень странно).. , использование GL_SRC_ALPHA вместо GL_ONE работает нормально, но моя проблема все еще остается   -  person MiJyn    schedule 15.05.2013
comment
Плохо, я только что проснулся, это (GL_SRC_ALPHA, GL_ONE), но после его использования вы должны вернуться к своим предыдущим настройкам, иначе эта функция смешивания используется для всех ваших объектов.   -  person Trax    schedule 15.05.2013
comment
@Trax, о, хорошо, и нет, это тоже не работает. Когда calc достигает 1, он становится намного ярче, чем когда он был равен 0. В GIMP яркость остается прежней.   -  person MiJyn    schedule 15.05.2013
comment
@Trax Я добавил новое видео, показывающее, как я хочу, чтобы оно выглядело   -  person MiJyn    schedule 15.05.2013
comment
Это может быть связано с неправильной текстурой (вы уверены, что текстура имеет альфа 1 в областях заднего плана?). Уберите все остальное из рендеринга, сделайте только тот эффект и только этот. Проверьте, работает ли он, возможно, другой код рендеринга меняет свое состояние.   -  person Trax    schedule 15.05.2013
comment
@Trax, я удалил все, а проблема все еще остается   -  person MiJyn    schedule 15.05.2013
comment
У вас включен альфа-тест?   -  person Full Frontal Nudity    schedule 17.05.2013
comment
@FullFrontalNudity Нет, не знаю. Нужно ли мне? И какую функцию я должен использовать, если это так?   -  person MiJyn    schedule 18.05.2013
comment
Альфа-тест отбрасывает определенные фрагменты на основе функции альфы этого фрагмента. Так что это проблема только в том случае, если он у вас включен, в этом случае его следует отключить. В качестве примечания попробуйте отключить проверку глубины при рисовании альфа-изображений.   -  person Full Frontal Nudity    schedule 18.05.2013
comment
@FullFrontalNudity, теста глубины тоже нет (никогда не включался в программе)   -  person MiJyn    schedule 18.05.2013
comment
Возможно, вам потребуется увидеть больше кода, связанного с gl. Из того, что вы показали, это выглядит правильно, и (src_alpha, one_minus_src_alpha) — это правильная функция для того, что вы пытаетесь сделать. В худшем случае вы можете отключить смешивание для первого отрисовки и снова включить для второго.   -  person Jonathan Chandler    schedule 18.05.2013
comment
@JonathanChandler Я так и сделал, этого достаточно? Или вы ищете что-то другое?   -  person MiJyn    schedule 18.05.2013
comment
@JonathanChandler, также я попытался отключить смешивание для первого розыгрыша и снова включить для второго, но все еще та же проблема!   -  person MiJyn    schedule 18.05.2013
comment
Ваш источник sprite.cpp на github имеет glPushAttrib для GL_COLOR_BUFFER_BIT, я не знаю, что это делает из опыта, но согласно opengl.org/sdk/docs/man2/xhtml/glPushAttrib.xml включает бит GL_ALPHA_TEST вместе с другими атрибутами (или я неправильно понимаю документацию). Вы можете объяснить?   -  person Full Frontal Nudity    schedule 18.05.2013
comment
@FullFrontalNudity, если я прав, это похоже на glPushMatrix, за исключением того, что оно работает для атрибутов. Хотя я могу ошибаться. Я попробую удалить его и посмотреть, работает ли он. EDIT: нет, та же проблема   -  person MiJyn    schedule 18.05.2013
comment
Я проголосовал за ваш вопрос, я не могу понять это :(. В крайнем случае я добавляю много glEnable/glDisable и перемещаю ваши операторы glColor повсюду, пока они не заработают, а затем выясните, почему Это работает. Удачи. Кроме того, я бы посоветовал вам очистить ваш основной цикл рендеринга, это облегчит вашу жизнь в будущем.   -  person Full Frontal Nudity    schedule 18.05.2013
comment
Во что вы рендерите? Если вы выполняете рендеринг в буфер с альфа-каналом, ваша вторая отрисовка может записывать в альфа-канал буфера. Затем, когда буфер отрисовывается на устройстве, эта альфа используется для смешивания конечного изображения.   -  person GuyRT    schedule 18.05.2013
comment
Просто чтобы добавить к моему последнему комментарию - даже если вы явно не выполняете рендеринг в FBO, ваш контекст OpenGL может использовать буфер (с альфой) и скомпоновать его с использованием альфы для устройства (контекст IIRC Rasperry Pi работает так). Вы можете попробовать glColorMask(1,1,1,0), чтобы проверить это.   -  person GuyRT    schedule 18.05.2013
comment
@FullFrontalNudity, я бы почти сделал это ... но я думаю, что это займет больше времени, чем оно того стоит (в крайнем случае - использовать шейдеры). И да, именно этим я и занимаюсь, пока жду ответа :)   -  person MiJyn    schedule 19.05.2013
comment
@GuyRT, это рендеринг в FBO (если вам интересно, вот источник: github.com/MiJyn/dbab/blob/master/src/postprocess.cpp). Как мне тогда это исправить?   -  person MiJyn    schedule 19.05.2013
comment
Поскольку создание/использование FBO находится под вашим контролем, я думаю, что самым простым способом было бы удалить альфа-канал из текстуры, которую вы используете в своем FBO (используйте GL_RGB вместо GL_RGBA для третьего параметра glTexImage2D в Post::Post ()). Если вам нужна альфа-версия в текстуре FBO, другим вариантом будет использование glBlendFuncSeparate вместо glBlendFunc или, как я сказал выше, использование glColorMask, чтобы избежать записи в альфа-канал.   -  person GuyRT    schedule 19.05.2013
comment
Еще одна мысль: отключите смешивание — glDisable(GL_BLEND) — в вашей функции Post::render().   -  person GuyRT    schedule 19.05.2013
comment
@GuyRT, спасибо, использование glDisable(GL_BLEND) работает!! Не могли бы вы преобразовать его в ответ?   -  person MiJyn    schedule 19.05.2013


Ответы (2)


Когда вы используете функцию glBlendFunc (с включенным смешиванием), те же коэффициенты используются для вычисления альфа-значения целевого фрагмента.

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

Решение состоит в том, чтобы просто отключить смешивание при рисовании полноэкранного четырехугольника. Кроме того, вы можете также удалить канал из текстуры, если вы его не используете (используйте GL_RGB вместо GL_RGBA для внутреннего формата текстуры).

person GuyRT    schedule 19.05.2013

Серая окантовка является побочным эффектом неиспользования предварительно умноженного альфа-канала.

Попробуйте использовать glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);, чтобы включить альфа-канал с предварительным умножением. Посмотрите предварительное умножение для получения дополнительной информации, но в основном все ваши текстуры и цвета должны быть предварительно умножены. Короче говоря, вы перебираете каждый пиксель и цвет и умножаете r, g и b на a. Итак, если бы у вас было 50% белого цвета (1, 1, 1, 0,5), теперь оно становится (0,5, 0,5, 0,5, 0,5). В этом случае ваш целевой цвет также должен быть (calc, calc, calc, calc).

person AshleysBrain    schedule 18.05.2013
comment
Я пробовал это, но тогда происходит другой эффект. Сначала текстура становится аномально яркой, а в конце, наконец, возвращается к нормальной яркости. Я пробовал как использовать вызов перед функцией, так и в середине (после рендеринга первого) - person MiJyn; 18.05.2013
comment
Кроме того, еще один вопрос: не будет ли (0,5, 0,5, 0,5, 0,5) (слишком) более прозрачным, чем (1,0, 1,0, 1,0, 0,5)? Или я вас не правильно понимаю? - person MiJyn; 19.05.2013