OpenSceneGraph: Gerenciando o Windows e os modos de exibição

imagem

1. Introdução


Já dissemos que a classe osg :: Camera gerencia o contexto gráfico OpenGL associado. O contexto gráfico encapsula informações sobre como e onde os objetos são desenhados e quais atributos de estado são aplicados a eles. O contexto é entendido como uma janela gráfica, ou melhor, sua área de cliente, ou buffer de pixel OpenGL, que armazena dados de pixels sem transferi-los para o buffer de quadros.

O OSG usa a classe osg :: GraphicsContext para representar um contexto gráfico abstrato e a classe osg :: GraphicsWindow para representar uma janela gráfica abstrata. Este último possui um método getEventQueue () para gerenciar eventos a partir de elementos da GUI. De um modo geral, um contexto gráfico é um conceito específico de plataforma; portanto, o OSG cuida da maior parte do trabalho de criação de uma janela e associa seu contexto ao contexto OpenGL. Quando você chama o método createGraphicsContext () da classe osg :: GraphicsContext (), o código necessário (e muito, acredite!) Será gerado automaticamente pelo pré-processador, dependendo da plataforma. Tudo o que é necessário para nós é passar para esse método um argumento do tipo osg :: GraphicsContex :: Traits que contém uma descrição de qual janela queremos receber.

1. A classe osg :: DisplaySettings


O OSG permite que o desenvolvedor gerencie as configurações globais de exibição, com base nas câmeras, visualizadores e elementos da cena. Para isso, é utilizado o padrão singleton, ou seja, um objeto exclusivo contendo essas configurações, implementadas na forma da classe osg :: DisplaySettings, que pode ser acessada de qualquer lugar do programa. Portanto, em nosso aplicativo, podemos alterar essas configurações a qualquer momento.

osg::DisplaySettings *ds = osg::DisplaySettings::instance(); 

Singleton osg :: DisplaySettings contém as configurações que se aplicam aos dispositivos de renderização recém-criados, o contexto OpenGL da janela de desenho. Você pode variar os seguintes parâmetros:

  1. setDoubleBuffer () - ativa / desativa o buffer duplo. Ativado por padrão.
  2. setDepthBuffer () - ativa / desativa o buffer de profundidade. Ativado por padrão.
  3. Defina a largura do buffer alfa, buffer de estêncil e buffer de acumulação usando métodos como setMinimumNumAlphaBits (). Por padrão, todos os parâmetros são 0.
  4. Permissão para usar anti-aliasing e sua profundidade usando o método setNumMultiSamples (). O padrão é 0.
  5. Ative o modo estéreo. Desativado por padrão.

Considere o uso desse singleton no exemplo de suavização

Osg singleton example :: DisplaySettings
main.h

 #ifndef MAIN_H #define MAIN_H #include <osgDB/ReadFile> #include <osgViewer/Viewer> #endif 

main.cpp

 #include "main.h" int main(int argc, char *argv[]) { (void) argc; (void) argv; osg::DisplaySettings::instance()->setNumMultiSamples(6); osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("../data/cessna.osg"); osgViewer::Viewer viewer; viewer.setSceneData(model.get()); return viewer.run(); } 


Essencial aqui é apenas um desafio.

 osg::DisplaySettings::instance()->setNumMultiSamples(6); 

- definir o parâmetro de suavização, que pode assumir os valores 2, 4 e 6, dependendo do dispositivo gráfico usado. Preste atenção na aparência da lâmina do parafuso cessna sem aplicar suavização



e após a sua aplicação



2. Alterne para o modo janela


A classe osgViewer :: Viewer pode ser reconfigurada muito rapidamente para ser exibida no modo janela. Como você notou, todos os nossos exemplos anteriores foram exibidos em tela cheia. Para alternar o visualizador para o modo janela, existe o método setUpViewInWindow (), que assume como parâmetros as coordenadas do canto superior esquerdo da janela, sua largura e altura em pixels

 viewer.setUpViewInWindow(50, 50, 800, 600); 

Opcionalmente, esse método aceita o quinto parâmetro - o número da tela na qual a janela deve ser exibida, caso você tenha mais de um monitor. Certamente, trabalhando com vários monitores no Windows, você observou que a cena se espalha para todos os monitores no modo de tela cheia (isso não é observado no Linux).

Além disso, nas configurações do projeto, você pode definir a variável de ambiente OSG_WINDOW dessa maneira



que será equivalente a chamar setUpViewInWindow (), que neste caso pode não ser executado.



Para especificar explicitamente a tela na qual o visualizador deve ser exibido no modo de tela inteira, você pode usar o método setUpViewOnSingleScreen () especificando o número da tela como um parâmetro (0 por padrão).

O OSG também suporta displays esféricos de demonstração. Você pode usar o método setUpViewFor3DSphericalDisplay () para personalizar a exibição em uma exibição.

3. Visualizador composto


A classe osgViewer :: Viewer controla uma única exibição exibindo um único gráfico de cena. Além disso, há uma classe osgViewer :: CompositeViewer que suporta várias visualizações e várias cenas. Possui os mesmos métodos run (), frame () e done () para controlar o processo de renderização, mas permite adicionar e remover visualizações independentes usando os métodos addView () e removeView (), além de obter visualizações por seu índice usando o método getView () O objeto view é descrito pela classe osgViewer :: View.

A classe osgViewer :: View é a classe base da classe osgViewer :: Viewer. Permite adicionar um nó raiz com dados da cena, um manipulador de câmera e manipuladores de eventos. A principal diferença entre essa classe (exibição) e a classe visualizador é que ela não permite renderizar a cena com chamadas run () ou frame (). Uma visualização típica que adiciona um cenário se parece com isso

 osgViewer::CompositeViewer multiviewer; multiviewer.addView( view ); 

O visualizador composto permite exibir uma cena em ângulos diferentes, exibindo esses ângulos em janelas diferentes. Também permite exibir cenas independentes em diferentes janelas. Vamos escrever um exemplo simples de como usar um visualizador composto

Exemplo composto
main.h

 #ifndef MAIN_H #define MAIN_H #include <osgDB/ReadFile> #include <osgViewer/CompositeViewer> #endif 

main.cpp

 #include "main.h" //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ osgViewer::View *createView(int x, int y, int w, int h, osg::Node *scene) { osg::ref_ptr<osgViewer::View> view = new osgViewer::View; view->setSceneData(scene); view->setUpViewInWindow(x, y, w, h); return view.release(); } //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ int main(int argc, char *argv[]) { (void) argc; (void) argv; osg::ref_ptr<osg::Node> model1 = osgDB::readNodeFile("../data/cessna.osg"); osg::ref_ptr<osg::Node> model2 = osgDB::readNodeFile("../data/cow.osg"); osg::ref_ptr<osg::Node> model3 = osgDB::readNodeFile("../data/glider.osg"); osgViewer::View *view1 = createView(50, 50, 320, 240, model1); osgViewer::View *view2 = createView(380, 50, 320, 240, model2); osgViewer::View *view3 = createView(185, 330, 320, 240, model3); osgViewer::CompositeViewer viewer; viewer.addView(view1); viewer.addView(view2); viewer.addView(view3); return viewer.run(); } 


Criaremos uma visão separada em uma função que assume como parâmetros a posição e o tamanho da janela, bem como a cena como um ponteiro para seu nó raiz.

 osgViewer::View *createView(int x, int y, int w, int h, osg::Node *scene) { osg::ref_ptr<osgViewer::View> view = new osgViewer::View; view->setSceneData(scene); view->setUpViewInWindow(x, y, w, h); return view.release(); } 

Aqui criamos uma visão controlada por um ponteiro inteligente para um objeto osgViewer :: View

 osg::ref_ptr<osgViewer::View> view = new osgViewer::View; 

defina os dados da cena exibida e o modo de exibição da janela na janela com a posição e tamanho especificados

 view->setSceneData(scene); view->setUpViewInWindow(x, y, w, h); 

Retornamos a visualização da função de acordo com as regras para retornar ponteiros inteligentes

 return view.release(); 

Agora, no programa principal, carregamos três modelos diferentes

 osgViewer::View *view1 = createView(50, 50, 320, 240, model1); osgViewer::View *view2 = createView(380, 50, 320, 240, model2); osgViewer::View *view3 = createView(185, 330, 320, 240, model3); 

crie três tipos diferentes

 osgViewer::View *view1 = createView(50, 50, 320, 240, model1); osgViewer::View *view2 = createView(380, 50, 320, 240, model2); osgViewer::View *view3 = createView(185, 330, 320, 240, model3); 

crie um visualizador composto e inclua visualizações criadas anteriormente

 osgViewer::CompositeViewer viewer; viewer.addView(view1); viewer.addView(view2); viewer.addView(view3); 

e execute a renderização exatamente da mesma maneira que fizemos no caso de uma cena

 return viewer.run(); 

Isso é tudo! Quando o programa é iniciado, temos três janelas diferentes. O conteúdo de cada janela pode ser controlado independentemente. Qualquer uma das janelas pode ser fechada da maneira padrão e sair completamente do aplicativo pressionando Esc.



3. A classe osg :: GraphicsContext :: Traits


A palavra "traços" na tradução do inglês significa "recursos". Portanto, a classe mencionada acima descreve os recursos da janela futura e contém todas as propriedades para descrever o contexto gráfico. Difere da classe osg :: DisplaySettings, que controla as características de todos os contextos gráficos das câmeras recém-criadas. As principais propriedades públicas desta classe estão listadas na tabela abaixo.

Atributo de classeTipoValor padrãoDescrição do produto
xint0 0A posição horizontal inicial da janela
yint0 0A posição vertical inicial da janela
larguraint0 0Largura da janela
alturaint0 0Altura da janela
windowNamestd :: string""Título da janela
windowDecorationboolfalsaSinalizador de exibição do título da janela
vermelhounsigned int8O número de bits de vermelho no buffer de cores OpenGL
verdeunsigned int8O número de bits de verde no buffer de cores OpenGL
azulunsigned int8O número de bits de azul no buffer de cores OpenGL
alfaunsigned int8O número de bits no buffer alfa do OpenGL
profundidadeunsigned int24O número de bits no buffer de profundidade do OpenGL
estêncilunsigned int0 0O número de bits no buffer de estêncil OpenGL
doubleBufferboolfalsaUse buffer duplo
amostrasunsigned int0 0Número de suavização primitivo
quadBufferStereoboolfalsaUse buffer estéreo quádruplo (para equipamento NVidia)
herditedWindowDataosg :: ref_ptrNuloDescritor de dados associado à janela

Para inicializar o objeto Traits, execute o seguinte código

 osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; traits->x = 50; traits->y = 100; ... 

4. Configure a janela do aplicativo OSG


Para criar uma janela com as características especificadas, você deve executar as seguintes etapas:

  1. Configure um objeto do tipo osg :: GraphicsContext :: Traits
  2. Criar um contexto de janela gráfica
  3. Vincule esse contexto gráfico à câmera
  4. Torne a câmera o visualizador principal

Exemplo de traços
main.h

 #ifndef MAIN_H #define MAIN_H #include <osg/GraphicsContext> #include <osgDB/ReadFile> #include <osgViewer/Viewer> #endif 

main.cpp

 #include "main.h" int main(int argc, char *argv[]) { (void) argc; (void) argv; osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; traits->x = 50; traits->y = 50; traits->width = 800; traits->height = 600; traits->windowName = "OSG application"; traits->windowDecoration = true; traits->doubleBuffer = true; traits->samples = 4; osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get()); osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setGraphicsContext(gc); camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); camera->setClearColor( osg::Vec4(0.2f, 0.2f, 0.4f, 1.0f) ); double aspect = static_cast<double>(traits->width) / static_cast<double>(traits->height); camera->setProjectionMatrixAsPerspective(30.0, aspect, 1.0, 1000.0); camera->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON); osg::ref_ptr<osg::Node> root = osgDB::readNodeFile("../data/cessna.osg"); osgViewer::Viewer viewer; viewer.setCamera(camera.get()); viewer.setSceneData(root.get()); return viewer.run(); } 


Para definir preferências de janela, crie uma instância da classe osg :: GraphicsContext :: Traits e inicialize-a com os parâmetros que precisamos

 osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; traits->x = 50; traits->y = 50; traits->width = 800; traits->height = 600; traits->windowName = "OSG application"; traits->windowDecoration = true; traits->doubleBuffer = true; traits->samples = 4; 

Depois disso, criamos um contexto gráfico passando um ponteiro para traços como as configurações

 osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get()); 

Crie uma câmera

 osg::ref_ptr<osg::Camera> camera = new osg::Camera; 

Associamos a câmera ao contexto gráfico criado

 camera->setGraphicsContext(gc); 

Configure a janela de visualização, defina a máscara de limpeza do buffer, defina a cor da limpeza

 camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); camera->setClearColor( osg::Vec4(0.2f, 0.2f, 0.4f, 1.0f) ); 

Configurar uma matriz de projeção em perspectiva

 double aspect = static_cast<double>(traits->width) / static_cast<double>(traits->height); camera->setProjectionMatrixAsPerspective(30.0, aspect, 1.0, 1000.0); 

Não se esqueça de ativar o teste de profundidade, para a exibição correta das faces

 camera->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON); 

Carregando modelo de aeronave

 osg::ref_ptr<osg::Node> root = osgDB::readNodeFile("../data/cessna.osg"); 

Configuramos e iniciamos o visualizador, indicando a câmera que configuramos na qualidade da câmera principal

 osgViewer::Viewer viewer; viewer.setCamera(camera.get()); viewer.setSceneData(root.get()); return viewer.run(); 

Na saída, temos uma janela com os parâmetros necessários



O título da janela não é exibido porque esta função está desativada nas configurações do meu gerenciador de janelas. Se você executar o exemplo no Windows ou Linux com configurações diferentes, o cabeçalho estará no seu lugar.

Para continuar ...

Source: https://habr.com/ru/post/pt437764/


All Articles