Мне нужно визуализировать сферу в текстуру (сделано с использованием объекта 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 на каждый пиксель, но сфера, поэтому я не понимаю, где можно ввести белизну. (Также было бы интересно узнать, почему включение глубинного тестирования имеет такой эффект.)
Я вижу два возможных источника ошибки здесь:
Если отсутствующие пиксели даже не присутствуют в FBO после рендеринга, должен быть какой-то механизм, который отбрасывает соответствующие фрагменты. Конвейер OpenGL включает в себя четыре различных типа тестов фрагментов, которые могут привести к отбрасыванию фрагментов:
Так что есть хороший шанс, что рендеринг в 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 перед чтением текстуры.
Предполагая, что рендеринг в FBO работает должным образом, единственным другим источником ошибки является смешивание текстуры с ранее визуализированной сценой. Есть два сценария:
Возможные причины отказа от фрагментов такие же, как в 1 .:
Поэтому вы должны убедиться, что все эти тесты отключены, особенно тест трафарета.
Предполагая, что все фрагменты достигают заднего буфера, смешивание — единственная вещь, которая все еще может привести к неправильному результату. С вашей функцией смешивания (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
значения в заднем буфере не имеют значения для смешивания, и мы предполагаем, что значения альфа в текстуре верны. Так что я не вижу причин, почему смешивание должно быть основной причиной здесь.
В заключение следует отметить, что единственной разумной причиной наблюдаемого результата является проверка трафарета. Если это не так, у меня нет вариантов 🙂
Я решил это или, по крайней мере, придумал работу вокруг.
Во-первых, белизна проистекает из того факта, что glClearColor
был установлен на glClearColor(1.0f, 1.0f, 1.0f, 1000.0f)
так что все, кроме планеты, даже не было написано в конце. Теперь я копирую содержимое заднего буфера (который является планетой, атмосферой и пространством вокруг него) в текстуру перед рендерингом сферы, и я рендеринг атмосферы и пространства до что операция копирования / блиц, так что они включены в него. Раньше все, кроме самой планеты, визуализировалось после моего четырехугольника, который — при использовании глубинного тестирования — очевидно, помещал все позади четырехугольника, делая его невидимым.
Реализованная реализация эффекта, которого я пытаюсь достичь, всегда использовала в своем коде такую блиц-операцию, но я не думала, что это необходимо для эффекта. Теперь я чувствую, что другого пути не может быть …