Monday, November 14, 2016

Coronax - S Project Blog , Coronax






+

Está bien, la gente, la hebilla y poner en sus gafas de espejo. Esta es mi última Retrochallenge 2015 07 de entrada, y es un doozy: Una tragedia de errores y un triunfo de la tarde-noche de la piratería. O algo. En nuestro último episodio emocionante, tuve cubos-polígono relleno y icosahedrons girando alrededor delante de un fondo estático. fondos estáticos son aburridos. Así que me puse a hacer el desplazamiento de fondo. Pensé que iba a ser fácil. Error # 1: Modo Dual-Campo de juego utilizando ScrollVPort () Lo complicado es que quería desplazar el fondo (la luna, las estrellas, y las pirámides) sin mover el primer plano (los polyhedrals). Convenientemente, el Amiga tiene un modo de gráficos específicamente para este tipo de cosa que se llama "Dual-Campo de juego Modo". La idea es que dividir los planos de bits entre dos "campos de juego", cada uno de los cuales puede desplegarlos de forma independiente en la dirección X o Y. Esto era bastante fácil de configurar. Tuve que cambiar mis bitplanes un poco, de modo que las formas 3D se dibujan en planos de bits 0 y 1, y en el fondo plano binario 0 de una estructura RasInfo separada. Ya que estaba desplazamiento horizontal, que también se duplicó el ancho de los mapas de bits de 320 a 640 píxeles. Pegué la misma imagen de fondo en este espacio ampliado. Pensé que si me desplacé el fondo 320 píxeles a la izquierda, se vería igual que la imagen original. Entonces podría establecer el desplazamiento de nuevo a 0 y empezar de nuevo, para un desplazamiento infinito falso. Era fácil, pero el efecto era algo torpe. Las pirámides más estrechas se movían a la misma velocidad que las pirámides en el horizonte, y la luna y las estrellas. Definitivamente no era el efecto que estaba buscando. Además, ScrollVPort () era un poco lento, y yo no podía prescindir de la velocidad. Error # 2: Cobre Las interrupciones Es una buena cosa que tenía éstos en la mano. Un montón de juegos de Amiga disponen de "scroll parallax", donde los objetos más cerca del espectador de desplazamiento a una velocidad diferente de los objetos en el fondo. Si esos objetos están separados verticalmente, que pueden ser representados por el mismo plano binario. La idea es que a medida que emite el chip gráfico de la imagen final, una línea de exploración a la vez, se puede entrar y cambiar los valores de los registros en el medio para cambiar cómo se dibujan las cosas. Es muy parecido a "competir con el rayo" en un Atari 2600 o C64. El cobre debe hacer ese tipo de cosas realmente fácil, pero tenía un dilema. El cobre puede establecer un valor en un registro en un momento preciso, pero en mi caso, el valor que había necesidad de escribir cambiaría cada cuadro. Yo no tenía una manera de cambiar la lista de cobre fácilmente porque yo estaba usando las funciones graphics. library para crear la lista de forma dinámica y de la mano libre para el sistema operativo utilizando la función (también bastante caro) MrgCop (). No querían más. Lo prometo. En mi lectura, que había descubierto que una de las cosas que el cobre podía hacer era lanzar una interrupción por escrito a la solicitud de registro de interrupción. Pensé que podría tener el cobre hacer eso, y luego mi manejador de interrupciones podrían fijar los registros con los valores correctos, que cambian dinámicamente para crear un efecto de desplazamiento suave. Sonaba como una buena idea, y pasó la mayor parte de la noche del sábado su aplicación. Esto fue difícil por varias razones. En primer lugar, mi manejador de interrupciones necesitaba ser escrito en lenguaje ensamblador 68000, que no he utilizado desde alrededor de 1991. Por suerte todavía tengo algunos libros antiguos sobre el tema, y ​​mi código no tiene que hacer nada demasiado sofisticado. El poco importante cuando cambié los registros fue de sólo unas pocas instrucciones: En el nivel de registro de hardware, el desplazamiento se divide en dos operaciones. Puede cambiar la posición de los píxeles son atraídos por hasta 16 píxeles, lo que le da el control fino. Para desplazarse más allá de eso, se cambia el registro que le dice al hardware de vídeo que byte de datos a leer a continuación. Era el momento que hizo que este enfoque un dolor. Hasta ahora me he dejado la mayor parte del sistema operativo que se ejecuta en segundo plano, y debido a que hubo un poco de retraso entre el momento pedí la interrupción y cuando mi manejador de interrupciones llamaron - casi todo un valor de línea de exploración de tiempo, y no era coherente de cuadro a cuadro. Eso era un problema porque mis requisitos de tiempo eran bastante apretado - que tenía que establecer la nueva dirección plano binario durante el tiempo de borrado horizontal entre una línea de exploración y la siguiente. Después de jugar un poco con diferentes listas de cobre y sus bucles de retardo, que tenía una solución que parecía funcionar bien. Había dividido la imagen de fondo en tres zonas. La parte superior, con la luna y las estrellas, era estacionaria. El medio, con las pirámides en el horizonte, desplaza a una velocidad de un píxel por trama. La parte inferior, con las pirámides de primer plano, desplaza más rápido - dos píxeles por imagen. Estaba bien, pero no era perfecto. De vez en cuando, tal vez un marco en el 60, el momento sería un poco apagado y no sería un problema técnico - uno de los conjuntos de pirámides se tendrá que recurrir en el lugar equivocado. Pero era 4 am, y, en general, se ve bastante bueno. Mientras yo estaba corriendo en WinUAE ... Error # 3: Esperar hasta el último minuto para probar el hardware real No he tenido mucho tiempo libre de este Retrochallenge, y debido a que he estado haciendo un montón de desarrollo, y toda mi captura de vídeo, en el emulador WinUAE. WinUAE es muy buena, así que pensé que si mi código trabajaba allí, que debería funcionar en la cosa real. Últimas palabras famosas. El momento más triste en retrocomputación es cuando una pieza de hardware amada comienza a mostrar su edad. El único problema es que mi Amiga ya hay stock. Antes, cuando estaba trabajando en la iteración anterior de este proyecto, cogí un acelerador ACA500. que proporciona un 14 MHz 68000 CPU. He estado haciendo mis pruebas en una configuración de valores de 7.14 MHz Amiga 500 emulado. Supuse para la prueba de hardware real, podía sacar la ACA500 y reemplazarlo con mi GVP A500 HD +. que proporciona una actualización de disco RAM y disco. Eso fue ayer por la noche, cuando el primero de una serie de catástrofes golpeó. La GVP ha realizado una labor admirable durante muchos años, pero anoche no arranque. A veces se comenzó a ejecutar el script de inicio de secuencia, pero se detendría después de unos segundos. Peor aún, el zumbido constante del motor comenzó a sonar ... tambaleante. No es una buena tambaleante. Un mal tambaleante. Definitivamente no es cómo se supone que se vea. Con el tiempo, me encontré con un viejo Workbench 2.0 disco de arranque, y pensé que resolvería mi problema - pero simplemente cambiado un problema para otra cosa. Yo era capaz de ejecutar mi programa de prueba en un Amiga funcionando a la velocidad de reloj correcta, pero que la estructura de temporización frágil que había puesto juntos por la rutina de desplazamiento justo quedó colapsado. Fue un desastre. Para colmo de males, el televisor Toshiba que estaba usando como un monitor completamente atornillado encima de los colores, volviendo el crepúsculo desierto telón de fondo en un miasma verde-marrón estridente. He probado un par de otros monitores, como se puede ver en el vídeo, pero sólo uno que tenía un problema. Todavía no sé por qué. Solución: Volviendo al principio Así que era lunes por la noche, y yo estaba a punto de salir del tiempo, y nada funcionaba. Así Bebí un poco de Coca-Cola, comí un poco de chocolate, se puso el disco en directo Crónicas de Hawkwind. y se puso a trabajar. Supuse las posibilidades de la fijación de mi tiempo por interrupciones eran casi nulas, así que me fui de nuevo al comienzo y examinó la lista de cobre. Si usted tuvo un puntero a la ubicación de memoria real que el cobre estaba leyendo, pensé que podría empujar nuevos valores en la lista de instrucciones. Además, el código auto-modificable fue uno de los pocos trucos no he probado durante este proyecto. El único problema es que yo no tenía esa lista. Yo estaba todavía en su mayoría con graphics. library del Amiga para manejar mis puntos de vista y las ventanas gráficas. En ese paradigma, he creado un fragmento de una lista de cobre para los cambios que quería ejecutar y, a continuación, llamado MrgCop (). MrgCop () tomaría todas las listas de cobre para todas las ventanas gráficas visibles y les fusionar-ordenar en una lista maestra que atribuye a la estructura Ver y le dijo al cobre para ejecutar cada cuadro. Así que empecé a cabo mediante la impresión de que la lista final de cobre y ver lo que parecía. Así es como comienza: Bueno, eso no se ve tan mal. La mayor parte de esas líneas sólo están estableciendo un registro de vídeo (columna izquierda) a un valor particular (columna derecha). No sé lo que la mitad de esos nombres de registro significa, pero los que más me interesan, han sido los registros de direcciones plano binario. Si tuviera que crear mi propia lista de cobre, que había necesidad de llenar esos valores con lo que los punteros real sería para una determinada ejecución del programa. Una vez que tuve mi lista, sólo atascado en la estructura Ver en lugar de la que graphics. library había creado para ella. Esta es una manera bastante sin gracia de hacerlo, y estoy seguro de que estoy perdiendo memoria de nuevo, pero el reloj seguía corriendo. Para mi rutina de desplazamiento, que había necesidad de restablecer esos registros durante los intervalos entre las líneas de exploración HBlank particulares. Por lo que añade en unas pocas líneas de hacerlo: Entonces yo podría escribir una rutina rápida que mi bucle principal del programa podría llamar a cada cuadro para llenar los nuevos valores relativos a las líneas de la lista de cobre: ¿Funcionó? ¡Sí! Y tengo que decir, es mucho mejor que el enfoque de manejo por interrupción ridícula haber perdido mi tiempo en. Esta rutina de desplazamiento es firme como una roca. Lo probé en el hardware real y los resultados miraba al igual que en el emulador. Ese fue un momento increíblemente satisfactorio. El éxito en el pasado! Por último, Crucé los dedos y el código probé en el Amiga real con el ACA500 adjunto. La rutina de desplazamiento aún funcionaba! La única diferencia fue la velocidad de cuadro, que se mejora considerablemente por el 68000 14 MHz. Y ahí es donde voy a dejar las cosas para Retrochallenge de este verano. Seguro que se parece mucho más impresionante que la versión Empecé con. El rendimiento es mucho mejor de lo que era, pero todavía no es hasta el tabaco, con lo que se ve en la demoscene después de, digamos, 1987. Creo que la próxima vez que vuelva a este proyecto vamos a estar buscando en un montón más lenguaje ensamblador y programación de metal desnudo. La cual debe ser divertido. Que había estado posponiendo pasar de alambre renderizado de polígonos rellenos porque yo estaba preocupado por lo que iba a pasar a mi imágenes por segundo, pero ahora que he finalmente poco la bala no es casi tan gran cosa como pensé que sería . Esa es otra ventaja de Blitter del Amiga: se hace todo el trabajo, y tomar todo el crédito. Como yo lo entiendo, esto es lo que sucede cuando se utiliza rutinas polígono relleno del graphics. library: El programa llama AreaMove () para iniciar el polígono y dar la ubicación de la primera vértice en coordenadas de pantalla. A continuación, llama AreaDraw () para cada vértice restante, y luego AreaEnd () cuando esté hecho. Las coordenadas de vértices se almacenan en una memoria intermedia temporal llamada AreaInfo unido a RastPort de la pantalla. El blitter se utiliza para dibujar el contorno del polígono en un búfer temporal denominado TmpRas, también unido al RastPort de la pantalla. El rectángulo que contiene el polígono se copia en una o más planos de bits de la memoria intermedia de pantalla utilizando un modo de relleno especial. Para cada fila, el Blitter escanea hasta que choca con el esquema y, a continuación, escribe bits de relleno hasta que choca con el contorno en el otro lado del polígono. (Los bits de relleno se pueden encender y apagar el tiempo múltiple por fila, de manera que esto se puede utilizar para rellenar polígonos cóncavos). El Blitter es muy flexible y se puede realizar una variedad de operaciones lógicas en sus entradas, aplicar entradas de máscara, y así sucesivamente. He realmente tan sólo una aproximación. En este caso, es encontrar la manera de rellenar un polígono arbitrario por el precio de la copia de un rectángulo entre dos planos de bits, que es un muy buen trato. Una vez que había sustituido el cubo de alambre con una versión sólida, empecé a jugar con los gráficos de nuevo. He utilizado algunos trucos con la gama de colores para hacer el cubo mira parcialmente transparente. Estoy usando tres planos de bits ahora, con los lados de diferentes colores del cubo dibujado en planos de bit 0 y 2, y los elementos de fondo dibujados en el plano 1. La paleta se ve así: Si quiero el cubo que aparezca sólida, sólo hay que hacer color 1 lo mismo que 3, 4 lo mismo que 6, y 5 de la misma que 7. Hacer cualquier par de diferentes tonos, y el fondo se "vea a través '. También utilicé el cobre para cambiar los valores de los colores reales en varias posiciones, por lo que los colores del cubo son de color cuando está en frente de la luna y más oscuro cuando está en frente de la pirámide, y de modo que el color de fondo visto a través de los fundidos del cubo la misma manera que lo hace sin el cubo en el camino. Es una falsificación, y no del todo tiene sentido porque las caras posteriores del cubo no están dibujados, pero aún así es bastante convincente buscando. También decidí que estaba cansado de ver que el hilado cubo en un solo lugar, por lo que yo jugaba con su animación un poco. Ahora tengo que orbitando alrededor del origen, acercándose a y luego más lejos de la cámara. Por último, he decidido añadir otra forma de nuevo en Tengo para envolver este proyecto en un par de días porque me voy para la Gen Con el miércoles, por lo que en honor de que he añadido un icosaedro -. La forma icónica de un veinte caras mueren. El icosaedro pone mucha más carga en la CPU que el cubo hace: 20 caras frente a 6, 12 vértices frente a 8. Se me corta la velocidad de fotogramas a la mitad, como se puede ver en el vídeo. Me estoy poniendo más de 20 fps desde el cubo, y poco más de 10 fps cuando el icosaedro es en pantalla. La implementación de un algoritmo de línea de dibujo no es tan difícil, pero ninguna pieza no trivial de código funciona bien en el primer intento. O el segundo. En los últimos días he dejado mi progreso en este proyecto dirigido por delante de mi documentación, por lo que vamos a tratar de ponerse al día. Esta noche, me gustaría discutir brevemente cómo dibujar líneas - y por qué es posible que no tenga que preocuparse. Hasta ahora, mi enfoque ha sido la de no cuidar - estoy usando las funciones graphics. library AmigaOS Mover () y draw () para hacer que las líneas reales de mis formas. Hay una buena razón para ello: Soy un vago. Además, graphics. library es, probablemente, bien optimizado, y puede tomar ventaja de algunos de que el hardware personalizado Amiga elegante. El Blitter, como el cobre hablé de la última vez, es uno de los coprocesadores gráficos de la Amiga, y es parte del chip Fat Agnus. Básicamente, un blitter sólo se mueve datos de una parte de la memoria a otro. Es adecuado para copiar cosas en un mapa de bits, o mover una imagen alrededor. Blitter del Amiga también tiene algunas funciones especiales - que puede dibujar líneas en la memoria de mapa de bits directamente, e incluso dibujar polígonos rellenos (vamos a llegar a eso en otra entrada). En la Bolsa de Amiga, el Blitter puede hacer todo esto mucho más rápidamente que la lata de la CPU. Por un lado, no tiene que seguir las instrucciones de ir a buscar para correr - que acaba de configurar sus registros y se deja ir, y va a mover datos lo más rápido posible. Además, blits pueden tener lugar de forma asíncrona, mientras que la CPU está haciendo otra cosa. No es exactamente el multiprocesamiento, pero es sin duda una ventaja. Las funciones graphics. library no me dan un control completo sobre cuándo debe esperar a que el Blitter y cuándo no, pero por ejemplo yo puedo utilizar el Blitter para despejar el uso de este dispositivo mientras la CPU está computando las matrices de transformación para utilizar mientras se dibuja el siguiente marco. El llevar a casa aquí es que las funciones graphics. library para dibujar líneas son fáciles de usar, rápido, y en realidad funcionan. Es posible hacer mejor si usted está escribiendo sus propias rutinas de ensamblaje que establecen la Blitter directamente, pero yo no estoy metiendo en que en esta etapa. Sin embargo, yo estaba un poco interesado en escribir mi propia rutina de línea de dibujo, sólo para ver cómo una solución de software compara la velocidad se refiere. El algoritmo más conocido por las líneas de dibujo (al menos, para dibujar líneas y sin antialiasing) es el algoritmo de Bresenham. En este algoritmo, iterar desde el inicio de la línea al final de la línea en la dirección positiva-x, dibujar un píxel en cada coordenada x y el uso de un valor mágica "error" de averiguar cuándo incrementar la coordenada y. Para las líneas "empinadas", que puede hacer la misma cosa básica, pero intercambiar los papeles de x e y. Una parte importante del desempeño del algoritmo es que su bucle principal sólo utiliza además entero y la resta. (Bueno, el valor de error no es en realidad la magia - se incrementa por Dx y Dy decrementos por contar básicamente por la pendiente de la recta - pero es bastante inteligente Puede leer los detalles sobre en Wikipedia.). Mi primer intento de implementar un algoritmo de trazado de líneas era tan lento que ni siquiera quiero medirlo, y por buenas razones. El cálculo de las coordenadas X e Y era lo suficientemente rápido, pero tratar de calcular qué parte de la memoria para cambiar a trazar esos valores tomó demasiado tiempo - y es necesaria una división entera caro. La solución consistió en averiguar la ubicación de memoria para el primer punto de la línea - la cual byte del plano binario y que algo de ese byte - y luego cambie gradualmente esos valores como dibujé la línea. Así que si el primer pixel estaba en el bit 1 del byte 0x0000ccc5, el píxel a su derecha estaba el bit 0, y uno a la derecha del que era el bit 7 del byte 0x0000ccc6. Yendo abajo o hacia arriba significa añadiendo o restando el número de bytes en una fila de mapa de bits. Una vez que lo hice, yo estaba de nuevo a usar además de enteros y la resta para todas las operaciones. Hubo, por supuesto, algunos problemas técnicos en el camino - se puede ver un par de ellos en la parte superior de este post. Una cosa que se mete con mi cabeza es que los bytes están dispuestos de izquierda a derecha en cada fila del mapa de bits, pero los bits de cada byte de ejecución de derecha a izquierda. Esa imagen de la derecha muestra mí hacer las cosas al revés. Lo que la rapidez qué la línea de software optimizado en gran medida de embutición ir rutina? Me complace informar que tomó aproximadamente 2,75 veces más largo que el Blitter para hacer la misma cantidad de trabajo. Fue un ejercicio divertido, pero he vuelto a usar las rutinas graphics. library de trabajo real - y vamos a entrar en más de esa mañana. Una de las grandes reivindicaciones del Amiga a la fama es su chipset de encargo, que le dio capacidades multimedia que eran básicamente desconocida hace 30 años. Pasé mi tiempo este fin de semana retro aprender algunos trucos nuevos viejos. El cobre es un coprocesador simple pero potente que es parte del chip de Agnus del Amiga. De todos los chips a medida, que es el único capaz de ejecutar su propio programa (muy simple). Tiene tres instrucciones: ESPERE - esperar a que el haz de alcanzar una determinada posición en la pantalla. MOVER - escribir un valor en uno de los registros de chip personalizado. PASE - no tome la siguiente instrucción. Aparentemente se puede usar SKIP para crear bucles, pero no he estropeado con eso todavía. ¿Qué se puede realmente hacer con eso? Muy pocas cosas. El cobre es lo que permite que el Amiga visualizar múltiples pantallas con diferentes resoluciones o paletas de forma simultánea. Se utiliza para crear modos gráficos especiales como "jamón", e incluso puede dibujar gráficos en bloques por su propia cuenta. En los equipos más antiguos, como el Commodore 64 o Atari 2600, una gran cantidad de rutinas de gráficos basado en la ejecución de código o el cambio de registros cuando el rayo alcanza un determinado punto de la pantalla, y todo el programa tuvo que ser escrito alrededor de eso. El cobre hace que este sea mucho más fácil, ya que va a correr a través de su programa de cada cuadro, mientras que la CPU - y su programa - se ocupa de otras cosas. Decidí utilizar el cobre para añadir un poco de color y estilo a mi programa de gráficos. Mi primer intento tomado de un ejemplo en el RKRM - cambió el fondo de un plano gris de un arco iris de rayas horizontales. El programa de cobre (también llamada una "lista de Cobre") era simple - cada 10 líneas o por lo que sería escribir un nuevo valor al registro de color 0, que contiene el color de fondo. Aunque mis gráficos sólo se estaban usando un único plano binario, de repente tuve una imagen con casi dos docenas de colores distintos. En comparación con mis ensayos con la ocultación de caras algoritmo de la semana pasada, conseguir las cosas lista de cobre al trabajo era una brisa. Lo hice correr en una "moda C Gotcha compilador de edad". En K & amp; R estilo C, las funciones no tienen que ser declaradas antes de ser utilizado - pero sin la declaración, el compilador asumirían que todos los argumentos se supone que son enteros - o por lo menos de tamaño int. Se me olvidó incluir el archivo de cabecera para las funciones de utilidad de lista de cobre graphics. library - que en realidad se supone que deben tomar las palabras de 16 bits como argumentos - que resulta en algunos errores extraños porque los valores que estaba pasando se estaban promoviendo enteros de las palabras a mis espaldas - delante de mis narices! Una vez que llegué que enderezó, me decidí a tener un poco de diversión. Se me ocurrió una lista de cobre que fue mi mejor intento de dar con un cielo crepuscular y la tierra estéril. El efecto tipo de trabajado, pero todavía necesita algo. No necesitaba exactamente mis habilidades artísticas mediocres, pero eso es lo que tiene. el modo de dos colores exóticos de deluxepaint IV. Amiga pantallas se componen de múltiples planos de bits. Esa no es la forma en que funciona el hardware de gráficos más modernos, pero tiene sus ventajas y desventajas. Un pro es que puedo sacar mis gráficos en un solo plano binario sin modificar otro. Por lo que añade un segundo plano binario de la pantalla, y para llenarlo en creé una imagen en deluxepaint IV - sólo algunas pirámides, una luna llena, y algunas estrellas. He convertido la imagen en un archivo de código fuente en C usando un programa llamado "IFF a la Fuente" por J. Tyberghein, que recuerdo vagamente la instalación en esta imagen del disco duro en la década de los 90. Con dos planos de bits Tengo cuatro colores. El fondo es 0, y las pirámides y la luna son de color 2. El cubo giratorio utiliza colores 1 y 3 (dependiendo de si una línea se superpone a la imagen o no). He añadido un par de entradas a la lista de cobre de modo que el color 2 sería de color blanco pálido en la parte superior (por la luna y las estrellas) y gris oscuro para el fondo (las pirámides). La mejor parte es que ninguno de esta lista Cobre cosas afectó mi velocidad de fotogramas. El programa de cobre no tiene un efecto notable. La imagen de los detalles del fondo se copia en la memoria intermedia de trama una vez al inicio del programa (bueno, dos veces desde mis gráficos son de doble memoria intermedia), y después de eso no tiene que hacer nada con ella. Me gusta el efecto global - que es mucho más divertido que mira fijamente gris y negro todo el tiempo. El vídeo en la parte superior muestra la transición de cómo se desarrollaron las cosas en el transcurso del fin de semana. Con la ocultación de caras, que casi parece un objeto sólido. Después de la reestructuración de mi programa de gráficos, una de las primeras características que quería añadir era la ocultación de caras. Esa es una técnica de gráficos básico en el que sólo se dibuja un polígono si en realidad está mirando hacia la cámara. Por ejemplo, recoger un cubo de Rubik (usted tiene un cubo de Rubik a su alcance, ¿no?). No importa cómo se gira el cubo, no se puede ver más de tres lados de la misma a la vez. Mientras la forma que está dibujando es un casco convexo, se puede sacrificar a los polígonos de copia de frente y sin ningún efecto visible. Y si estás reproduciendo en modo de línea, al igual que he estado haciendo hasta ahora, se puede obtener una especie de eliminación de líneas ocultas fuera de él. En principio, la ocultación de caras es muy simple. Vamos a echar un lado del cubo de Rubik, que es un polígono cuadrado. Se puede pensar en cada uno de sus bordes como un vector. Si se toma el producto vectorial de dos de los bordes, se obtiene un vector que es perpendicular al polígono y hacia afuera de la "parte delantera". A continuación, a determinar un vector que va desde la cámara a uno de los vértices del polígono. A continuación, se calcula el producto escalar de los dos vectores. Si el producto escalar es positivo, el polígono está de espaldas a la cámara y que no tiene que dibujarlo. Pensé que era un problema simple agradable que podía cortar con rapidez. ¿Cómo podría estropear algo tan simple? Ah. Déjame contar las formas… En primer lugar, tenía que cambiar mi estructura de datos. vértices Hasta el momento, sólo había utilizado y bordes (donde un borde era sólo un par de índices en el conjunto de vértices). Ahora lo que necesitaba para realizar un seguimiento de caras, que son polígonos compuestos por múltiples aristas. Dado que cada borde puede ser compartida por dos caras, he añadido un valor lógico hasta el borde para comprobar si ya había sido dibujado cada cuadro. Hasta ahora, agradable y fácil. Hay un problema con el uso del producto cruzado de dos bordes de averiguar el vector normal de una cara: algo que se llama polígono de bobinado. Con el fin de asegurarse de que la normalidad está apuntando hacia el exterior, en lugar de hacia adentro, usted tiene que escoger sus vectores de borde de modo que van en sentido antihorario alrededor del borde del polígono (mirando hacia abajo desde el lado que usted quiere ser el "top "). Mis estructuras de bordes compartidos no acababa de resolver el problema - no había manera de definirlos de manera que estarían en sentido antihorario para cada rostro referencia a ellos. Podría hacer que funcione, pero era más fácil añadir una lista de índices de vértices en el orden correcto para cada forma. Es un poco redundante, pero en este momento la velocidad es más importante para mí que la eficiencia de la memoria, y se hizo el trabajo: Por supuesto, ahora que tenía toda esa estructura de datos para trabajar, tuve que conseguir que todo llenados correctamente, lo cual fue un verdadero dolor de cabeza. Quiero hacer otros objetos, pero voy a tener que encontrar la manera de definir mediante programación. Con todas esas piezas en su lugar, pude probar mi ocultación de caras rutina y ver fracasar miserablemente. Um, yay? Knuth escribe en algún lugar sobre los peligros de la optimización prematura, pero se topó con optimizaciones que añadí un año y medio atrás y rápidamente se olvidó de. Yo sólo les redescubierto cuando volaron en mi cara. Por ejemplo, durante la Segunda Guerra Retrochallenge 2014, tomé un acceso directo al multiplicar vértices por mi matriz de transformación: Sólo computé los valores X e Y. No tenía un buffer de profundidad ni nada, así que no necesitaba para calcular Z. Cue mí, ayer por la noche, mirando desconcertado cuando cada punto de un cubo tenía Z == 0. Vaya. El mayor optimización que hice el año pasado fue mi punto fijo macros matemáticas. lo cual me permitió calcular los valores de números reales utilizando sólo operaciones aritméticas con enteros, que son mucho más rápido que cualquiera de las bibliotecas de punto flotante de la Amiga. La desventaja es que los números de punto fijo tienen un rango limitado - más o menos aproximadamente 32.000, en este caso. Durante un tiempo, pensé que tenía un problema en el que estaba rebosante esos valores. Probablemente era, pero eso fue sólo un signo de una más grande, más tonto error. Es importante, cuando se trabaja en 3D, siempre saber qué sistema se está trabajando en la coordenada, y qué conjunto de transformaciones que está solicitando a sus datos. Tengo este mal desde el principio, y cuando traté de fijar la primera vez que yo era diferente, pero sigue siendo incorrecto. por lo que me ha costado mucho tiempo, y he tenido que volver a lo básico y mirar los números reales en una situación muy simple antes de que yo entendía lo que estaba pasando. En mi primera aplicación, me gustaría crear una matriz de transformación individual para cada cuadro que se aplicó a mis datos de entrada. Un conjunto fijo de vértices se fue en un extremo, y un conjunto de coordenadas de la pantalla salió por el otro. Por lo que este marco era algo como esto: Ahora, coordenadas de la pantalla nunca iban a ser el marco de referencia adecuado para los cálculos de descarte (Me di cuenta después mirando a resultados durante una hora). Necesitaba ver mis vértices en algún lugar en medio de ese oleoducto, que por desgracia significaba que cada vértice tendría que ser transformado dos veces. Oh, mi pobre tasa de fotogramas! Por desgracia, por alguna razón decidí calcular los vértices con la proyección del × × Camera_Translation Model_Transform. Esta fue la elección equivocada debido a la forma en que la proyección en perspectiva interactúa con los valores Z de los vértices. Pero no podía darse cuenta de que ese era mi problema hasta que, en un desesperado intento de simplificar la situación, que sustituyó a la proyección en perspectiva con una proyección ortográfica - y las cosas empezaron a trabajar de la manera que se suponía. Por cierto, en el curso de este proceso he descubierto que mi traducción cámara había estado equivocado todo el tiempo. y la forma en realidad estaba siendo representa detrás de la cámara! La única razón por la que estaba viendo nada en absoluto era que, para ahorrar tiempo, nunca me molestó probar la parte delantera o trasera planos de recorte (!) Esto también significa que las formas eran todos están elaborando volteado a lo largo del eje Z, añadiendo a mi consternación. Juro que en realidad no sé cómo se supone que este material a trabajar. ¡Por favor creeme! Para finalmente obtener las cosas, me encontré con la ocultación de caras de rutina en los vértices del polígono después de que se multiplicaron por el Camera_Translation y matrices Model_Transform, pero no la proyección de pantalla o transformadas. Por fin, el bingo! Un cubo que no se puede ver a través de al otro lado! No es una victoria perfecta, sin embargo. Es más lento de lo que era. Los cálculos adicionales que estoy haciendo cuestan más que el tiempo que estoy ahorrando al no dibujar las líneas para los polígonos de respaldo frente. Ahora que el derecho de la matemáticas, podemos solucionar algunos de los que hasta - por ejemplo, puede ser que sea más rápido para calcular las normales de una vez y luego sólo les transformar cada cuadro. Después de eso, ya veremos. Mensaje de navegación




No comments:

Post a Comment