{
Nesta lição, ensinarei como usar três métodos diferentes de filtragem de textura.
Ensina como usar o teclado para mover objetos na cena e também como aplicar iluminação simples em uma cena OpenGL.
Esta lição contém muito conteúdo. Se você tiver dúvidas sobre as lições anteriores, volte e revise-as primeiro.
Antes de entrar no código por trás dele, é importante ter um bom entendimento do básico.
Ainda modificamos o código da primeira lição.
A diferença de antes é que sempre que houver alguma grande mudança, escreverei o código inteiro.
Primeiro temos que adicionar a unidade SysUtils e a unidade Glaux.
}
Usos
SysUtils,
opengl,
Windows,
Mensagens,
Glaux Em '../../GLAUX/Glaux.pas';
//As linhas a seguir adicionam novas variáveis.
//Adicionamos três variáveis booleanas.
// A variável light rastreia se a luz está acesa.
//As variáveis lp e fp são usadas para armazenar se as teclas 'L' e 'F' estão pressionadas.
//Explicarei a importância dessas variáveis mais tarde. Por enquanto, deixe isso de lado.
light : Boolean; // fonte de luz ligada/desligada;
lp : Boolean; // A tecla L está pressionada?
fp : Boolean; // A tecla F está pressionada?
//Agora defina 5 variáveis para controlar o tamanho do passo do ângulo de rotação em torno do eixo xey,
//E a velocidade de rotação em torno do eixo xey.
//Além disso, uma variável z é criada para controlar a distância até a profundidade da tela.
xrot: GLfloat; // rotação X
yrot : GLfloat; // rotação Y
xspeed : GLfloat; // Velocidade de rotação X
yspeed : GLfloat; // Velocidade de rotação Y
z : GLfloat = -5.0 f; // Distância profunda na tela
//Em seguida, defina o array usado para criar a fonte de luz.
//Usaremos duas luzes diferentes.
//A primeira é chamada de luz ambiente. A luz ambiente vem de todas as direções.
//Todos os objetos na cena são iluminados pela luz ambiente.
//O segundo tipo de fonte de luz é chamado de luz difusa.
//A luz difusa é gerada por uma fonte de luz específica e cria reflexos nas superfícies dos objetos em sua cena.
//Qualquer superfície de objeto diretamente iluminada por luz difusa torna-se muito brilhante,
//As áreas pouco iluminadas parecem mais escuras.
//Isso produzirá um efeito de sombra muito bom nas bordas da caixa de madeira que criamos.
//O processo de criação de uma fonte de luz é exatamente igual ao de criação de uma cor.
//Os três primeiros parâmetros são os componentes de três cores RGB e o último é o parâmetro do canal alfa.
//Portanto, no código a seguir obtemos luz ambiente branca meio brilhante (0,5f).
//Se não houver luz ambiente, as áreas não atingidas pela luz difusa ficarão muito escuras.
LightAmbient: Array[0..3] Of GLfloat = (0,5, 0,5, 0,5, 1,0); //Parâmetros de luz ambiente (novos);
//Na próxima linha de código geramos a luz difusa mais brilhante.
//Todos os valores dos parâmetros são levados ao valor máximo de 1.0f.
//Vai brilhar na frente da nossa caixa de madeira e ficar bem.
LightDiffuse: Array[0..3] Of GLfloat = (1.0, 1.0, 1.0, 1.0) // Parâmetros de luz difusa (novos);
//Finalmente salvamos a posição da fonte de luz.
//Os três primeiros parâmetros são iguais aos de glTranslate.
//Os deslocamentos no eixo XYZ são respectivamente.
//Como queremos que a luz incida diretamente na frente da caixa de madeira, os deslocamentos no eixo XY são ambos 0,0.
//O terceiro valor é o deslocamento no eixo Z.
//Para garantir que a luz esteja sempre na frente da caixa de madeira,
//Então movemos a fonte de luz da tela em direção ao observador (que é você).
//Normalmente chamamos a posição da tela, ou seja, o vidro da tela do monitor, de ponto 0,0 do eixo Z.
//Portanto, o deslocamento no eixo Z é finalmente definido como 2,0.
//Se você puder ver a fonte de luz, ela flutua na frente do seu monitor.
//Claro, você não pode ver a caixa se ela não estiver atrás do vidro da tela do monitor.
//『Nota do tradutor: Agradeço a paciência de NeHe.
//Para ser sincero, às vezes fico irritado. Por que ele fala tão bobagem sobre uma coisa tão simples?
//Mas se tudo estivesse claro, você ainda folhearia páginas como essa e leria sem parar? 』
//O último parâmetro é considerado 1.0f.
//Isso dirá ao OpenGL que as coordenadas especificadas aqui são as posições da fonte de luz. Explicarei mais em tutoriais futuros.
LightPosition: Array[0..3] Of GLfloat = (0.0, 0.0, 2.0, 1.0) // Posição da fonte de luz (nova));
//A variável filter monitora o tipo de textura usada na exibição.
//A primeira textura (textura 0) é construída usando o método de filtragem gl_nearest (não suave).
//A segunda textura (textura 1) usa o método gl_linear (filtragem linear),
//A imagem mais próxima da tela parece mais suave.
//A terceira textura (textura 2) usa o método de filtragem mipmapped,
//Isso criará uma textura muito bonita.
//Dependendo do nosso tipo de uso, o valor da variável de filtro é igual a 0, 1 ou 2 respectivamente.
//Vamos começar com a primeira textura.
//texture aloca espaço de armazenamento para três texturas diferentes.
//Eles estão localizados em textura[0], textura[1] e textura[2] respectivamente.
filtro: GLuint; // Tipo de filtro
textura: Array[0..2] Of GLuint; // Espaço de armazenamento para 3 texturas
Procedimento glGenTextures(n: GLsizei; Var texturas: GLuint externo stdcall);
opengl32;
Procedimento glBindTexture(destino: GLenum; textura: GLuint externo);
opengl32;
Função gluBuild2DMipmaps(destino: GLenum; componentes, largura, altura: GLint;
formato, tipo: GLenum dados: Ponteiro): Inteiro stdcall;
'gluBuild2DMipmaps';
{
Agora carregue um bitmap e use-o para criar três texturas diferentes.
Esta lição usa a biblioteca auxiliar glaux para carregar bitmaps.
Portanto você deve confirmar se a biblioteca glaux está incluída durante a compilação.
Eu sei que tanto o Delphi quanto o VC++ incluem a biblioteca glaux, mas não há garantia de que outras linguagens a tenham.
"Nota do tradutor: glaux é uma biblioteca auxiliar OpenGL. De acordo com as características de plataforma cruzada do OpenGL,
O código deve ser comum em todas as plataformas. Mas a biblioteca auxiliar não é a biblioteca padrão oficial do OpenGL.
Não disponível em todas as plataformas. Mas está disponível na plataforma Win32.
Haha, claro que o BCB também não é problema. 』Aqui eu apenas anoto o código recém-adicionado.
Se você tiver dúvidas sobre uma determinada linha de código, consulte o Tutorial 6.
Essa lição explica o carregamento e a criação de texturas detalhadamente.
Após o trecho de código anterior e antes de glResizeWnd (),
Adicionamos o seguinte código. Isso é quase idêntico ao código usado para carregar o bitmap na Lição 6.
}
Função LoadBmp (nome do arquivo: pchar): PTAUX_RGBImageRec;
Var
BitmapFile : Thandle; // identificador de arquivo
Começar
If Filename = '' Then // Certifique-se de que o nome do arquivo seja fornecido.
resultado := Nil; // Se não for fornecido, retorne NULL;
BitmapFile := FileOpen(Filename, fmOpenWrite); //Tenta abrir o arquivo
Se BitmapFile > 0 Então // O arquivo existe?
Começar
FileClose(BitmapFile); //Fecha o identificador
result := auxDIBImageLoadA(filename); //Carrega o bitmap e retorna o ponteiro
Fim
Outro
resultado := Nil; // Se o carregamento falhar, retorne NiL.
Fim;
Function LoadTexture: boolean; //Carrega o bitmap e converte-o em uma textura
Var
Status: booleano; // Indicador de status
TextureImage: Array[0..1] Of PTAUX_RGBImageRec; // Cria espaço de armazenamento de textura
Começar
Estado := falso;
ZeroMemory(@TextureImage, sizeof(TextureImage)); // Define o ponteiro para NULL
TextureImage[0] := LoadBMP('Walls.bmp');
Se TextureImage[0] <> Nulo Então
Começar
Status := VERDADEIRO; // Define o status como VERDADEIRO;
glGenTextures(1, textura[0]); // Cria textura
//Na Lição 6 usamos mapeamento de textura linear filtrada.
//Isso requer uma quantidade bastante alta de poder de processamento da máquina, mas eles parecem muito bons.
//Nesta lição, a primeira textura que vamos criar utiliza o método GL_NEAREST.
//Em princípio, este método não realiza filtragem.
//Consome muito pouco poder de processamento e parece ruim.
//A única vantagem é que nosso projeto pode rodar normalmente tanto em máquinas rápidas quanto lentas.
//Você notará que usamos GL_NEAREST para MIN e MAG,
//Você pode misturar GL_NEAREST e GL_LINEAR.
//A textura ficará melhor, mas nos preocupamos mais com a velocidade, por isso usamos todos os mapas de baixa qualidade.
//MIN_FILTER é usado quando a imagem é desenhada em tamanho menor que o tamanho original da textura.
//MAG_FILTER é usado quando a imagem é desenhada maior que o tamanho original da textura.
// Cria o mapa de filtro mais próximo
glBindTexture(GL_TEXTURE_2D, textura[0]);
//Gera textura
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].tamanhoX,
TexturaImagem[0].tamanhoY, 0, GL_RGB, GL_UNSIGNED_BYTE,
TexturaImage[0].data);
//A próxima textura é a mesma da Lição 6, filtragem linear. A única diferença é que desta vez é colocado
//textura[1]. Porque esta é a segunda textura. Se colocado
//textura[0], substituirá a textura GL_NEAREST criada anteriormente.
glBindTexture(GL_TEXTURE_2D, textura[1]); //Use uma textura típica gerada a partir de dados bitmap
//Gera textura
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].tamanhoX,
TexturaImagem[0].tamanhoY, 0, GL_RGB, GL_UNSIGNED_BYTE,
TexturaImage[0].data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//A seguir está uma nova maneira de criar texturas. Mapeamento Mip!
//『Nota do tradutor: não consigo traduzir esta palavra em chinês, mas não importa. Depois de ler este parágrafo, você saberá que o significado é o mais importante. 』
//Você pode notar que quando a imagem fica muito pequena na tela, muitos detalhes são perdidos.
//O padrão que parecia bom agora ficou feio. Quando você diz ao OpenGL para criar uma textura mapeada em mip,
//OpenGL tentará criar texturas de alta qualidade de diferentes tamanhos. Quando você desenha uma textura mapeada em mip na tela,
//O OpenGL escolherá a textura mais bonita (com mais detalhes) que criou para desenhar,
//Em vez de apenas dimensionar a imagem original (o que resultará em perda de detalhes).
//Eu disse uma vez que existem maneiras de contornar as limitações que o OpenGL impõe à largura e altura da textura - 64, 128, 256, etc.
//A solução é gluBuild2DMipmaps. Pelo que descobri, você pode usar bitmaps arbitrários para criar texturas.
//OpenGL irá dimensioná-lo automaticamente para o tamanho normal.
//Por ser a terceira textura, salvamos em textura[2]. Desta forma, todas as três texturas desta lição foram criadas.
//Cria textura MipMapped
glBindTexture(GL_TEXTURE_2D, textura[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST); // (novo)
//A linha a seguir gera textura mapeada em mip.
//Usamos três cores (vermelho, verde, azul) para gerar uma textura 2D.
//TextureImage[0].sizeX é a largura do bitmap,
//TextureImage[0].sizeY é a altura do bitmap,
//(====Por algum motivo, esta função no Delphi não possui o parâmetro height,
//Mas tem isso na ajuda não sei mais o que o Delphi vai fazer, o que me deixa deprimido...
//Finalmente, eu mesmo escrevi um gluBuild2DMipmaps anteriormente,
//Para carregar a função gluBuild2DMipmaps em glu32.dll =====)
//GL_RGB significa que usamos cores RGB por sua vez.
//GL_UNSIGNED_BYTE significa que a unidade de dados de textura são bytes.
//TextureImage[0].data aponta para o bitmap que usamos para criar a textura.
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0].sizeX,
TextureImage[0].sizey, GL_RGB, GL_UNSIGNED_BYTE,
TexturaImage[0].data); //(novo) }
Fim;
Se atribuído(TextureImage[0]) Then // Se a textura existe
Se atribuído(TextureImage[0].data) Then // Se a imagem de textura existe
TextureImage[0].data := Nil; // Libera a memória ocupada pela imagem de textura
TextureImage[0] := Nil; // Libera a estrutura da imagem
resultado := Status; // Status de retorno
Fim;
//Então é hora de carregar a textura e inicializar as configurações do OpenGL.
//A primeira linha da função GLInit usa o código acima para carregar a textura.
//Depois de criar a textura, chamamos glEnable(GL_TEXTURE_2D) para habilitar o mapeamento de textura 2D.
//O modo de sombra está definido para sombreamento suave (sombreamento suave).
//A cor de fundo é definida como preta, ativamos o teste de profundidade e, em seguida, ativamos os cálculos de perspectiva otimizados.
Procedimento glInit(); // Inicie todas as configurações do OpenGL aqui
Começar
If (Not LoadTexture) Then // Chama a sub-rotina de carregamento de textura
exit; // Se não conseguir carregar, saia
glEnable(GL_TEXTURE_2D); // Habilita mapeamento de textura
glShadeModel(GL_SMOOTH); // Habilita suavização de sombra
glClearColor(0.0, 0.0, 0.0, 0.0); // fundo preto
glClearDepth(1.0); //Definir o buffer de profundidade
glEnable(GL_DEPTH_TEST); // Habilita teste de profundidade
glDepthFunc(GL_LESS); // Tipo de teste de profundidade realizado
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //Cálculo de projeção de perspectiva altamente otimizado
//Agora comece a configurar a fonte de luz. A próxima linha abaixo define a quantidade de luz ambiente emitida,
//Fonte de luz light1 começa a emitir luz.
//No início desta lição, armazenamos a quantidade de luz ambiente no array LightAmbient.
//Agora usaremos esse array (luz ambiente com meio brilho).
glLightfv(GL_LIGHT1, GL_AMBIENT, @LightAmbient[0]);
//Em seguida definimos a quantidade de luz difusa. Ele é armazenado na matriz LightDiffuse (luz branca com brilho total).
glLightfv(GL_LIGHT1, GL_DIFFUSE, @LightDiffuse[0]);
//Em seguida, defina a posição da fonte de luz.
//A posição é armazenada no array LightPosition
//(localizado exatamente no centro da frente da caixa de madeira, X-0.0, Y-0.0, moveu 2 unidades em direção ao observador na direção Z <fora da tela>).
glLightfv(GL_LIGHT1, GL_POSITION, @LightPosition); // Posição da fonte de luz
//Finalmente, habilitamos a fonte de luz número um. Ainda não ativamos GL_LIGHTING,
//Então você não consegue ver nenhuma luz.
//Lembre-se: apenas configurar, posicionar ou mesmo habilitar a fonte de luz não funcionará.
//A menos que habilitemos GL_LIGHTING.
glEnable(GL_LIGHT1); // Habilita fonte de luz nº 1;
Fim;
//O próximo trecho de código desenha o cubo texturizado. Eu apenas anoto o novo código.
//Se você tiver dúvidas sobre código sem anotações, volte para a Lição 6.
Procedimento glDraw(); // Todo desenho começa aqui
Começar
glClear(GL_COLOR_BUFFER_BIT Ou GL_DEPTH_BUFFER_BIT); // Limpa tela e buffer de profundidade;
glLoadIdentity(); //Redefinir a matriz de observação do modelo atual
//As próximas três linhas de código posicionam e giram o cubo de textura.
//glTranslatef(0.0,0.0,z) move as unidades Z do cubo ao longo do eixo Z.
//glRotatef(xrot,1.0f,0.0f,0.0f) gira o cubo em torno do eixo X xrot.
//glRotatef(yrot,0.0f,1.0f,0.0f) gira o cubo yrot em torno do eixo Y.
glTranslatef(0.0, 0.0, z); // Move para dentro/fora da tela z unidades;
glRotatef(xrot, 1.0, 0.0, 0.0); // Gira em torno do eixo X
glRotatef(yrot, 0.0, 1.0, 0.0); // Gira em torno do eixo Y;
//A próxima linha é semelhante ao que fizemos na Lição 6.
//A diferença é que desta vez a textura que ligamos é a textura[filtro],
//Em vez de textura[0] na lição anterior.
//Sempre que pressionarmos a tecla F, o valor do filtro aumentará.
//Se este valor for maior que 2, a variável filter será redefinida para 0.
//Quando o programa for inicializado, o valor da variável filter também será definido como 0.
//Usando a variável filter podemos selecionar qualquer uma das três texturas.
glBindTexture(GL_TEXTURE_2D, textura[filtro]); //Selecione a textura determinada pelo filtro
glBegin(GL_QUADS); // Começa a desenhar quadriláteros
//glNormal3f é novo nesta lição. Normal significa normal.
//A chamada normal refere-se a uma reta que passa por um ponto de uma superfície (polígono) e é perpendicular a esta superfície (polígono).
//Ao usar uma fonte de luz, um normal deve ser especificado. A normal informa ao OpenGL a orientação do polígono e indica a frente e o verso do polígono.
//Se as normais não forem especificadas, coisas estranhas podem acontecer: superfícies que não deveriam ser iluminadas são iluminadas, e a parte de trás do polígono também é iluminada....
//A propósito, a normal deve apontar para fora do polígono. Olhando para a frente da caixa você notará que a normal está na mesma direção do eixo Z positivo.
//Isso significa que o normal está apontando para o observador – você mesmo. Isto é exatamente o que esperamos.
//Para o verso da caixa de madeira, como queremos, o normal é ficar de costas para o observador.
//Se o cubo for girado 180 graus ao longo do eixo X ou Y, a normal na parte frontal ainda estará voltada para o observador, e a normal na parte posterior ainda estará voltada para longe do observador.
//Em outras palavras, não importa qual seja a superfície, desde que esteja voltada para o observador, a normal dessa superfície aponta para o observador.
//Como a fonte de luz está imediatamente adjacente ao observador, sempre que a normal estiver voltada para o observador, esta superfície será iluminada.
//E quanto mais próximo o normal estiver da fonte de luz, mais brilhante ele parecerá.
//Se você colocar o ponto de observação dentro do cubo, você terá escuridão dentro do normal.
//Porque o normal aponta para fora. Se não houver fonte de luz dentro do cubo, é claro que ficará escuro como breu.
// Frente
glNormal3f(0.0, 0.0, 1.0); // pontos normais para o observador
glTexCoord2f(0,0, 0,0);
glVertex3f(-1.0, -1.0, 1.0); // Textura e canto inferior esquerdo do quadrante
glTexCoord2f(1,0, 0,0);
glVertex3f(1.0, -1.0, 1.0); // Textura e canto inferior direito do quadrante
glTexCoord2f(1,0, 1,0);
glVertex3f(1.0, 1.0, 1.0); //Textura e canto superior direito do quadrante
glTexCoord2f(0,0, 1,0);
glVertex3f(-1.0, 1.0, 1.0); //Textura e canto superior esquerdo do quadrante
// mais tarde
glNormal3f(0.0, 0.0, -1.0); // Normal fica afastado do visualizador
glTexCoord2f(1,0, 0,0);
glVertex3f(-1.0, -1.0, -1.0); // Textura e canto inferior direito do quadrante
glTexCoord2f(1,0, 1,0);
glVertex3f(-1.0, 1.0, -1.0); //Textura e canto superior direito do quadrante
glTexCoord2f(0,0, 1,0);
glVertex3f(1.0, 1.0, -1.0); //Textura e canto superior esquerdo do quadrante
glTexCoord2f(0,0, 0,0);
glVertex3f(1.0, -1.0, -1.0); // Textura e canto inferior esquerdo do quadrante
//superfície superior
glNormal3f(0.0, 1.0, 0.0); // normal para cima
glTexCoord2f(0,0, 1,0);
glVertex3f(-1.0, 1.0, -1.0); //Textura e canto superior esquerdo do quadrante
glTexCoord2f(0,0, 0,0);
glVertex3f(-1.0, 1.0, 1.0); // Textura e canto inferior esquerdo do quadrante
glTexCoord2f(1,0, 0,0);
glVertex3f(1.0, 1.0, 1.0); // Textura e canto inferior direito do quadrante
glTexCoord2f(1,0, 1,0);
glVertex3f(1.0, 1.0, -1.0); //Textura e canto superior direito do quadrante
// Fundo
glNormal3f(0.0, -1.0, 0.0); //normal voltado para baixo
glTexCoord2f(1,0, 1,0);
glVertex3f(-1.0, -1.0, -1.0); // Textura e canto superior direito do quadrante
glTexCoord2f(0,0, 1,0);
glVertex3f(1.0, -1.0, -1.0); //Textura e canto superior esquerdo do quadrante
glTexCoord2f(0,0, 0,0);
glVertex3f(1.0, -1.0, 1.0); // Textura e canto inferior esquerdo do quadrante
glTexCoord2f(1,0, 0,0);
glVertex3f(-1.0, -1.0, 1.0); // Textura e canto inferior direito do quadrante
// certo
glNormal3f(1.0, 0.0, 0.0); //normal à direita
glTexCoord2f(1,0, 0,0);
glVertex3f(1.0, -1.0, -1.0); // Textura e canto inferior direito do quadrante
glTexCoord2f(1,0, 1,0);
glVertex3f(1.0, 1.0, -1.0); //Textura e canto superior direito do quadrante
glTexCoord2f(0,0, 1,0);
glVertex3f(1.0, 1.0, 1.0); //Textura e canto superior esquerdo do quadrante
glTexCoord2f(0,0, 0,0);
glVertex3f(1.0, -1.0, 1.0); // Textura e canto inferior esquerdo do quadrante
// esquerda
glNormal3f(-1.0, 0.0, 0.0); //normal à esquerda
glTexCoord2f(0,0, 0,0);
glVertex3f(-1.0, -1.0, -1.0); // Textura e canto inferior esquerdo do quadrante
glTexCoord2f(1,0, 0,0);
glVertex3f(-1.0, -1.0, 1.0); // Textura e canto inferior direito do quadrante
glTexCoord2f(1,0, 1,0);
glVertex3f(-1.0, 1.0, 1.0); //Textura e canto superior direito do quadrante
glTexCoord2f(0,0, 1,0);
glVertex3f(-1.0, 1.0, -1.0); //Textura e canto superior esquerdo do quadrante
glEnd();
xrot := xrot + xspeed; // xrot aumenta unidades xspeed;
yrot := Yrot + yspeed; // yrot aumenta a unidade yspeed;
Fim;
//Agora vá para a função principal WinMain().
//Adicionaremos código de controle aqui para ligar e desligar a fonte de luz, girar a caixa de madeira, alternar os métodos de filtragem e mover a caixa de madeira para mais perto e mais longe.
// Perto do final da função WinMain() você verá a linha de código SwapBuffers(hDC).
//Em seguida, adicione o seguinte código após esta linha.
//O código irá verificar se a tecla L foi pressionada.
//Se a tecla L foi pressionada, mas o valor de lp não é falso, significa que a tecla L não foi liberada e nada acontecerá neste momento.
SwapBuffers(h_DC); // Buffer de troca (buffer duplo)
Se (keys[ord('L')] e não lp) Então
Começar
//Se o valor de lp for falso,
//Significa que a tecla L ainda não foi pressionada ou foi liberada, então lp será definido como TRUE.
//A razão para verificar estas duas condições ao mesmo tempo é evitar que a tecla L seja pressionada.
//Este código é executado repetidamente e faz com que o formulário pisque continuamente.
//Depois que lp for definido como verdadeiro, o computador saberá que a tecla L foi pressionada.
//Podemos ligar/desligar a fonte de luz de acordo: a variável booleana light controla a ativação/desativação da fonte de luz.
lp := verdadeiro; // lp está definido como VERDADEIRO
light := Não light; // Muda a fonte de luz para TRUE/FALSE;
Se não houver luz, então // Se não houver fonte de luz
glDisable(GL_LIGHTING) //Desativa a fonte de luz
Mais // Outros
glEnable(GL_LIGHTING); //Habilita fonte de luz
Fim;
If Not keys[ord('L')] Then //A tecla L foi liberada?
lp := FALSE; // Se sim, defina lp como FALSE;
//Então faça uma verificação semelhante para a tecla "F".
//Se a tecla "F" for pressionada e a tecla "F" não for pressionada ou nunca tiver sido pressionada,
//Define a variável fp como verdadeira. Isso significa que a tecla está sendo pressionada.
//Em seguida, adicione um à variável de filtro. Se a variável do filtro for maior que 2
//(Como o array que usamos aqui é textura[3], texturas maiores que 2 não existem),
//Redefinimos a variável de filtro para 0.
If (keys[ord('F')] And Not fp) Then // A tecla F está pressionada?
Começar
fp := VERDADEIRO; // fp está definido como VERDADEIRO
inc(filtro); // Adiciona um ao valor do filtro
Se filtro > 2 Então // É maior que 2?
filtro := 0; // Se for redefinido para 0
Fim;
If Not keys[ord('F')] Then //A tecla F foi liberada?
fp := FALSE; // Se fp estiver definido como FALSE
//Essas quatro linhas verificam se a tecla PageUp está pressionada. Nesse caso, diminua o valor da variável z. Desta forma, a chamada para glTranslatef(0.0f,0.0f,z) incluída na função DrawGLScene afastará a caixa de madeira do visualizador.
Se chaves[VK_PRIOR] Então //PageUp é pressionado?
z := z - 0.02; // Se pressionado, move a caixa de madeira para dentro da tela.
//As próximas quatro linhas verificam se a tecla PageDown está pressionada. Em caso afirmativo, aumente o valor da variável z. Desta forma, a chamada glTranslatef(0.0f,0.0f,z) incluída na função DrawGLScene aproximará a caixa de madeira do observador.
Se chaves[VK_NEXT] Então // PageDown está pressionado?
z := z + 0.02; //Se pressionado, move a caixa de madeira em direção ao observador.
//Agora verifique as teclas de seta. Pressione as teclas de direção esquerda e direita para diminuir ou aumentar xspeed de acordo.
//Pressione as teclas de direção para cima e para baixo para diminuir ou aumentar a velocidade y de acordo.
//Lembre-se que em tutoriais futuros se os valores de xspeed e yspeed forem aumentados, o cubo irá girar mais rápido.
//Se você continuar pressionando uma determinada tecla de direção, o cubo girará mais rápido naquela direção.
If keys[VK_UP] Then // A tecla de direção para cima está pressionada?
xspeed := xspeed - 0.01; //Se sim, reduza xspeed
If keys[VK_DOWN] Then //A tecla de direção para baixo foi pressionada?
xspeed := xspeed + 0.01; //Se sim, aumente xspeed
If keys[VK_RIGHT] Then //A tecla de direção Direita está pressionada?
yspeed := yspeed + 0.01; //Se sim, aumente yspeed
If keys[VK_LEFT] Then //A tecla de direção Esquerda está pressionada?
yspeed := yspeed - 0.01; //Se sim, reduza yspeed
If (keys[VK_ESCAPE]) Then // Se a tecla ESC for pressionada
concluído := Verdadeiro
Execute-o e veja o efeito