{
Bienvenidos a la lección nueve. A esta altura ya deberías tener un buen conocimiento de OpenGL.
"CKER: Si no, debe ser culpa de mi traductor...".
(Myling agregó: Mi pecado es aún mayor, jaja)
Ha aprendido todos los detalles de la configuración de una ventana OpenGL.
Aprenda a mapear y agregar luz y mezcla de colores (transparencia) a objetos giratorios.
Esta lección debe considerarse un tutorial intermedio.
Aprenderá cómo mover un mapa de bits alrededor de una escena 3D y eliminar píxeles negros del mapa de bits (mediante combinación de colores).
Luego, colorea las texturas en blanco y negro y, finalmente, aprenderás a crear colores intensos.
Y mezcle texturas con diferentes colores entre sí para obtener un efecto de animación simple.
Haremos modificaciones basadas en el código de la primera lección. Primero agregue algunas variables al comienzo del código fuente del programa.
Reescribí todo el código para mayor claridad.
}
var
h_RC: HGLRC; // Contexto de representación (tabla de descripción de sombreado).
h_DC: HDC // Contexto del dispositivo (tabla de descripción del dispositivo)
h_Wnd: HWND // identificador de ventana
h_Instance: HINST; // Instancia del programa (instancia).
teclas: Array[0..255] Of Boolean; // Matriz para rutinas de teclado
{Las siguientes líneas se agregaron recientemente.
twinkle y tp son variables booleanas, lo que significa que solo se pueden establecer en VERDADERO o FALSO.
twinkle se utiliza para rastrear si el efecto de parpadeo está habilitado.
tp se utiliza para comprobar si se presiona o suelta la tecla 'T'.
(tp=TRUE cuando se presiona, tp=FALSE cuando se suelta).}
centelleo: booleano; // Estrellas centelleantes (nuevas)
tp: booleano; // ¿Se presiona 'T' (nuevo)
{Ahora creemos una estructura.
La estructura de las palabras suena aterradora, pero no lo es. (Este es el tipo de registro de Delphi)
Una estructura utiliza un conjunto de tipos simples de datos (y variables, etc.) para expresar una combinación más amplia de datos similares.
Sabemos que estamos siguiendo las estrellas.
Puedes ver las estrellas debajo;
Cada estrella tiene tres valores de color enteros. Uno rojo (r), uno verde (g) y uno azul (b).
Además, cada estrella está a una distancia diferente del centro de la pantalla,
Y puede ser cualquier ángulo en 360 grados con el centro de la pantalla como origen.
Un número de punto flotante de dist para realizar un seguimiento de la distancia.
Un número de ángulo en coma flotante realiza un seguimiento del valor del ángulo de la estrella.
Entonces utilizamos un conjunto de datos para describir el color, la distancia y el ángulo de las estrellas en la pantalla.
Lamentablemente estamos rastreando más de una estrella.
Pero no es necesario crear 50 valores rojos, 50 valores verdes, 50 valores azules, 50 valores de distancia.
y 50 valores de ángulo, y simplemente cree una estrella de matriz. }
Tipo
estrellas = Registro //Crea una estructura para estrellas, nombra la estructura estrellas
r, g, b: entero; // color de las estrellas
dist: GLfloat; // La distancia de la estrella al centro.
ángulo: GLfloat; // El ángulo de la estrella actual
Fin;
var
estrella: Array[0..49] De estrellas // Utilice la estructura 'estrellas' para generar una matriz 'estrella' que contenga 50 elementos
{A continuación configuramos varias variables de seguimiento:
La variable de distancia (zoom) de la estrella al observador,
El ángulo (inclinación) en el que vemos las estrellas,
y el giro variable que hace que la estrella titilante gire alrededor del eje Z.
La variable de bucle se utiliza para dibujar 50 estrellas.
textura[1] se utiliza para almacenar una textura en blanco y negro.
Si necesitas más texturas,
Debe aumentar el tamaño de la matriz de texturas según la cantidad de texturas que decida usar.
}
zoom: GLfloat = -15.0; // La distancia de la estrella al observador.
inclinación: GLfloat = 90.0; // La inclinación de la estrella
spin: GLfloat; // La rotación de la estrella titilante.
bucle: GLuint; // Global l Variable de bucle
textura: Array[0..1] Of GLuint // Almacena una textura
Procedimiento glGenTextures(n: GLsizei; Var texturas: GLuint external);
opengl32;
Procedimiento glBindTexture(destino: GLenum; textura: GLuint externo);
opengl32;
{
El código inmediatamente superior es el código que usamos para cargar la textura.
No voy a explicar este código en detalle.
Este es exactamente el mismo código que usamos en las Lecciones 6, 7 y 8.
El mapa de bits cargado esta vez se llama star.bmp.
Aquí usamos glGenTextures(1, &texture[0]),
para generar una textura. La textura utiliza filtrado lineal.
}
Función LoadTexture: boolean; //Carga el mapa de bits y lo convierte en una textura.
var
Estado: booleano; // Indicador de estado
TextureImage: Array[0..1] Of PTAUX_RGBImageRec // Crea espacio de almacenamiento de texturas;
Comenzar
Estado: = falso;
ZeroMemory(@TextureImage, sizeof(TextureImage) // Establece el puntero en NULL
TextureImage[0] := LoadBMP('Star.bmp');
Si TextureImage[0] <> Nil entonces
Comenzar
Estado := VERDADERO // Establecer estado en VERDADERO;
glGenTextures(1, textura[0]); // Crear textura
// Crear mapa de filtro más cercano
glBindTexture(GL_TEXTURE_2D, textura[0]);
// Generar textura
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // (nuevo)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
ImagenTextura[0].datos);
Fin;
Si está asignado (TextureImage[0]) Entonces // Si la textura existe
Si está asignado (TextureImage[0].data) Entonces // Si la imagen de textura existe
TextureImage[0].data := Nil; // Libera la memoria ocupada por la imagen de textura.
TextureImage[0] := Nil; // Liberar la estructura de la imagen.
resultado := Estado; // Estado de devolución
Fin;
{Establezca el modo de renderizado OpenGL en glInit(). No vamos a utilizar pruebas de profundidad aquí,
Si usa el código de la Lección 1,
Confirme si se han eliminado glDepthFunc(GL_LEQUAL) y glEnable(GL_DEPTH_TEST).
De lo contrario, los resultados que verás serán un desastre.
Aquí usamos mapeo de textura,
Así que asegúrese de haber agregado cualquier código que no se haya incluido en la primera lección.
Notarás que habilitamos el mapeo de texturas mezclando colores.
}
Procedimiento glInit();
Comenzar
If (Not LoadTexture) Then // Llama a la subrutina de carga de texturas (nueva)
salir; // Si no se pudo cargar, salir (nuevo)
glEnable(GL_TEXTURE_2D); // Habilitar mapeo de textura
glShadeModel(GL_SMOOTH); // Habilitar suavizado de sombras
glClearColor(0.0, 0.0, 0.0, 0.5); // fondo negro
glClearDepth(1.0); //Establece el búfer de profundidad
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Corrección de perspectiva realmente buena.
glBlendFunc(GL_SRC_ALPHA, GL_ONE); // Establece la función de mezcla de colores para lograr un efecto translúcido
glEnable(GL_BLEND); // Habilitar la combinación de colores
{El siguiente es el nuevo código.
Se establecen el ángulo inicial, la distancia y el color de cada estrella.
Notarás lo fácil que es modificar las propiedades de una estructura.
Se recorrerán las 50 estrellas.
Para cambiar el ángulo de estrella[1] todo lo que tenemos que hacer es estrella[1].ángulo=un valor determinado;
¡Es así de simple! }
For loop:= 0 To 49 Do // Crea un bucle para configurar todas las estrellas
Comenzar
star[loop].angle := 0.0; // Todas las estrellas comienzan desde el ángulo cero
{La distancia de la estrella del bucle desde el centro se divide por el valor del bucle por el número total de estrellas y luego se multiplica por 5,0.
Básicamente, esto hace que esta última estrella esté un poco más alejada del centro que la estrella anterior.
De esta manera, cuando el bucle es 50 (la última estrella), el bucle dividido por num es exactamente 1,0.
La razón por la que necesitamos multiplicar por 5,0 es porque 1,0*5,0 es 5,0.
『CKER: ¡Tonterías, tonterías! ¿Por qué este extranjero se parece a Kong Yiji? :)』
5.0 ya está muy cerca del borde de la pantalla. No quiero que las estrellas salgan volando de la pantalla, por eso 5.0 es la mejor opción.
Por supuesto, si sitúas la escena más profundamente en la pantalla,
Quizás podrías usar un valor superior a 5,0, pero las estrellas parecerían más pequeñas (todo debido a la perspectiva).
También notarás que el color de cada estrella es un número aleatorio del 0 al 255.
Quizás se pregunte por qué el rango de valores de color aquí no es el rango habitual de OpenGL de 0,0 a 1,0.
La función de configuración de color que usamos aquí es glColor4ub en lugar del glColor4f anterior.
ub significa que el parámetro es de tipo Byte sin firmar.
El rango de valores de un byte es 0~255.
Parece más fácil usar el valor de byte para obtener un número entero aleatorio que obtener un número aleatorio de punto flotante.
}
star[loop].dist := (Trunc(loop) / 50) * 5.0 // Calcula la distancia de la estrella al centro;
star[loop].r := random(256); // Establece un componente rojo aleatorio para star[loop]
star[loop].g := random(256); // Establece un componente rojo aleatorio para star[loop]
star[loop].b := random(256); // Establece un componente rojo aleatorio para star[loop]
Fin;
Fin;
{
Ahora pasamos al código de dibujo glDraw().
Si está utilizando el código de la Lección 1, elimine el código antiguo de DrawGLScene y simplemente copie el código a continuación.
De hecho, el código de la primera lección sólo tiene dos líneas, por lo que no hay mucho que eliminar.
}
Procedimiento glDraw();
Comenzar
glClear(GL_COLOR_BUFFER_BIT O GL_DEPTH_BUFFER_BIT // Borrar pantalla y búfer de profundidad);
glBindTexture(GL_TEXTURE_2D, textura[0]); // Selecciona textura
For loop:= 0 To 49 Do // Loop para configurar todas las estrellas
Comenzar
glLoadIdentity(); // Antes de dibujar cada estrella, restablece la matriz de observación del modelo
glTranslatef(0.0, 0.0, zoom); // Profundiza en la pantalla (usando el valor de 'zoom')
glRotatef(tilt, 1.0, 0.0, 0.0); // Inclinar el ángulo de visión (usando el valor de 'inclinación')
{
Ahora muevamos las estrellas.
La estrella comienza en el centro de la pantalla.
Lo primero que debemos hacer es rotar la escena a lo largo del eje Y.
Si lo giramos 90 grados el eje X ya no es de izquierda a derecha, sale de la pantalla de adentro hacia afuera.
Para que quede más claro, pongamos un ejemplo. Imagínate que estás parado en medio de una casa.
Ahora imagina que la pared a tu izquierda dice -x y la pared frente a ti dice -z.
La pared de la derecha es +x y la pared detrás de ti es +z.
Si toda la casa se gira 90 grados hacia la derecha, pero no te mueves, entonces la pared de enfrente será -x en lugar de -z.
Todas las demás paredes también se mueven. -z aparece a la derecha, +z aparece a la izquierda y +x aparece detrás de usted.
¿Estás loco? Al rotar la escena, cambiamos la orientación de los planos x y z.
La segunda línea de código mueve un valor positivo a lo largo del eje x.
Por lo general, un valor positivo en el eje x significa moverse hacia el lado derecho de la pantalla (es decir, la dirección positiva habitual del eje x).
Pero aquí, dado que rotamos el sistema de coordenadas alrededor del eje y, la dirección positiva del eje x puede ser en cualquier dirección.
Si lo giramos 180 grados, se reflejarán los lados izquierdo y derecho de la pantalla.
Entonces, cuando nos movemos a lo largo del eje x positivo, podría ser hacia la izquierda, hacia la derecha, hacia adelante o hacia atrás.
}
glRotatef(star[loop].angle, 0.0, 1.0, 0.0); //Gira al ángulo de la estrella dibujada actualmente.
glTranslatef(star[loop].dist, 0.0, 0.0); // Avanza a lo largo del eje X
{
El siguiente código tiene un pequeño truco.
Las estrellas son en realidad una textura plana.
Ahora dibujas un quad plano en el centro de la pantalla y aplicas una textura, y se ve bien.
Todo es como lo imaginaste. Pero cuando giras 90 grados a lo largo del eje y,
Los únicos dos lados de la textura en la pantalla frente a usted son el lado derecho y el izquierdo. Simplemente parece una línea delgada.
Esto no es lo que queremos. Queremos que las estrellas estén siempre frente a nosotros, sin importar cómo se gire o incline la pantalla.
Logramos esto cancelando cualquier rotación realizada a la estrella antes de dibujarla.
Puede invertir la rotación para contrarrestar la rotación. Cuando inclinamos la pantalla, en realidad giramos la estrella en su ángulo actual.
Al invertir el orden, "antigiramos" la estrella en su ángulo actual. Es decir, la estrella gira el valor negativo del ángulo actual.
eso es,
Si giramos la estrella 10 grados, la giramos -10 grados para que la estrella vuelva a mirar a la pantalla en ese eje.
La primera línea a continuación cancela la rotación a lo largo del eje y. Luego, también necesitamos compensar la inclinación de la pantalla a lo largo del eje x.
Para ello, solo necesitamos girar nuevamente la pantalla -inclinar-.
Después de cancelar la rotación en los ejes x e y, la estrella ahora vuelve a estar completamente frente a nosotros.
}
glRotatef(-star[loop].angle, 0.0, 1.0, 0.0); // Cancelar el ángulo de la estrella actual
glRotatef(-tilt, 1.0, 0.0, 0.0); // Cancelar inclinación de la pantalla
{Si twinkle es VERDADERO, primero dibujamos una estrella sin girar en la pantalla:
Reste el número actual de estrellas (bucle) del número total de estrellas (num) y luego reste 1.
para extraer los diferentes colores de cada estrella (esto se hace porque el rango del bucle es de 0 a num-1).
Por ejemplo, cuando el resultado es 10, utilizamos el color de la estrella número 10.
De esta forma los colores de las estrellas adyacentes siempre son diferentes. No es una buena idea, pero funciona.
El último valor es el componente del canal alfa. Cuanto menor sea el valor, más tenue será la estrella.
Dado que el centelleo está habilitado, cada estrella terminará apareciendo dos veces.
El programa se ejecutará más lento, dependiendo del rendimiento de su máquina.
Pero los colores de las estrellas dibujadas en dos pasadas se mezclan entre sí y producen un gran efecto.
Al mismo tiempo, dado que las estrellas en la primera pasada no rotaron, las estrellas después de habilitar el parpadeo parecen un efecto de animación.
(Si no comprende esto, simplemente vaya y vea usted mismo el efecto de ejecución del programa).
Vale la pena señalar que colorear texturas es fácil.
Aunque la textura en sí es blanca y negra, la textura cambiará a cualquier color que hayamos seleccionado antes de pintarla.
Además, también vale la pena señalar que el valor de color que utilizamos aquí es de tipo byte,
en lugar de los habituales números de coma flotante. Incluso el componente del canal alfa es así. }
Si (centelleo) Entonces // Habilitar efecto centelleo
Comenzar
//Especifica un color usando un valor de byte
glColor4ub(estrella[(50 - bucle) - 1].r, estrella[(50 - bucle) - 1].g,
estrella[(50 - bucle) - 1].b, 255);
glBegin(GL_QUADS); // Comenzar a dibujar quads con mapeo de texturas
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, 0.0);
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, 0.0);
glEnd(); // Fin del dibujo del cuadrilátero
Fin;
{
Ahora dibuja la segunda pasada de las estrellas.
La única diferencia con el código anterior es que esta vez las estrellas definitivamente se dibujarán, y esta vez las estrellas girarán alrededor del eje z.
}
glRotatef(spin, 0.0, 0.0, 1.0); // Gira la estrella alrededor del eje z.
//Especifica un color usando un valor de byte
glColor4ub(estrella[bucle].r, estrella[bucle].g, estrella[bucle].b, 255);
glBegin(GL_QUADS); // Comenzar a dibujar quads con mapeo de texturas
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, 0.0);
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, 0.0);
glEnd(); // Fin del dibujo del cuadrilátero
{El siguiente código representa el movimiento de las estrellas.
Aumentamos el valor de giro para rotar todas las estrellas (revolución).
Luego, aumenta el ángulo de rotación de cada estrella en loop/num.
Esto hace que las estrellas más alejadas del centro giren más rápido. Finalmente reduce la distancia de cada estrella desde el centro de la pantalla.
Parece que las estrellas son absorbidas constantemente hacia el centro de la pantalla. }
giro := giro + 0.01; // La revolución de la estrella
star[loop].angle := star[loop].angle + Trunc(loop) / 50 // Cambia el ángulo de rotación de la estrella;
star[loop].dist := star[loop].dist - 0.01 // Cambia la distancia de la estrella desde el centro;
{Las siguientes líneas comprueban si la estrella ha tocado el centro de la pantalla.
Cuando la estrella llega al centro de la pantalla, le damos un nuevo color y la movemos 5 unidades hacia afuera.
La estrella emprenderá su viaje de regreso al centro de la pantalla. }
Si (star[loop].dist < 0.0) Entonces // ¿Ha llegado la estrella al centro?
Comenzar
star[loop].dist := star[loop].dist + 5.0 // Mueve 5 unidades hacia afuera
star[loop].r := random(256); // Asigna un nuevo componente rojo
star[loop].g := random(256); // Asigna un nuevo componente verde
star[loop].b := random(256); // Asigna un nuevo componente azul
Fin;
Fin;
Fin;
{
Ahora agregamos el código para monitorear el teclado.
Baje a WinMain(). Busque la línea SwapBuffers(hDC).
Agregaremos el código de monitoreo del teclado después de esta línea.
El código verificará si se ha presionado la tecla T.
Si se presiona y suelta la tecla T, se ejecutará el código del bloque if.
Si twinkle es FALSO, se volverá VERDADERO.
viceversa. Mientras se presione la tecla T, tp se vuelve VERDADERO.
Esto evita que el código dentro del bloque se ejecute repetidamente si sigue presionando la tecla T.
}
If (keys[ord('T')] And Not tp) Then // Si se ha presionado la tecla T y el valor de tp es FALSO
Comenzar
tp := VERDADERO; // En caso afirmativo, establezca tp en VERDADERO
twinkle := No twinkle // Invierte el valor de twinkle;
Fin;
{
El siguiente código verifica si se ha liberado la tecla T.
Si es así, establezca tp=FALSE.
A menos que el valor de tp sea FALSO,
De lo contrario no sucederá nada mientras se mantiene presionada la tecla T. Entonces esta línea de código es importante.
}
If (Notkeys[Ord('T')]) Then // ¿Se ha liberado la tecla T?
Comenzar
tp := FALSO; // Si es así, tp es FALSO
Fin;
{El código restante verifica si se presionan las teclas de flecha arriba y abajo, la tecla de avance de página o la tecla de avance de página. }
If (keys[VK_UP]) Then // ¿Se presiona la tecla de flecha hacia arriba?
inclinación := inclinación - 0.5 // Inclina la pantalla hacia arriba
If (keys[VK_DOWN]) Then // ¿Se presiona la tecla de flecha hacia abajo?
inclinación := inclinación + 0,5 // Inclina la pantalla hacia abajo
If (keys[VK_PRIOR]) Then // ¿Se presiona la tecla de avance de página?
zoom := zoom - 0.2 // Alejar
If (keys[VK_NEXT]) Then // ¿Se presiona la tecla de avance de página?
zoom := zoom + 0.2 // Acercar
{
En esta lección hago todo lo posible para explicar cómo cargar una textura de mapa de bits en escala de grises.
Después de eliminar su color de fondo (usando colores mezclados), coloréalo nuevamente y finalmente haz que se mueva en la escena 3D.
Te he mostrado cómo crear hermosos efectos de color y animación.
El principio de implementación es superponer una copia de mapa de bits al mapa de bits original.
Hasta ahora, siempre que comprendas bien todo lo que te he enseñado,
Deberías poder crear tu propia demostración 3D sin ningún problema.
¡Todos los conceptos básicos cubiertos! }
//========myling:
// Se han traducido las conferencias 1 a 9. Como dijo NEHE, se han explicado básicamente los conocimientos básicos.
// Miré los siguientes tutoriales y parecen estar escritos por otras personas. Si hay buenos ejemplos, los seguiré selectivamente.
//Renovada, estoy muy cansada, toma una siesta :), hasta la próxima