c++ - 接收到输入时 OpenGL 重绘场景

标签 c++ multithreading opengl

我在可视化 C++ 应用程序中实现了一个线程,该线程在 OpenGL 窗口中绘制了一系列与立方体 vector 相关的立方体,即我所拥有的中心、侧面和水平面。它是这个类对象的 vector ,就像一棵树,有不同的层次和层次。在主要细化过程中,此对象中的多维数据集发生变化:添加、删除……在细化的每一步……

我只需要在每个步骤完成时重绘(刷新)OpenGL 窗口的内容,以获得该立方体列表演变的动态表示。

我的意思是:

  • 第一步完成,我将数组传递给 OpenGL 线程,进行绘制。
  • 第二步运行,OpenGL窗口内容维护第一个立方体。
  • 第二步完成,OpenGL 的内容已更新为新的立方体。
  • 等等...

OpenGL 线程处于后台模式线程中......我只需要在我进行详细说明时看到立方体的演变......现在,问题在于语句 glutMainLoop() 的情况是连续的...... .它太重或崩溃,即使是带有 Nvidia Quadro 4000 的系统......OpenGL 窗口显示,但被阻塞,无法移动,有时呈灰色或不显示任何内容。

这是我的一段代码(所有与 OpenGL 相关的代码):

#include <iostream>
#include <opencv\cv.h>
#include <opencv\highgui.h>
#include <opencv2\highgui\highgui.hpp>
#include <windows.h>
#include <process.h>
#include <queue>
#include <array>
#include <vector>
#include <GL/glut.h>
#include <GL/freeglut.h>

using namespace std;
using namespace cv;


 //Premessa delle funzioni di posizionamento con mouse 
  void mouseCB(int button, int stat, int x, int y);
  void mouseMotionCB(int x, int y);

  //funzioni di inizializzazione e pulizia
  bool initSharedMem();
 void clearSharedMem();
 void initLights();
 void setCamera(float posX, float posY, float posZ, float targetX, float targetY, float    targetZ);
  void toOrtho();
 void toPerspective();

 //variabili e costanti
 const int   SCREEN_WIDTH    = 640;
 const int   SCREEN_HEIGHT   = 480;
const float CAMERA_DISTANCE = 10.0f;

int screenWidth;
int screenHeight;
bool mouseLeftDown;
 bool mouseRightDown;
 bool mouseMiddleDown;
 float mouseX, mouseY;
float cameraAngleX;
 float cameraAngleY;
float cameraDistance;
int drawMode;

 ///////////////////////////////////////////////////////////////////////////////
 // Funzione inizializzazione OpenGL standard
 ///////////////////////////////////////////////////////////////////////////////
void init()
{
glShadeModel(GL_SMOOTH);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING); 
glEnable(GL_TEXTURE_2D);
glEnable(GL_CULL_FACE);
glEnable(GL_COLOR_MATERIAL);
initLights();
 }

 ///////////////////////////////////////////////////////////////////////////////
 // Funzione di inizializzazione globale delle variabili
 ///////////////////////////////////////////////////////////////////////////////
bool initSharedMem()
{
screenWidth = SCREEN_WIDTH;
screenHeight = SCREEN_HEIGHT;

mouseLeftDown = mouseRightDown = mouseMiddleDown = false;
mouseX = mouseY = 0;

cameraAngleX = cameraAngleY = 0.0f;
//cameraDistance = CAMERA_DISTANCE;
cameraDistance = 0.3f;
drawMode = 0; // 0:pieno, 1: solo contorni, 2:punti

return true;
}

 ///////////////////////////////////////////////////////////////////////////////
 // Funzione di pulitura variabili globali
 ///////////////////////////////////////////////////////////////////////////////
void clearSharedMem()
{
 }

 ///////////////////////////////////////////////////////////////////////////////
 // Inizializzazione Luci
 ///////////////////////////////////////////////////////////////////////////////
void initLights()
{
GLfloat lightKa[] = {.2f, .2f, .2f, 1.0f};  // luce ambientale
GLfloat lightKd[] = {.7f, .7f, .7f, 1.0f};  // luce diffusa
GLfloat lightKs[] = {1, 1, 1, 1};           // luce speculare

glLightfv(GL_LIGHT0, GL_AMBIENT, lightKa);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightKd);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightKs);

// posizione delle luci
float lightPos[4] = {0, 0, 20, 1}; 
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);

//Attiva tutti i settaggi delle luci
glEnable(GL_LIGHT0);                        }

 ///////////////////////////////////////////////////////////////////////////////
 //  Posizione della telecamera e direzioni
 ///////////////////////////////////////////////////////////////////////////////
 void setCamera(float posX, float posY, float posZ, float targetX, float targetY, float   targetZ)
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(posX, posY, posZ, targetX, targetY, targetZ, 0, 1, 0); // eye(x,y,z),  focal(x,y,z), up(x,y,z)
 }

///////////////////////////////////////////////////////////////////////////////
// Impostazione proiezione ortogonale
///////////////////////////////////////////////////////////////////////////////
 void toOrtho()
{
// Imposta il viewport di tutta la finestra
glViewport(0, 0, (GLsizei)screenWidth, (GLsizei)screenHeight);

// Imposta il frustum di visione
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, screenWidth, 0, screenHeight, -1, 1);

// passaggio a modelview per interattività
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}



 ///////////////////////////////////////////////////////////////////////////////
 // Impostazione come perspective
///////////////////////////////////////////////////////////////////////////////
void toPerspective()
{ 
// Imposta il viewport di tutta la finestra
glViewport(0, 0, (GLsizei)screenWidth, (GLsizei)screenHeight);

//frustum perspective
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

//gluPerspective(60.0f, (float)(screenWidth)/screenHeight, 1.0f, 1000.0f);

gluPerspective(60.0f, (float)(screenWidth)/screenHeight, 10.0f, 0.0f); // FOV,   AspectRatio, NearClip, FarClip

// switch to modelview matrix in order to set scene
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

   ///////////////////////////////////////////////////////////////////////////////
  //  Funzione ricorsiva di disegno
  ///////////////////////////////////////////////////////////////////////////////
  void addraw(cubo temp)
 {
//se non ci sono sottocubi
   if (temp.lista_sottocubi.size() == 0)
   {        
        if (temp.livello == LMAXI) {
             double centro[3]={(temp.V[6].x)/2, (temp.V[6].y)/2,         (temp.V[6].z)/2};
             glPushMatrix();
             glTranslatef(centro[0],centro[1],centro[2]);
             glColor3ub(0,0,255);
             glutSolidCube(temp.lato);
             glPopMatrix();
        }
}
//se i sottocubi ci sono
else {
    for (int i=0;i<(int)temp.lista_sottocubi.size();i++){
            addraw(temp.lista_sottocubi[i]);
        }
 }
}

 ///////////////////////////////////////////////////////////////////////////////
 // Funzione disegno principale
 ///////////////////////////////////////////////////////////////////////////////
 void draw()
{

// clear buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glPushMatrix();

//spostamento del disegno
glTranslatef(0, 0, -cameraDistance);
glRotatef(cameraAngleX, 1, 0, 0);   // pitch
glRotatef(cameraAngleY, 0, 1, 0);   // heading

//lancio funzione di disegno vera e propria
addraw(prova);

//reset
glPopMatrix();
glutSwapBuffers();
 }
 //////////////////////////////////////////////////////////////////////////////
 //  Funzione di reshape
 ///////////////////////////////////////////////////////////////////////////////
void reshape(int w, int h)
{
 screenWidth = w;
  screenHeight = h;
 toPerspective();
 }

   ///////////////////////////////////////////////////////////////////////////////
    //  Funzione di refresh temporizzato della finestra
    ///////////////////////////////////////////////////////////////////////////////

    void timerCB(int millisec){
glutTimerFunc(millisec, timerCB, millisec);
glutPostRedisplay();
  }

 ///////////////////////////////////////////////////////////////////////////////
// Funzione rilevamento movimenti del mouse
///////////////////////////////////////////////////////////////////////////////
void Motion(int x,int y)
{
if(mouseLeftDown)
{
    cameraAngleY += (x - mouseX);
    cameraAngleX += (y - mouseY);
    mouseX = x;
    mouseY = y;
}
if(mouseRightDown)
{
    cameraDistance -= (y - mouseY) * 0.2f;
    mouseY = y;
    }
 }

  ///////////////////////////////////////////////////////////////////////////////
 // Funzione per rilevamento bottoni mouse
 ///////////////////////////////////////////////////////////////////////////////
void Mouse(int button, int state, int x, int y)
{
mouseX = x;
mouseY = y;

if(button == GLUT_LEFT_BUTTON)
{
    if(state == GLUT_DOWN)
    {
        mouseLeftDown = true;
    }
    else if(state == GLUT_UP)
        mouseLeftDown = false;
}

 else if(button == GLUT_RIGHT_BUTTON)
 {
    if(state == GLUT_DOWN)
    {
        mouseRightDown = true;
    }
    else if(state == GLUT_UP)
        mouseRightDown = false;
 }

 else if(button == GLUT_MIDDLE_BUTTON)
 {
    if(state == GLUT_DOWN)
    {
        mouseMiddleDown = true;
    }
    else if(state == GLUT_UP)
        mouseMiddleDown = false;
   }
  }

   ///////////////////////////////////////////////////////////////////////////////
  // Inizializzazione di GLUT
  ///////////////////////////////////////////////////////////////////////////////
  void initGLUT(){
 //parametri fake per il lancio di InitGlut
char *myargv[1];
int myargc = 1;
myargv[0]=strdup("MyOpenGL");

//Inizializzazione Glut basso livello
glutInit(&myargc,myargv);

//Lancio funzioni di settaggio finestra,visualizzazione ed altro
glutInitDisplayMode( GLUT_RGBA| GLUT_DOUBLE | GLUT_DEPTH |GLUT_STENCIL);    
glutInitWindowSize(screenWidth, screenHeight);
glutInitWindowPosition(850,100);
glutCreateWindow("Ricostruzione attuale");

    //callback delle funzioni richiamate
    glutDisplayFunc(draw);
    glutTimerFunc(33,timerCB,33);
    glutReshapeFunc(reshape);
    glutMouseFunc(Mouse);
    glutMotionFunc(Motion);

}

  ///////////////////////////////////////////////////////////////////////////////
 //  Thread richiamato per lanciare OPENGL
 ///////////////////////////////////////////////////////////////////////////////

void DRAW3D (void *param){

//abbassa priorità del thread a backgroud
if(!SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN))
    {
        dwError = GetLastError();
        if (ERROR_THREAD_MODE_ALREADY_BACKGROUND == dwError)
        _tprintf(TEXT("Gia' in background\n"));
        else _tprintf(TEXT("Errore nell'entrare in modalita' background (%d)\n"), dwError);
    }

    // Lancia funzione di inizializzazione variabili globali
    initSharedMem();

    //initiGLUT
    initGLUT();
    init();

    //ciclo OpenGL
    glutMainLoop();

    _endthread();

其中 prova 是立方体对象的 vector 容器,该对象是从一个类实例化的,该类通过 6 个顶点以及边长 (lato) 和水平来定义立方体。

使用简单的第一级“读取和绘制”函数(无递归)删除递归函数“addraw”解决了问题(窗口显示正确的 1° 级立方体,可旋转,可缩放......没有崩溃或阻塞窗口)但是我需要在每个分支中绘制所有最大级别的立方体...所以我需要对 vector 进行递归扫描...

所以,我不知道该怎么做...有人可以帮助我吗?

1) 如何只在需要时刷新 OpenGL 绘图? 2) 如何用OpenGL线程绘制包含在多级 vector 中的一系列立方体?

我在 Windows 7 64 位下的 Visual C++ 2010,freeglut 2.8.1

最佳答案

绝对最简单的事情是创建一个显示回调并使用类似 glutPostRedisplay (...) 的方法作为信号通知您线程的主循环来调用您的显示回调。在 GLUT 中,该函数基本上递增一个计数器,该计数器在主循环的每次迭代结束时重置,并告诉 GLUT 窗口脏了(需要重绘),如果它的值 > 0。

信号量在这里就有点过分了,当您需要防止同时访问资源时,它们很有用。那根本不是你需要的。解决这个问题最复杂的方法是让绘图线程休眠,直到它收到重绘信号。对于非交互式渲染,这是一种可接受的方法,但对于交互式渲染,一个简单的忙等待循环检查上面描述的“脏”标志就可以完成工作(事实上,我相信这是GLUT 主循环的一些实现是如何工作的)。

我建议在这里避免 GLUT 的原因是某些实现(例如 OS X 附带的版本)在辅助线程中运行其主循环时存在已知问题。

关于c++ - 接收到输入时 OpenGL 重绘场景,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23019393/

相关文章:

c++ - 在静态上使用未命名的命名空间

c++ - 比较两组 std::weak_ptr

c++ - CUDA 错误 : name followed by "::" must be a class or namespace

c++ - OpenGL 混合在纹理周围创建白色边框

opengl - VTK(可视化工具包)与 OSG(OpenSceneGraph),其他?

c++ - 如何在 OpenCV 的 cvShowImage() 函数调用的窗口中显示中文文本?

c - 单核和双核多线程

multithreading - 使用关键部分避免 Delphi 中的缓存一致性问题?

java - 一个 Java 线程如何检查另一个线程的状态,例如另一个是否被阻止?

c++ - 用于读写的 OpenCL OpenGL 互操作内核参数