2013-05-04 3 views
0

Я закодировал небольшую программу OpenGL с использованием шейдеров OpenGL и GLSL. Вот экран моего приложения:OpenGL рендеринг работает неправильно с OpenCV с использованием шейдеров GLSL

enter image description here

Теперь моя цель состоит в том, чтобы смешать мой OPENGL кадр и один из веб-камеры в уникальной раме с помощью OpenCV. Прежде чем делать это с помощью шейдеров GLSL, я попытался сделать очень простую программу, рисуя цветной треугольник с некоторыми базовыми функциями OpenGL (glBengin, glVertex и т. Д.).

static int  initGL() 
{ 
    if (!glfwInit()) 
     return (-1); 

    if (!glfwOpenWindow(500, 500, 8, 8, 8, 0, 24, 0, GLFW_WINDOW)) { 
     glfwTerminate(); 
     return (-1); 
    } 

    glEnable(GL_PROJECTION); 
    glLoadIdentity(); 
    gluPerspective(45.0f, 500.0f/500.0f, 0.1f, 100.0f); 
    gluLookAt(0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); 

    return (0); 
} 

static void  drawGL() 
{ 
    glBegin(GL_TRIANGLES); 
    glColor3ub(255, 0, 0); 
    glVertex3f(-1.0f, 0.0f, 0.0f); 
    glColor3ub(0, 255, 0); 
    glVertex3f(0.0f, 1.0f, 0.0f); 
    glColor3ub(0, 0, 255); 
    glVertex3f(1.0f, 0.0f, 0.0f); 
    glEnd(); 
} 

int    main(void) 
{ 
    initGL(); 

    CvCapture *capture = cvCaptureFromCAM(CV_CAP_ANY); 

    if (!capture) { 
     fprintf(stderr, "ERROR: capture is NULL \n"); 
     getchar(); 
     return (-1); 
    } 

    while (1) 
    { 
     glClear(GL_COLOR_BUFFER_BIT); 
     glEnable(GL_MODELVIEW); 

     IplImage *frame = cvQueryFrame(capture); 

     if (!frame) { 
      fprintf(stderr, "ERROR: frame is null...\n"); 
      getchar(); 
      break; 
     } 

     glDrawPixels(frame->width, frame->height, GL_RGB, GL_UNSIGNED_BYTE, frame->imageData); 

     drawGL(); 

     glfwSwapBuffers(); 

     if ((cvWaitKey(10) & 255) == 27) break; 
    } 

    cvReleaseCapture(&capture); 
    cvDestroyWindow("mywindow"); 

    return (EXIT_SUCCESS); 
} 

Вот рендер:

enter image description here

Как вы можете видеть результат является правильным. Теперь я хотел попробовать свою первую программу, используя шейдеры GLSL с OpenCV, как показано ниже, но когда мое приложение запущено, у меня есть черный экран. Я пробовал несколько тестов, и проблема, похоже, начинается, когда я вызываю функцию glUseProgram (поэтому, когда я хочу привязать шейдер программы -> в моем коде, она соответствует вызову program-> bind()). Но здесь я использую функцию glDrawPixels для загрузки моего видеофрагмента. Я думаю, что это не хорошая функция, если я хочу использовать шейдеры GLSL. Вот часть моего кода C++:

[...] 

/*My GLSL shaders initialization*/ 

[...] 
int       main(int ac, char **av) 
{ 
    bool     isAlive = true; 
    unsigned int   vaoID = 0; 
    SDL_Event    event; 
    GLuint     textureID = 0; 
    ShaderProgram   *program = NULL; 

    if (!glfwInit()) 
     return (-1); 

    if (!glfwOpenWindow(WIDTH, HEIGHT, 8, 8, 8, 0, 24, 0, GLFW_WINDOW)) { 
     glfwTerminate(); 
     return (-1); 
    } 

    glEnable(GL_DEPTH_TEST); 

    //Viewport initialization 

    glViewport(0, 0, WIDTH, HEIGHT); 

    //Vertex declaration 

    VertexDeclaration *vDeclar = initVertexDeclaration(); 

    //Glew init component 

    glewInit(); 

    //VBO initialization 

    VertexBuffer *vBuffer = initVBO(); 

    //Shaders initialization 

    program = initShaders("triangle-pf.vert", "triangle-pf.frag"); 

    //Texture initialization 

    textureID = loadBMPTexture("Box.bmp"); 

    //VAO initialization 

    initVAO(vaoID, vBuffer, textureID, vDeclar); 

    //Screen capture Initialization 

    CvCapture *capture = cvCaptureFromCAM(CV_CAP_ANY); 

    if (!capture) { 
     fprintf(stderr, "ERROR: capture is NULL \n"); 
     getchar(); 
     return (-1); 
    } 

    //Main loop 

    while (isAlive == true) 
    { 
     //eventListener(&event, &isAlive); 

     if (glfwGetKey(GLFW_KEY_ESC)) 
      isAlive = false; 

     glClearDepth(1.0f); 
     glClearColor(0.13f, 0.12f, 0.13f, 1.0f); 
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

     //--------------------------------------------------- 

     IplImage *frame = cvQueryFrame(capture); 

     if (!frame) { 
      fprintf(stderr, "ERROR: frame is null...\n"); 
      getchar(); 
      break; 
     } 

     //--------------------------------------------------- 

     program->bind(); 

     //Projection matrix 

     glm::mat4 ProjectionMatrix = glm::perspective(45.0f, 500.0f/500.0f, 0.1f, 100.0f); 

     //View matrix 

     glm::mat4 ViewMatrix = glm::lookAt(glm::vec3(0.0f, 0.0f, 8.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); 

     //Model matrix 

     glm::mat4 ModelMatrix = glm::mat4(1.0f); 
     ModelMatrix = glm::translate(ModelMatrix, glm::vec3(0.0f, 0.0f, 0.0f)); 
     ModelMatrix = glm::rotate(ModelMatrix, angle, glm::vec3(1.0f, 1.0f, 1.0f)); 
     ModelMatrix = glm::scale(ModelMatrix, glm::vec3(1.0f, 1.0f, 1.0f)); 

     //Prepare matrix 

     glm::mat4 ModelViewMatrix = ViewMatrix * ModelMatrix; 
     glm::mat3 NormalMatrix = glm::mat3(glm::vec3(ModelViewMatrix[0]), glm::vec3(ModelViewMatrix[1]), glm::vec3(ModelViewMatrix[2])); 
     glm::mat4 ModelViewProjectionMatrix = ProjectionMatrix * ModelViewMatrix; 
     glm::vec4 LightPositionVec1 = ViewMatrix * glm::vec4(LightPosition1[0], LightPosition1[1], LightPosition1[2], LightPosition1[3]); 

     //Send source light properties 

     program->setUniform("LightInfos[0].La", glm::vec3(0.000000f, 0.000000f, 0.000000f)); 
     program->setUniform("LightInfos[0].Ld", glm::vec3(0.800000f, 0.800000f, 0.800000f)); 
     program->setUniform("LightInfos[0].Ls", glm::vec3(1.000000f, 1.000000f, 1.000000f)); 
     program->setUniform("LightInfos[0].Le", glm::vec3(0.200000f, 0.200000f, 0.200000f)); 

     /*program->setUniform("LightInfos[1].La", glm::vec3(0.000000f, 0.000000f, 0.000000f)); 
     program->setUniform("LightInfos[1].Ld", glm::vec3(0.800000f, 0.800000f, 0.800000f)); 
     program->setUniform("LightInfos[1].Ls", glm::vec3(0.000000f, 1.000000f, 1.000000f)); 
     program->setUniform("LightInfos[1].Le", glm::vec3(0.200000f, 0.200000f, 0.200000f));*/ 

     //Send model materials properties 

     program->setUniform("MaterialInfos.Ka", glm::vec3(0.000000f, 0.000000f, 0.000000f)); 
     program->setUniform("MaterialInfos.Kd", glm::vec3(1.000000f, 1.000000f, 1.000000f)); 
     program->setUniform("MaterialInfos.Ks", glm::vec3(1.000000f, 1.000000f, 1.000000f)); 
     program->setUniform("MaterialInfos.Ke", glm::vec3(0.200000f, 0.000000f, 0.200000f)); 
     program->setUniform("MaterialInfos.Shininess", 10.0f); 

     //Send light position 

     program->setUniform("LightInfos[0].Position", LightPositionVec1); 

     //Send matrix 

     program->setUniform("ProjectionMatrix", ProjectionMatrix); 
     program->setUniform("NormalMatrix", NormalMatrix); 
     program->setUniform("ModelViewMatrix", ModelViewMatrix); 
     program->setUniform("ModelMatrix", ModelMatrix); 
     program->setUniform("MVP", ModelViewProjectionMatrix); 

     glDrawPixels(frame->width, frame->height, GL_RGB, GL_UNSIGNED_BYTE, frame->imageData); 

     //VAO binding 

     glBindVertexArray(vaoID); 

     //Render meshes 

     glDrawArrays(GL_TRIANGLES, 0, vBuffer->getSize()); 

     glBindVertexArray(0); 

     program->release(); 

     angle += 0.50f; 

     glFlush(); 
     glfwSwapBuffers(); 
    } 

    unsigned int vboID = vBuffer->getHandle(); 
    glDeleteBuffers(1, &vboID); 
    glDeleteVertexArrays(1, &vaoID); 
    return (0); 
} 

Так что я думаю, что проблема исходит от glDrawPixels, которые не могут быть использованы с GLSL шейдеров. Я пробовал несколько возможных путей без каких-либо успехов. Может быть, мне нужно отправить буфер видеофрагмента прямо в пиксельный шейдер? В этом случае, как я могу это сделать? Я действительно потерян. Кто-нибудь может мне помочь?

+0

«Смешайте мою рамку opengl и одну из моей веб-камеры в уникальной рамке с помощью OpenCV», что это значит? Не можете ли вы просто сделать квад в фоновом режиме и использовать данные изображения из OpenCV в качестве текстуры, а затем нарисовать другие 3D-объекты сверху? Я не понимаю, почему вы хотите использовать шейдер. Что должен делать шейдер? –

+0

Я использую шейдеры для вычисления некоторых световых эффектов, которые невозможно визуализировать с использованием базового Opengl. Я просто хочу отобразить свой куб и иметь видео в реальном времени в качестве фона (например, пример с треугольником выше). Это похоже на сопоставление видеорамки (с моей веб-камеры) и другого фрейма с кубом. Вы видите, что я имею в виду ? – user1364743

+0

Да, это называется дополненной реальностью. Вам нужны эти световые эффекты для вашего фона или 3D-объектов? –

ответ

0

Способ, которым вы должны установить это, - использовать данные изображения в качестве текстуры. This link может быть хорошей отправной точкой. Затем вы можете отобразить квад в фоновом режиме, который заполняет весь экран, и использует текстуру для определения цвета каждого пикселя. Преимущество над glDrawPixels() заключается в том, что если вы масштабируете окно (и квадрат), изображение из видео будет масштабироваться соответствующим образом.

Если вам нужно, вы можете использовать текстуру в шейдере при рендеринге этого квадранта: Шейдер фрагмента (пикселя) вызывается для каждого пикселя, и вы должны использовать пробоотборник для получения цвета из текстуры. Затем вы можете изменить этот цвет в соответствии с вашими потребностями в освещении.

То, что вы нарисовываете поверх этого, зависит от вас.

+0

Хорошо, это хороший ответ. Спасибо. Я попробую это. Итак, о небольшой программе, которую я написал выше с цветным треугольником, это означает, что если я просто верну видеопоток в контексте OpenGL (без треугольника), OpenGL создаст (в фоновом режиме) текстуру (с буфером пикселей с веб-камеры для каждого видеокадра) и отправить его в свой фрагментарный шейдер и нарисовать его на экране. Я знаю, что OpengL использует свои собственные шейдеры (но процедура скрыта). Поэтому я должен воспроизвести одно и то же поведение, но на этот раз мои собственные шейдеры. Это правильно ? – user1364743

+1

Я не знаю, как реализовано 'glDrawPixels'. Это может даже зависеть от аппаратного обеспечения. Но я все еще не вижу причины использовать шейдер для рендеринга фона, если вам не нужно изменять способ его визуализации. –

+0

Я просто хочу применить свои шейдеры на своей 3D-модели, а не на фоне, потому что это видеопоток. Окружающая среда, зарегистрированная веб-камерой, должна быть одинаковой. Я хочу применить эффекты моей яркости к своей 3D-модели. Как вы сказали, это дополненная реальность. – user1364743

Смежные вопросы