Вопрос по render, rendering, off-screen, 3d, opengl – Могу ли я использовать OpenGL для рендеринга вне экрана? [Дубликат]

4

На этот вопрос уже есть ответ здесь:

Как использовать GLUT / OpenGL для рендеринга в файл? 5 ответов

Я хочу попробовать сделать простую программу, которая берет 3D-модель и переводит ее в изображение. Можно ли как-нибудь использовать OpenGL для рендеринга изображения и поместить его в переменную, которая содержит изображение, а не отображает изображение? Я нене хочу видеть, что яЯ просто хочу сохранить его. Есть ли способ сделать это с OpenGL?

Ваш Ответ

2   ответа
6

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

7

Я предполагаю, что вы знаете, как рисовать вещи на экране с помощью OpenGL, и вы написали такую функцию, какdrawStuff сделать это.

Прежде всего вы должны решить, насколько велик ваш конечный рендер; Я'м выбирая здесь квадрат, размером 512х512. Вы также можете использовать размеры, которые не являются степенью двойки, но для простотыs придерживаться этого формата на данный момент. Иногда OpenGL становится требовательным к этой проблеме.

const int width = 512;
const int height = 512;

Затем вам нужно три объекта, чтобы создать область рисования вне экрана; это называетсяобъект буфера кадра как сказал user1118321.

GLuint color;
GLuint depth;
GLuint fbo;

FBO хранит буфер цвета и буфер глубины; также у вас на экране рендеринга есть эти два буфера, но вы нене хочу использовать их, потому что вы неЯ не хочу рисовать на экране. Чтобы создать FBO, вам нужно сделать что-то вроде следующеготолько раз например при запуске:

glGenTextures(1, &color);
glBindTexture(GL_TEXTURE_2D, color);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);

glGenRenderbuffers(1, &depth);
glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);

glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

Сначала вы создаете область памяти для хранения цвета пикселей, а затем область глубины пикселей (которая в компьютерной графике используется для удаления скрытых поверхностей), и, наконец, вы подключаете их к FBO, который в основном содержит ссылку на оба объекта. Рассмотрим в качестве примера первый блок с 6 вызовами:

glGenTextures создает имя для текстуры; имя в OpenGL - это просто целое число, потому что строка будет слишком неэффективной.glBindTexture связывает текстура к цели, а именноGL_TEXTURE_2D; последующие вызовы, которые указывают ту же цель, будут работать с этой текстурой.3-й, 4-й и 5-й вызов относятся к цели, которой манипулируют, и вы должны обратиться к документации OpenGL для получения дополнительной информации.Последний звонокglBindTexture отвязывается текстура от цели. Поскольку в какой-то момент вы передадите контроль своемуdrawStuff Функция, которая, в свою очередь, будет выполнять всю свою часть вызовов OpenGL, теперь вам нужно очистить рабочее пространство, чтобы избежать вмешательства в созданный вами объект.

Чтобы переключиться с рендеринга экрана на рендеринг вне экрана, вы можете использовать логическую переменную где-нибудь в вашей программе:

if (offscreen)
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
else
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

drawStuff();

if (offscreen)
    saveToFile();

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

Функция saveToFile отвечает за загрузку результата рендеринга и преобразование его в файл. Это сильно зависит от операционной системы и языка, который вы используете. Например, в Mac OS X с C это будет выглядеть примерно так:

void saveImage()
{
    void *imageData = malloc(width * height * 4);

    glBindTexture(GL_TEXTURE_2D, color);
    glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);

    CGContextRef contextRef = CGBitmapContextCreate(imageData, width, height, 8, 4 * width, CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), kCGImageAlphaPremultipliedLast);
    CGImageRef imageRef = CGBitmapContextCreateImage(contextRef);
    CFURLRef urlRef = (CFURLRef)[NSURL fileURLWithPath:@"/Users/JohnDoe/Documents/Output.png"];
    CGImageDestinationRef destRef = CGImageDestinationCreateWithURL(urlRef, kUTTypePNG, 1, NULL);
    CGImageDestinationAddImage(destRef, imageRef, nil);        
    CFRelease(destRef);

    glBindTexture(GL_TEXTURE_2D, 0);

    free(imageData);
}

Похожие вопросы