Documente Academic
Documente Profesional
Documente Cultură
COMPUTACIÓN GRÁFICA
COMITÉ DIRECTIVO
PRIMERA EDICIÓN
@ Copy Rigth
Universidad Nacional Abierta y a Distancia
ISBN
2005
Centro Nacional de Medios para el Aprendizaje
3
4) Sistema de coordenadas 40
!
" # $%#& # ' $() '
"' # '# *+
1) Algoritmos básicos 58
1.1 Especificación de una discretización 59
1.2 Métodos de discretización 59
1.3 Segmentos de recta 60
1.3.1 Segmentos de recta DDA 60
4
2) Llenado de áreas 70
3)Transformaciones 71
3.1 Breve repaso sobre matrices 72
3.2 Cambios de escala 74
3.3 Rotación 75
3.4 Coordenadas homogéneas y traslación 77
3.5 Rotación alrededor de un punto cualquiera 79
3.6 Otras transformaciones 80
, $) & ( %-& .,
1) API 2D de Java 87
1.1 Características generales del API 2D de Java 87
1.1.1 Mejoras de gráficos, texto e imágenes 87
1.1.2 Modelo de Renderizado 88
1.1.3 Métodos de renderizado de Graphics2D 90
1.1.4 Sistema de coordenadas 91
1.1.5 Fuentes 93
1.1.6 Imágenes 94
1.1.7 Rellenos y Filetes 95
1.1.8 Composiciones (composites) 96
1.1.9 Los paquetes del API 2D de Java 97
1.2. La clase Graphics 99
1.2.1 Métodos generales de la clase Graphics 100
1.2.2 Obtener un contexto gráfico 101
1.3 Figuras básicas en Java 2D (Shape) 103
1.3.1 Formas Rectangulares 104
1.3.3 GeneralPath 104
1.3.2 QuadCurve2D y CubicCurve2D 110
1.3.4 Áreas 112
1.4 Texto y Fuentes 115
1.5 Imágenes 119
1.5.1 El modelo de imágenes de modo inmediato y el BufferedImage 120
1.5.2 Filtrado de un BufferedImage 120
1.5.3 Uso de un BufferedImage para Doble Búfer 125
5
! (&&/
Gracias a la paranoia de la Guerra Fría, el Departamento de Defensa de Estados
Unidos creó la Agencia de Proyectos de Investigación Avanzada (ARPA, por sus
siglas en inglés). En torno a esta organización, jóvenes ingenieros trabajaron en
varios centros académicos de Estados Unidos para lograr que la computación
dejara de ser un campo reservado a expertos, como lo era a mediados del siglo
XX. Efectivamente, a inicios de la década de los sesenta, la computación ya se
había abierto un poco a las universidades, pero seguía siendo asunto de una élite.
Sin embargo, a principios de la siguiente década, la computación se convirtió en
una industria y comenzó a perfilarse como una subcultura.
El equipo que durante varios años fue auspiciado por el ARPA estuvo dirigido por
Douglas C. Engelbart. El concepto de microcomputadora actual surgió de aquel
grupo; Engelbart insistía en que las nuevas computadoras debían poder ser
utilizadas por personas no especialistas. Para ello, fue necesario el desarrollo e
integración de la computación gráfica, la computación interactiva y la de tiempo
compartido.
Ivan Sutherland, del Lincoln Laboratory del MIT y parte del grupo de Engelbart,
desarrolló el campo de la computación gráfica, es decir, la incorporación de una
pantalla a una computadora. En 1962, creó el primer sistema de interfaz gráfica, el
Sketchpad. Poco después, la computadora DEC-PDP-1, financiada por la DEC
(Digital Equipment Corporation), y diseñada por ingenieros del MIT, fue la primera
microcomputadora que mostraba información en una pantalla. Atrás quedaba la
penosa comunicación con la computadora por medio de tarjetas y cintas que
confundía la interpretación y requería de un especialista en todo momento.
En tercer lugar, también durante los años 60, surge la computación de tiempo
compartido, el sistema por medio del cual una misma computadora puede dar
servicio a muchas personas, a través de terminales. La trascendencia de la
computación de tiempo compartido estriba en que gracias a dicha forma de trabajo
se desarrollaron una serie de técnicas encaminadas a permitir la transmisión de
información —comunicación— entre los usuarios; ejemplo derivado de ello es el
correo electrónico.
Este curso, le proporcionará una base conceptual sólida para que posteriormente
a través del aprendizaje autónomo usted emprenda la profundización y la práctica
en el aprendizaje de otras herramientas de graficación, lo mismo que el desarrollo
de gráficos que puedan ser útiles en múltiples campos de desempeño, como los
mencionados en párrafos anteriores.
A través del desarrollo de las diferentes unidades temáticas usted conocerá los
fundamentos conceptuales de la graficación en computador, así como los
elementos matemáticos y algorítmicos para dibujar gráficos en dos y tres
dimensiones. También adquirirá las destrezas necesarias para utilizar las
facilidades proporcionadas por una API gráfica.
Para el desarrollo de las diferentes unidades del Módulo del curso Computación
Gráfica se ha intentado recopilar la información más relevante y actualizada,
organizándola de forma coherente y didáctica,... por lo menos es la esperanza de
la autora que el lector encuentre en esta recopilación un material agradable,
legible y actual. Se ha puesto especial interés en asegurar fuentes de calidad,
pues aunque la principal fuente de consulta es internet, se han seleccionado los
9
! (&&/
!
'& '# " !1 #
2/#! #
• Aportar a la fundamentación teórica del estudiante, como
base para la construcción de un discurso coherente y
sustentado, a través de la profundización en la terminología,
fundamentos tecnológicos, físicos y matemáticos de de la
representación gráfica en el computador.
$)
'!1 #
• Que el estudiante utilice y comprenda los diferentes
conceptos relacionados con el la representación de gráficos
en el computador y los componentes hardware - software
necesarios partiendo de los fundamentos teóricos y
tecnológicos de esta disciplina.
11
2 &'2!
( '
Individual
Grupo de Curso
24
!( 1 (&/ ' & "2(! &/ %-&
1
http://www.ldc.usb.ve/~vtheok/cursos/ci4325/historia.html
13
A corto plazo:
• Las aplicaciones de tiempo compartido entre varios usuarios
• La interfaz electrónica de entrada-salida para el despliegue y la comunicación
de la información simbólica y gráfica
14
A largo plazo:
• La lectura óptica de caracteres.
• El reconocimiento y la producción de la voz humana.
• La comprensión del lenguaje natural.
• La programación heurística.
Ya en los años 50’s era obvio que el computador podía manipular imágenes son
gráficos y dibujos tan bien como el texto o los números (oscillon, wirlwind, el juego
spacewar y sage ya se habían construido2). Se comienza entonces a explorar el
potencial de la comunicación gráfica entre el hombre y la máquina. Fue IVAN
SUTHERLAND en su trabajo pionero en el MIT Lincoln Laboratory llamado el
sistema 'Sketchpad' .
• El uso de los lápices de luz ("light pen") para la construcción interactiva de los
dibujos.
• La separación de los sistemas de coordenadas para describir el mundo y el
espacio de representación en el computador.
• La aplicación de operaciones recursivas como mover y borrar a toda la
jerarquía que defina un objeto o escena gráfica.
No pasó mucho tiempo sin que las compañías se empezaran a interesar por las
gráficas en computadora, IBM, por ejemplo lanzó al mercado la IBM 2250, la
primera computadora comercial con un sistema gráfico. La compañía Magnavox, a
su vez obtuvo la licencia para distribuir un sistema de videojuegos creado por
Ralph Baer, el producto fue denominado Odyssey. El Odyssey fue el primer
producto orientado al consumidor con gráficas generadas por computador.
Dave Evans fue contratado por la universidad de Utah para crear el laboratorio de
ciencias de la computación. Evans tomó como interés principal el desarrollar
gráficas por computadora. Evans contrató a Sutherland, y es en Utah donde
Sutherland perfecciona una interfaz de HMD (head mounted display), que había
desarrollado algunos años antes. En ese periodo, Evans y Sutherland eran
frecuentemente asesores de compañías, no obstante, constantemente se
encontraban frustrados por la falta de tecnología, razón que más adelante los llevó
a fundar su propia empresa.
"A Theory of Fractal Sets", explica que una línea es un objeto unidimesional, el
plano es un espacio bidimensional; no obstante, si la línea describe una curva de
manera que cubra la superficie del plano deja de ser unidimensional, aunque
tampoco es bidimensional.
3
Learning Computing History. A Brief History of Computer Graphics[En línea]
http://www.comphist.org/computing_history/new_page_6.htm.
21
♦ 1982: Steven Lisberger - "Tron", la primera película de Disney que hace uso
intensivo de los gráficos tridimensionales
Tom Brighman - "Morphing" primera secuencia de película juega con
un carácter femenino que deforma y se transforma a sí misma en la
forma de un lince.
Jhon Walkner y Dan Drake - AutoCAD
♦ 1983: Jaron Lanier - "DataGlove", una película de realidad virtual que usa
un guante instalado con interruptores y sensores para detectar el
movimiento de la mano.
♦ 1984: Tech de Wavefron. - Polhemus, primer software paras gráficos en 3D
♦ 1985: Pixar Animation Studios. Cortometrajes “Luxo Jr.” - 1989 y “Tin toy”
NES – Sistema de juegos casero Nintendo
22
24
!( 2# ' -& &/ & "2(! &
Cuanto mayor y más nítida sea una imagen y cuantos más colores tenga, más
difícil es de presentar y manipular en la pantalla de un computador. Las
fotografías, dibujos y otras imágenes estáticas deben pasarse a un formato que el
computador pueda manipular y presentar. Entre esos formatos están los gráficos
de mapas de bits (o de píxeles), conocido en el ámbito de la computación gráfica
como raster y los gráficos vectoriales.
23
%-& # %#!
'
Las imágenes de mapa de bits (bitmaps o imágenes raster) están formadas por
una rejilla de celdas, a cada una de las cuales, denominada píxel (Picture
Element, Elemento de Imagen), se le asigna un valor de color y luminancia
propios, de tal forma que su agrupación crea la ilusión de una imagen de tono
continuo.
Una imagen de mapa de bits se crea mediante una rejilla de pixeles única. Cuando
se modifica su tamaño, se modifican grupos de pixeles, no los objetos o figuras
que contiene, por lo que estos suelen deformarse o perder alguno de los pixeles
que los definen. Por lo tanto, una imagen de mapa de bits está diseñada para un
tamaño determinado, perdiendo calidad si se modifican sus dimensiones,
dependiendo esta pérdida de la resolución a la que se ha definido la imagen.
unidades de medida son los pixeles por pulgada (ppp o ppi, pixels per inch, en
inglés) o los pixeles por centímetro (más raramente). Cuanto mayor sea esta
resolución, más contenedores de información (pixeles) tiene el archivo digital, más
calidad tendrá la imagen y más peso en Kb tendrá el archivo.
Una vez definida la resolución de pantalla, el tamaño de los pixeles dependerá del
tamaño físico de la pantalla, medido en pulgadas. En la próxima sección se
profundizará sobre este punto.
Una forma común de clasificar las imágenes según su resolución es aquella que
las divide en imágenes de alta resolución (hi-res) e imágenes de baja resolución
(low-res). Una imagen de alta resolución está prevista para la impresión, teniendo
generalmente 300 ppp o más. Una imagen de baja resolución está prevista
solamente para su exhibición en pantalla, teniendo generalmente una resolución
de 100 ppp o menos.
A mayor resolución, más píxeles hay en una imagen, más grande es su mapa de
bits, mayor información contiene y mayor capacidad de distinguir los detalles
espaciales finos, por lo que tendrá más definición, permitiendo un mayor detalle,
unas transiciones de color más sutiles y una mayor calidad de reproducción.
%-& 1'&!
Por ejemplo, una línea se define en un gráfico de mapa de bits mediante las
propiedades de cada uno de los píxeles que la forman, mientras que en un gráfico
vectorial se hace por la posición de sus puntos inicial y final y por una función que
describe el camino entre ellos. Análogamente, un círculo se define vectorialmente
por la posición de su punto central (coordenadas x,y) y por su radio (r).
Cada vector en un gráfico vectorial tiene una línea de contorno, con un color y un
grosor determinados, y está relleno de un color a elegir. Las características de
contorno (o filete) y relleno se pueden cambiar en cualquier momento.
Las imágenes vectoriales se almacenan como una lista que describe cada uno de
sus vectores componentes, su posición y sus propiedades.
24
!( , 5 6 '7' -!
6 '2
"2(! &/ %-&
Existen multitud de componentes que son necesarios para lograr realizar buenos
productos gráficos, sin embargo en este apartado nos centraremos en la
clasificación y características de los más comunes, a partir de una características
fundamental: usan representación vectorial o raster. Para ello se utiliza un
documento presentado por Claudio Delrieux4.
Los resultados gráficos de una aplicación pueden mostrarse en una gran variedad
de dispositivos de salida. Normalmente estos dispositivos son o bien de pantalla o
bien de impresión. Sin embargo, desde el punto de vista de la Computación
gráfica, es importante otra clasificación, referida al modo en que los mismos son
manejados por la computadora. De esa manera, podemos ver que existen
dispositivos de los siguientes tipos:
4
Introducción a la Computación gráfica. Departamento de Ingeniería Eléctrica. Universidad Nacional del Sur.
[En línea] http://www.memi.umss.edu.bo/~mscinfo/cursos/graficos/main.htm
28
Actualmente estos dispositivos son más caros, pero tienen ciertas ventajas que los
hacen únicos. Por ejemplo, tienen mucha mejor resolución y precisión que los
dispositivos de ráster, y requieren un ancho de banda de comunicación mucho
menor dado que no reciben la discretización completa de las primitivas sino
solamente su posición.
Plotters: Grafican en una hoja (que en algunos casos puede ser de gran tamaño)
sobre la cual se desliza una pluma movida por motores de pasos de gran
precisión.
necesidad de refresco. Por lo tanto, una imagen muy compleja a la cual se van
agregando elementos en orden es idealmente representada por estos dispositivos.
Un elemento se representa “pintándolo” por medio de una serie de recorridas del
cañón electrónico. El borrado, sin embargo, no puede hacerse en forma selectiva,
por lo que no se puede alterar la posición de un elemento sin tener que borrar y
redibujar todos los demás.
Sin embargo, su precisión y velocidad sin necesidad de memoria volátil los hace
ideales para la representación de imágenes de radares.
Los dispositivos de barrido (raster) surgen como alternativa. Los elementos del
dibujo se almacenan en forma de pixeles. Cada vez que se refresca la imagen el
cañón barre todos los pixeles.
Los monitores más populares pueden tener resoluciones de hasta 1200 * 1024
pixeles (aunque este límite avanza día a día), con una cantidad de colores limitada
por las prestaciones de la tarjeta gráfica. Esto representa una calidad más que
aceptable para la mayor parte de las aplicaciones. A continuación se presentan
los diferentes estándares y su capacidad de resolución5:
5
Tomado de: Apuntes de gráficos [En línea] http://www.ii.uam.es/~pedro/graficos/
teoria/Conceptos/ConceptosFundamentales.htm
31
Las señales de barrido son enviadas al monitor, pero también se utilizan para
encontrar la posición de memoria en la cual está almacenada la información
gráfica de cada pixel que constituye una línea de barrido. Esto se realiza por
medio de una unidad aritmética que encuentra una dirección lineal a partir de los
valores de la señal de barrido horizontal y vertical. La dirección lineal habilita la
salida del valor almacenado en un lugar de la memoria del buffer de pantalla.
Dicho valor es transformado en información gráfica por medio de una tabla de
color, excepto en el modo true color (color verdadero) que se explicará más
adelante.
,9 #2 #!1 # '' !
Para lograr un sistema flexible los microcontroladores no identifican cada tecla con
su carácter serigrafiado en la misma, sino que se adjudica un valor numérico a
cada una de ellas que sólo tiene que ver con su posición física. Si no se hiciera así
ese sistema sería muy dependiente de cada idioma, también hay que tener en
cuenta que idiomas como por ejemplo en francés tienen teclados AZERTY en
lugar del que se tiene en Estados Unidos QWERTY.
En los teclados AT los códigos generados son diferentes, por lo que por razones
de compatibilidad es necesario traducirlos. De esta función se encarga el
controlador de teclado que es otro microcontrolador (normalmente el 8042), éste
ya situado en el PC. Este controlador recibe el Keyboard Scan Code (Kscan Code)
y genera el propiamente dicho Scan Code. En cualquier caso ya sea teclado PS/2
ó AT el Scan Code es entregado a la BIOS del PC para identificar la tecla pulsada.
En cuanto a las pantallas, el tipo de pantalla táctil más sencillo está compuesto de
una red de líneas sensibles, que determinan la situación de una presión mediante
la unión de los contactos verticales y horizontales.
35
Figura 17 Dispositivos apuntadores indirectos: ratón, touchpad, trackpoint, joystick, tableta gráfica, etc
Los ratones (mouse) suelen estar constituidos por una caja con una forma más o
menos anatómica en la que se encuentran dos botones que harán los famosos
clics de ratón siendo transmitidos por el cable al puerto PS/II o al puerto de serie.
Los ratones mecánicos mantienen dentro de esta caja una bola que sobresale de
la caja a la que se pegan 4 rodillos ortogonalmente dispuestos que serán los que
definan la dirección de movimiento del ratón. El ratón se mueve por una alfombrilla
ocasionando el movimiento de la bola que a su vez origina el movimiento de uno o
36
Existen modelos en los que la transmisión se hace por infrarrojos eliminando por
tanto la necesidad de cableado. Otros presentan la bola en la parte superior de la
caja no estando por tanto en contacto con la alfombrilla y teniendo que ser movida
por los dedos del usuario aunque se origina el mismo efecto. Otros utilizan diodos
emisores de luz (led), para capturar el movimiento del ratón, en este caso se
denominan ratones ópticos.
,* -
!6 ' ' -& &/
Los paquetes de animación consisten en uno o varios módulos con los que es
posible modelar, animar y dar apariencia real a un objeto. En un principio, las
empresas de animación programaban su propio software con el cual luego
trabajaban. Poco a poco fueron surgiendo distintos programas, los cuales podían
ser adquiridos a través de una licencia de uso.
Composición de la escena
Rénder (creación de la imagen final)
El modelado puede ser realizado por programas dedicados (como Lightwave 3D,
Rhinoceros 3D o Moray), un componente de una aplicación (Shaper, Lofter en 3D
Studio) o por un lenguaje de descripción de escenas (como en POV-Ray. En
algunos casos, no hay una distinción estricta entre estas fases; en dichos casos, el
modelado es sólo una parte del proceso de creación de escenas (por ejemplo, con
Caligari trueSpace).
Las mallas de triángulos son populares ya que está probado que son fáciles de
'
renderizar'usando Scanline rendering.
A pesar de haber muchos paquetes de modelado y animación 3D, los cuatro que
se han ganado la mayor popularidad son:
39
Junto a estos paquetes mayores, hay otros que no se han ganado tal aceptación
general, pero que no son simples juguetes. Algunos son:
Caligari trueSpace - una aplicación 3D integrada, con una interfaz muy intuitiva.
Una característica distintiva de esta aplicación es que todas las fases de creación
de gráficos 3D son realizadas dentro de un único programa. No es tan avanzado
como los paquetes líderes, pero provee características como simulación de
fenómenos físicos (viento, gravedad, colisiones entre cuerpos).
Cinema4d - Motor de rénder rápido, cálculo de radiosidad.
formZ - Ofrece manipulación topológica de las geometrías.
Rhinoceros 3D - Un potente modelador bajo NURBS.
POV-Ray - Un avanzado software gratuito de Raytracing. Usa su propio lenguaje
de descripción de escena, con características como macros, bucles y
declaraciones condicionales. Es completamente gratuito aunque no fue lanzado
bajo GPL. No incluye modelador.
Moray - Modelador para POV-Ray.
NaN*Blender - Programa de modelado y animación libre, con características como
soporte para programación bajo Python con un amplia gamma de script en
constante desarrollo, posee un motor robusto para la programacion de juegos, un
40
Cada software tiene sus ventajas y desventajas frente a los demás, pero la
posibilidad de realizar un trabajo de calidad no depende de esto, sino de los
conocimientos, la creatividad, y no tanto del software.
Las siguientes APIs para gráficos por computadora son particularmente populares:
OpenGL
Direct3D (subconjunto de DirectX para producir gráficos interactivos en 3D)
RenderMan
En esta dirección web encontrará los enlaces a las páginas web de los
principales software para graficación 3D.
http://www.soloarquitectura.com/favoritos/software3d.html
24
!( 9 #!
'" '& ' #
6
Introducción a la Computación gráfica. Departamento de Ingeniería Eléctrica. Universidad Nacional del Sur.
[En línea] http://www.memi.umss.edu.bo/~mscinfo/cursos/graficos/main.htm
41
uno de los muchos espacios que se utilizarán para factorizar adecuadamente las
diversas tareas de un sistema gráfico.
Por último, en el soporte gráfico del buffer de pantalla, un punto se representa con
un pixel, y dicha representación se efectúa accesando una posición de memoria
con un contenido dado. Este espacio se denomina espacio de pantalla y se
direcciona a partir del sistema de coordenadas físico, cuyo origen es el vértice
superior izquierdo. Es posible encontrar varias correspondencias posibles entre el
sistema de coordenadas físico y un sistema de coordenadas arbitrario en el
espacio de la escena. En la literatura normalmente se considera que un pixel es
un “punto con extensión" en el espacio de la escena, y por lo tanto el origen de
dicho espacio coincide con el vértice superior izquierdo del pixel (0,0). Como se
muestra en la siguiente figura. Una precisión mayor llevaría a enunciar que se
encuentra en el centro del pixel (0.0).
24
!( * ! (&&/ !
' 4 '&
Los colores forman parte de la vida misma, y el ser humano es uno de los seres
privilegiados de la Naturaleza por poder disfrutar de ellos. En cualquier momento
de la vida se están recibiendo constantemente impresiones de color, en la calle,
trabajando, navegando por internet, estas impresiones tiene la facultad de exaltar,
tranquilizar, de poner de buen humor o de inspirar pena. Es el mundo de color.
Figura 20 Espectro con los 6 colores apreciados por Newton (violeta, azul, verde, amarillo, naranja y rojo)
Unos años más tarde, el físico inglés Thomas Young realizó el experimento a la
inversa. En primer lugar determinó por investigación que los seis colores del
espectro pueden quedar reducidos a tres colores básicos: el verde, el rojo y el azul
intenso. Tomó entonces tres linternas y proyectó tres haces de luz a través de
filtros de los colores mencionados, haciéndolos coincidir en un mismo espacio; los
haces verde, rojo y azul se convirtieron en luz blanca. En otras palabras, Young
recompuso la luz.
Así, la luz blanca, esa luz que rodea al ser humano, está formada por luz de seis
colores; y cuando incide en algún cuerpo éste absorbe alguno de dichos colores y
7
http://www.newsartesvisuales.com/funda/COLOR1.HTM
8
http://www.desarrolloweb.com/articulos/1444.php?manual=47. Artículo publicado por Luciano Moreno.
9
http://www.lilliputmodel.com/articulos/cebrian/teoria_color1.htm
10
Introducción a la Computación gráfica. Departamento de Ingeniería Eléctrica. Universidad Nacional del
Sur. [En línea] http://www.memi.umss.edu.bo/~mscinfo/cursos/graficos/main.htm
43
refleja otros. Esto da lugar al siguiente principio: Todos los cuerpos opacos, al ser
iluminados, reflejan todos o parte de los componentes de la luz que reciben.
En la práctica, y para comprender mejor este fenómeno, se dirá que, por ejemplo,
un tomate rojo absorbe el verde y el azul y refleja el rojo; y un plátano amarillo
absorbe el color azul y refleja los colores rojo y verde, los cuales, sumados,
permiten ver el color amarillo.
El color es una sensación subjetiva y nadie puede asegurar a ciencia cierta que
percibe los colores igual que otro. De todas formas los hombres vemos más o
menos igual y partiendo de esta premisa se deberá estudiar la teoría del color.
Podemos ver las cosas que nos rodean porque La Tierra recibe la luz del Sol, esta
estrella inunda constantemente el planeta con su luz, y gracias a ella es también
posible la vida.
La luz del Sol está formada en realidad por un amplio espectro de radiaciones
electromagnéticas de diferentes longitudes de onda, formando un espectro
continuo de radiaciones, que comprende desde longitudes de onda muy
pequeñas, de menos de 1 picómetro (rayos cósmicos), hasta longitudes de onda
muy grandes, de más de 1 kilómetro.
El ser humano tan solo es capaz de visualizar un subconjunto de ellas, las que van
desde 380 (violeta) a 780 nanómetros (rojo), esto lo apreció Newton en su
experimento.
44
Los conos se concentran en una región cerca del centro de la retina llamada
fóvea. Su distribución sigue un ángulo de alrededor de 2° contados desde la fóvea.
La cantidad de conos es de 6 millones y algunos de ellos tienen una terminación
nerviosa que va al cerebro.
Los conos son los responsables de la visión del color y se cree que hay tres tipos
de conos, sensibles a los colores rojo, verde y azul, respectivamente. Dada su
forma de conexión a las terminaciones nerviosas que se dirigen al cerebro, son los
responsables de la definición espacial. También son poco sensibles a la intensidad
de la luz y proporcionan visión fotópica (visión a altos niveles).
pero a grandes rasgos y a nivel práctico son suficientes los conceptos estudiados
hasta ahora.
* ' # '&
No es necesaria la unión de todas las longitudes del espectro visible para obtener
el blanco, ya que si se mezcla sólo rojo, verde y azul se obtiene el mismo
resultado. Es por esto por lo que estos colores son denominados colores
primarios, porque la suma de los tres produce el blanco. Además, todos los
colores del espectro pueden ser obtenidos a partir de ellos.
Los colores aditivos son los usados en trabajo gráfico con monitores de ordenador,
ya que el monitor produce los puntos de luz partiendo de tres tubos de rayos
catódicos, uno rojo, otro verde y otro azul. Por este motivo, el modelo de definición
de colores usado en trabajos digitales es el modelo RGB (Red, Green, Blue).
Esta forma aditiva de percibir el color no es única. Cuando la luz solar choca
contra la superficie de un objeto, éste absorbe diferentes longitudes de onda de su
espectro total, mientras que refleja otras. Estas longitudes de onda reflejadas son
precisamente las causantes de los colores de los objetos, colores que por ser
producidos por filtrado de longitudes de onda se denominan colores sustractivos.
Este fenómeno es el que se produce en pintura, donde el color final de una zona
va a depender de las longitudes de onda de la luz incidente reflejadas por los
pigmentos de color de la misma.
Un coche es de color azul porque absorbe todas las longitudes de onda que
forman la luz solar, excepto la correspondiente al color azul, que refleja, mientras
que un objeto es blanco porque refleja todo el espectro de ondas que forman la
luz, es decir, refleja todos los colores, y el resultado de la mezcla de todos ellos da
como resultado el blanco. Por su parte, un objeto es negro porque absorbe todas
las longitudes de onda del espectro: el negro es la ausencia de luz y de color.
El sistema CMYK, define los colores de forma similar a como funciona una
impresora de inyección de tinta o una imprenta comercial de cuatricromía. El color
resulta de la superposición o de colocar juntas gotas de tinta semitransparente, de
los colores cian (un azul brillante), magenta (un color rosa intenso), amarillo y
negro, y su notación se corresponde con el valor en tanto por ciento de cada uno
de estos colores.
Otro modelos de definición del color es el modelo HSV o HSB, que define los
colores en función de los valores de tres importantes atributos de estos, matiz
(Hue), saturación (Saturation) y brillo (Value).
49
El matiz del color (Hue), también conocido como tono es el color en sí mismo,
supone su cualidad cromática, es -simplemente- un sinónimo de color. Es la
cualidad que define la mezcla de un color con blanco y negro. Está relacionado
con la longitud de onda de su radiación. Según su tonalidad se puede decir que un
color es rojo, amarillo, verde.
El brillo (Value) o brillantez tiene que ver con la intensidad o el nivel de energía. Es
la luminosidad de un color (la capacidad de reflejar el blanco. Alude a la claridad
u oscuridad de un tono. Es una condición variable, que puede alterar
fundamentalmente la apariencia de un color. La luminosidad puede variar
añadiendo negro o blanco a un tono.
El color en las tarjetas gráficas, como vimos, se representa por medio del espacio
cromático RGB . Esto significa que el color de cada pixel se representa por medio
50
En dichos modos, el acceso del índice del color de un pixel se efectúa según la
aplicación utilizada para diseñar el gráfico. Por ejemplo, en C gráfico esta
asignación se realiza por medio de la sentencia putpixel(x,y,c), mientras que
asignar una entrada en la tabla de colores se realiza por medio de la sentencia
setrgbpalette(c,r,g,b). En dicho modelo se utiliza la sentencia putpixel(x,y,c) para
acceder al buffer de pantalla y dibujar un pixel en la posición x, y con el índice de
color c, con x, y, c de tipo entero. En Java la instrucción Color micolor = new
Color(r,g,b) define una objeto de la clase Color cuya coloración estará definida por
los valores de sus parámetros enteros r, g, b. A su vez, para dibujar un pixel en el
dispositivo gráfico actual no se define un método, pero es posible realizarlo a partir
del método drawRect(x,y, 0, 0) de la clase Graphics. Este método dibuja un
rectángulo con 0 pixeles de ancho y 0 pixeles de alto en la coordenada precisada
por x, y (que son enteros), el resultado final de este método es el dibujo de un
pixel en la ventana de gráficos.
En los modos gráficos VGA y super VGA, los parámetros r, g, b son de tipo
unsigned int, pero se truncan los dos bit menos significativos, dado que el rango
efectivo de cada componente es de 0 a 63. Por lo tanto es conveniente utilizar una
aritmética dentro de dicho rango para representar los colores, y multiplicar por 4
en el momento de la llamada.
Los modos gráficos VGA y SVGA permiten definir en general 256 colores
simultáneos (“paleta” gráfica) de entre 256K colores posibles. Estas posibilidades
pueden ser, en algunos casos, poco satisfactorias, no sóolo porque la paleta sea
limitada, sino porque los colores son definibles con poca precisión en algunos
casos. Si bien el ojo humano detecta aproximadamente 350.000 colores diferentes
(y es capaz de distinguir aproximadamente 50.000 en forma simultánea), esta
sensibilidad no es uniforme en todo el espacio cromático, sino que es mucho
mayor en ciertas áreas (por ejemplo en el eje naranja-violeta) y mucho menor en
otras (por ejemplo en el eje magenta-verde).
personas con visión cromática muy sensible que siguen encontrando diferencias
de matiz entre colores contiguos en la gama del amarillo-anaranjado y del
violáceo. Probablemente la mejor solución hubiera sido contar con tecnología CSV
en las tarjetas gráficas, dado que la conversión al RGB del monitor se puede hacer
dentro de la controladora de video.
*9 '! # #!
%!& #7 %" & #
Cada pixel de cada cara reclamará un color determinado, es decir, una terna de
reales (R(p), G(p), B(p)). Esta terna debe transformarse a una terna (R,G,B) dentro
de la aritmética de la tarjeta gráfica. Al mismo tiempo, los valores de (R,G,B)
deben estar asociados a uno de los índices de color disponibles.
De esa forma, se eligen 6 intensidades permitidas para los primarios rojo y azul, y
7 para el primario verde (que es para el cual el ojo humano es más sensitivo). De
esa manera, el espacio RGB de la tarjeta queda “cuantizado” en 150 prismas
rectangulares, y todos los colores representables que caen dentro de un mismo
prisma se aproximan al valor del vértice más cercano. La determinación de los
6*7*6 valores se debe realizar en forma experimental, teniendo en cuenta la
corrección del monitor utilizado. En un determinado monitor (un NEC MultiSync
3D) para una posición adecuada en las perillas de brillo y contraste, los resultados
elegidos fueron rojo = (0,20, 32, 45, 55, 63), verde = (0, 15, 22, 30, 40, 50, 63) y
azul = (0, 25, 35, 45, 55, 63). Debemos recordar que en este modo gráfico, es
posible dar un valor entero de 0 a 63 a la intensidad en cada primario. La
estructura de la cuantización del espacio RGB elegida resulta ser muy práctica en
el momento de encontrar el color con el cual pintar un pixel. Antes de ejecutar la
53
La estructura de la cuantización del espacio RGB elegida resulta ser muy práctica
en el momento de encontrar el color con el cual pintar un pixel. Antes de ejecutar
la grabación, es decir, como paso de inicialización de la interfaz, se almacena la
paleta en la tabla de colores de la pantalla.
Una forma muy económica de producir este efecto consiste en perturbar para cada
primario la cuantización elegida. Si para el primario R se reclama un valor R, el
cual está comprendido entre rojo[r] y rojo[r+1] se perturbará la elección del valor r
o r+1 en la generación del índice de color asociado al pixel (lo propio se efectúa
con los otros dos primarios). Para ello se genera un número aleatorio rnd
54
R − rojo[r ]
uniformemente distribuido entre 0 y 1. Si rnd ≥ se utiliza r+1, y
rojo[r + 1] − rojo[r ]
en caso contrario se utiliza r. En el ejemplo mencionado más arriba, la elección
para la cuantización del rojo está circunscripta a los valores predefinidos 32 o 45.
Como 35 es más cercano a 32 que a 45, la probabilidad de que se utilice dicho
valor es mayor a la de utilizar 45. De esa manera, se transforma el aliasing
cromático producido por la baja frecuencia de muestreo en un ruido uniforme.
Fuentes Relacionadas
OUTING, Steve. “News sites repeat mistakes of the past. We still don´t recognize
the power of interactivity”. Editor & Publisher. 4 de Mayo. VNU eMedia Inc.
Consultado en abril de 2002 en:
55
www.editorandpublisher.com/editorandpublisher/features_columns/article_display.j
sp?vnu_content_id=1461161
0 :
! (&&/
!
'& '# " !1 #
2/#! #
Introducir al estudiante en el conocimiento de los principales
algoritmos y estructuras de datos utilizados en Computación
Gráfica para modelar y visualizar escenas en 2 y 3
dimensiones, como fundamento para la visualización gráfica en
el computador.
2 &'2!
( '
58
Individual
Grupo de Curso
24
!( !
" #$%#& #
Es muy difícil escoger un conjunto de primitivas gráficas que sea adecuado para la
representación de todo tipo de entidades gráficas. Sin embargo, el siguiente
subconjunto en la práctica resulta suficiente:
11
DELRIEUX, Claudio. Introducción a la computación gráfica. [En línea]
http://www.dc.uba.ar/people/materias/cgr/util.htm. Universidad Nacional del Sur. Departamento de
Ingeniería eléctrica. Claudio@acm.org.
59
Dada una primitiva gráfica a discretizar, debemos encontrar los pixeles que la
representen de la manera más correcta posible. Para ello, lo más adecuado es
caracterizar matemáticamente a dicha primitiva, de modo que su discretización
60
pueda efectuarse en forma sencilla. Entre los diversos métodos que pueden
plantearse destacamos los dos siguientes:
3- Java no tiene una sentencia básica para dibujar puntos (pixeles), en este caso
se utiliza la sentencia g.drawRect (línea 35) para dibujar un rectángulo con un
ancho y alto de 0, que en su ejecución se traduce a pintar un único pixel
ubicado en el punto enviado como parámetro.
4- En la misma sentencia g.drawRect (línea 35) se utiliza el “casting” a enteros
para lograr la discretización de las coordenadas flotantes.
63
Por lo tanto, la elección del paso E o D depende de que el valor absoluto de e+m
sea o no menor que el valor absoluto de e+m-1. Expresado de otra manera, sea e
65
∆y
e0 = 2∆x − 0.5 = 2∆y − ∆x
∆x
Paso a E : e = e+2∆y
Paso a D: e = e+2(∆y-∆x)
x = r * cosθ
y = r * sen θ
Estas ecuaciones serán las que ocuparemos para calcular cada punto (x,y) del
círculo, donde el r será obviamente el radio de círculo y θ será el ángulo que forma
el radio con la parte positiva del eje x. En forma gráfica sería así:
El ángulo deberá estar en radianes ya que las funciones de seno y coseno que
incluye Java, trabajan con los ángulos en radianes. La fórmula para transformar
grados a radianes es la siguiente:
gra dos * π
radianes =
180
12
ALBORNOZ Roberto. Programación gráfica en lenguaje C. [En línea]
http://www.geocities.com/programacion_grafica/prog_graf.htm. Fecha de consulta: Septiembre de 2005.
67
* $() '2 4 #
* 4 # '( '#
13
DAVIDSON, Steven. Curso de gráficos con clase. [En línea] http://graficos.conclase.net/curso/index.php
Fecha de consulta: Diciembre de 2005. steven@conclase.net
69
Como se podrá deducir del código el objeto Punto incluye las coordenadas x e y
de un punto en el plano cartesiano.
* 4 # '( '#
x i = cx + r * cos( i* )
y i = cy + r * sen( i* )
donde:
i = 0,1,2,...,N-1,
r es el radio de la circunferencia, y
c = (cx, cy) es la coordenada del centro geométrico de la circunferencia y del
polígono.
24
!( ' '% ' #
24
!( , #- " & '#
Estos cambios son fáciles de realizar porque la imagen gráfica ha sido codificada
en forma de números y almacenada en el interior del ordenador. Los números son
susceptibles a las operaciones matemáticas denominadas transformaciones.
Las imágenes gráficas que se han generado están compuestas por un conjunto de
segmentos que están representados por las coordenadas de sus extremos.
Algunos cambios en la imagen pueden ser fácilmente realizados mediante la
aplicación de algunas operaciones matemáticas sobre estas coordenadas. Antes
de ver algunas de las posibles transformaciones, es necesario repasar algunas de
las herramientas matemáticas que se necesitarán, como la multiplicación de
matrices.
Esta es una propiedad muy útil ya que permitirá combinas varias transformaciones
gráficas en una sola transformación, produciendo como resultado unos cálculos
más eficientes.
matrices cuadradas (tienen el mismo número de columnas y de filas) con todos los
elementos 0 excepto los elementos de la diagonal principal, que valen todos 1. Por
ejemplo
De forma matemática A = AI
, "$ # ''#&
¿Cómo se aplica todo esto a los gráficos? Bueno, consideremos un punto P1=[x1
y1] como una matriz de 1x2. Si la multiplicamos por una matriz T2x2, obtendremos
otra matriz que puede ser interpretada como otro punto.
Por tanto, la matriz T es una aplicación entre el punto original P1 y el nuevo punto
P2. Si suponemos la imagen compuesta por los vértices de un polígono. ¿Qué
pasará si transformamos cada uno de los puntos mediante una multiplicación por
una matriz T y dibujamos el resultado? ¿Qué aspecto tendrá esta nueva imagen?
La respuesta, por supuesto, depende de los elementos de la matriz T. Si, por
ejemplo, escogemos la matriz identidad entonces la imagen no se verá alterada.
Sin embargo, si escogemos la matriz
entonces
Cada una de las nuevas coordenadas x tiene el doble de valor que las antiguas.
Las líneas horizontales serán dos veces más largas en la nueva imagen. La nueva
imagen tendrá la misma altura, pero parecerá que la hemos estirado hasta
alcanzar el doble del ancho original.
,, ! &/
De forma análoga:
dando
A la vista de estas ecuaciones podemos imaginar una matriz que relacione las
coordenadas del punto original y del punto girado:
Así la matriz de transformación para una rotación en sentido contrario a las agujas
del reloj de ángulo φ alrededor del origen es
Para una rotación en el sentido de las agujas del reloj, basta sustituir en la
expresión anterior el valor del ángulo por −φ. Así nos queda
77
En general, con el fin de trasladar un imagen (Tx, Ty), cada punto (x1, y1) se
convierte en uno nuevo (x2, y2) donde
Tal combinación sería deseable; por ejemplo, hemos visto que la rotación
alrededor de un punto que no sea el origen puede realizarse mediante una
traslación, una rotación u otra traslación. Sería deseable combinar estas tres
transformaciones en una sola transformación por motivos de eficacia y elegancia.
Una forma de hacer esto es emplear matrices 3x3 en vez de matrices 2x2,
introduciendo una coordenada auxiliar w. Este método recibe el nombre de
coordenadas homogéneas. En estas coordenadas, los puntos están definidos
por tres coordenadas y no por dos. Así un punto (x, y) estará representado por la
tripleta (xw, yw, w). Las coordenadas x e y se pueden recuperar fácilmente
dividiendo los dos primeros números por el tercero respectivamente. No
emplearemos la coordenada w hasta que no veamos las transformaciones
tridimensionales de perspectiva. En dos dimensiones su valor suele ser 1 para
simplificar. Sin embargo, lo veremos de forma general como anticipo de las
transformaciones tridimensionales.
se convierte en
78
Si dividimos ahora por el tercer valor w tenemos (Exx, Eyy) que es el punto
correcto cambiado de escala.
la rotación es
Cabe destacar que esta matriz se puede formar también mediante una rotación
inicial de ángulo θ y una traslación definida por los valores contenidos en la tercera
fila.
Las tres transformaciones de cambio de escala, rotación y traslación son las más
útiles y las más usadas. Son también posibles otras transformaciones. Dado que
una matriz 2x2 cualquiera
deformación en el eje y
deformación en el eje x
Las primeras tres reflexiones son simples cambios de escala pero con factores
negativos. Las simetrías respecto a las rectas y=x e y=-x pueden realizarse
mediante un cambio de escale y un giro posterior. Es posible realizar las
deformaciones mediante una secuencia de rotaciones y cambios de escala,
aunque es mucho más fácil aplicar la matriz resultante. De igual forma se pueden
construir transformaciones de cambio de escala y rotación a partir de las
deformaciones.
)
' && #
(' !
'# ' & #
,0 :
! (&&/
15
Una API (del inglés Application Programming Interface - Interfaz de Programación de Aplicaciones) es un
conjunto de especificaciones de comunicación entre componentes software. Representa un método para
conseguir abstracción en la programación, generalmente (aunque no necesariamente) entre los niveles o capas
inferiores y los superiores del software. Uno de los principales propósitos de una API consiste en
proporcionar un conjunto de funciones de uso general, por ejemplo, para dibujar ventanas o iconos en la
pantalla. De esta forma, los programadores se benefician de las ventajas de la API haciendo uso de su
funcionalidad, evitándose el trabajo de programar todo desde el principio. Las APIs asimismo son abstractas:
el software que proporciona una cierta API generalmente es llamado la implementación de esa API.
Wikipedia. http://es.wikipedia.org/wiki/API. Fecha de consulta: Enero de 2006.
84
Esta unidad final del curso de Computación Gráfica quiere acercarlo aún más a la
visualización de gráficos computacionales. Aunque se reconoce que la
información que se proporciona es bastante limitada, los límites se los impone su
creatividad y sus deseos de realizar nuevas cosas. En la sección de Enlaces
relacionados podrá encontrar enlaces con una gran cantidad de información
adicional, para ayudarlo a hacer volar su imaginación.
16
FROUFE, Agustín. Tutorial de Java. [En línea]
http://www.itapizaco.edu.mx/paginas/JavaTut/froufe/introduccion/indice2.html#quince. Fecha de consulta:
Noviembre de 2005.
17
Java en Castellano. Gráficos con Java 2D. Traducción del curso de Sun Microsystems realizada por Juan
Antonio Palos (ozito) [En línea] http://www.programacion.com/java/tutorial/2d/1/
18
Programación en Castellano. Curso de programacion Java en 3D. Traducción del curso de Sun
Microsystems realizada por Juan Antonio Palos (ozito) [En línea]
http://www.programacion.com/tutorial/3d/1/
85
!
'& '# " !1 #
2/#! #
Introducir al estudiante en el conocimiento de los principales
algoritmos y estructuras de datos utilizados en Computación Gráfica,
especialmente en la generación de gráficos en dos dimensiones.
2 &'2!
( '
Individual
Grupo de Curso
24
!( ': 1
&!
'4#!& # ' ' '# ' ': 1
Cuando se usa en conjunto con al Java Media Framework y otras APIs de Java
Media, el API 2D de Java puede utilizarse para crear y visualizar animaciones y
otras presentaciones multimedia. Los APIs de Java Animation y Java Media
Framework le proporcionan al API 2D de Java el soporte para el renderizado.
19
Traducción libre de un archivo de ayuda construido a partir de la documentación del J2SE. [En línea]
http://www.confluent.fr/javadoc/indexe.html. El documento de ayuda fue construido por Franck Allimant.
20
CAD-CAM se utiliza para definir el Diseño y Modelamiento asistido por computador
88
Para usar las características del API 2D de Java, tenemos que forzar el objeto
Graphics pasado al método de dibujo de un componente a un objeto Graphics2D.
Como se muestra en el siguiente código
setStroke
setPaint
setComposite
setTransform
setClip
setFont
setRenderingHints
gp = new GradientPaint(0f,0f,blue,0f,30f,green);
g2.setPaint(gp);
9 #!
'" '& ' #
Aunque el sistema de coordenadas para una ventana o una pantalla podría ser
muy distinto que para una impresora, estas diferencias son invisibles para los
programas Java. Las conversiones necesarias entre el espacio de usuario y el
espacio de dispositivo se realizan automáticamente durante el dibujado.
Espacio de usuario
El espacio del usuario representa una abstracción uniforme de todas los posibles
sistemas de coordenadas de dispositivos. El espacio de dispositivo para un
dispositivo particular podría tener el mismo origen y dirección del espacio del
usuario, o podrían ser diferentes. Sin embargo, las coordenadas del espacio del
usuario son automáticamente transformadas en las apropiadas para el espacio del
dispositivo cuando se dibuja un objeto gráfico. Frecuentemente, la plataforma
subyacente o driver del dispositivo se utilizan para desarrollar esta conversión.
Espacio de dispositivo
• GraphicsEnvironment
• GraphicsDevice
• GraphicsConfiguration
Transformaciones
espacio del usuario al espacio del dispositivo, son representadas por objetos de la
clase AffineTransform, que define las reglas para manipular coordenadas usando
matrices.
* (' !
'#
Las figuras que una fuente usa para representar los caracteres en las cadenas se
denominan Glyphs. Una fuente puede representar un carácter como una a con
tílde usando varios glyphs, o representar ciertas combinaciones de caracteres
como la fi de final con un único glyph. En el API Java 2D, una glyph es
simplemente un Shape que puede ser manipulado y dibujado en la misma forma
que cualquier otro objeto Shape.
Una fuente puede ser entendida como una colección glyphs. Una única fuente
puede tener muchas versiones, tales como heavy, médium, oblique, ghotic y
regular. Estas diferentes versiones son llamadas caras (faces) . Todas las caras
de una fuente tienen un diseño tipográfico similar y pueden ser reconocidas como
miembros de una misma familia. En otras palabras, una colección de glyphs con
una forma particular de estilo conforma una font face, una colección de formas de
font faces forman una font family, y una colección de font families conforma el
grupo de fuentes disponible en un GraphicsEnvironment particular.
En el API Java 2D, las fuentes se especifican por un nombre que describe una
particular font face (por ejemplo: Helvetica Bold) Es diferente a como se asume en
el JDK 1.1, en las que las fuentes eran descritas por nombres lógicos que
tomaban la forma de diferentes font face dependiendo de las fuentes disponibles
en la plataforma particular. Para lograr compatibilidad el API Java 2D soporta la
especificación de fuentes por su nombre lógico y también por su nombre de font
face.
94
En una imagen de color indexado, los colores en la imagen están limitados a los
colores especificados en una tabla de colores, a menudo, el resultado es que sólo
es posible usar unos pocos colores en la imagen. Sin embargo, un índice requiere
menos almacenamiento que un valor de color, por tanto el resultado es que las
imágenes de colores indexados son más pequeñas. El formato de píxel es
popular para las imágenes que contienen sólo 16 o 256 colores.
Una objeto ColorSpace encapsula las reglas que gobiernan la forma como un
conjunto de valores numéricos corresponden a un color particular. La
implementación del ColorSpace en el java.awt.color representa los espacios de
color más popular, incluyendo RGB y escala de grises. Es importante aclarar que
un espacio de color no es una colección de colores, el define las reglas como
deberán ser interpretados los valores de colores individuales.
@ '' #7 '!
'#
Los patrones de rellenos están definidos por objetos que implementan la interfaz
Paint. La clase Color, que está disponible en versiones anteriores de AWT, es un
tipo simple de un objeto Saint usado para definir rellenos de colores sólidos. El
API 2D de Java proporciona dos implementaciones adicionales para Paint,
TexturePaint y GradientPaint.
96
En Java 2D, el renderizado de la línea exterior y el relleno de una figura son dos
operaciones separadas:
• Usando el método draw se dibuja el contorno (línea exterior) de la figura
usando el estilo de lápiz especificado en el atributo Stroke y el patrón de
relleno especificado por el atributo Paint.
• Usado el método fill se rellena el interior de la figura con el patrón especificado
en el atributo Paint.
C #2 =('!
'# ' ': 1
Las clases del API Java 2D está organizada en los siguientes paquetes:
• java.awt
• java.awt.geom
• java.awt.font
• java.awt.color
• java.awt.image
• java.awt.image.renderable
• java.awt.print
El paquete java.awt contiene algunas clases e interfaces del API Java 2D,
obviamente no todas las clases del java.awt son clases del Java 2D.
El API Java 2D mejora las siguientes clases heredadas de la clase image de AWT
• ColorModel
99
• DirectColorModel
• IndexColorModel
Antes de comenzar en serio con los componentes gráficos que proporciona el API
2D de java, es necesario, hacer una pequeña revisión de la clase Graphics,
superclase de Graphics2D y revisar algunos conceptos básicos acerca del
contexto gráfico, que posteriormente permitirán comprender mucho mejor los
ejemplos que se presentarán.
Hay muchas otras clases, como la clase Rectangle y la clase Polygon, que utilizan
como soporte a las operaciones que se pueden realizar con la clase Graphics.
Para poder revisar esta clase, quizá una de las mejores formas sea a través de
sus múltiples métodos, intentando agruparlos por funcionalidad, que es lo que se
ha intentado aquí, aunque si el lector quiere una referencia completa y una
descripción de los métodos de esta clase deberá recurrir a la documentación que
JavaSoft proporciona sobre el AWT.
Hay que empezar hablando del constructor de la clase Graphics, que no tiene
argumentos; aunque Graphics es una clase abstracta, por lo que las aplicaciones
no pueden llamar a este constructor directamente. Se puede obtener un objeto de
tipo Graphics a partir de otro objeto Graphics llamando al método getGraphics()
sobre un componente. También se puede recibir un objeto Graphics como
parámetro cuando se van a sobreescribir los métodos paint() o update().
En esta categoría estarían incluidos los métodos útiles en general, sin una
asignación específica de funcionalidad con respecto a acciones determinadas de
dibujo. A continuación se enumeran algunos de los métodos considerados
generales, para seguir con la descripción y uso de algunos de ellos en
aplicaciones de ejemplo.
create(), crea un nuevo objeto de tipo Graphics que es copia del objeto Graphics
que ha invocado al método.
setColor( Color ), fija el color del contexto gráfico al color que se pasa como
parámetro. Todas las operaciones gráfica siguientes que utilicen este contexto
gráfico, utilizarán el color que se especifica en este método.
translate( int,int ), traslada el origen del contexto gráfico al punto que se pasa en
los dos parámetros en el sistema de coordenadas que se esté utilizando.
$!
'' ( & !
'?! %-&
La verdad es que se han escrito varias veces las palabras contexto gráfico, y no
se ha proporcionado al lector una explicación concreta de lo que significan estos
términos. Hay varias definiciones, para unos significa que la aplicación ha
conseguido la habilidad para pintar o colocar imágenes sobre un componente que
tiene la característica de soportar el pintado o visualización de imágenes. Otros
autores prefieren decir que cada objeto Graphics representa una determinada
superficie de dibujo, luego ese objeto Graphics define un contexto gráfico a través
del cual se pueden manipular todas las actividades gráficas sobre esa superficie.
Y otros autores indican que un objeto Graphics es la superficie última sobre la que
se pueden colocar líneas, figuras y texto, por lo cual puede recibir también el
nombre de contexto gráfico al aunar información sobre la zona de dibujo, más la
fuente de caracteres, color y cualquier otro factor.
Ahora que ya se sabe lo que es un contexto gráfico, hay que ver cómo se
consigue crear uno. Para empezar, esto no puede hacerse instanciando
directamente un objeto de tipo Graphics, ya que la clase Graphics es abstracta y
102
no puede ser instanciada por el código de la aplicación, así que hay que recurrir a
formas indirectas para conseguir el contexto gráfico.
Hay otros dos caminos para obtener un contexto gráfico y, son sorprendentemente
simples, porque se hace automáticamente, y es cuando se sobreescriben los
métodos paint() y update(), en los cuales Java pasa como parámetro el contexto
gráfico del objeto al que pertenece el método.
Hay que tener en cuenta que el método repaint() pide al sistema que redibuje el
componente tan pronto como sea posible, pero esto lo hará el método update()
que se llame a continuación. No hay una relación uno a uno entre las llamadas a
repaint() y update(), por lo que es posible que múltiples llamadas a repaint()
puedan recogerse en una sola llamada a update().
En síntesis, el método paint() es el que ofrece el sistema para poder pintar lo que
se quiera sobre un determinado componente. En la clase base Component, este
método no hace absolutamente nada. Normalmente, en el caso de applets, se
sobreescribe para hacer presentar un rectángulo relleno con el color de fondo.
103
Las clases del paquete java.awt.geom definen gráficos primitivos comunes, como
puntos, líneas, curvas, arcos, rectángulos y elipses.
Excepto para Point2D y Dimension2D, cada una de las otras clases geométricas
implementa el interfaz Shape, que proporciona un conjunto de métodos comunes
para describir e inspeccionar objetos geométricos bi-dimensionales.
Con estas clases podemos crear de forma virtual cualquier forma geométrica y
dibujarla a través de Graphics2D llamando al método draw o al método fill.
,, ' ' !
<
La clase GeneralPath permite crear una curva arbitraria especificando una serie
de posiciones a lo largo de los límites de la forma.
/*
* Este es un ejemplo sobre el dibujo de Shapes, proporcionado por la
* documentación de Java en la versión 1.2.
*/
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
/*
* La clase se crea como hija de la clase Applet. Si se define como hija
* directa de la clase Frame, se tiene problemas al redimensionar el
* Frame, ya que no se redibujan automáticamente las figuras.
*/
while ( !fontFits ) {
if ( (fontMetrics.getHeight() <= maxCharHeight)
&& (fontMetrics.stringWidth(longString) <= xSpace) ) {
fontFits = true;
}
else {
if ( size <= minFontSize ) {
fontFits = true;
}
else {
g2.setFont(font = new Font(name,
style,
--size));
fontMetrics = g2.getFontMetrics();
}
}
}
return fontMetrics;
}
/* Toma las dimensiones del contexto y lo divide para saber el ancho y alto de
* cada una de las celdas de la cuadrícula donde dibujará
*/
Dimension d = getSize();
int gridWidth = d.width / 6;
int gridHeight = d.height / 2;
int x = 5;
int y = 7;
int rectWidth = gridWidth - 2*x;
int stringY = gridHeight - 3 - fontMetrics.getDescent();
int rectHeight = stringY - fontMetrics.getMaxAscent() - y - 2;
/* Asigna el filete, crea unos vectores con las coordenadas de los puntos del polígono,
* crea el objeto GeneralPath (polygon) trazando lineas entre las coordenadas
* y finalmente cierra el poligono. Dibuja el polígono y el texto inferior
* correspondiente.
*/
g2.setStroke(stroke);
int x1Points[] = {x, x+rectWidth, x, x+rectWidth};
int y1Points[] = {y, y+rectHeight, y+rectHeight, y};
GeneralPath polygon = new GeneralPath(GeneralPath.WIND_EVEN_ODD, x1Points.length);
polygon.moveTo(x1Points[0], y1Points[0]);
for ( int index = 1; index < x1Points.length; index++ ) {
polygon.lineTo(x1Points[index], y1Points[index]);
};
polygon.closePath();
g2.draw(polygon);
g2.drawString("GeneralPath", x, stringY);
/* Realiza los mismo pasos que para el polígono anterior, lo que varía es
* que en este caso no se cierra el polígono
*/
int x2Points[] = {x, x+rectWidth, x, x+rectWidth};
int y2Points[] = {y, y+rectHeight, y+rectHeight, y};
GeneralPath polyline = new GeneralPath(GeneralPath.WIND_EVEN_ODD, x2Points.length);
polyline.moveTo (x2Points[0], y2Points[0]);
for ( int index = 1; index < x2Points.length; index++ ) {
polyline.lineTo(x2Points[index], y2Points[index]);
};
g2.draw(polyline);
g2.drawString("GeneralPath (Abierto)", x, stringY);
x += gridWidth;
g2.setPaint(fg);
g2.drawString("Ellipse2D con gradiente", x, stringY);
x += gridWidth;
/* Define los arreglos de las coordenadas para el polígono. Crea el polígono uniendo
* los puntos con líneas. Asigna el color rojo y dibuja el polígono relleno.
* Retorna el valor de la pintura a negro y dibuja el polígono mediante draw, lo
* que origina que se sibuje el filete del polígono.
*/
int x3Points[] = {x, x+rectWidth, x, x+rectWidth};
int y3Points[] = {y, y+rectHeight, y+rectHeight, y};
GeneralPath filledPolygon = new GeneralPath(GeneralPath.WIND_EVEN_ODD,
x3Points.length);
filledPolygon.moveTo(x3Points[0], y3Points[0]);
for ( int index = 1; index < x3Points.length; index++ ) {
filledPolygon.lineTo(x3Points[index], y3Points[index]);
};
filledPolygon.closePath();
g2.setPaint(Color.yellow);
g2.fill(filledPolygon);
g2.setPaint(fg);
g2.setStroke(wideStroke);
g2.draw(filledPolygon);
g2.drawString("GeneralPath con relleno y contorno", x, stringY);
}
El siguiente código crea una curva cuadrática con dos puntos finales y un punto de
control. Las posiciones de los puntos se seleccionan con respecto al tamaño de la
ventana.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
Dimension d = getSize();
int w = d.width;
int h = d.height;
//Crea los objetos que definen los puntos de inicio, final y control
111
//Dibuja la curva
g2.draw(quad);
//Crea el Frame
JFrame f = new JFrame("Dibujando un QuadCurve2D");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
//Crea el applet de acuerdo a la clase ShapesDemo2D
JApplet applet = new EjemploQuad();
//Agrega el objeto applet al Frame
f.getContentPane().add("Center", applet);
applet.init();
f.pack();
f.setSize(new Dimension(400,300));
f.show();
}
}
,9 '#
Unión Sustracción
import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.applet.*;
import javax.swing.*;
/*
* Este applet dibuja una pera, usando métodos de Constructive Area Geometry (CSG)
* para adición, sustracción e intersección.
*/
setBackground(Color.white);
}
double ew = w/2;
double eh = h/2;
g2.setColor(Color.green);
g2.setColor(Color.black);
/* Crea el pedazo de tronco a partir del llenado del Area resultante de la sustracción de
* dos objetos Area creados a partir de una elipse.
*/
stem.setFrame(ew, eh-42, 40.0, 40.0);
st1 = new Area(stem);
stem.setFrame(ew+3, eh-47, 50.0, 50.0);
st2 = new Area(stem);
st1.subtract(st2);
g2.fill(st1);
g2.setColor(Color.yellow);
9 '?! 7 (' !
'#
Es posible mostrar una cadena de texto con cualquier tipo de letra disponible en el
sistema, en cualquier tamaño y en el estilo que se seleccione. Para determinar las
fuentes que están disponibles en el sistema es necesario llamar el método
GrpahicsEnvironment.getAvailableFontFamilyNames. Este método retorna un
arreglo de cadenas que contiene los nombres de las familias de las fuentes
disponibles, cualquiera de estas cadenas, además del tamaño y el estilo, pueden
ser utilizados como argumentos para crear un nuevo objeto Font.
Font thisFont;
...
Para controlar la fuente que se utiliza para dibujar el texto, es necesario enviar los
atributos de la fuente al contexto Graphics2D antes de renderizar. Los atributos
de la fuente se envían pasando un objeto Font al método setFont. En este
ejemplo, los atributos son envidos al construir el nuevo objeto Font y la cadena se
dibuja en el centro del componente usando esta fuente. Cada vez que se
modifiquen los atributos, se construye un nuevo objeto Font y se envía al contexto
Graphics 2D en el metodo Paint() para que sean redibujados. El método
getFontMetrics permite medir la longitud en píxeles de la cadena considerando los
nuevos atributos, de manera que siempre se dibuje en el centro del componente.
g2.setFont(thisFont);
String cadena = "Seleccione una fuente, tamaño y estilo para modificarme";
FontMetrics medida = g2.getFontMetrics();
int ancho = medida.stringWidth( cadena );
int alto = medida.getHeight();
//Dibuja la cadena en el centro del panel correspondiente
g2.drawString( cadena, w/2-ancho/2, h/2-alto/2 );
/*
* Ejemplo de selección de fuentes. Construido para el Tutorial
* de Java2D de Sun Microsystems.
*/
import java.lang.Integer;
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Vector;
int nuevoestilo = 0;
String nuevotam = "10";
/*Se asignan los valores para el combo de tamaño, los posibles tamaños serán 10,
*12,14,16,18. Se define como máximo número de filas a mostrar 9. Se agrega el combo
*al panel correspondiente.
*/
cmbTamano = new JComboBox( new Object[]{ "10", "12", "14", "16", "18"} );
cmbTamano.setMaximumRowCount( 9 );
cmbTamano.addItemListener(this);
pnlTamano.add(cmbTamano);
/*Se arma el combo de estilo a partir de los estilos predeterminados.se siguen los mismo
*pasos que para los combos anteriores y finalmente se incluye el combo en el panel
*correspondiente.
*/
cmbEstilo = new JComboBox( new Object[]{
"PLAIN",
"BOLD",
"ITALIC",
"BOLD & ITALIC"} );
cmbEstilo.setMaximumRowCount( 9 );
cmbEstilo.addItemListener(this);
cmbTamano.setMaximumRowCount( 9 );
pnlEstilo.add(cmbEstilo);
//Cambia la fuente del contexto, de acuerdo con los nuevos atributos seleccionados en los combo
fontC.cambiarFuente(nuevafuente, nuevoestilo, nuevotam);
}
Font thisFont;
public pnlLetra(){
thisFont = new Font("Arial", Font.PLAIN, 10);
}
// Este método es el que modifica la fuente de acuerdo con los nuevos parámetros
public void cambiarFuente(String nf, int nest, String ntam){
Integer nuevoTam = new Integer(ntam);
int tam = nuevoTam.intValue();
thisFont = new Font(nf, nest, tam);
repaint();
}
g2.setColor(Color.darkGray);
g2.setFont(thisFont);
String cadena = "Seleccione una fuente, tamaño y estilo para modificarme";
FontMetrics medida = g2.getFontMetrics();
int ancho = medida.stringWidth( cadena );
int alto = medida.getHeight();
//Dibuja la cadena en el centro del panel correspondiente
g2.drawString( cadena, w/2-ancho/2, h/2-alto/2 );
}
}
* " ' ' "% ' '# ' " "' ! 7 '
(-
-'' " '
BufferedImage es la clase clave del API del modo-inmediato. Esta clase maneja
una imagen en memoria y proporciona métodos para almacenar, interpretar y
dibujar cada dato de pixel. Un BufferedImage puede ser renderizado en un
contexto Graphics o en un contexto Graphics2D.
Un BufferedImage es
esencialmente un Image con un
búfer de datos accesible. Un
BufferedImage tiene un
ColorModel y un Raster de los
datos de la imagen.
Figura 56 Clase BufferedImage (Sun Microsystems)
* ! '( (-
-'' " '
22
En un proceso de doble búfer los elementos gráficos son dibujados fuera de la pantalla en el BufferedImage
y luego son copiados a la pantalla a través de llamadas al método drawImage de Graphics2D
121
• Tranformación afin.
• Escalado.
• Modificación de Aspecto.
• Combinación Linear de Bandas.
• Conversión de color.
• Convolución.
Para construir y aplicar este tipo de filtrado al BufferedImage, este ejemplo usa un
código similar al del siguiente fragmento.
El código completo de la aplicación, que contiene los cuatro filtros aplicados a las
imágenes es el siguiente:
/*
* Ejemplo de aplicación de filtros utilizando BufferedImage y BufferedImageOp.
* Versión modificada del ejemplo del Tutorial de Java 2D de Sun Microsystems.
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.*;
import java.awt.geom.AffineTransform;
import java.awt.font.TextLayout;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.event.WindowAdapter;
import java.applet.*;
import java.net.URL;
/* El objeto MediaTracker, optimiza el proceso de cargado de la imagen al bloquear la tarea hasta que
* la imagen esté totalmente cargada, con lo que se elimina el parpadeo que se produce al ir
* presentándose en la pantalla partes de esa imagen que no está totalmente cargada.
*/
try {
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(imagen, 0);
tracker.waitForID(0);
}
catch ( Exception e ) { }
int iancho = imagen.getWidth(this);
int ialto = imagen.getHeight(this);
vectorbi[i] = new BufferedImage(iancho, ialto, BufferedImage.TYPE_INT_RGB);
g2.setColor(Color.black);
float[][] datos = {{0.1f, 0.1f, 0.1f, // Matriz del Filtro
0.1f, 0.2f, 0.1f,
0.1f, 0.1f, 0.1f},
SHARPEN3x3_3};
switch ( i ) {
case 0 :
case 1 : x = i==0?5:anchoap/2+3; y = 15;
Kernel kernel = new Kernel(3,3,datos[i]);
ConvolveOp cop = new ConvolveOp(kernel,
ConvolveOp.EDGE_NO_OP,
null);
cop.filter(vectorbi[i],biorig);
bitrans = new AffineTransformOp(transformacion,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
break;
case 2 : x = 5; y = altoap/2+15;
byte chlut[] = new byte[256];
for ( int j=0;j<200 ;j++ )
chlut[j]=(byte)(256-j);
ByteLookupTable blut=new ByteLookupTable(0,chlut);
LookupOp lop = new LookupOp(blut, null);
lop.filter(vectorbi[i],biorig);
bitrans = new AffineTransformOp(transformacion,AffineTransformOp.TYPE_BILINEAR);
break;
case 3 : x = anchoap/2+3; y = altoap/2+15;
RescaleOp rop = new RescaleOp(1.1f,20.0f, null);
rop.filter(vectorbi[i],biorig);
bitrans = new AffineTransformOp(transformacion,AffineTransformOp.TYPE_BILINEAR);
}
*, # '( (-
-'' " '2 $ ' E-
'
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
import java.awt.image.*;
/* Toma las coordenas de la última vez que el usuario presiono el mouse y se ejecutó
* el evento mousePressed.
*/
int ult_x, ult_y;
boolean primeraVez = true;
TexturePaint texturaRelleno, texturaFilete;
Rectangle area;
/* Esta variable es True si el usuario dió clic o movio el mouse fuera del area del rectangulo,
* falso de lo contrario
*/
boolean estaFuera = false;
// Maneja el evento cuando el usuario arrastra el mouse miesntras mantiene presionado el botón.
128
if(!estaFuera){
updateLocation(e);
} else {
BufferedShapeMover.lblTexto.setText("Posicione el cursor en el rectángulo y luego
arrastre");
}
}
/* Chequea si el cursor está dentro del rectángulo cuando el usuario suelta el botón del mouse
* e.getX y e.getY proporcionan las coordenadas donde se soltó el botón
*/
if(rect.contains(e.getX(), e.getY())){
updateLocation(e);
} else {
BufferedShapeMover.lblTexto.setText("Posicione el cursor en el rectángulo y luego
arrastre");
estaFuera = false;
}
}
/* Si el método chequearRect retorna verdadero actualiza el contenido del texto para que
* muestre la localización actual del rectángulo, de lo contrario muestr un mensaje
*/
if (chequearRect()) {
BufferedShapeMover.lblTexto.setText("Rectángulo localizado en " +
rect.getX() + ", " +
rect.getY());
} else {
BufferedShapeMover.lblTexto.setText("Por favor no intente arrastrar el rectángulo"+
" fuera del área");
}
repaint();
}
if(primeraVez){
Dimension dim = getSize();
int ancho = dim.width;
int alto = dim.height;
area = new Rectangle(dim);
bi = (BufferedImage)createImage(ancho, alto);
contexto = bi.createGraphics();
rect.setLocation(ancho/2-50, alto/2-25);
contexto.setStroke(new BasicStroke(10.0f));
primeraVez = false;
}
if((rect.x+100)>area.width){
nuevo_x = area.width-99;
}
if(rect.x < 0){
nuevo_x = -1;
}
if((rect.y+50)>area.height){
nuevo_y = area.height-49;
}
if(rect.y < 0){
nuevo_y = -1;
}
rect.setLocation(nuevo_x, nuevo_y);
return false;
}
}
130
24
!( , ': 1
$%#& ': 1 ,
El API 3D de Java es un árbol de clases Java que sirven como interfaz para
sistemas de renderizado de gráficos tridimensionales y un sistema de sonido. El
programador trabaja con constructores de alto nivel para crear y manipular objetos
geométricos en 3D. Estos objetos geométricos residen en un universo virtual, que
luego es renderizado. El API está diseñado con flexibilidad para crear universos
virtuales precisos de una ámplia variedad de tamaños, desde astronómicos a
subatómicos.
23
Programación en Castellano. Curso de programacion Java en 3D. Traducción del curso de Sun
Microsystems realizada por Juan Antonio Palos (ozito) [En línea]
http://www.programacion.com/tutorial/3d/1/
131
Los programas Java 3D pueden escribirse para ser ejecutados como aplicaciones
solitarias o como applets en navegadores que hayan sido extendidos para
soportar Java 3D, o ámbos.
"2'3 & :1 ,
Todo programa Java 3D está, al menos parcialmente, ensamblado por objetos del
árbol de clases Java 3D. Esta colección de objetos describe un universo virtual,
que va a ser renderizado. El API define unas 100 clases presentadas en el
paquete javax.media.j3d.
Hay cientos de campos y métodos en las clases del API Java 3D. Sin embargo, un
sencillo universo virtual que incluya animación puede construirse con unas pocas
clases. Esta sección describe un conjunto mínimo de objetos y sus interacciones
para renderizar un universo virtual.
Esta sección incluye el desarrollo de un sencillo pero completo programa Java 3D,
llamado HelloJava3Dd.java, que muestra un cubo giratorio. El programa de
ejemplo se desarrolla de forma incremental, y se presenta en varias versiones,
para demostrar cada parte del proceso de programación Java 3D.
Además del paquete corazón de Java 3D, se usan otros paquetes para escribir
programas Java 3D. Uno de estos paquetes es com.sun.j3d.utils al que
normalmente se hace referencia como clases de utilidades de Java 3D. El paquete
132
de las clases corazón incluye sólo las clases de menor nivel necesarias en la
programación Java 3D.
En el resto del texto, el término objeto visual se utilizará para hacer referencia a
un "objeto del escenario gráfico" (por ejemplo, un cubo o una esfera). El término
objeto sólo se usará para referirse a un ejemplar de una clase. El término
contenido se usará para referirnos a objetos visuales en un escenario gráfico
como un todo.
24
Como es de su conocimiento, el paquete java.awt define el "Abstract Windowing Toolkit" (AWT). Las
clases AWT crean una ventana para mostrar el renderizado. El paquete javax.vecmath define clases de
vectores matemáticos para puntos, vectores, matrices y otros objetos matemáticos.
133
es el raíz. Se puede acceder a otros nodos siguiendo los arcos desde el raíz. Los
nodos de un árbol no forman bucles. Un escenario gráfico está formado desde los
árboles con raíces en los objetos Locale. Los NodeComponents y las referencias
a arcos no forman parte del escenario gráfico.
Sólo existe un camino desde la raíz de un árbol a cada una de las hojas; por lo
tanto, sólo hay un camino desde la raíz hasta el escenario gráfico de cada nodo
hoja. El camino desde la raíz de un escenario gráfico hasta una hoja especificada
es el camino al escenario gráfico del nodo hoja. Como un camino de un escenario
gráfico trata exactamente con un sola hoja, hay un camino de escenario gráfico
para cada hoja en el escenario.
El símbolo de la flecha sólida representa una relación padre-hijo entre dos objetos.
La flecha punteada es una referencia a otro objeto. Los objetos referenciados
pueden ser compartidos entre diferentes ramas de una escenario gráfico. En la
Figura 60, se puede observar un sencillo escenario gráfico.
Es posible crear un escenario gráfico ilegal. Se puede ver uno en la Figura 61.
Este escenario es ilegal porque viola las propiedades de un DAG. El problema son
los dos objetos TransformGroup(TG) que tienen al mismo objeto Shape3D como
hijo. Recuerda que una hoja sólo puede tener un padre. En otras palabras, sólo
puede haber un camino desde el objeto Locale hasta la hoja (o un camino desde
la hoja hasta el objeto Locale).
Las explicaciones del árbol y de las estructuras DAG son correctas. Sin embargo,
el sistema de ejecución Java 3D reporta el error en términos de la relación hijo-
padre. Un resultado de la limitación de la estructura de árbol es que cada objeto
Shape3D está limitado a un sólo padre. Para el ejemplo de la Figura 61, se
lanzará una excepción 'multiple parent' en el momento de la ejecución. La Figura
62, con un padre para cada objeto Shape3D, muestra una posible solución para
este escenario gráfico.
136
Cada escenario gráfico tiene un sólo VirtualUniverse. Este objeto tiene una lista
de objetos Locale. Un objeto Locale proporciona una referencia a un punto en el
universo virtual. Se puede pensar en los objetos Locale como marcas de tierra que
determinan la localización de los objetos visuales en el universo virtual.
En la Figura 63 se pueden ver los tres primeros niveles del árbol de clases del API
Java 3D. En esta parte del árbol aparecen las clases VirtualUniverse, Locale,
Group, y Leaf.
Clase Node
La clase Node es una superclase abstracta de las clases Group y Leaf. Esta
clase define algunos de los métodos importantes de sus subclases. Las subclases
de Node componen escenarios gráficos.
138
Clase Group
La clase Group es la superclase usada en especificación de localización y
orientación de objetos visuales en el universo virtual. Dos de las subclases de
Group son: BranchGroup y TransformGroup. En la representación gráfica de un
escenario gráfico, los simbolos de Group (círculos) normalmente se anotan con
BG para BranchGroups, TG para TransformGroups, etc. La Figura 60 muestra
algunos ejemplos de esto.
Clase Leaf
La clase Leaf es la superclase usada para especificar la forma, el sonido y
comportamiento de los objetos visuales en el universo virtual. Algunas de las
subclases de Leaf son: Shape3D, Light, Behavior, y Sound. Estos objetos
podrían no tener hijos pero podrían referenciar a NodeComponents.
Clase NodeComponent
La clase NodeComponent es la superclase usada para especificar la geometría,
la apariencia, la textura y las propiedades de material de un nodo Shape3D (Leaf).
Los NodeComponents no forman parte del escenario gráfico, pero son
referenciados por él. Un NodeComponent podría ser referenciado por más de un
objeto Shape3D.
Esta receta ignora algunos detalles pero ilustra el concepto fundamental para toda
la programación Java 3D: crear la rama gráfica del escenario gráfico es la
programación principal. En vez de ampliar esta receta, los siguientes párrafos
explican una forma sencilla de construir un escenario gráfico muy similar con
menos programación.
Los programas Java 3D escritos usando la receta básica tienen ramas de vista
gráfica con idéntica estructura. La regularidad de la estructura de las ramas de
vista gráfica tambien se encuentra en la clase de utilidad SimpleUniverse. Los
ejemplares de esta clase realizan los pasos 2, 3 y 4 de la receta básica. Usando la
clase SimpleUniverse en programación Java 3D se reduce significativamente el
tiempo y el esfuerzo necesario para crear las ramas de vista gráfica.
Consecuentemente, el programador tiene más tiempo para concentrarse en el
contenido. Esto es de lo que se trata el escribir programas Java 3D.
La clase SimpleUniverse
Figura 64 Universo virtual mínimo proporcionado por la clase SimpleUniverse (en azul)
Constructores de SimpleUniverse
Paquete: com.sun.j3d.utils.universe
Esta clase de utilidad crea todos los objetos necesarios para la rama de vista
gráfica. Especificamente crea los objetos Locale, VirtualUniverse, ViewingPlatform,
y Viewer (todos con sus valores por defecto). Los objetos tiene las relaciones
apropiadas para formar la rama de vista gráfica.
Los típicos programas Java 3D mueven la vista hacía atrás (z positivo) para hacer
que los objetos se acerquen, al origen dentro de la vista. La clase SimpleUniverse
tiene un miembro que es un objeto de la clase ViewingPlatform. Esta clase tiene
un método setNominalViewingTransform que selecciona la posición del ojo para
que esté centrado en (0, 0, 2.41) buscando en dirección z negativa hacia el origen.
142
void setNominalViewingTransform()
9 ( '" 4 :1 ,
while(true) {
Procesos de entrada
If (petición de salida) break
Realiza comportamientos
Atraviesa el escenario gráfico
y renderiza los objetos visuales
}
Limpieza y salida
144
, )
'"2 ' 2 & &/ ' '&'!
El programa Java 3D típico empieza definiendo una nueva clase que extiende la
clase Applet. El ejemplo HelloJava3Da.java es una clase definida para extender la
clase Applet. Los programas Java 3D podrían escribirse como aplicaciones, pero
usar applets ofrece una forma más sencilla de producir una aplicación con
ventanas.
El paso 3 de esta sencilla receta es crear la rama de contenido gráfico. Esta rama
se crea en el fragmento de código que se muestra en la Figura 67.
El tamaño de la ventana
de la aplicación resultante
se especifica en la Figura 68 Método main que crea la ventana invocando MainFrame
construcción de la clase
MainFrame.
Los tres fragmentos de código anteriores (Figura 66, Figura 67 y Figura 68) forman
un programa Java 3D completo cuando se usan las sentencias import adecuadas.
A continuación se pueden ver las sentencias import necesarias para compilar la
clase HelloJava3Da. Las clases más comunmente usadas en Java 3D se
encuentran en los paquetes javax.media.j3d, o javax.vecmath.
Como no se explica cada línea de código del ejemplo HelloJava3Da, las ideas
básicas de ensamblar un programa Java 3D deberían estar claras habiendo leído
el ejemplo. La siguiente sección presenta cada una de las clases usadas en el
programa.
Clase BranchGroup
Los objetos de este tipo se usan para formar escenarios gráficos. Los ejemplares
de BranchGroup son la raíz de los sub-gráficos. Los objetos BranchGroup son los
únicos que pueden ser hijos de los objetos Locale. Los objetos BranchGroup
pueden tener varios hijos. Los hijos de un objeto BranchGroup pueden ser otros
objetos Group o Leaf.
BranchGroup() Los ejemplares de BranchGroup sirven como raíz para las ramas
del escenario gráfico; los objetos BranchGroup son los únicos
objetos que pueden insertarse en un conjunto de objetos Locale.
Clase Canvas3D
La clase Canvas3D deriva de la clase Canvas del AWT. Por lo menos un objeto
Canvas3D debe ser referenciado en la rama de vista gráfica del escenario gráfico.
Clase Transform3D
Clase TransformGroup
Clase Vector3f
Clase ColorCube
9 ! &/ ' $)
'! #
Una simple rotación del cubo puede hacer que se vea más de una de sus caras. El
primer paso es crear la transformación deseada usando un objeto Transform3D.
La rotación se especifica
usando el método rotX() de la
línea 27. Entonces se crea el
objeto TransformGroup en la
línea 31 para contener la
transformación de rotación.
Para crear estas dos rotaciones simultáneas se requiere combinar dos objetos
Transform3D de rotación. El ejemplo rota el cubo sobre los ejes x e y. Se crean
dos objetos Transform3D, uno por cada rotación (líneas 24 y 25). Las rotaciones
individuales se especifican para los dos objetos TransformGroup (líneas 27 y 28).
152
rotate.rotX(Math.PI/4.0d);
tempRotate.rotY(Math.PI/5.0d);
rotate.mul(tempRotate);
objRoot.addChild(objRotate);
objRotate.addChild(new ColorCube(0.4));
simpleU.getViewingPlatform().setNominalViewingTransform();
simpleU.addBranchGraph(scene);
} // Fin del constructor HelloJava3Db
Java 3D tiene una representación interna para una universo virtual y los métodos
para hacer la conversión. Hay dos formas para hacer que el sistema Java 3D haga
la conversión de la representación interna. Una forma es compilar todas las
ramas gráficas. La otra forma es insertar una rama gráfica en un universo virtual
para darle vida.
Compilar Contenidos
Capacidades
Una vez que una rama gráfica empieza a vivir o es compilada el sistema de
renderizado Java 3D la convierte a una representación interna más eficiente. El
efecto más importante de esta conversión es la mejora del rendimiento de
renderizado.
Pero también tiene otros efectos, uno de ellos es fijar el valor de transformaciones
y otros objetos en el escenario gráfico. A menos que especificamente se le
proporcionen al programa, este no tendrá la capacidad de cambiar los valores de
los objetos del escenario gráfico una vez que estén vivos.
Cada objeto visual del universo virtual puede tener sus propio comportamiento
predefinido. De hecho, un objeto visual puede tener varios comportamientos. Para
especificar un comportamiento para un objeto visual, el programador crea objetos
que especifiquen el comportamiento, añade el objeto visual al escenario gráfico y
hace las referencias apropiadas entre los objetos del escenario gráfico y los
objetos Behavior.
La siguiente lista enumera los pasos que se requieren para especificar una
animación con un objeto Interpolator. Los cinco pasos forman una receta para
crear un comportamiento de animación con interpolación:
* )
'"2 ' "2 ! " ' ! 05' :1 , &
Este fragmento de código se usa con otros fragmentos anteriores para crear el
programa de ejemplo HelloJava3Dc.java. Al ejecutar la aplicación veremos como
se renderiza el ColorCube con un comportamiento de rotación cada cuatro
segundos.
* #'# =(' !
' 1' ' 2 2 " ' & "2 ! " ' !
' " &/
Clase RotationInterpolator
Clase Alpha
Los objetos de la clase Alpha se usan para crear una función que varía en el
tiempo. La clase Alpha produce un valor entre cero y uno, inclusives. El valor que
produce depende de la hora y de los parámetros del objeto Alpha. Los objetos
161
La clase Alpha proporciona objetos para convertir la hora en un valor alpha (un
valor entre 0 y 1). El objeto Alpha es efectivamente una función de tiempo que
genera valores alpha entre cero y uno. La función "f(t)" y las características del
objeto Alpha están determinadas por parámetros definidos por el usuario:
Los parámetros:
loopCount : número de veces que se ejecuta este objeto alpha; un valor de -1
especifica un bucle indefinido..
increasingAlphaDuration : tiempo en milisegundos que tarda el objeto alpha en ir
de cero a uno.
Región Progamada
Hay varias formas de especificar una región programada, la más sencilla es crear
un objeto BoundingSphere. Otras opciones incluyen BoundingBox y
BoundingPolytope.
Clase BoundingSphere
+ )
'"2 ' & "$ &/ ' #- " &/ 7
"2 ! " ' ! 05' :1 ,
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.*;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
163
rotate.rotX(Math.PI/4.0d);
tempRotate.rotZ(Math.PI/5.0d);
rotate.mul(tempRotate);
objRoot.addChild(objRotate);
objRotate.addChild(objSpin);
RotationInterpolator rotator =
new RotationInterpolator(rotationAlpha, objSpin, yAxis,
0.0f, (float) Math.PI*2.0f);
return objRoot;
} // Fin del método CreateSceneGraph
public HelloJava3Dd() {
setLayout(new BorderLayout());
GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
simpleU.getViewingPlatform().setNominalViewingTransform();
164
simpleU.addBranchGraph(scene);
} // Fin del constructor de HelloJava3Dd
Figura 83 Escena gráfica que combina transformación Figura 84 Ejecución del ejemplo HelloJava3Dd.java
y comportamiento
(' !
'# ' & #
FOLEY, James D.; VAN DAM, Andries; FEINER, Steven K. y HUGHES, John F.
Computer graphics: principles and practice, Addison Wesley, 1996.
JAVA EN CASTELLANO. Gráficos con Java 2D. Traducción del Tutorial de Sun
Microsystems realizada por Juan Antonio Palos (ozito) [En línea]
http://www.programacion.com/java/tutorial/2d/1/. Fecha de consulta: Noviembre
de 2005.
MANZANEDO, Miguel Angel et al. Guía rápida de aprendizaje del lenguaje Java.
[En línea] http://pisuerga.inf.ubu.es/lsi/Invest/Java/Tuto.Oct98/index.htm. Fecha
de consulta: Noviembre de 2005.