Подтвердить что ты не робот

Внедрение буфера кадров

Я "взламывал" одну из своих любимых игр с того момента, когда был моложе, и мне удалось перехватить вызовы OpenGL и ввести код С++ с помощью обертки opengl32.dll. Я смог придумать для этого несколько интересных применений, но моя текущая цель - внедрить пост-обработчики glsl-шейдеров в эту старую игру, чтобы она выглядела немного более современной. Игра была первоначально выпущена в конце 90-х, поэтому ее использование OpenGL и его кода рендеринга ограничено/примитивно/устарело.

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

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

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

Это код для инициализации фреймбуфера:

void initFB()
{
  /* Texture */
  glActiveTexture(GL_TEXTURE0);
  glGenTextures(1, &fbo_texture);
  glBindTexture(GL_TEXTURE_2D, fbo_texture);

  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

  glBindTexture(GL_TEXTURE_2D, 0);

    /* Depth buffer */
  glGenRenderbuffers(1, &fbo_depth);
  glBindRenderbuffer(GL_RENDERBUFFER, fbo_depth);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 1920, 1080);  
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo_depth);
  glBindRenderbuffer(GL_RENDERBUFFER, 0);

  /* Framebuffer to link everything together */
  glGenFramebuffers(1, &fbo);
  glBindFramebuffer(GL_FRAMEBUFFER, fbo);

  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_texture, 0);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo_depth);

  GLenum status;
  if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
    fprintf(stderr, "glCheckFramebufferStatus: error %p", status);
  }

  glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

Это код, который вызывается после wglSwapBuffers:

GLenum fboBuff[] =  { GL_COLOR_ATTACHMENT0 };
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glDrawBuffers(1, fboBuff);
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);

Это код, который вызывается до glFlush():

glBindFramebuffer(GL_FRAMEBUFFER, 0);
glPopAttrib(); // Restore our glEnable and glViewport states  

... Draw an Overlay containing with fbo texture binded ...

Здесь - трассировка gl одного кадра.

Это почти 800 строк, но обученный глаз opengl должен уметь видеть, какие вызовы возникают, когда. Я удалил несколько сотен строк вызовов, которые я, по крайней мере, понимаю.

4b9b3361

Ответ 1

Я не совсем уверен, что вы хотите сделать. Запустить игру, чтобы сделать вам fbo? Нарисуйте вещи сверху? Для начала попробуйте подключить все вызовы wgl и gl. http://research.microsoft.com/en-us/projects/detours/ - это хорошее место для начала.

Но, снова прочитав свой пост, я думаю, вы уже это знаете. Это поможет узнать, что вы хотите сделать.

  • Предоставление наложения: Hook SwapBuffers, сделайте свой материал там
  • Захват: снова зацепите SwapBuffers
  • Рендеринг текстур и выполнение эффектов post: Hook BindFramebuffer. Но есть буфер catch: frame 0 по умолчанию при запуске, поэтому код, который его не использует, не будет запускать BindFramebuffer, только чтобы установить его обратно на 0. Попробуйте подключиться glClear или любой другой вызов первым.

Не стесняйтесь обращаться ко мне с более подробной информацией. Похоже на забавный образовательный проект, с которым я хотел бы помочь:)

Я только что прочитал ваше сообщение перед публикацией, и ваша проблема может быть намного проще. Как программа Windows, ваша цель предполагает, что fbo 0 привязан, когда он начинает рендеринг кадра. Просто сделай это. Прежде чем это сделать, он вернется к fbo 0. Не делайте push/pop. Просто убедитесь, что ваш fbo имеет тот же размер (на окнах больше, также хорошо). Однако вам нужно зацепить BindFramebuffer. Всякий раз, когда ваша игра вызывает привязку 0, вам нужно привязать вас вместо этого. Но нет необходимости делать что-либо еще, как касаться видового экрана, игра должна позаботиться об этом уже. Когда вы, наконец, визуализируете свой крюк swapBuffers, просто убедитесь, что восстановили все, что вы изменили.

Также вам действительно не нужен вызов DrawBuffers. Это смутило моль из меня и, вероятно, также от вашей цели.:) Ваша цель делает код GL 1.2, вы делаете 3... 4...

Ответ 2

По моему опыту, то, что вы пытаетесь сделать, вполне возможно с помощью метода перехвата GL для без шейдерного приложения GL1.x.

Как я быстро взломал, вы можете просто забыть FBO и просто использовать glCopyTexSubImage(), когда исходное приложение меняет местами буферы, копировать визуализированный контент в текстуру и тексты ваших функций постпроцессинга.

Некоторые вещи, о которых вы должны позаботиться, при таком подходе к инъекции GL:

  • могут быть разные контексты GL (хотя это более вероятно для приложений САПР, чем обычные игры)
  • old GL позволил пользователю напрямую управлять идентификатором объекта - без необходимости вызовов функций glGen* (по-прежнему выполнялись Nice приложения). Если вы сами создаете новые объекты, оригинальное приложение не будет знать и может повторно использовать эти идентификаторы. Если вы хотите получить это право, вам придется прозрачно переназначить идентификаторы объектов (возможно, используя некоторую хеш-таблицу) - это большая работа, так как задействовано много функций GL. Другой злой взлом - это использовать некоторые маловероятные идентификаторы объектов самостоятельно.
  • GL - это конечный автомат, поэтому вы должны быть очень осторожны, чтобы восстановить состояние, в котором ожидает игра (насколько это возможно). OTOH, вы также должны быть готовы к тому, что исходное приложение может иметь любое состояние GL, когда вы получили изменение, чтобы перехватить его - так что вам может понадобиться reset много вещей.

Я могу заверить вас, что действительно можно придать рендеринг текстуре в какое-то старое приложение GL, как и я сам. Работал очень хорошо с Quake3 и другими известными играми того времени. Я не вижу ошибки obviuos с вашим текущим подходом. Я немного кое-что: вы также должны перехватить glDrawBuffer() и передать любой рисунок, который приложение собирается сделать для GL_BACK (при условии, что здесь используется приложение с двумя буферами) к вашему цветному вложению. Однако в журнале, который вы опубликовали, нет следа этой функции, поэтому игра могла установить его один раз при запуске.

Я также не понимаю, почему вы используете glFlush. Это не хороший маркер для чего-либо в частности. Если игра использует двойную буферизацию, SwapBuffers будет наилучшим приближением к "фрейму", который вы можете получить. Просто вставьте свои собственные творения объектов объектов непосредственно после создания контекста (вы можете перехватить wglCreateCintext() и друзей), и уже настроил рендеринг для FBO. На SwapBuffers просто нарисуйте содержимое текстуры, используя ваши шейдеры, в реальный задний буфер, выполните реальный обмен буфером и восстановите рендер в настройке FBO.

Я не знаю, знаете ли вы об этом или нет, но проект с открытым исходным кодом Chromium действительно предлагает хороший fframework для перехвата OpenGL. Хотя в центре внимания может быть рендеринг распределенного кластера, он также будет работать в настройке alocal и позволяет писать SPU (единицы обработки потока), где вы можете просто спроектировать функцию C для любой из функций GL, которые вы хотите подключить, Проект устарел и не находится в активном развитии с 5 лет или около того, потому что тип манипуляции с потоком GL, который был создан, не будет работать с более современным программируемым конвейером, но он все равно будет хорошо работать с старым старым GL1. x конвейер с фиксированной функцией...

Ответ 3

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

Хотя у меня нет связанного с этим опыта кодирования игр, когда у меня было приложение, которое я пытался модифицировать, я бы разобрал приложение, чтобы изучить его структуру, и выборочно применять патчи в памяти для перенаправления определенных функций и сегменты кода для замен, которые я предоставил.

Я бы предварительно загрузил разделяемую библиотеку, которая бы перезаписала определенные части памяти программы условными/безусловными инструкциями перехода/вызова и выборочно NOP'ингами, чтобы мой код стал неотъемлемой частью программы. Это определенно не было изящным, но это позволило мне быстро устранить недостатки в исходном коде.