Я пытался реализовать что-то вроде игры Antichamber (более высокоточного этот трюк показано ниже) на прошлой неделе:OpenGL - как реализовать «портального рендеринга»
Вот видео, что я надеюсь достичь (даже если это было сделано с Unreal Engine 4, я не использую это): https://www.youtube.com/watch?v=Of3JcoWrMZs
Я искал лучший способ сделать это, и я узнал о трафарете буфер. Между this и кодом this (функция drawPortals()) Я нашел онлайн, мне удалось почти реализовать его.
Он прекрасно работает с одним порталом в другую комнату (не перекрестный портал, то есть вы не можете пройти через него и быть телепортированы в другую комнату). В моем примере я рисую портал в простой квадратной комнате со сферой; за порталом есть еще одна сфера, которую я использовал, чтобы проверить, был ли буфер глубины работать правильно и рисунок его за порталом:
Проблемы возникают, когда я добавить еще один портал, рядом с этим. В этом случае мне удается правильно отобразить другой портал (освещение выключено, но сфера по праву имеет другой цвет, чтобы показать, что это еще одна сфера):
Но если повернуть камеру таким образом, что первый портал должен быть протянута через второй, то глубина первой становится неправильным, а второй портал получает обращается за первой, как это:
пока он должно быть примерно так:
Итак, это проблема. Я, вероятно, что-то неправильно сделал с буфером глубины, но я не могу найти что.
Мой код для рендеринга части в значительной степени это:
glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
// First portal
glPushMatrix();
// Disable writing to the color and depht buffer; disable depth testing
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
// Make sure that the stencil always fails
glStencilFunc(GL_NEVER, 1, 0xFF);
// On fail, put 1 on the buffer
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
// Enable writing to the stencil buffer
glStencilMask(0xFF);
// Clean the buffer
glClear(GL_STENCIL_BUFFER_BIT);
// Finally draw the portal's frame, so that it will have only 1s in the stencil buffer; the frame is basically the square you can see in the pictures
portalFrameObj1.Draw();
/* Now I compute the position of the camera so that it will be positioned at the portal's room; the computation is correct, so I'm skipping it */
// I'm going to render the portal's room from the new perspective, so I'm going to need the depth and color buffers again
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glClear(GL_DEPTH_BUFFER_BIT);
// Disable writing to the stencil buffer and enable drawing only where the stencil values are 1s (so only on the portal frame previously rendered)
glStencilMask(0x00);
glStencilFunc(GL_EQUAL, 1, 0xFF);
// Draw the room from this perspective
portalRoomObj1.Draw();
glPopMatrix();
// Now the second portal; the procedure is the same, so I'm skipping the comments
glPushMatrix();
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
glStencilFunc(GL_NEVER, 1, 0xFF);
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
glClear(GL_STENCIL_BUFFER_BIT);
portalFrameObj2.Draw();
/* New camera perspective computation */
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glClear(GL_DEPTH_BUFFER_BIT);
glStencilMask(0x00);
glStencilFunc(GL_EQUAL, 1, 0xFF);
portalRoomObj2.Draw();
glPopMatrix();
// Finally, I have to draw the portals' frames once again but this time on the depth buffer, so that they won't get drawn over; first off, disable the stencil buffer
glDisable(GL_STENCIL_TEST);
// Disable the color buffer
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glClear(GL_DEPTH_BUFFER_BIT);
// Draw portals' frames
portalFrameObj1.Draw();
portalFrameObj2.Draw();
// Enable the color buffer again
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
/* Here I draw the rest of the scene */
UPDATE
мне удалось выяснить, что проблема есть, но я до сих пор не в состоянии решить. Это не связано с буфером глубины на самом деле, а с трафаретом.
В принципе, способ, которым я рисую первый портал, таков: 1) Заполните биты портального кадра в буфере трафарета с помощью 1s; за пределами портала есть только 0s 2) Нарисуйте портал, где трафарет имеет 1 сек (так, чтобы он рисовался на портале рамы
И я повторяю это для второго портала.
Для первого портала, я получаю на шаге 1 что-то вроде этого, то (простите за глупые рисунки, я ленивый):
Тогда я начинается со вторым порталом:
Но теперь, между шагом 1 и 2, я говорю трафарету рисовать только там, где биты 1s; поскольку буфер теперь очищен, я потерял следы 1-го из первого портала, поэтому, если часть кадра второго портала находится за предыдущим кадром, 1-е из вторых кадров по-прежнему будет нарисовано с комнатой второго портала, независимо от того, буфер глубины. Вид как на этой картинке:
Я не знаю, если мне удалось объяснить это правильно ...