Создание и смешивание динамической текстуры в OpenGL

Мне нужно визуализировать сферу в текстуру (сделано с использованием объекта Framebuffer (FBO)), а затем альфа-смешать эту текстуру с обратным буфером. Пока что я не делаю никакой обработки с текстурой, кроме очистки ее в начале каждого кадра.

Я должен сказать, что моя сцена состоит из ничего, кроме планеты в пустом пространстве, сфера должна появиться рядом с планетой или вокруг нее (вроде как луна на данный момент). Когда я рендерим сферу прямо в задний буфер, она отображается правильно; но когда я делаю промежуточный шаг рендеринга в текстуру, а затем смешиваю эту текстуру с задним буфером, сфера появляется только тогда, когда она находится перед планетой, часть, которая не находится впереди, просто «обрезается» «:

Сфера, которая отрезана от края планеты

Я отрисовываю сферу, используя glutSolidSphere к полноэкранной текстуре RGBA8, привязанной к FBO, чтобы убедиться, что каждый пиксель сферы получает альфа-значение 1,0. Затем я передаю текстуру в программу фрагментного шейдера и использую этот код для рендеринга полноэкранного четырехугольника — с отображенной на нем текстурой — в буферный буфер во время альфа-смешения:

glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);

glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glBegin(GL_QUADS);
glTexCoord2i(0, 1);
glVertex3i(-1,  1, -1);   // TOP LEFT
glTexCoord2i(0, 0);
glVertex3i(-1, -1, -1);   // BOTTOM LEFT
glTexCoord2i(1, 0);
glVertex3i( 1, -1, -1);   // BOTTOM RIGHT
glTexCoord2i(1, 1);
glVertex3i( 1,  1, -1);   // TOP RIGHT
glEnd();
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glEnable(GL_DEPTH_TEST);

glDisable(GL_BLEND);

Это код шейдера (взят из файла FX, написанного на Cg):

sampler2D BlitSamp = sampler_state
{
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = Clamp;
AddressV = Clamp;
};

float4 blendPS(float2 texcoords : TEXCOORD0) : COLOR
{
float4 outColor = tex2D(BlitSamp, texcoords);
return outColor;
}

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

РЕДАКТИРОВАТЬ: Я попытался просто отрисовать пустой полноэкранный четырехугольник прямо в задний буфер, и даже он был обрезан по краям планеты. По какой-то причине что позволяет проверка глубины рендеринга квадрата (то есть удаление линий glDisable(GL_DEPTH_TEST) а также glEnable(GL_DEPTH_TEST) in the code above) избавился от проблемы, но теперь все, кроме планеты и сферы, кажется белым:

Сфера с белым неправильным белым фоном

Я удостоверился (и мог подтвердить), что альфа-канал текстуры равен 0 на каждый пиксель, но сфера, поэтому я не понимаю, где можно ввести белизну. (Также было бы интересно узнать, почему включение глубинного тестирования имеет такой эффект.)

1

Решение

Я вижу два возможных источника ошибки здесь:

1. Рендеринг в FBO

Если отсутствующие пиксели даже не присутствуют в FBO после рендеринга, должен быть какой-то механизм, который отбрасывает соответствующие фрагменты. Конвейер OpenGL включает в себя четыре различных типа тестов фрагментов, которые могут привести к отбрасыванию фрагментов:

  1. Тест ножниц: Вряд ли это может быть причиной, так как тест ножниц воздействует только на прямоугольную часть экрана.
  2. Альфа Тест: Столь же маловероятно, поскольку все ваши фрагменты должны иметь одинаковое альфа-значение.
  3. Тест трафаретаТакже маловероятно, если вы не используете трафаретные операции при рисовании фоновой планеты и копируете буфер буфера из заднего буфера в FBO.
  4. Тест глубиныТо же, что и для проверки трафарета.

Так что есть хороший шанс, что рендеринг в FBO здесь не проблема. Но просто чтобы быть абсолютно уверенным, вы должны прочитать текстуру вложения и сбросить ее в файл для проверки. Для этого вы можете использовать следующую функцию:

void TextureToFile(GLuint texture, const char* filename) {
glBindTexture(GL_TEXTURE_2D, texture);
GLint width, height;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);

std::vector<GLubyte> pixels(3 * width * height);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixels[0]);

std::ofstream out(filename, std::ios::out | std::ios::binary);
out << "P6\n"<< width << '\n'
<< height << '\n'
<< 255 << '\n';
out.write(reinterpret_cast<const char*>(&pixels[0]), pixels.size());
}

Полученный файл представляет собой портативное растровое изображение (.Ppm). Обязательно отсоедините FBO перед чтением текстуры.

2. Отображение текстуры

Предполагая, что рендеринг в FBO работает должным образом, единственным другим источником ошибки является смешивание текстуры с ранее визуализированной сценой. Есть два сценария:

а) фрагменты отбрасываются

Возможные причины отказа от фрагментов такие же, как в 1 .:

  1. Тест ножниц: Нет, влияет только на прямоугольные области.
  2. Альфа Тест: Вероятно, нет, сфера, покрытая текселями, должна иметь одинаковое альфа-значение.
  3. Тест трафарета: Это может быть причиной, если вы используете операции трафарета / тестирование трафарета, когда рисуете фоновую планету, а старое состояние трафарета все еще активно.
  4. Тест глубиныМожет быть причина, но, поскольку вы уже отключили это, это действительно не должно иметь никакого эффекта.

Поэтому вы должны убедиться, что все эти тесты отключены, особенно тест трафарета.

б) неправильные результаты от смешивания

Предполагая, что все фрагменты достигают заднего буфера, смешивание — единственная вещь, которая все еще может привести к неправильному результату. С вашей функцией смешивания (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) значения в заднем буфере не имеют значения для смешивания, и мы предполагаем, что значения альфа в текстуре верны. Так что я не вижу причин, почему смешивание должно быть основной причиной здесь.

Заключение

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

1

Другие решения

Я решил это или, по крайней мере, придумал работу вокруг.

Во-первых, белизна проистекает из того факта, что glClearColor был установлен на glClearColor(1.0f, 1.0f, 1.0f, 1000.0f)так что все, кроме планеты, даже не было написано в конце. Теперь я копирую содержимое заднего буфера (который является планетой, атмосферой и пространством вокруг него) в текстуру перед рендерингом сферы, и я рендеринг атмосферы и пространства до что операция копирования / блиц, так что они включены в него. Раньше все, кроме самой планеты, визуализировалось после моего четырехугольника, который — при использовании глубинного тестирования — очевидно, помещал все позади четырехугольника, делая его невидимым.

Реализованная реализация эффекта, которого я пытаюсь достичь, всегда использовала в своем коде такую ​​блиц-операцию, но я не думала, что это необходимо для эффекта. Теперь я чувствую, что другого пути не может быть …

0