quarta-feira, 6 de novembro de 2013

Desenhando figuras geométricas com o OpenGL e o OpenTK

Neste segundo post da nossa série sobre o OpenGL no Visual Studio, vamos tratar um pouco sobre o desenho de figuras geométricas. Para aqueles que desejam executar os passos aqui em C#, recomendo o post de Christiam Mena, que está em espanhol, mas é de fácil compreensão (e é uma das fontes de nosso texto, ao lado dos tutoriais da NeHe Productions).

Inicializando o ViewPort

Antes de desenharmos qualquer coisa em nosso GLControl, devemos primeiro definir algumas das propriedades do ViewPort, que é a janela de visualização de desenhos. No artigo de Christiam Mena, ele cria uma função separada para fazer esta inicialização, o que nos permite usar o mesmo código em mais de um local. A função fica assim:
public: System::Void SetupViewport()
        {
            float aspectRatio = safe_cast<float>(glGraphicWindow->Width)/safe_cast<float>(glGraphicWindow->Height);
            GL::Viewport(0, 0, glGraphicWindow->Width, glGraphicWindow->Height);
            GL::MatrixMode(MatrixMode::Projection);
            GL::LoadIdentity();
            GL::Ortho(-1, 1, -1, 1, -1, 1);
            GL::MatrixMode(MatrixMode::Modelview);
            GL::LoadIdentity();
        }
O comando Viewport vai definir as dimensões da cena OpenGL, e por isto usamos as dimensões do próprio controle GLControl que criamos.
Depois disto, usamos o comando MatrixMode, com o parâmetro Projection. Isto vai instruir ao OpenGL que os próximos comandos irão afetar a matriz de projeção. LoadIdentity é similar a um reset. Ele vai reinicializar a matriz de projeção para seus valores padrão.
Já o comando Ortho cria o volume de visualização ortográfica.
Usamos novamente o comando MatrixMode para trabalharmos agora com a matriz Modelview. É nesta matriz que as informações de nosso modelo serão armazenadas. Como fizemos com a matriz de projeção, resetamos a matriz ModelView com o comando LoadIdentity.
Agora vamos empregar esta função no evento Load do controle GLControl:
private: System::Void glGraphicWindow_Load(System::Object^  sender, System::EventArgs^  e) 
         {
            GL::ClearColor(Color::Black);
            SetupViewport();
         }
O comando ClearColor já foi apresentado no último post da série. Chamando aqui nossa função SetupViewport, nosso ViewPort está inicializado.

Desenhando um polígono

O nosso polígono será desenhado na função Paint do controle GLControl. O código para desenhá-lo esta a seguir:
private: System::Void glGraphicWindow_Paint(System::Object^  sender, System::Windows::Forms::PaintEventArgs^  e) 
         {
            GL::Clear(ClearBufferMask::ColorBufferBit | ClearBufferMask::DepthBufferBit);
            GL::Color3(Color::Red);
            GL::Begin(BeginMode::Quads);
            GL::Vertex2(-0.5f, 0.5f);
            GL::Vertex2(-0.5f, -0.5f);
            GL::Vertex2(0.5f, -0.5f);
            GL::Vertex2(0.5f, 0.5f);
            GL::End();
            glGraphicWindow->SwapBuffers();
         }
O código aqui foi baseado no código de Christiam. O comando Clear prepara o nosso buffer para o desenho. Color3 é o comando usado para escolher a cor que vamos usar para desenhar os vértices. É o comando Begin que informa que estamos iniciando o desenho de polígonos. Ele deve ser encerrado posteriormente por um comando End. Entre estes dois comandos, devemos informar os vértices de nosso desenho, e o parâmetro usado em Begin informará se estes vértices fazem parte de triângulos ou quadrados. Aqui informamos que vamos desenhar Quadrados.
Assim, o comando Vertex2 é o comando usado para criar um vértice 2D. Como são 4 vértices, criamos apenas um quadrado.
Por fim, depois do comando End, temos o SwapBuffers, que troca o buffer de trabalho com o buffer em exibição.
Agora, o Christiam observa aqui algo muito interessante. Se o seu GLControl for um retângulo (com uma largura diferente da altura), seus quadrados também ficarão assim. A solução para isto é calcular, na inicialização do ViewPort, a razão de aspecto de seu controle, e usar isto no comando Ortho. A função SetupViewport então ficará assim:
public: System::Void SetupViewport()
        {
            GL::Viewport(0, 0, glGraphicWindow->Width, glGraphicWindow->Height);
            GL::MatrixMode(MatrixMode::Projection);
            GL::LoadIdentity();
            GL::Ortho(-aspectRatio, aspectRatio, -1, 1, -1, 1);
            GL::MatrixMode(MatrixMode::Modelview);
            GL::LoadIdentity();
        }
Nosso quadrado agora poderá ficar assim:


Além disto, o controle GLControl possui uma propriedade Dock, que se definida para Fill, fará com que o controle ocupe toda a janela. Fazendo-se isto, poderemos redimensionar a janela, o que causará o mesmo efeito no controle. Observe que isto fará com que nosso retângulo mude de lugar ou até desapareça. Para mudar isto, crie o evento Resize do controle GLControl, e adicione o seguinte código:
private: System::Void glGraphicWindow_Resize(System::Object^  sender, System::EventArgs^  e) 
         {
            SetupViewport();
            glGraphicWindow->Invalidate();
         }
A função Invalidate invalida toda a cena. Isto na prática faz com que a cena seja redesenhada.

Trabalhando com cores

Como foi dito acima, o comando Color escolhe a cor que será usada. Quando desenhamos nosso quadrado, escolhemos a cor vermelha e mantivemos esta cor assim... No entanto, podemos escolher uma cor diferente para cada vértice do quadrado. Por exemplo no código abaixo:
private: System::Void glGraphicWindow_Paint(System::Object^  sender, System::Windows::Forms::PaintEventArgs^  e) 
         {
            GL::Clear(ClearBufferMask::ColorBufferBit | ClearBufferMask::DepthBufferBit);
            GL::Begin(BeginMode::Quads);
            GL::Color3(Color::Red);
            GL::Vertex2(-0.5f, 0.5f);
            GL::Color3(Color::Blue);
            GL::Vertex2(-0.5f, -0.5f);
            GL::Color3(Color::Green);
            GL::Vertex2(0.5f, -0.5f);
            GL::Color3(Color::Yellow);
            GL::Vertex2(0.5f, 0.5f);
            GL::End();
            glGraphicWindow->SwapBuffers();
         }
Nós teremos o seguinte efeito:

Conclusão

Criamos aqui um quadrado a partir de 4 vetores e definimos cores diferentes para cada um deles. O próximo passo é seguir para o desenho 3D.

Nenhum comentário:

Postar um comentário

Você também poderá gostar de