Criando texturas
Como estamos usando um cubo, nada melhor do que uma textura de uma caixa para ilustrar nosso exemplo. Estamos portanto pegando a textura de exemplo dos tutoriais da Nehe Productions.Como aplicar esta textura às faces de nosso cubo?
Bem, o primeiro passo é habilitar as texturas, através do comando:
GL::Enable(EnableCap::Texture2D);Assim, habilitamos as texturas. Depois disto, precisamos criar uma textura e atribuir a ela uma imagem. Quando criarmos nosso cubo, devemos então indicar qual o ponto da textura que estamos empregando.
Para criar e carregar a textura, vamos criar uma função, assim como no tutorial da Widget-101, que pode ser lido em espanhol para aqueles que querem fazer o mesmo em C#. A nossa função ficará como está descrito abaixo:
public: int loadTexture(String^ filename) { int id = GL::GenTexture(); GL::BindTexture(TextureTarget::Texture2D, id); //LOAD FILE Bitmap^ image; try { image = gcnew Bitmap(filename); } catch (...) { MessageBox::Show("Imagem não pode ser carregada", "Erro", MessageBoxButtons::OK, MessageBoxIcon::Exclamation); return -1; }; BitmapData^ imageData = image->LockBits(Rectangle(0, 0, image->Width, image->Height), ImageLockMode::ReadOnly, System::Drawing::Imaging::PixelFormat::Format32bppRgb); GL::TexImage2D(TextureTarget::Texture2D, 0, PixelInternalFormat::Rgb, imageData->Width, imageData->Height, 0, OpenTK::Graphics::OpenGL::PixelFormat::Bgra, PixelType::UnsignedByte, imageData->Scan0); image->UnlockBits(imageData); //TEXTURE PROPERTY GL::TexParameter(TextureTarget::Texture2D, TextureParameterName::TextureMinFilter, (int)TextureMinFilter::Linear); GL::TexParameter(TextureTarget::Texture2D, TextureParameterName::TextureMagFilter, (int)TextureMagFilter::Linear); return id; }A primeira função nova é GenTexture, que informa ao OpenGL que queremos gerar um nome de textura. Depois disto usamos a função BindTexture, para vincular o nome que criamos a dados de textura. Isto na prática informa ao OpenGL que estamos usando a textura fornecida no segundo argumento. O próximo passo é carregar a imagem. Isto é feito através do objeto Bitmap, que pega o caminho da imagem passado como argumento para a função.
Depois disto, usamos o objeto BitmapData. Este objeto é o que nos dá acesso aos dados do Bitmap, a seus pixels. A propriedade Scan0 deste objeto é o que nos permite fazer isto, e ele será usado como argumento para a função TexImage2D do OpenGL. É esta a função que carrega os dados da imagem para o OpenGL. O que esta função recebe como parâmetros?
O primeiro parâmetro é qual o tipo de textura que estamos carregando, aqui, uma textura 2D. O próximo parâmetro é o nível de detalhe da imagem, geralmente deixado em 0. O próximo parâmetro é a quantidade de componentes de dados. Como nossa textura é colorida, teremos 3 componentes, vermelho, azul, verde. Os dois próximos parâmetros são largura e altura da textura. O sexto parâmetro é a borda, que geralmente é deixada em 0. O sétimo parâmetro é o formato da imagem, que em nosso caso é Azul, Verde, Vermelho, Alpha Blending, nesta ordem. O próximo parâmetro, PixelType::UnsignedByte, informa que os dados são compostos por unsigned bytes. Por fim, fornecemos a propriedade Scan0 de nossa imagem.
As duas funções TexParameter definem algumas propriedades para quando a textura for maior que a imagem usada (a imagem terá que ser "esticada") ou quando a textura for menor que a imagem usada (a imagem terá que ser "compactada"). Os dois usam o filtro linear.
Usando as texturas
Agora que temos nossa textura, chegou a hora de usá-la. Nós escolhemos a textura com a mesma função que escolhemos uma textura ao criá-la: BindTexture. Como criamos só uma textura, nem precisamos chamá-la aqui. Mas se você criar mais de uma textura, é necessário selecionar qual você deseja através desta função. Um detalhe importante desta função é que ela não pode ser chamada entre GL::Begin e GL:End. Você sempre terá que chamá-la antes destas duas funções.Dito isto, vamos agora reescrever nosso evento Paint:
private: System::Void glGraphicWindow_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) { GL::Clear(ClearBufferMask::ColorBufferBit | ClearBufferMask::DepthBufferBit); OpenTK::Matrix4 lookat = OpenTK::Matrix4::LookAt(OpenTK::Vector3::UnitZ * 3, OpenTK::Vector3::Zero, OpenTK::Vector3::UnitY); GL::MatrixMode(MatrixMode::Modelview); GL::LoadMatrix(lookat); GL::Rotate(angle, OpenTK::Vector3::UnitY); GL::Begin(BeginMode::Quads); { GL::Color3(Color::White); // Face frontal GL::TexCoord2(1.0f, 1.0f); GL::Vertex3(0.5f, 0.5f, -0.5f); GL::TexCoord2(0.0f, 1.0f); GL::Vertex3(-0.5f, 0.5f, -0.5f); GL::TexCoord2(0.0f, 0.0f); GL::Vertex3(-0.5f, -0.5f, -0.5f); GL::TexCoord2(1.0f, 0.0f); GL::Vertex3(0.5f, -0.5f, -0.5f); // Face traseira GL::TexCoord2(1.0f, 1.0f); GL::Vertex3(0.5f, -0.5f, 0.5f); GL::TexCoord2(0.0f, 1.0f); GL::Vertex3(-0.5f, -0.5f, 0.5f); GL::TexCoord2(0.0f, 0.0f); GL::Vertex3(-0.5f, 0.5f, 0.5f); GL::TexCoord2(1.0f, 0.0f); GL::Vertex3(0.5f, 0.5f, 0.5f); // Face Direita GL::TexCoord2(1.0f, 1.0f); GL::Vertex3(0.5f, 0.5f, 0.5f); GL::TexCoord2(0.0f, 1.0f); GL::Vertex3(0.5f, -0.5f, 0.5f); GL::TexCoord2(0.0f, 0.0f); GL::Vertex3(0.5f, -0.5f, -0.5f); GL::TexCoord2(1.0f, 0.0f); GL::Vertex3(0.5f, 0.5f, -0.5f); // Face esquerda GL::TexCoord2(1.0f, 1.0f); GL::Vertex3(-0.5f, 0.5f, 0.5f); GL::TexCoord2(0.0f, 1.0f); GL::Vertex3(-0.5f, -0.5f, 0.5f); GL::TexCoord2(0.0f, 0.0f); GL::Vertex3(-0.5f, -0.5f, -0.5f); GL::TexCoord2(1.0f, 0.0f); GL::Vertex3(-0.5f, 0.5f, -0.5f); // Face superior GL::TexCoord2(1.0f, 1.0f); GL::Vertex3(0.5f, 0.5f, 0.5f); GL::TexCoord2(0.0f, 1.0f); GL::Vertex3(-0.5f, 0.5f, 0.5f); GL::TexCoord2(0.0f, 0.0f); GL::Vertex3(-0.5f, 0.5f, -0.5f); GL::TexCoord2(1.0f, 0.0f); GL::Vertex3(0.5f, 0.5f, -0.5f); // Face inferior GL::TexCoord2(1.0f, 1.0f); GL::Vertex3(0.5f, -0.5f, 0.5f); GL::TexCoord2(0.0f, 1.0f); GL::Vertex3(-0.5f, -0.5f, 0.5f); GL::TexCoord2(0.0f, 0.0f); GL::Vertex3(-0.5f, -0.5f, -0.5f); GL::TexCoord2(1.0f, 0.0f); GL::Vertex3(0.5f, -0.5f, -0.5f); } GL::End(); glGraphicWindow->SwapBuffers(); }Fizemos algumas modificações na função do último post. A primeira foi retirar todas as seleções de cores. Deixamos apenas a seleção da cor branca, no início do processo. Isto acontece por que o OpenGL mistura a cor da textura com a cor que você seleciona. Assim, se você usar vermelho, sua textura irá se misturar com o vermelho, dando uma textura avermelhada. Deixamos em branco, pois assim o OpenGL usará apenas a cor da textura.
A textura é aplicada através do comando TexCoord2, usada acima. Ela usa dois argumentos, que são as coordenadas X e Y da textura. Algo precisa ser dito sobre estas coordenadas. Elas variam entre 0 e 1, sendo que 0 é a origem do eixo e 1 é a coordenada máxima daquele eixo (largura ou altura da textura). Agora que nosso evento Paint está modificado, vamos modificar o evento Load para carregar nossa textura:
private: System::Void glGraphicWindow_Load(System::Object^ sender, System::EventArgs^ e) { GL::ClearColor(Color::Black); GL::Enable(EnableCap::DepthTest); GL::Enable(EnableCap::Texture2D); textureID = loadTexture("Crate.bmp"); SetupViewport(); angle = 0.0f; tmrAnimate->Enabled = true; }Chamamos a função que criamos com o nome da imagem como parâmetro (a imagem está salva no mesmo diretório do executável). A variável textureID é uma variável global que usamos para salvar o ID de nossa textura. Agora que habilitamos as texturas e carregamos a textura do exemplo, podemos executar o programa, que nos dará o seguinte resultado:
O que acontece se mudarmos a cor de Branco para Azul?
E assim, terminamos a aplicação de texturas.
Nenhum comentário:
Postar um comentário