Tesis Electrónicas UACh - Universidad Austral de Chile

Anuncio
UNIVERSIDAD AUSTRAL DE CHILE
SEDE PUERTO MONTT
ESCUELA DE INGENIERIA EN COMPUTACION
Integración de Tecnologías .Net y OpenGL, Aplicadas al Desarrollo de un Editor
para Escenarios 3D.
Seminario de Titulación para optar al
título de Ingeniero en Computación
PROFESOR PATROCINANTE:
Sr. Mauricio Henríquez Schott
CO-PATROCINANTE:
Sr. Pablo Mansilla Ojeda
Felipe Andrés Morales Saldivia
PUERTO MONTT - CHILE
2008-2009
A Mi Madre por su apoyo incondicional...
A g r a d e z c o públicamente a las siguientes personas:
Al Sr. Mauricio Henríquez Schott por guiarme durante el desarrollo del
presente proyecto.
Al Sr. Pablo Mansilla Ojeda por a p o y a r m e en la realización de este
proyecto.
M u c h a s Gracias
INDICE
Síntesis
Abstract
1. Introducción .................................................................................................. 1
2. Planteamiento del problema ........................................................................ 5
2.1 Antecedentes ........................................................................................... 5
2.1.1 Definición del problema .................................................................... 5
2.1.2 Esfuerzos anteriores........................................................................ 23
2.1.3 Solución Propuesta ......................................................................... 29
2.2 Justificación ........................................................................................... 31
2.2.1 Situación sin proyecto: ................................................................... 31
2.2.2 Situación con proyecto: .................................................................. 31
2.3 Delimitación............................................................................................ 32
3. Objetivos...................................................................................................... 34
3.1 Objetivo General .................................................................................... 34
3.2 Objetivos Específicos ............................................................................ 34
4. Metodología ................................................................................................. 35
5. Plan de Trabajo y Cronograma .................................................................. 39
5.1 Actividades ............................................................................................. 39
5.2 Carta Gantt ............................................................................................. 42
6. Recursos...................................................................................................... 43
6.1 Hardware................................................................................................. 43
6.2 Software .................................................................................................. 43
7. Análisis de la Solución ............................................................................... 44
7.1 Descripción de la solución.................................................................... 44
7.1.1 Módulo Editor 3D. ............................................................................ 45
7.1.1.1 Caso de uso: Crear/Editar/Eliminar Mundo. ............................ 46
7.1.1.2 Caso de uso: Crear/Editar/Eliminar Objeto. ............................. 49
7.1.1.3 Caso de uso: Crear/Editar/Eliminar Luz. .................................. 52
7.1.1.4 Caso de uso: Nueva/Guardar/Cargar Escena. ......................... 53
7.1.2 Módulo Generador de Código Fuente. ........................................... 54
7.1.2.1 Caso de uso: Generar código Fuente Escena. ........................... 54
7.2 Establecimiento de herramientas de desarrollo ................................. 55
7.3 Investigación de Tecnologías ............................................................... 56
7.3.1 Tao FrameWork ................................................................................ 56
7.3.2 Visual Studio 2008 ........................................................................... 59
7.3.3 Microsoft .NET Framework versión 2.0 (x86). ................................ 59
6.3.4 Tecnología de desarrollo basadas Reflection de Plataforma .NET.
.................................................................................................................... 60
7.3.5 Tecnología XML 1.0.......................................................................... 61
7.3.6 Mono 2.4 y MonoDevelop 2.0. ......................................................... 62
7.4 Validación de Requerimientos ........................................................... 63
8. Diseño de la Solución ................................................................................. 64
8.1 Diagrama de clases ............................................................................... 65
8.2 Diccionario de clases de editor OpenGL ............................................. 66
8.4 Casilla de Responsabilidades. ............................................................ 144
8.5 Diagrama de Procesos. ....................................................................... 145
8.5.1 Diagrama de Proceso Creación y edición de un Objeto 3D. ...... 145
8.5.2 Diagrama de Proceso Guardar escena. ....................................... 147
8.5.3 Diagrama de Proceso Cargar escena. .......................................... 148
8.5.4 Diagrama de Proceso Generación código Fuente de la escena
Diseñada con el Editor 3D. ..................................................................... 149
8.5.5 Diagrama de Proceso de Selección de objetos Mediante el Mouse.
.................................................................................................................. 150
9. Construcción del Software....................................................................... 152
9.1 Construcción Aplicación versión Beta (solo Funcionalidad de Editor
3D). .............................................................................................................. 152
9.1.1 Construir una ventana que despliegue un Objeto en el mundo. 152
9.1.2 Capacidad de agregar en forma dinámica objetos al mundo y
además que se desplieguen. ................................................................. 154
9.1.3 Crear una clase que ofrezca Primitivas OpenGL personalizadas.
.................................................................................................................. 154
9.1.4 Definir tipos Objetos que derivan de Entity. ................................ 155
9.1.5 Crear interfaz visual y lógica para creación de Objetos. ............ 156
9.1.6 Exhibir las propiedades del mundo y objetos en una paleta de
propiedades............................................................................................. 158
9.1.7 Seleccionar el mundo o los objetos desplegados en la ventana
mediante el Mouse. ................................................................................. 159
9.1.8 Trasladar/Rotar/Escalar objetos en forma dinámica mediante el
Mouse y Paleta de Propiedades. ........................................................... 165
9.1.9 Trasladar/Rotar la cámara en forma dinámica mediante el Mouse y
Paleta de Propiedades. ........................................................................... 169
9.1.10 Selección de cámaras.................................................................. 170
9.1.11 Crear una interfaz visual para la aplicación. ............................. 171
9.1.12 Aplicar Texturas a Objetos de tipo Entity. ................................. 177
9.1.13 Construir funcionalidad que permita crear Objetos Entity
compuestos de Otros. ............................................................................ 180
9.1.14 Construir Funcionalidad que permita aplicar planos de corte a
objetos de tipo Entity.............................................................................. 181
9.1.15 Construir funcionalidad que permita crear y editar fuentes de
Luz. ........................................................................................................... 183
9.1.16 Construir funcionalidad que permita editar el mundo y sus
Objetos mediante el teclado. ................................................................. 186
9.1.17 Construir funcionalidad que permita revisar la escena mediante
una animación Básica que rote la cámara por la escena. ................... 190
9.1.18 Construir funcionalidad que permita guardar y cargar la escena
mediante el uso de la Tecnología Xml. ................................................. 191
9.1.19 Integración de funcionalidades. ................................................. 199
9.2 Construcción aplicación versión Final (Editor 3D + Generador de
código Fuente). .......................................................................................... 202
9.2.1 Generador de clase que despliegue la escena diseñada con la
aplicación. ............................................................................................... 202
9.2.2 Generador de Proyecto .Net que despliegue la escena diseñada
con la aplicación. .................................................................................... 207
10. Pruebas .................................................................................................... 209
10.1 Conceptos generales de las pruebas realizadas. ........................... 209
10.1.1 Pruebas de Unidad....................................................................... 209
10.1.2 Pruebas de Integración. .............................................................. 209
10.1.3 Pruebas de Sistema y Evaluación. ............................................. 210
10.2 Plan de pruebas. ................................................................................ 211
10.2.1 Pruebas Funcionales. .................................................................. 211
10.2.2 Estrategias de las Pruebas. ........................................................ 212
10.2.3 Tipos de Pruebas. ........................................................................ 213
11. Conclusiones y Recomendaciones ....................................................... 215
12. Bibliografía .............................................................................................. 224
13. Anexos ..................................................................................................... 226
Síntesis
El objetivo de este seminario es el desarrollo de un editor de gráficos 3D
con funcionalidad de exportación del modelo a código fuente C# y OpenGL, lo
cual implica:

Construcción de un software para diseño 3D usando la API OpenGL, que
ofrezca las funcionalidades básicas y comunes a todos los software de
diseño de este tipo.
 Construcción de un módulo que permita exportar el código de la escena
diseñada al formato nativo de llamadas a funciones, tipos y estructuras
de la librería 3D.
 Desarrollar el software siguiendo un estándar de definición de interfaces
entre clases, lo cual permitirá que la escena generada sea consumible
por otros procesos.
 Utilización de herramientas y técnicas de programación de punta para
este tipo de desarrollos, como Reflection y XML, entre otras.
Para este seminario de Titulación, la metodología elegida es XP
(eXtreme Programming), esto basándose en la naturaleza del proyecto, se
decidió usar una metodología ágil, y dentro de éstas XP es una de las mejores
evaluadas.
El desarrollo de esta aplicación proporcionó como producto un entorno
de diseño de escenarios en tres dimensiones, el cual puede ser utilizado en
entornos matemáticos, robótica y propósito general, con el cual el desarrollador
puede sin ser experto en OpenGL, diseñar modelos complejos, que sin la ayuda
de esta herramienta le sería muy arduo.
Otro producto obtenido del desarrollo de esta aplicación fue la
encapsulación de la dificultad del trabajo con OpenGL, ya que parte de esta
aplicación dió como producto una biblioteca de clases llamada ZeroFxCore, la
cual permite crear desde escenarios simples hasta complejos, esto sin
necesidad de usar la aplicación propiamente tal. Además, con el uso de
biblioteca antes mencionada, el diseño de las escenas en forma programática
reduce drásticamente la cantidad de líneas de código, con lo cual se puede
concluir, que el uso de la librería ZeroFxCore dá como resultado una
disminución del código necesario para desplegar una primitiva, en una escala
promedio de 5 es a 1.
Finalmente, relacionada con la extensibilidad de la aplicación, queda
totalmente abierta para agregar nuevas funcionalidades tales como aplicación
de Físicas, Animaciones avanzadas, aplicación de motor de partículas entre
otras muchas funcionalidades aplicables, por lo cual a juicio del alumno tesista
es un muy buen tema a retomar como parte una nueva tesis.
Abstract
The objective of this seminar is the development of a 3D graphics editor with the
functionality to export the model to C# source code and OpenGL, which
involves:
 Construction of a 3D design software using the OpenGL API that provides
basic functionality common to all the design software of this type.
 Construction of a module that allows to the designed scene be exported
to native format functions calls, types and structures of the 3D library.
 Software Developing using standard interfaces definitions between
classes, which allow the generated scene to be consumed by other
processes.
 Use of tools and cutting edge programming techniques for such
developments, such as Reflection and XML, among others.
For
this
project,
the
chosen
methodology
was
XP
(eXtreme
Programming), that based on the nature of the project, we decided to use an
agile methodology, and within these XP is one of the best evaluated.
The development of this application provides as a product an
environment for three dimensions scene design, that can be used in
mathematical environments, robotics and general purpose, with which the
developer without been and OpenGL expert can designing complex models,
without the help of this tool will be very hard.
Another product of the development of this application was the OpenGL
difficulty encapsulation, as part of this application a class library called
ZeroFxCore was produced, which allows the creation from simple to complex
scenarios, without using the application itself. Furthermore, the use of the library
mentioned above, the design of programmatically scenes drastically reduces the
amount of code lines, so that it can be concluded that the use of the library
ZeroFxCore results in a decrease of the code for deploy a primitive, on a
average scale of 5 to 1.
Finally, related to the extensibility of the application, is completely open to
add new functionality such as application of Physics, advanced Animations,
particle engine among many other features, so the view of the thesis student is
that it is a very good topic for further thesis works.
1. Introducción
La computación gráfica se centra en el estudio, diseño y visualización de
imágenes por computadora. Entre las principales áreas de aplicación se
encuentran: el diseño asistido por computador (CAD - Computer Assisted
Design), gráficos interactivos (IG - Interactive Graphics), manufactura asistida
por computador (CAM - Computer Assisted Manufacturing), graficación
interactiva
en
multimediales,
los
negocios,
entretenimiento,
estadística,
medicina,
cartografía,
simulación
y
arte,
sistemas
animación
para
visualización científica, entre otras.
El área de aplicación que se abordará con el desarrollo de éste proyecto
es el CAD. Dentro de los problemas que se encuentran en él, tenemos que para
su desarrollo y estudio, se deben usar complejas APIs (Application Program
Interface, Interfaz para programas de Aplicación, por sus siglas en inglés) o
también llamada librerías gráficas, que requieren un conocimiento avanzado de
programación y manejo de la misma. No obstante, existen herramientas que
permiten a un usuario sin experiencia usar todas las características de estas
librerías, sin embargo enmascaran en su totalidad el manejo de éstas, no
permitiendo que el usuario o programador, conozca el funcionamiento de las
mismas; además, impiden la reutilización de las llamadas nativas generadas
1
internamente por la herramienta, esto debido a que trabajan con formatos de
archivos propietarios, los cuales son interpretados sólo por la aplicación.
En el siguiente documento se describirá como se pretende abordar el
problema, para lo cual, en la primera parte se estudiarán algunas APIs
disponibles y sus características, además se expondrá algunos editores 3D
para su manipulación, se explicará porque se hace necesario el uso de éstos y
también se mostrarán algunos Engines o “Motores Gráficos”, los cuales se
presentan como otra opción para la manipulación de las APIs. Tanto para los
editores 3D como para los motores gráficos, se expondrán sus características,
ejemplos, ventajas y desventajas. En especial se analizará el porqué se
imposibilita al programador tomar el código fuente generado internamente por la
herramienta para ser usado directamente, lo cual se pretende solucionar con el
desarrollo del proyecto.
También se abordarán los esfuerzos anteriores en cuanto a lo que
herramientas exportadoras de tipos y estructuras de datos de modelos hechos
con editores 3D o Engines se refiere. Sin embargo, este tipo de herramientas
tampoco se presentan como una solución completa al problema que se
pretende resolver en términos de la exportación de código fuente y llamadas
nativas a la API.
2
Posteriormente se abordará la metodología de desarrollo de software que
se uso para llevar a cabo este proyecto, se describirán las etapas de la
metodología y dejará establecido los roles que cumplirán el alumno tesista y el
profesor a cargo en cada una de las etapas del proyecto, además se expondrá
la cronología de cada una de estas etapas, esbozada en la correspondiente
carta Gantt.
En el contexto de implementación del la aplicación, se abordarán las
fases de ésta, tales como análisis, la cual abordará la toma de requerimientos
mediante la técnica de casos de uso, esta fase también involucra la selección
de herramientas de desarrollo lo cual se abordará mediante una adecuada
investigación de las herramientas que finalmente fueron seleccionadas.
Otra etapa de la implementación que se abordará es el diseño, la cual
describirá y mostrará diversos diagramas de diseño necesarios para la correcta
construcción de la aplicación.
Posteriormente, se describirá paso a paso la fase de construcción del
software, esta etapa y las antes nombradas (análisis, diseño) esta dirigidas por
la metodología XP.
3
Finalmente, en el contexto de implementación, se abordará la etapa de
pruebas, la cual describirá las diversas pruebas a las que fue sometida la
aplicación para asegurar su correcto desempeño y funcionamiento.
4
2. Planteamiento del problema
2.1 Antecedentes
2.1.1 Definición del problema
Hoy las gráficas tridimensionales son usadas en un gran número de
ambientes, que van desde su uso en la cinematografía, video juegos y
simulación, hasta el diseño gráfico asistido por computadora, CAD (Computer
Assisted Design, Diseño Asistido por Computador, por sus siglas en inglés).
Las dos APIs para desarrollo de gráficas 3D más populares son DirectX
de Microsoft y OpenGL, originalmente de Silicon Graphics. Las diferencias entre
ambas librerías, van desde las estructuras internas utilizadas, lógica que se
emplea para su manipulación, hasta la forma en la que se distribuyen; por
ejemplo mientras que OpenGL es un software libre y gratuito, soportado por un
gran número de empresas, desarrolladores y usuarios; para DirectX, se deben
pagar licencias para su utilización y además, la comunidad de programadores y
empresas es menor.
5
Las grandes empresas que requieren de diseño gráfico, especialmente
3D, si bien utilizan las dos APIs antes mencionadas, por lo general no trabajan
con estas a nivel de lenguaje nativo (directamente con la librería que
implementa la API en particular), sino más bien usando software de interfaz
gráfica para su manipulación, tales como “Maya” o “3D Studio Max”, los cuales
son softwares comerciales, y sus licencias, en sus versiones más básicas, no
bajan de los $500 mil pesos chilenos o 800 euros, aún cuando también existen
versiones libres u OpenSource ampliamente difundidas como “Blender”, por
ejemplo.
Éste tipo de software, permite a un usuario sin experiencia en
programación, a través del Mouse, teclado y otros dispositivos de entrada,
diseñar complejos entornos 3D, incluyendo las animaciones de movimientos
necesarias. Posteriormente, de ser requerido, a estas escenas tridimensionales,
se le puede agregar lógica de comportamiento a través de programación
especializada.
Dentro de las alternativas gratuitas se encuentra la anteriormente
mencionada “Blender”, el cual es un programa multiplataforma, dedicado
especialmente al modelado y creación de gráficos tridimensionales. Este
programa fue inicialmente distribuido de forma gratuita, pero sin el código
fuente, con un manual disponible para la venta. Actualmente “Blender” es
6
totalmente Opensource, cabe destacar que es compatible con todas las
versiones de Windows, Mac OS X, Linux, Solaris, FreeBSD e IRIX.
Actualmente, se está llevando a cabo la producción del primer
largometraje animado realizado íntegramente con Software Libre, usando a
“Blender” como herramienta principal. Se trata de “Plumíferos”, proyecto que
está impulsando aun más el desarrollo de este programa, sobre todo a nivel de
animación y manejo de librerías a gran escala. Se espera el estreno de este film
durante el 2009.
Dentro de las alternativas comerciales como se mencionó anteriormente,
se tiene a “Autodesk 3D Studio Max”, el cual es un programa de creación de
gráficos y animación 3D desarrollado por Autodesk Media & Entertainment
(anteriormente conocidos como Discreet y Kinetix). Fue desarrollado como
sucesor para sistemas operativos Win32 del 3D Studio creado para DOS.
Kinetix fue más tarde fusionada con la última adquisición de Autodesk, Discreet
Logic.
“3D Studio Max” es uno de los programas de animación 3D más
utilizados, dispone de una sólida capacidad de edición, una potente arquitectura
de plugins y una larga tradición en plataformas Microsoft Windows, este
programa es utilizado en mayor medida por los desarrolladores de videojuegos,
7
aunque también lo es en el desarrollo de proyectos de animación, como
películas o anuncios de televisión, efectos especiales y en arquitectura en
general.
La siguiente figura, muestra la interfaz de “3D Studio Max” (Figura 1),
con simples selecciones y movimientos del mouse o uso del teclado podemos
diseñar escenarios partir de figuras predefinidas (elipse en la imagen).
Figura 1
8
En la siguiente figura (Figura 2), podemos ver como se ha modelado un
Bolígrafo usando 3D Studio Max a partir de objetos predefinidos tales como
cilindros, discos, conos, esferas, cajas y otros objetos. Además, después de
terminar de agregar los objetos necesarios para crear el bolígrafo, podemos
agregar texturas a éstos para mejorar aun más el detalle del modelo.
Figura 2
9
El problema es, que desde el punto de vista del programador, una de las
desventajas principales de este tipo de software para asistir el diseño 3D,
además de su alto costo en el caso de las versiones comerciales, es el hecho
de que una vez que está la escena terminada o lista para agregar lógica de
programación adicional, el software de diseño no entrega las llamadas a la API
nativa (OpenGL o DirectX), sino que trabajan con formatos de archivos
propietarios, los cuales son interpretados sólo por la aplicación misma. Por lo
cual, para poder trabajar con la escena generada, se debe pagar o desarrollar
complejos parseadores o exportadores que obtengan las estructuras y tipos
nativos de la librería.
A continuación, se mostrará una sección de un archivo de 3D Studio
Max, el cual representa el diseño de un cubo (box). Mediante comentarios se
distinguirán las secciones más relevantes de este archivo.
10
*3DSMAX_ASCIIEXPORT 200
*COMMENT "AsciiExport Version 2,00 - Sun May 11 14:51:21 2008"
//configuración del escenario
*SCENE {
*SCENE_FILENAME "Box.max"
*SCENE_FIRSTFRAME 0
*SCENE_LASTFRAME 100
*SCENE_FRAMESPEED 30
*SCENE_TICKSPERFRAME 160
*SCENE_BACKGROUND_STATIC 0.0000 0.0000 0.0000
*SCENE_AMBIENT_STATIC 0.0000
0.0000 0.0000
}
//sección de materiales
*MATERIAL_LIST {
*MATERIAL_COUNT 0
}
//definición del objeto Box01
*GEOMOBJECT {
*NODE_TM {
*NODE_NAME "Box01"//nombre del objeto
*INHERIT_POS 0 0 0
*INHERIT_ROT 0 0 0
*INHERIT_SCL 0 0 0
*TM_ROW0 0.9476
-0.3154
0.0514
*TM_ROW1 0.3157
0.9488 0.0020
*TM_ROW2 -0.0494
0.0144 0.9987
*TM_ROW3 -1.0049
-1.7364
0.0000
*TM_POS -1.0049
-1.7364 0.0000//posición del objeto
*TM_ROTAXIS 0.0194 0.1576 0.9873//rotaciones del objeto
*TM_ROTANGLE 0.3253
//cantidad de rotación
*TM_SCALE
1.0000 1.0000 1.0000//escala del objeto
*TM_SCALEAXIS 0.0000 0.0000 0.0000//escala de los ejes
*TM_SCALEAXISANG 0.0000
//del objeto
}
//mapeado de los vértices del objeto
*MESH {
*TIMEVALUE 0
*MESH_NUMVERTEX 8
*MESH_NUMFACES 12
*MESH_VERTEX_LIST {
*MESH_VERTEX
0
-15.0845
-11.6455
-0.5533
*MESH_VERTEX
1
4.3299 -18.1078
0.4991
-6.3397
14.6349
-0.4991
*MESH_VERTEX
2
*MESH_VERTEX
3
13.0747
8.1727 0.5533
*MESH_VERTEX
4
-15.9390
-11.3969
16.7365
*MESH_VERTEX
5
3.4754 -17.8592
17.7889
-7.1942
14.8836
16.7907
*MESH_VERTEX
6
*MESH_VERTEX
7
12.2202
8.4213 17.8431
}
}
*PROP_MOTIONBLUR
*PROP_CASTSHADOW
*PROP_RECVSHADOW
*WIREFRAME_COLOR
0
1
1
0.6941
0.5804 0.1059//color del objeto
}
11
Como se puede ver, en este archivo existen secciones con información
respecto a la escena, materiales y objetos, en éste caso en particular con el
objeto “Box01”, en la sección del objeto podemos distinguir:

NODE_NAME: nombre del objeto.

TM_POS: posición del objeto en coordenadas xyz.

TM_SCALE: escala del objeto en los ejes xyz.

TM_SCALEAXIS: escala de los ejes xyz del objeto.

TM_ROTAXIS: proporción en que esta rotado el objeto en los ejes xyz.

TM_ROTANGLE: ángulo en que esta rotado el objeto.

WIRE_FRAME_COLOR: color del objeto en los tres componentes RGB.

MESH: en esta sección va todo lo referente a los vértices del objeto con
los cuales se construye.
Otra característica de este archivo, es que la jerarquía de objetos se
representa mediante nodos los cuales son parte de un árbol.
Como se mostró anteriormente para un único objeto, la cantidad de
información es abundante, además ésta no es análoga a ningún lenguaje de
programación, ni llamadas nativas de alguna librería gráfica, por lo tanto para
utilizar el diseño, en alguna aplicación que lo requiera, se hace necesario un
parseador o exportador, que convierta la información desde el archivo hasta
12
algún lenguaje de programación agregando las llamadas nativas de alguna
librería gráfica (OpenGL o DirectX).
El archivo generado por 3D Studio Max (.3DS) ya es un formato que se
puede considerar como estándar en el mundo 3D, ya que prácticamente no hay
software que no sea compatible con éste, Lightwave, Maya, 3D Studio MAX,
Truespace, Blender.
Para que quede aún más clara la nula similitud entre la estructura del
archivo Max y las llamadas nativas en OpenGL, se mostrará el código necesario
para construir un cubo de 6 caras, al igual que en el ejemplo con 3D Studio
Max.
//Método que construye un cubo
public static void RenderCube(double x)
{
Gl.glPushMatrix();
RenderSquare(x); // llamada a método que construye el cuadrado 1
Gl.glRotated(90, 1, 0, 0);
RenderSquare(x); // llamada a método que construye el cuadrado 2
Gl.glRotated(90, 1, 0, 0);
RenderSquare(x); // llamada a método que construye el cuadrado 3
Gl.glRotated(90, 1, 0, 0);
RenderSquare(x); // llamada a método que construye el cuadrado 4
Gl.glRotated(90, 0, 1, 0);
RenderSquare(x); // llamada a método que construye el cuadrado 5
Gl.glRotated(180, 0, 1, 0);
RenderSquare(x); // llamada a método que construye el cuadrado 6
Gl.glPopMatrix();
}
13
//Método que construye un cuadrado
public static void RenderSquare(double x)
{
Gl.glPushMatrix();
// Se establece el método de construcción del cuadrado
Gl.glBegin(Gl.GL_POLYGON);
// Coordenadas vértice 1 para aplicación texturas
Gl.glTexCoord2f(1.0f, 1.0f);
// Coordenada vértice 1
Gl.glVertex3d(x, x, x);
// Coordenadas vértice 2 para aplicación texturas
Gl.glTexCoord2f(0.0f, 1.0f);
// Coordenada vértice 2
Gl.glVertex3d(x, -x, x);
// Coordenadas vértice 3 para aplicación texturas
Gl.glTexCoord2f(0.0f, 0.0f);
// Coordenada vértice 3
Gl.glVertex3d(-x, -x, x);
// Coordenadas vértice 4 para aplicación texturas
Gl.glTexCoord2f(1.0f, 0.0f);
// Coordenada vértice 4
Gl.glVertex3d(-x, x, x);
// Se finaliza la construcción del cuadrado
Gl.glEnd();
Gl.glPopMatrix();
}
Durante los últimos años, se han desarrollado también “Motores
Gráficos” (Graphic Engines), especialmente diseñados para facilitar la
construcción de juegos y/o simulaciones.
Estos motores gráficos, de igual forma que los software de diseño 3D
antes mencionados, se basan en la utilización interna de OpenGL o DirectX,
pero limitan la cantidad de acciones, sobre las figuras predefinidas u otros
elementos que el programador puede realizar dentro del motor, así como
14
también limita las acciones que se pueden asociar a estas figuras (acciones
predefinidas). No obstante lo anterior, si bien estos motores tienen algunas
limitaciones, no es menos cierto que también incorporan muchas características
ampliamente desarrolladas; tales como:

Detección de colisiones: conjunto de algoritmos matemáticos que
nos permiten simular el comportamiento de los objetos en la realidad.
Por ejemplo, que dos objetos no se intersequen, o que un personaje
camine sobre el suelo y luego pueda subir gradas. La detección de
colisiones es un tema bastante complejo que debe estar dentro del
núcleo de cualquier motor 3D.

Generadores de partículas: algoritmos para crear efectos mediante
el uso partículas o puntos en el espacio, con estos generan efectos
de fuego, polvo, lluvia, nieve y otros.

Inteligencia Artificial: algoritmos para modelar el comportamiento de
los jugadores no humanos (NPC en inglés, PNJ en castellano), y para
ello la IA debe estar dentro del núcleo del motor 3D.

Físicas: conjunto de algoritmos que buscan simular la física del
mundo real.

Utilización de todas las capacidades de la tarjeta gráfica: los
motores gráficos se caracterizan por utilizar todas las tecnologías
disponibles al tiempo de desarrollo de éste, un caso puntual es la
15
tecnología pixel shader (abreviatura PS), la cual es un programa de
sombreado, normalmente ejecutado en la unidad de procesamiento
gráfico. En OpenGL, se conoce como fragmento de sombreado, esta
tecnología fue inmediatamente implementada por los nuevos motores
gráficos no así por los software de diseño 3D.
El objetivo principal de estos motores, es el desarrollo de video juegos,
muchas de las características antes nombradas no están presentes en los
editores gráficos convencionales.
Un buen ejemplo de estos motores son “UnrealEngine 3”, “CrisisEngine
2” y “Star War Unleashed Engine”, con los cuales están hechos la mayoría de
los juegos conocidos como “NextGen” (juegos diseñados para las consolas y
computadoras de última generación) [Edge2007] a continuación una lista de
ellos.
Unreal Engine 3 [EpicGames2008]:

Bioshock (2007) Irrational Games.

Brothers In Arms: Hell's Highway (2007) Gearbox Software.

Gears of War (2006) Epic Games.

Unreal Tournament 3 (2007) Epic Games.
16
Crisis Engine 2 [CrytekGames2008]:

Crysis (2007) Crytek.

Entropia Universe (2008) Crytek.
El Engine de Star Wars: Force Unleashed, es el que promete
revolucionar lo que se denomina Next-Gen, y que dota de un realismo nunca
antes visto. Hasta acciones tan simples como las de caminar, saltar o subir
unas escaleras [SerranoLobo2007].
La principal característica de este motor es que combina tres tecnologías
de punta las cuales son Euphoria, DMM (Digital Molecular Matter) y Havok.
Euphoria es una tecnología de IA (Inteligencia Artificial) aplicada a
físicas, la cual se genera en tiempo real, no hay absolutamente ningún detalle
que responda a scripts previstos por adelantado, que es la principal
característica, la cual proporciona un realismo muy superior a lo antes visto. Un
ejemplo práctico de esto es lo que ocurre al lanzar a un oponente sobre una
superficie, esto tendrá decenas de resultados diferentes, además Euphoria dota
a los rivales de un instinto de preservación que les empujará a tratar de tomarse
de lo que tengan a mano, incluso si es otro rival. Los títulos más famosos
17
diseñados con esta Tecnología son Star Wars: Force Unleashed y Grand Theaf
Auto IV, el estreno de estos dos ocurrió durante primer semestre del 2008.
En el caso DMM (Digital Molecular Matter), su tarea se basa en
representar la resistencia de los materiales de forma realista. En un juego como
Star Wars: Force Unleashed, en el que
la destrucción de objetos es muy
común, no se puede pasar por alto que la madera no se comporta como el
metal (uno se quiebra, el otro antes se dobla). Así tenemos que nuestro
personaje afecta al mundo que lo rodea y lo modifica siempre de manera
diferente, según la fuerza de los impactos, el ángulo y la parte dañada, por lo
cual se ha producido un gran avance tecnológico, frente al clásico objeto que
siempre se destruye en el mismo lugar.
Otra tecnología de punta que ocupa el Engine de Star War: Force
Unleashed es Havok Game Dynamics SDK. Es un motor físico (simulación
dinámica) utilizado en videojuegos y recrea las interacciones entre objetos y
personajes del juego. Por lo que detecta colisiones, gravedad, masa y velocidad
en tiempo real llegando a recrear ambientes mucho más realistas y naturales.
Havok en sus últimas versiones se ejecuta por entero por hardware mediante el
uso de la GPU (procesador gráfico), liberando así de dichos cálculos a la CPU.
Este se apoya en las librerías de Direct3D y OpenGL compatibles con Shader
Model 3.0.
18
Por otra parte, cabe mencionar que existen motores que no hacen uso
de las APIs convencionales. Un caso puntual de ésto, es el Cristal Tools, el cual
utiliza la API Open GL/ES, que es una versión optimizada para el uso del
procesador Cell Broadband (CPU PlayStation 3), la empresa desarrolladora de
este motor es una de las más reconocidas en el rubro de video juegos a nivel
mundial, hablamos de SquareEnix, actualmente se está desarrollando un video
juego con Cristal Tools, el cual es uno de los más esperados para Playstation 3
según la opinión de expertos en el tema [Sinclair2008], este será Final Fantasy
XIII, se espera el estreno de éste durante el año 2010 solo para esta consola.
En la siguiente figura (Figura 3), se muestra el motor del juego Warcraft
III, con el uso simple del mouse y teclado se puede construir escenarios con
objetos preconstruidos (elipse en la imagen), dentro de estos hay terrenos,
puertas, ventanas, unidades, etc. Además, existen diferentes variantes por cada
uno de ellos, con una simple selección del mouse en la paleta de la derecha, ya
podemos empezar a crear nuestro escenario al cual, una vez terminado se
puede agregar inteligencia artificial a las unidades.
19
Figura 3
En la siguiente figura (Figura 4), podemos ver las variantes de terrenos
que hay a disposición (elipse en la imagen). Además a éstos se le pueden
aplicar relieves. También se muestra un escenario terminado (pantalla del
centro) el cual ya puede ser utilizado por el juego Warcarft 3 o DotaAllstar
(juego que también hace uso del Motor de Warcraft 3)
20
Figura 4
Por ejemplo, los archivos que genera el motor de Warcraft 3 en
estructura son muy similares a los generados 3D Studio Max, poseen la mismas
secciones y agregan algunas como efectos gráficos avanzados y generación de
partículas, pero a diferencia de los archivos 3DS Max, éstos se generan en dos
archivos, uno del modelo (muy similar a los 3Ds Max) y otro de Inteligencia
Artificial, éste posee un lenguaje de script muy similar a uno de programación,
21
pero que es propio del motor, el cual es para describir el comportamiento de las
unidades controladas por la CPU; el siguiente diagrama muestra el contenido
de cada uno de los archivos mencionados.
Motor gráfico
Warcraft 3
Archivo de Modelo (secciones)
 Objetos
 Texturas
 Motor de partículas
 Efectos gráficos avanzados
 Animaciones
Archivo IA
 Script de
comportamiento de
jugador no humano
Figura 5
Por último, cabe mencionar que la alternativa en la que el desarrollador
use directamente alguna de estas librerías de desarrollo 3D (no mediante
software de diseño o de motores gráficos), para lo cual, se requiere tener un
manejo avanzado de las instrucciones de las APIs, además de un buen manejo
en lenguajes de programación, lo cual se traduce en que la curva de
aprendizaje se torne ardua y dificultosa, incluso para labores sencillas.
22
2.1.2 Esfuerzos anteriores
Cabe mencionar que ninguna de las herramientas de diseño 3D antes
expuestas proporcionan información que pueda ser usada por el programador
directamente. Sin embargo, existen algunas soluciones externas a estos
softwares que si lo permiten.
Existen varias alternativas de exportación de información del modelo
diseñado con herramientas de diseño 3D, algunas sólo exportan información del
modelo, otras van un poco más lejos exportando las llamadas nativas de alguna
API gráfica.
A continuación se tratará el tema más en detalle, ya que representan los
esfuerzos llevados a cabo antes del proyecto que se quiere concretar.
Una de estas alternativas es la librería Lib3ds [Kyprianidis2007] que nos
permite exportar información de los modelos diseñados con 3D Studio Max a
partir del archivo de la aplicación.

Configuración de Atmósfera.

Configuración mapa de sombras.

Establecimiento de Viewport.

Materiales.
23

Cámaras.

Luces.

Mallas.

Fotogramas clave.

Jerarquía.
Cabe destacar que esta Libreria es gratuita, OpenSource y funciona bajo
la plataforma Linux, actualmente está disponible para ser descargada la versión
1.30.
El siguiente código obtiene e imprime información referente a las
cámaras, usando la librería de cámara de Lib3ds.
#include <lib3ds/camera.h>//conjunto
#include <lib3ds/chunk.h> // de librerías lib3ds
#include <lib3ds/io.h>
//necesarias para obtener información
#include <stdlib.h>
// de las cámaras
#include <math.h>
#include <string.h>
void lib3ds_camera_dump(Lib3dsCamera *camera)
{
ASSERT(camera);//se selecciona la cámara
// Se imprime el nombre de la cámara
printf(" name:
%s\n", camera->name);
// Se imprime la posición de la cámara
printf(" position: (%f, %f, %f)\n",
camera->position[0], camera->position[1], camera->position[2]);
// Se imprime objetivo de la cámara
printf(" target
(%f, %f, %f)\n",
camera->target[0], camera->target[1], camera->target[2]);
24
}
// Se imprime el tipo de cámara
printf(" see_cone: %s\n", camera->see_cone ? "yes" : "no");
// Se imprime la posición más cercana que ve la cámara
printf(" near_range: %f\n", camera->near_range);
// Se imprime la posición más lejana que ve la cámara
printf(" far_range: %f\n", camera->far_range);
printf("\n");
La información de la cámara fue obtenida mediante la librería lib3ds
como se aprecia en el código anterior, posteriormente ésta debe ser tomada por
el programador para ser usada en la API que éste estime conveniente, lo que
implica que el programador debe dominar la API elegida.
Otra alternativa es “The Maya Exporter Factfile” [Bateman2004], a
diferencia de lib3ds es un conjunto de plugins que se utilizan para obtener
información de los modelos diseñados con Maya. Este esfuerzo fue
desarrollado por Robert Bateman en el año 2004, este conjunto de plugins son
capaces de obtener los siguientes datos.

Texturas

Materiales

Luces

Cámaras

Transformaciones

Animaciones
25

Bump Maps

Poligonal Meshes.
Estos plugins obtienen información del modelo mediante el archivo maya,
lo que implica que el programador debe saber usar OpenGL, para poder tomar
estos datos y representar el modelo, cabe mencionar que estos plugins no
están incluidos en maya y funcionan a partir de la versión 4.0, este esfuerzo, es
uno los mas similares al proyecto que se quiere concretar.
A continuación, se mostrará parte del código fuente que usa estos
plugins, el cual obtiene datos acerca de los objetos en la escena, tenemos que
tomar en consideración que al igual que el archivo de 3Ds Max los objetos
(figuras 3D) son nodos llamados Mesh, los cuales son parte de un árbol.
Código que obtiene el nombre de los Mesh.
#include<maya/MFnMesh.h>//conjunto de plugins
#include<maya/MItDag.h>// maya exporter
// Se crea un iterador para recorrer todos los Mesh
MItDag it(MItDag::kDepthFirst,MFn::kMesh);
while(!it.isDone())
{
// Asignamos la función al Objeto
MFnMesh fn(it.item());
if( !fn.isIntermediateObject() )
{
// Imprime el nombre del Mesh
26
cout<<"Mesh "<< fn.name().asChar() <<endl;
}
}
// Siguiente objeto
it.next();
El código anterior sólo recorre el árbol e imprime los nombres de los
objetos en la escena, el siguiente código es un poco más complejo, ya que
obtiene las coordenadas de los vértices de los objetos en la escena.
#include<maya/MFnMesh.h>>// plugin maya exporter
void outputMeshVertices(MObject& obj)
{
// Asignamos la función al Objeto
MFnMesh fn(obj);
// Arreglo que contendrá la posición de los vértices
MPointArray vts;
// Se obtiene los las posiciones de los vértices
fn.getPoints(vts);
// Imprime el número de vértices
cout << "NumVerts " << vts.length() << endl;
// Imprime la posición de los vértices
for(int i=0;i!=vts.length();++i) {
// print vertex cout << vts[i].x <<" "
<< vts[i].y <<" "
<< vts[i].z << "\n";
}
}
27
La información fue obtenida usando los algoritmos anteriores, a través de
algunos de los plugins que componen el Maya Exporter, ahora teniendo éstos
datos, el programador debe codificar el modelo usando la API que estime
conveniente (OpenGL o DirectX).
Existen motores gráficos que también se pueden considerar esfuerzos
anteriores, ya que poseen kits de desarrollo para .Net y Java, un caso de esto
es Ogre3d [Ogre3d2008], éste genera las instrucciones, por ejemplo en C# y
llamadas OpenGL de lo diseñado con él, no obstante la curva de aprendizaje
del programador se torna ardua ya que este código es sumamente complejo, y
además se debe considerar que las instrucciones de la API se enmascaran
totalmente, lo cual no permite el aprendizaje de ésta por parte del programador.
A continuación se mostrará uná línea de código fuente usando los kits de
desarrollo de Ogre3d en donde solamente se diseñó un cubo con textura (cubo
preconstruido) de tamaño 10.
// Código C usando kits Ogre 3d
mSceneMgr->setSkyBox(true, "Examples/SpaceSkyBox", 10);
Como se puede apreciar, el uso de la API está totalmente enmascarada,
más aun, el programador esta ceñido al uso de kits de desarrollo de Ogre3d
para usar el modelo en otra aplicación, no obstante se puede ver que la
28
cantidad de líneas para diseñar un cubo es menor, que usando la API
directamente.
2.1.3 Solución Propuesta
Considerando lo anteriormente expuesto, se propone el desarrollo de
un entorno de diseño 3D, el cual por un lado entregará funcionalidades
similares a las que un editor 3D tradicional, y por otro proveerá de la opción de
entregar código nativo de la API que se requiere para la generación de la
escena, permitiendo al programador iniciado en el tema de las graficas 3D el
uso de la librería, o incluso al programador avanzado, desarrollar gran parte del
entorno 3D requerido en esta herramienta, para luego exportar el código a su
propia aplicación para continuar con su desarrollo, agregando lógica compleja o
específica de la solución que se desea implementar.
Otra área de aplicación de esta herramienta, es la del diseño de los
escenarios tridimensionales que sean consumidos por otros programas que lo
requieran, por ejemplo, representar figuras 3D a partir de ecuaciones
matemáticas, o representación de mundos tridimensionales para entornos de
automatización y robótica en general.
29
Dentro de las funcionalidades de editor 3D se incluirán las siguientes
características:

Objetos 3D tales como esferas, cilindros, cajas y otros.

Objetos 2D tales como discos, círculos, planos, polígonos y triángulos.

Objetos de robótica tales como tanques y cámaras.

Cámaras en modo normal y multivista.

Aplicación de Texturas, las cuales se podrá aplicar a la mayoría de los
objetos antes mencionados, para mejorar el detalle del diseño.

Aplicación de planos de corte para los objetos antes nombrados.

Diseño mediante mouse, con el cual se podrá seleccionar, mover,
escalar y rotar los objetos.

Movimiento de la cámara en la escena mediante teclado y mouse.

Se dispondrá de una grilla de propiedades, como lo hay en programas
similares, para la edición de propiedades de los objetos presentes en la
escena.
30
2.2 Justificación
2.2.1 Situación sin proyecto:
Actualmente no existe ninguna herramienta de diseño en tres
dimensiones basadas en OpenGL diseñada en Chile.
Actualmente no existe una herramienta para diseñar escenarios tres
dimensiones que genere código OpenGL a partir de la escena, ya que las
existentes trabajan con formatos de archivos propietarios, los cuales son
interpretados sólo por la aplicación misma. Por lo cual, para poder trabajar con
la escena generada, se debe pagar o desarrollar complejos parseadores o
traductores que obtengan las estructuras y tipos nativos de la librería OpenGL.
2.2.2 Situación con proyecto:
El desarrollo del proyecto proporcionará un entorno de diseño de
escenarios en tres dimensiones, el cual puede ser utilizado en entornos
matemáticos, robótica y propósito general, con el cual el desarrollador puede
sin ser experto en OpenGL, diseñar modelos complejos, que sin la ayuda de
esta herramienta le sería muy arduo. Además el desarrollador puede utilizar el
31
modelo generado con la herramienta y luego exportarlo a llamadas nativas
OpenGL, algo muy similar a lo que hace la librería Lib3ds, las cuales pueden
ser ocupadas en lo que el desarrollador estime conveniente.
Cabe mencionar, que en la solución propuesta, la funcionalidad de
exportación estará integrada al software de diseño a diferencia de la librería
Lib3ds que no lo está con 3D Studio Max o así mismo con los plugins externos
para Maya.
2.3 Delimitación

El editor de escenarios en 3 dimensiones usará la API OpenGL, no se
contempla el uso de otras APIs, como sí lo hace 3D Studio Max y otros.

Se pondrá a disposición un conjunto de figuras 3D básicas para la
construcción de escenarios tales como esferas, cilindros, cajas, discos,
círculos, polígonos, planos entre otras, con las cuales, ya sea
modificando, escalando, rotando o cortando, se pueden construir
escenarios más complejos.

Existirán herramientas de animación básica como el movimiento de la
cámara para la revisión de la escena.
32

Este proyecto no involucra el desarrollo de herramientas de animación
avanzadas para las figuras (mover éstas de acuerdo a una ecuación),
como lo hace 3D Studio Max.

El software no será compatible con otros editores (3D Studio Max, Maya,
Blender, etc.).

No tendrá soporte para manejo de físicas, generación de partículas y
otras técnicas complejas como si lo hacen los motores gráficos
(Engines).

Tendrá la funcionalidad de exportar a llamadas nativas OpenGL del
modelo generado, las características exportables del modelo son:
configuración
de
la
escena
(posición
de
la
cámara
y
otras
configuraciones) y figuras en la escena (posición, color, escala, planos
de corte, texturas, luces y parámetros propios de la figura), no obstante
no se exportarán mapa de sombras.
33
3. Objetivos
3.1 Objetivo General
Desarrollo de un editor de gráficos 3D con funcionalidad de exportación
del modelo a código fuente C# y OpenGL.
3.2 Objetivos Específicos

Construcción de un software para diseño 3D usando la API OpenGL, que
ofrezca las funcionalidades básicas y comunes a todos los software de
diseño de este tipo.

Exportar el código de la escena diseñada al formato nativo de llamadas a
funciones, tipos y estructuras de la librería 3D, para proveer la posibilidad
de utilizarlo en el desarrollo de otros programas.

Desarrollar el software siguiendo un estándar de definición de interfaces
entre clases, lo cual permitirá que la escena generada sea consumible
por otros procesos que la requieran (representaciones matemáticas,
mundos 3D para automatización en general, entre otros).

Utilización de herramientas y técnicas de programación de punta para
este tipo de desarrollos, como Reflection y XML, entre otras.
34
4. Metodología
Para este seminario de Titulación, la metodología elegida es XP
(eXtreme Programming), esto basándose en la naturaleza del proyecto, y
debido a que continuamente hay que repetir el ciclo de investigación y
desarrollo, se decidió usar una metodología ágil, y dentro de éstas XP es una
de las mejores evaluadas [Flower2003].
XP es una metodología ágil centrada en potenciar las relaciones
interpersonales como clave para el éxito en desarrollo de software,
promoviendo el trabajo en equipo, preocupándose por el aprendizaje de los
desarrolladores, y propiciando un buen clima de trabajo. XP se basa en
realimentación continua entre el cliente y el equipo de desarrollo, comunicación
fluida
entre
todos
los
participantes,
simplicidad
en
las
soluciones
implementadas y coraje para enfrentar los cambios. XP se define como
especialmente adecuada para proyectos con requisitos imprecisos y muy
cambiantes, y donde existe un alto riesgo técnico [XtremePrograming2007].
En este caso, el desarrollador es el alumno tesista, y el cliente será el
profesor patrocinante. Además este último, cumple el rol de encargado de
pruebas.
35
Si bien es cierto, la descripción específica de XP no calza en su
totalidad con el trabajo requerido, sí se ajusta en gran medida con el
desempeño requerido en las etapas de desarrollo del proyecto.
En la carta Gantt que se presenta más adelante se detallan las
iteraciones (ciclo de tareas) que se consideraron necesarias de efectuar en
cada etapa.
El ciclo de vida de XP consta de 5 fases o etapas: Etapa de
Exploración, Etapa de Planificación, Etapa de Producción, Etapa de
Mantenimiento y Etapa de Muerte del Proyecto.
I Etapa de Exploración:
En esta fase, se identificará el ámbito del proyecto y se definirá en
términos generales lo que el software realizará en base al análisis de los
requerimientos. Se establecerán las herramientas de desarrollo a utilizar y por
último se investigarán algunas tecnologías necesarias para el proyecto tales
como XML y OpenGL, el estudiante tesista en esta etapa está encargado de
todas las tareas antes mencionadas.
II Etapa de Planificación:
36
Se validan los requerimientos, se modela la solución, se diseña y
finalmente se construye el software, esta etapa es la más importante, el diseño
y construcción del software está a cargo del estudiante tesista, la revisión del
correcto desarrollo de estas tareas está a cargo del profesor patrocinante.
III Etapa de Producción:
Se implementa la marcha blanca, que se refiere a corrección de errores,
de ser necesario optimización de código, entrega de manuales de usuario del
software y la entrega final del proyecto. Las tareas de esta etapa son
desarrolladas por el alumno tesista y revisadas por el profesor patrocinante.
IV Etapa de Mantenimiento:
No será detallada en el proyecto, por corresponder a la parte posterior a
la entrega del mismo. No obstante, ésta se refiere a algunas modificaciones
puntuales que pueden ser requeridas por el cliente (profesor patrocinante)
después de entregado el proyecto y el encargado de hacer estas
modificaciones es el alumno tesista.
37
V Etapa de Muerte:
Solo se nombra en la carta Gantt, como una de las etapas del ciclo de
vida elegido, pero no se lleva a cabo.
38
5. Plan de Trabajo y Cronograma
Como la metodología lo indica, en cada una de las fases del ciclo de vida
de la aplicación existen tareas que se deben completar y son las que a
continuación se detallan.
5.1 Actividades
I. Etapa de Exploración
1. Análisis de requerimientos
Se definirá en términos generales lo que el software hará en base
al análisis del los requerimientos.
2. Establecimiento de herramientas de desarrollo
Se establecerán las herramientas de desarrollo que se utilizarán
para desarrollar el proyecto.
3. Investigación de Tecnologías
Se investigarán las tecnologías que se utilizarán para el desarrollo
del proyecto, las cuales son: OpenGL, XML y Reflection en un
primer momento.
II. Etapa de Planificación
1. Validación de Requerimientos:
39
En esta parte del proyecto se probará que los requerimientos que
definen el software son lo que el cliente realmente necesita.
2. Modelo de la solución
2.1 Iteración Etapa de Planificación - Modelo de
Solución
Se diseñarán los diagramas de clases del software. Estos
serán revisados por el cliente y de ser necesario serán
nuevamente rediseñados y revisados nuevamente.
3. Diseño de la Solución
3.1 Iteración Etapa de Planificación - Diseño de la
Solución
Se entregará un prototipo del software sin funcionalidades
sólo interfaz, el cual pasará por un ciclo de revisión y
corrección hasta que el cliente quede conforme.
3.2 Aceptación del diseño de la solución (Cliente)
Teniendo en cuenta que los diagramas de clases y el
prototipo de la solución han sido revisados y aceptados se
procede con la siguiente etapa.
4. Construcción del Software
40
4.1 Iteración Etapa de Planificación - Construcción del
Software Beta
Se procede con a la codificación del software con
funcionalidades mínimas. Éste pasará por un ciclo de
revisión y aplicación de mejoras al código, al menos una
vez.
4.2 Iteración Etapa de Planificación - Construcción del
Software versión 1.0
Se precede con a la codificación del software con
funcionalidades completas, éste pasará por un ciclo de
revisión y aplicación de mejoras al código, al menos una
vez hasta que el cliente quede conforme.
4.3 Fabricación de manual de usuario
Se procede con la redacción del manual de usuario del
software.
III. Etapa de Producción
1. Marcha blanca
Se completarán pruebas de desempeño del software y se
realizarán ajustes de ser necesarios. Además, serán revisados los
manuales de usuario.
2. Entrega Final del proyecto
41
Se entregará el proyecto al final de la marcha blanca, esto será
entregado al cliente en 2 copias en CD. Cada copia contendrá el
ejecutable del software más su código fuente y su correspondiente
manual de usuario.
IV. Etapa de Mantenimiento
De ser necesario y el cliente lo solicita se harán modificaciones al
software.
5.2 Carta Gantt
La calendarización del proyecto contempla el trabajo de 5 días por
semana, con un total de 8 horas diarias. El total de horas trabajadas en el
proyecto corresponde a 1800 horas hombre o 12 meses, y los recursos son: el
alumno tesista, que hará las veces de programador, y el profesor guía que hará
de jefe de proyecto, para más detalle ver carta Gantt resumen adjunta en los
anexos digitales en la ruta “\Anexos\CartaGantt\”.
42
6. Recursos
6.1 Hardware
-
CPU AMD Turion X2 de 2 GHZ.
-
1 GB de RAM.
-
256 MB ATI X1600 DDR3.
-
Disco duro de 120 GB.
6.2 Software
-
Visual Studio 2005 ó 2008 bajo Windows XP y lenguaje C#.
-
Librerías OpenGL en sistemas operativos Windows y Linux.
-
Estándar XML versión 1.2.
-
Mono/MonoDevelop en Linux para pruebas de códigos fuentes
generados por la aplicación.
43
7. Análisis de la Solución
De acuerdo a las características que presenta este proyecto de Tesis, el
software es parte fundamental para concretar los objetivos planteados por el
cliente, lo que se centraliza finalmente en un software con las funcionalidades
de un editor de gráficos 3D y además la funcionalidad de generación de código
fuente.
El sistema de construcción para este software esta guiado por la
metodología de desarrollo XP, que se puede englobar dentro de las
metodologías ligeras, las cuales son aquellas que priorizan los resultados
directos y que reducen la documentación tradicional que ofrecen la mayoría de
las metodologías. XP es una metodología que permite un desarrollo de software
adaptable más que previsible, se basa en la simplicidad, la comunicación y la
realimentación o reutilización del código desarrollado; lo cual posibilita un
software escalable y de un mejoramiento futuro de forma dinámica.
7.1 Descripción de la solución
Los requerimientos solicitados por el cliente consisten en el desarrollo de
un editor de escenarios 3D con todas las funcionalidades básica que implica un
software de este tipo y además la funcionalidad de generación de código fuente
44
de lo diseñado. En consecuencia, con lo anterior la construcción de esta
solución se dividirá en dos módulos, los cuales son: un Editor 3D y un
Generador de código fuente de lo diseñado con el editor.
A continuación se analizarán los requerimientos solicitados por el cliente
mediante la técnica de “casos de uso”, la cual sirve
para la captura de
requisitos potenciales de una aplicación como ésta.
7.1.1 Módulo Editor 3D.
Las funcionalidades deben ser similares a las que un editor 3D presenta,
las cuales a grandes rasgos ofrecen un mundo en tres dimensiones sobre el
cual construir escenarios con el uso de primitivas 3D como: cubos, esferas,
conos, luces, cámaras y otros. Además ofrecer múltiples interfaces para la
manipulación de éstos (mouse, teclado y paleta de propiedades) para así hacer
la tarea de construir estos escenarios menos compleja para el usuario. Con lo
anterior, se proponen los siguientes diagramas de casos de uso como se
observa en el diagrama [1] para la construcción de esta solución.
45
Diagrama Nº [1]: Modelo de Casos de Uso Módulo Editor 3D.
Existen 4 casos de uso a nivel macro en lo que se refiere al Editor 3D, los
cuales a su vez incluyen casos de usos especializados, a continuación se
abordaran estos casos de uso.
7.1.1.1 Caso de uso: Crear/Editar/Eliminar Mundo.
Este caso de uso incluye los siguientes subcasos.
46
Diagrama Nº [2]: Modelo de Casos de Uso Crear/Editar/Eliminar Mundo
ACTOR (ES): USER
APLICACIÓN
1. Crea un nuevo mundo al
2. Muestra el nuevo mundo.
seleccionar en el menú la opción
nueva escena o al presionar el
botón “limpiar escena”.
3. Edita el mundo mediante el
4. Refleja los cambios en el
mouse, teclado y paleta de
mundo.
propiedades.
5. Elimina el mundo al presionar el
6. Elimina la escena (Mundo y
botón “Limpiar escena”.
Objetos) y crea una totalmente
nueva.
7. Selecciona el mundo Mediante el
8. Carga sus propiedades en la
mouse.
paleta para su edición y habilita
la edición con el Mouse del
mundo.
9. Selecciona una cámara mediante
10. Muestra el mundo desde la
el menú.
cámara seleccionada.
47
12. Habilita
animación
básica
mediante paleta de propiedades
y menú.
14. Selecciona la modalidad de
despliegue del mundo ya sea en
modo Design o Render.
16. Habilita la Traslación de la
cámara mediante el mouse,
seleccionando
el
botón
“Trasladar”
en el formulario
principal de la aplicación o
presionando [CTRL + q] teniendo
en cuenta que el mundo debe
estar seleccionado.
18. Habilita la Rotación de la cámara
mediante el mouse y teclado,
seleccionando el botón “Rotar” en
el formulario principal de la
aplicación o presionando [CTRL
+ r] teniendo en cuenta que el
mundo debe estar seleccionado.
20. Traslada la cámara con las teclas
direccionales, esta traslación se
comportará dependiendo del tipo
de traslación que se seleccionó
en el menú de la aplicación o de
la cámara que está seleccionada
actualmente.
22. Habilita el despliegue del valor
que representa el número de
frames por segundo que muestra
la ventana por donde se visualiza
el mundo 3D esto mediante la
paleta de propiedades, teniendo
48
11. Configura
dinámicamente
modalidades de
traslación,
rotación,
escalamiento
del
mundo y sus objetos, de
manera que estas queden de
manera óptima para la cámara
seleccionada.
13. Despliega
una
animación
básica que consiste en la
rotación de la cámara por el
mundo.
15. Despliega el mundo en la
modalidad seleccionada.
17. Refleja Trasladando la cámara
al mover el mouse.
19. Refleja Rotando la cámara al
mover el mouse.
21. Refleja Trasladando la
cámara.
23. Despliega el valor de los
frames por segundo en el
encabezado de la ventana por
donde se muestra el mundo
3D.
en cuenta que el mundo debe
estar seleccionado.
24. Habilita o deshabilita los planos
coordenados mediante paleta de
propiedades.
25. Configura el nivel de detalle de
los objetos presentes en el
mundo mediante menú y paleta
de propiedades.
7.1.1.2 Caso de uso: Crear/Editar/Eliminar Objeto.
Este caso de uso Crear/Editar/Eliminar Objetos, posee especializaciones
que corresponden a todos los objetos que soportará la aplicación, a
continuación el detalle de estos casos de uso correspondiente a un tipo de
objeto del total que soportará la aplicación, ya que todos los casos de uso
Crear/Editar/Eliminar de los de los otros tipos de objetos son similares o iguales
al que se describirá a continuación (esfera), no obstante estos casos de uso se
incluirán en anexos.
49
Diagrama Nº [3]: Modelo de Casos de Uso Crear/Editar/ Eliminar Esfera.
Independiente de haber mostrado el diagrama casos de uso de
Crear/Editar/ Eliminar una esfera, a continuación se abordará la descripción de
casos de uso desde el punto de vista de un Objeto general que representa
todos los tipos de objetos representables por la aplicación.
ACTOR (ES): USER
APLICACIÓN
1. Crea un nuevo objeto mediante el
2. Muestra el nuevo objeto
teclado o formulario de creación y
creado.
edición de objetos.
3. Edita el objeto mediante el
4. Refleja los cambios en el
Mouse, teclado y paleta de
objeto.
propiedades.
5. Elimina el objeto al presionar el
6. Refleja la eliminación del
botón “Eliminar” en el formulario
objeto.
50
de creación y edición de objetos
y mediante teclado presionando
“Suprimir”.
7. Selecciona el objeto Mediante el
Mouse.
8. Carga sus propiedades en la
paleta para su edición y habilita
la edición con el Mouse del
objeto.
9. Configura el nivel de detalle del
objeto mediante menú y paleta
de propiedades.
10. Asigna una textura al objeto
mediante paleta de propiedades.
11. Carga la textura y se la asocia
al objeto.
12. Habilita Planos de corte para el
objeto mediante paleta de
propiedades.
14. Habilita la Traslación del objeto
mediante
el
Mouse,
seleccionando el botón Trasladar
en el formulario principal de la
aplicación teniendo en cuenta
que el objeto debe estar
seleccionado.
16. Habilita la Rotación del objeto
mediante
el
Mouse,
seleccionando el botón “Rotar” en
el formulario principal de la
aplicación presionado [CTRL + q]
teniendo en cuenta que el objeto
debe estar seleccionado.
18. Habilita la Escala del objeto
mediante
el
mouse,
seleccionando el botón “Escalar”
en el formulario principal de la
aplicación presionado [CTRL + q]
teniendo en cuenta que el objeto
debe estar seleccionado.
20. Crea objeto de tipo Custom en el
formulario de creación y edición
13. Refleja la aplicación del plano
de corte al objeto.
51
15. Refleja Trasladando el objeto
en el mundo al mover el
Mouse.
17. Refleja Rotando el objeto en el
mundo al mover el mouse.
19. Refleja Escalando el objeto en
el mundo al mover el mouse.
de objetos el cual puede estar
compuesto por uno o más
objetos.
21. Edita objeto de tipo Custom en el
formulario de creación y edición
de objetos ya sea eliminado,
editando,
desvinculando
a
objetos hijos.
Excepciones:
a. Las texturas no se visualizan si la escena está en modalidad de
diseño.
b. No todos los tipos de objetos soportan texturas.
c. La Textura debe ser cuadrada de tamaño potencia de 2.
7.1.1.3 Caso de uso: Crear/Editar/Eliminar Luz.
ACTOR (ES): USER
APLICACIÓN
1. Crea
una
nueva
Luz
al
1. Muestra la nueva fuente de luz.
seleccionar el botón “Luz” en el
menú de la aplicación o
presionado [CTRL + l].
2. Edita la fuente de luz mediante
3. Refleja los cambios de la luz en
paleta de propiedades, mouse.
el mundo.
4. Elimina la luz seleccionado la luz
y
presionando
el
botón
“Suprimir”.
5. Selecciona la luz Mediante el
6. Carga sus propiedades en la
Mouse.
paleta para su edición y habilita
la edición con el Mouse de la
fuente de luz.
7. Habilita la Traslación de la
8. Refleja Trasladando la fuente
Fuente de Luz mediante el
de luz en el mundo al mover el
mouse, seleccionando el botón
mouse.
“Trasladar”
en el formulario
principal de la aplicación o
presionando [CTRL + q] teniendo
en cuenta que la fuente de luz
debe estar seleccionada.
Excepciones:
52
a. Las fuentes de luz no se pueden rotar ni escalar.
b. La aplicación resiste un máximo de ocho Fuentes de luz.
c. La ubicación de la luz solo es visualizable en modalidad Design, en
modalidad Render solo se visualiza el efecto de esta sobre los objetos
de la escena.
7.1.1.4 Caso de uso: Nueva/Guardar/Cargar Escena.
ACTOR (ES): USER
APLICACIÓN
1. Crea una nueva escena mediante
2. Despliega una escena Limpia y
el menú de la aplicación
lista para diseñar.
seleccionando la opción “Nueva
Escena”.
3. Guarda una escena mediante el
4. Genera un archivo de respaldo
menú
de
la
aplicación
que contiene toda la escena
seleccionando la opción “Guardar
usando como soporte la
Escena”, posteriormente debe
tecnología XML. Este archivo
digitar el nombre del archivo
es guardado con el nombre
donde se guardara la escena y
especificado por el usuario.
por ultimo debe presionar el
botón “Guardar”.
5. Carga una escena mediante el
6. Despliega la escena que fue
menú
de
la
aplicación
cargada desde el archivo XML.
seleccionando la opción “Cargar
Escena”, posteriormente debe
seleccionar el archivo de la
escena y por último debe
presionar el botón “Abrir”.
Observaciones:
a. La aplicación guardara en el documento XML las texturas asociadas a
los objetos de escena, esto debe hacerlo en forma binaria.
53
7.1.2 Módulo Generador de Código Fuente.
Las funcionalidades de este módulo se centra en generar el código
fuente de lo diseñado con el módulo del Editor 3D, para poder usar este código
en lo que el Actor “USER” desee, el código fuente generado por esta solución
será en el lenguaje de programación C#.
A continuación se presenta el diagrama Nº [2] de casos de uso para el
módulo “Generador de Código Fuente”.
Diagrama Nº [4]: Modelo de Casos de Uso Módulo “Generador de Código
fuente”.
7.1.2.1 Caso de uso: Generar código Fuente Escena.
54
ACTOR (ES): USER
APLICACIÓN
1. Genera el código fuente en una
2. Genera
un
archivo
con
clase C# seleccionando en el
extensión “cs” con la lógica
menú de la aplicación la opción
necesaria para generar una
“Generar archivo clase”.
escena.
3. Genera el código fuente en un
4. Genera un Proyecto del tipo
proyecto “VS2008” seleccionando
“Visual. Studio 2008” listo para
en el menú de la aplicación la
compilar y ejecutar.
opción “Generar código fuente”
en “proyecto VS”.
5. Genera el código fuente en un
6. Genera un proyecto del tipo
proyecto “VS2008” seleccionando
“Visual. Studio 2008” y además
en el menú de la aplicación la
ejecuta Visual Studio 2008.
opción “Generar código fuente”
Con el proyecto ya cargado
en “proyecto VS” ejecutando
solo hace falta compilar y
“VS2008”.
ejecutar.
Excepciones:
a. El fuente generado al compilarse y ejecutarse desplegará la escena
en modalidad Render ya que la modalidad Design solo está destinada
a el editor 3D.
7.2 Establecimiento de herramientas de desarrollo
Para establecer las herramientas de desarrollo del software solicitado, se
tomaron en cuenta las solicitudes del cliente y otras establecidas por la
naturaleza de la aplicación.
Las herramientas o tecnologías que se usaron en esta solución son las
siguientes.
1. Tao Framework 2.1 el cual incluye:
55
1. Tao.OpenGl 2.1.0.12.
2. Tao.FreeGlut 2.4.0.2.
2. Microsoft .NET Framework versión 2.0 (x86).
3. IDE Microsoft Visual Studio 2008 (C#).
4. Tecnología de desarrollo basadas en Reflection de Plataforma .Net.
5. Tecnología XML 1.0.
6. Mono Framework 2.4.
7. IDE MonoDevelop 2.0.
Las herramientas mencionadas anteriormente para el desarrollo de la aplicación
serán descritas en la etapa de Investigación de Tecnologías.
7.3 Investigación de Tecnologías
7.3.1 Tao FrameWork
Una de las tecnologías que se usó para el desarrollo de la aplicación es
Tao Framework 2.1.0, la cual es una colección de librerías multiplataforma
orientadas a gráficos y multimedia, además facilita la portabilidad entre los
Frameworks .NET y Mono. Una de las librerías que se usarán en la aplicación
es OpenGL (Open Graphics Library) la cual viene contenida dentro de un
56
“Wrapper/Envoltorio” llamado Tao.OpenGl, esto debido a que no puede ser
usada directamente por entornos manejados ya que está diseñada para ser
usada en el lenguaje de programación C, por tanto Tao.OpenGl permite el uso
de esta en .Net/Mono. OpenGL es una especificación estándar que define una
API multilenguaje y multiplataforma para escribir aplicaciones que produzcan
gráficos 2D y 3D. La interfaz consiste en más de 250 funciones diferentes que
pueden usarse para dibujar escenas tridimensionales complejas a partir de
primitivas geométricas simples, tales como puntos, líneas y triángulos. Fue
desarrollada originalmente por Silicon Graphics Inc. (SGI) en 1992 y se usa
ampliamente en CAD, realidad virtual, representación científica, visualización de
información y simulación. También se usa en desarrollo de videojuegos, donde
compite con Direct3D para plataformas de Microsoft Windows. La descripción
más completa de la API esta en los antecedentes del proyecto.
Otra librería que se ocupará de este FrameWork es FreeGlut, la cual es
una biblioteca de utilidades para programas OpenGL. Esta al igual que OpenGL
no puede ser usada directamente por entornos manejados, por ende usaremos
un
“Wrapper/Envoltorio”
llamado
Tao.FreeGlut.
FreeGlut
principalmente
proporciona diversas funciones de entrada/salida con el sistema operativo.
Entre las funciones que ofrece se incluyen declaración y manejo de ventanas y
la interacción por medio del teclado y ratón. También posee rutinas para el
dibujo de diversas primitivas geométricas (tanto sólidas como en modo
57
wireframe/enrejado) que incluyen cubos, esferas, entre otros. También tiene
soporte para creación de menús emergentes.
En resumen Tao.OpenGl y Tao.FreeGlut son solo “Wrappers/Envoltorios”
de las librerías OpenGL y FreeGlut, las cuales están escritas en el lenguaje de
programación C y compiladas según la plataforma, por lo tanto desde un
entorno de maquina virtual como lo es .NET/Mono y C#, es imposible acceder a
ellas si no es mediante un “wrapper”.
Otras librerías que contiene Tao Framework 2.1 no ocupadas en la
aplicación son las siguientes:
1. Tao.OpenAl 1.1.0.1 (librería multiplataforma para el manejo de audio
tridimensional).
2. Tao.Cg 2.0.0.0 (define un nuevo lenguaje similar a C para programación
de shaders/sombras).
3. Tao.DevIl 1.6.8.3 (librería para cargar y guardar gran cantidad de
formatos de imágenes).
4. Tao.Sdl
1.2.13.0
(proporcionan
funciones
básicas
para
realizar
operaciones de dibujo, gestión de efectos de sonido, música, carga y
gestión de imágenes con apoyo de otras librerías).
58
5. Tao.Ode 0.9.0.0 (librería para la simulación de la dinámica de cuerpos
rígidos.).
7.3.2 Visual Studio 2008
Otra tecnología que se usará para el desarrollo de la solución es el
entorno de desarrollo integrado (IDE, por sus siglas en inglés) Visual Studio
2008 y el lenguaje C#, se eligió esta tecnología debido a que es una de las
plataformas de desarrollo más usadas a nivel mundial y dentro del país; por
tanto adquirir experiencia en el uso de esta agrega valor agregado al desarrollo,
además es una de las herramientas solicitadas por el cliente para el desarrollo
de la aplicación. Una de las características de Visual Studio 2008 es la
posibilidad de seleccionar el Framework, aún cuando para la aplicación se
usara el .NET 2.0 ya que fue solicitado por el cliente, no obstante la aplicación
quedara fácilmente portable a versiones más recientes como por ejemplo el
Framework 3.5.
7.3.3 Microsoft .NET Framework versión 2.0 (x86).
59
Para esta aplicación fue seleccionado el Microsoft .NET Framework
versión 2.0 (x86) esto debido principalmente a que
Mono Framework 2.4
(Framework que implementa el estándar de la ECMA para máquinas virtuales
multiplataforma equivalente a .Net 2.0 y superiores, para sistemas operativos
Linux, Unix, MacOS, Sun Solares, Sparc, ARM, MIPS entre otros) soporta de
manera estable aplicaciones desarrolladas para el Microsoft .NET Framework
versión 2.0 no así para versiones más recientes de este. Al cliente le interesa
que la aplicación quede portable al sistema operativo Linux, no obstante la
aplicación está orientada principalmente al Framework .Net 2.0 de Microsoft.
6.3.4 Tecnología de desarrollo basadas Reflection de Plataforma .NET.
Otra de las tecnologías seleccionadas es Reflection de .Net, que está
ubicada dentro del NameSpace “System.Reflection” del mismo. Este contiene
clases e interfaces que proporcionan una vista administrada de los campos, los
métodos y los tipos cargados, con la posibilidad de crear e invocar tipos
dinámicamente.
Esta tecnología se usará debido a la naturaleza de la aplicación donde se
requiere la ejecución de métodos en forma dinámica, ejecución de métodos de
objetos específicos dentro de una colección genérica y además uno de los
60
requerimientos que se refiere a la generación de código fuente, con lo cual hace
que esta tecnología sea indispensable para el desarrollo de esta aplicación.
7.3.5 Tecnología XML 1.0.
Para esta aplicación se necesita un método de respaldo y restauración
de datos de lo diseñado con la aplicación, para esto se ha seleccionado la
tecnología XML sigla en inglés de Extensible Markup Language («lenguaje de
marcas ampliable»), es un metalenguaje extensible de etiquetas desarrollado
por el World Wide Web Consortium (W3C). XML propone un estándar para el
intercambio de información estructurada entre diferentes plataformas. Se puede
usar en bases de datos, editores de texto, hojas de cálculo y casi cualquier cosa
imaginable.
XML es una tecnología sencilla que tiene a su alrededor otras que la
complementan y la hacen mucho más grande y con posibilidades mucho
mayores. Tiene un papel muy importante en la actualidad ya que permite la
compatibilidad entre sistemas para compartir la información de una manera
segura, fiable y fácil.
61
7.3.6 Mono 2.4 y MonoDevelop 2.0.
Otra característica que esta aplicación implementó es que el código
fuente generado debe ser multiplataforma y además se debió portar una versión
de la aplicación a Mono Framework para el sistema operativo Linux, con lo cual
para probar el código fuente, se uso FrameWork Mono 2.4 el cual es un
proyecto liderado por la corporación informática Novell (antes de Ximian) para
crear un estándar compatible con las especificaciones de la organización ECMA
y un conjunto de herramientas .NET, incluye entre sus características un
compilador del lenguaje C# y un entorno denominado CLR (Common Language
Runtime). Mono se puede ejecutar en Linux, BSD, Unix, Mac OS X, Solaris y
sistemas operativos Microsoft Windows, además en un número muy amplio de
otras arquitecturas como RISC, Sparc, Arm, entre otras.
Debemos hacer una distinción: Mono 2.4 es el FrameWork, por lo tanto
para probar el código fuente se necesita un entorno de desarrollo, el cual es
llamado “MonoDevelop”, diseñado primordialmente para C# y otros lenguajes
.NET como Nemerle, Boo, y Java (vía IKVM.NET). MonoDevelop originalmente
fue una adaptación de SharpDevelop para Gtk#, pero desde entonces se ha
desarrollado para las necesidades de los desarrolladores de Mono. El IDE
incluye manejo de clases, ayuda incorporada, completación automática de
62
código, Stetic (diseñador de GUI para Gtk#), soporte para proyectos, y un
depurador integrado. Para el desarrollo de la aplicación se utilizará la versión
2.0 de MonoDevelop.
7.4 Validación de Requerimientos
Para esta etapa se contempló reuniones iterativas para validar los
requerimientos extraídos primordialmente desde los análisis de “casos de usos”.
Estas reuniones
consistieron en presentaciones donde se fueron validando
todos los casos de uso. Además se presentaron prototipos de la aplicación con
algunas funcionalidades mínimas; estas reuniones se realizaron para validar los
requerimientos y en base a esto ir mejorando el prototipo. Una vez validado
este, se dió paso al diseño con la información sacada de esta etapa y de las
anteriores etapas de la metodología.
63
8. Diseño de la Solución
En esta etapa de la metodología, XP enfatiza que no se puede establecer
una definición temprana de una arquitectura definitiva para la aplicación, si no
que dicha arquitectura va evolucionando a medida que se realizan las
iteraciones de diseño, con la información que se obtuvo de las actividades
anteriores se desarrollará una primera versión del diseño el cual irá
evolucionando durante cada una de las iteraciones.
Basándose en el paradigma de la orientación a objeto, en el cual se
desarrolló la aplicación, el diagrama de clases otorga una representación ideal
para el diseño de ésta. Los productos que se quieren obtener
de esta
representación son los siguientes:

Las clases de objetos de la aplicación.

Las relaciones que existen entre estas clases.

Una descripción en detalle de para qué sirve cada una de estas clases; esto
incluye descripción de sus miembros, propiedades y métodos.

Descripción de Interfaces.
64
8.1 Diagrama de clases
El diagrama de clases es un tipo de diagrama estático que describe la
estructura de un sistema o aplicación mostrando sus clases, atributos y las
relaciones entre ellos [UML2007], a continuación se mostrará el diagrama de
clases de la aplicación desarrollada, este se encuentra reducido mostrando los
miembros y métodos más representativos de cada clase, no obstante el
diagrama completo se encuentra en los anexos, además en capítulos
posteriores se abordará el “diccionario de clases”, el cual describe los miembros
y métodos en detalle del diagrama completo.
65
Diagrama de Clases Editor 3D y Desensamblador de Código.
8.2 Diccionario de clases de editor OpenGL
A continuación se describirá en detalle cada una de las clases de la
aplicación, esto involucra una descripción de sus miembros propiedades y
métodos en detalle, todo esto para comprender de mejor forma la función de
cada una de las clases y las relaciones entre ellas.
66
8.2.1 Class World:
Es la clase encargada de inicializar la ventana Glut por la que se muestra
el mundo y además despliega la escena donde están contenidos los objetos de
tipo Entity, esta clase hereda de la clase XmlConverter con el fin de obtener
comportamientos y métodos para guardar y restaurar las propiedades de los
objetos de esta clase en un archivo XML. Además, esta clase posee los
métodos suscritos a los callbacks de Glut para la captura de información del
teclado y mouse.
8.2.1.1 Miembros:
Modificador
acceso
Private
de Tipo
Double
Nombre
Valor
Fps
0
Frames por segundo en la ventana Glut
Private
String
xml_file
Directorio del archivo Xml donde se guarda la escena.
Private
Int
num_type_entity
Cantidad de tipos de objetos.
Private
XmlNode
Textura
Nodo Xml que servirá para guardar o restaurar una textura.
Private
Trajectory
camera_position
Posición de la cámara.
67
15
Private
Vector
camera_rotation
Rotación de la cámara.
Private
Bool
fps_enable
False
frames por segundo no visible(en la ventana glut)
Private
Int
View_mode
0
Bool
EjeXYZ
True
Bool
PlaneX
False
Bool
PlaneY
True
Bool
PlaneZ
False
Tipo cámara.
Private
Eje XYZ visible.
Private
Plano X=0 no visible.
Private
Plano y=0 visible.
Private
Plano z=0 no visible.
Private
Bool
traslate_mode_camera_in_z True
Modo de traslación de cámara con referencia al plano z=0 habilitado.
Private
Bool
traslate_mode_camera_in_x False
Modo de traslación de cámara con referencia al plano x=0 deshabilitado.
Private
Bool
traslate_mode_camera_in_y False
Modo de traslación de cámara con referencia al plano y=0 deshabilitado.
68
Private
Bool
rotate_mode_camera
False
Modo de rotación de cámara deshabilitado.
Private
Double
traslate_factor_camera
1
Rotate_factor_camera
10
traslate_mode_mouse
True
traslate_mode_mouse_in_x
False
Factor de traslación de la cámara.
Private
Double
Factor de rotación de la cámara.
Private
Bool
Modo de traslación con el mouse.
Private
Bool
Modo de traslación con el mouse con referencia al plano X=0 habilitado.
Modificador
de Tipo
Nombre
Valor
acceso
Private
Bool
traslate_mode_mouse_in_y False
Modo de traslación con el mouse con referencia al plano Y=0 habilitado.
Private
Bool
traslate_mode_mouse_in_z
True
Modo de traslación con el mouse con referencia al plano Z=0 habilitado.
Private
Bool
Rotate_mode_mouse
False
Modo de Rotación con el mouse deshabilitado.
Private
Bool
Rotate_mode_mouse_in_x
False
Modo de Rotación con el mouse con referencia al plano x=0 deshabilitado.
Private
Bool
rotate_mode_mouse_in_y False
Modo de Rotación con el mouse con referencia al plano y=0 deshabilitado.
69
Private
Bool
rotate_mode_mouse_in_z True
Modo de Rotación con el mouse con referencia al plano z=0 habilitado.
Private
Bool
scale_mode_mouse
False
Modo de Escalado con el mouse deshabilitado.
Private
Bool
scale_mode_mouse_in_x
False
Modo de Escalado con el mouse con referencia al plano x=0 deshabilitado.
Private
Bool
scale_mode_mouse_in_y
False
Modo de Escalado con el mouse con referencia al plano y=0 deshabilitado
Private
Bool
scale_mode_mouse_in_z
True
Modo de Escalado con el mouse con referencia al plano z=0 habilitado.
Private
Bool
Selection_mode_Mouse
True
Modo de selección con el mouse habilitado.
Private
Bool
BToggle
Variable utilizada para la animación.
Private
Int
Hits
Cantidad de veces que ha sido seleccionado un objeto determinado.
Private
Int
Glutwnd
Identificador ventana glut.
Private
Int
oldX,oldY
Variables auxiliares que hacen posible la edición dinámica de objetos con el
mouse.
70
Private
Int
animation_interval
1
Design_mode
False
Intervalo de animación.
Private
Bool
Modo de diseño deshabilitado.
Private
Vector
Size
Tamaño del mundo.
Private
Int
Width
812
Int
Height
540
Double
Rotation
True
Ancho ventana glut.
Private
Alto ventana glut.
Private
Variable para la animación de la cámara (Rotación).
Private
Int
GlutWnd
Identificador ventana glut.
Private
Type
ClassObj
Variable de tipo type que será usada para aplicar reflection sobre esta clase.
Modificador
acceso
Private
de Tipo
Int[]
Nombre
History_names
Arreglo que guarda historial de nombres.
Private
Int
Prkeyent
Clave del objeto seleccionado actualmente.
71
Valor
Private
List<Entity>
Entities
Colección de objetos del mundo.
Private
Bool
Preview
False
Anima la cámara para que rote por la escena.
Private
Bool
Render_mode
True
Modo render habilitado.
8.2.1.2 Métodos:
Private void Init()
Descripción:
Inicializa la ventana Glut y sus manejadores.
Private void Show()
Descripción:
Despliega el mundo 3D en la ventana Glut e inicializa el buffer de profundidad,
de colores, texturas y carga la matriz identidad.
Private void ReshapeHandler(int width, int height)
Descripción:
72
Método
manejador
que
repinta
la
ventana
Glut
cada
vez
que
es
redimensionada.
Requiere los parámetros:
Width: Tipo Int, que contiene el nuevo ancho de la ventana por donde se
visualiza la escena.
Height: Tipo Int, que contiene el nuevo alto de la ventana por donde se visualiza
la escena.
Private void MouseHandler(int button, int estate, int x, int y)
Descripción:
Método manejador que captura las coordenadas xy cada vez que se hace un
click en la ventana Glut.
Requiere los parámetros:
Button: Tipo Int, que contiene el botón del mouse que fue presionado.
Estate: Tipo Int, que contiene si e botón fue presionado o fue desprecionado.
x: Tipo Int, que contiene la coordenada x del pixel de la ventana que fue
clickeado con el mouse.
y: Tipo Int, que contiene la coordenada y del pixel de la ventana que fue
clickeado con el mouse.
73
Private void InitEntityFromXml():
Descripción:
Método encargado de crear los objetos del mundo desde el Xml, solo los
inicializa no le asigna datos a sus propiedades.
Private void KeyboardHandler(byte key, int x, int y)
Descripción:
Método manejador que captura las teclas (mientras está en foco la ventana glut)
cada vez que son presionadas.
Requiere los parámetros:
Key: Tipo byte, que contiene la tecla que fue presionada.
x, y: Tipos int, que contienen las coordenadas x,y del pixel sobre el cual está el
puntero del mouse al momento de presionar una tecla(teclado).
Private void KeyboardHandlerS(int key, int x, int y)
Descripción:
Método manejador que captura las teclas (mientras está en foco la ventana glut)
especiales (down, left, rigth, up) cada vez que son presionadas.
Requiere los parámetros:
Key: Tipo int, que contiene la tecla que fue presionada.
74
x,y: Tipos int, que contienen las coordenadas x, y del pixel sobre el cual está el
puntero del mouse al momento de presionar una tecla(teclado).
Private void Paint():
Descripción:
Método encargado de pintar la escena 3D que se muestra por la ventana en
forma dinámica, cada cambio que se hace en la escena en tiempo de ejecución
es mostrado gracias a este método.
Public override void SaveToXML(XmlElement parent):
Descripción:
Método encargado de guardar en el documento XML todas las propiedades de
la clase World.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento XML padre.
Public override void LoadFromXML(XmlNode parent)
Descripción:
Método encargado de cargar desde el XML todas las propiedades de la clase
World.
Requiere los parámetros:
75
Parent: Tipo XmlNode, que contiene el nodo XML padre.
Public void ShowFps():
Descripción:
Método encargado de desplegar los frames por segundo que se están
mostrando por la ventana que muestra la escena.
public virtual void ToSource(StreamWriter writer)
Descripción:
Método que escribe el código fuente del mundo.
Requiere los parámetros:
writer: de tipo StreamWriter en cual la se escribirá el código del mundo (World).
public int SearchCode(string nameMethod)
Descripción:
Método que busca el código fuente de un método en particular dentro de la lista
de métodos desensamblados (Methods de tipo List <DissasemblerMethod>)
para construir el código del mundo.
Requiere los Parámetros:
nameMethod: de tipo string que corresponde al nombre del método
desensamblado al que se le desea ocupar el código.
76
public int SearchCodeField(string nameClass)
Descripción:
Método que busca las fields de una clase, esto dentro de la lista de Fields
desensamblados (Fields de tipo List < DissasemblerClassField>) de la clase
World.
Requiere los Parámetros:
nameClass: de tipo string, corresponde al nombre de la clase a la cual se quiere
obtener el código de sus fields.
public string replaceVar(string body)
Descripción:
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase World por el valor constante que tienen estas en
tiempo de ejecución.
Requiere los Parámetros:
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
8.2.1.3 Propiedades:
Public String Name: establece u obtiene el nombre del mundo.
77
Public trajectory CameraPosition: establece u obtiene la posición de la
cámara en el mundo.
Public Vector CameraRotation: establece u obtiene la rotación de la cámara
en el mundo.
Public Entity Entities: establece u obtiene los objetos del mundo (objetos de
tipo Entities).
Public bool TraslateModeMouse: Habilita o deshabilita el movimiento de
traslación del objeto con el Mouse.
Public bool TraslateModeMouseX: Habilita o deshabilita el movimiento de
traslación de objetos del mundo con el Mouse, usando como referencia el plano
YZ o X=0.
Public bool TraslateModeMouseY: Habilita o deshabilita el movimiento de
traslación de objetos del mundo con el Mouse, usando como referencia el plano
XZ o Y=0.
78
Public bool TraslateModeMouseZ: Habilita o deshabilita el movimiento de
traslación de objetos del mundo con el Mouse, usando como referencia el plano
XY o Z=0.
Public bool RotateModeMouse: Habilita o deshabilita el movimiento de
Rotación de los objeto del mundo con el Mouse.
Public bool RotateModeMouseX: Habilita o deshabilita el movimiento de
Rotación de los objeto del mundo con el Mouse, con referencia al plano YZ.
Public bool RotateModeMouseY: Habilita o deshabilita el movimiento de
Rotación de los objeto del mundo con el Mouse, con referencia al plano XZ.
Public bool RotateModeMouseZ: Habilita o deshabilita el movimiento de
Rotación de los objeto del mundo con el Mouse, con referencia al plano XY.
Public bool ScaleModeMouse: Habilita o deshabilita el escalamiento de los
objetos del mundo con el Mouse.
Public bool ScaleModeMouseX: Habilita o deshabilita el escalamiento de los
objetos del mundo con el Mouse, con referencia al plano YZ.
79
Public bool ScaleModeMouseY: Habilita o deshabilita el escalamiento de los
objetos del mundo con el Mouse, con referencia al plano XZ.
Public bool ScaleModeMouseZ: Habilita o deshabilita el escalamiento de los
objetos del mundo con el Mouse, con referencia al plano XY.
Public bool Histfig: establece u obtiene un arreglo que tiene un contador en
cada posición del arreglo, de cada tipo de figura que ha sido creada en el
mundo esta propiedad se utiliza para la construcción del nombre de los objetos
tipo Entity.
Public dateTime Time: Obtiene o establece la fecha y hora del mundo.
Public Vector Size: Obtiene o establece el tamaño del mundo.
Public bool TraslateModeCameraX: Habilita o deshabilita el movimiento de
traslación de la cámara en el mundo con el teclado, usando como referencia el
plano YZ.
Public bool TraslateModeCameraY: Habilita o deshabilita el movimiento de
traslación de la cámara en el mundo con el teclado, usando como referencia el
plano XZ.
80
Public bool TraslateModeCameraZ: Habilita o deshabilita el movimiento de
traslación de la cámara en el mundo con el teclado, usando como referencia el
plano XY.
Public bool RotateModeCamera: Habilita o deshabilita el movimiento de
Rotación de la cámara con el teclado.
Public int RotateFactorCamera: Obtiene o establece la cantidad de rotación
que se moverá la cámara.
Public int TraslateFactorCamera: Obtiene o establece la cantidad de
traslación que se moverá la cámara.
Public int Prkeyent: Obtiene o establece el identificador del objeto que está
seleccionado.
Public bool RenderMode: Obtiene o establece el modo de renderizado
(true=render false=wire) en que mostrará el mundo.
81
8.2.2 Class Entity:
Es la clase que reúne las características (métodos, propiedades y
miembros) en común de todos los objetos (Entities) representables por el
software.
8.2.2.1 Miembros:
Modificador
acceso
Private
de Tipo
Nombre
Trajectory
Valor
Location
Posición de la entidad.
Private
Vector
Rotation
Rotación de la entidad.
Private
Vector
Scale
Escala de la entidad.
Private
Bool
plane_qutX
False
plane_qutY
False
plane_qutY
False
plano de corte en x.
Private
Bool
plano de corte en y.
Private
Bool
plano de corte en z.
Private
List<Entity>
Entities
Lista de entidades que componen la entidad.
82
Private
List<Action>
Actions
Lista de acciones de la entidad.
Private
List<Input>
Inputs
Lista de entradas de la entidad.
Private
List<Output>
Outputs
Lista de salidas de la entidad.
Private
System.Drawing.Image Textura
Textura entidad.
Private
Vector
Color de la entidad.
Color
Private
on_Focus
Bool
Foco entidad.
Private
Int
Slice
Detalle del modelo del Objeto 3D.
Private
Int
Stacks
Detalle del modelo del Objeto 3D.
8.2.2.2 Métodos:
public virtual void NormalRender()
Descripción:
Método que muestra el objeto en modalidad render.
83
False
public virtual void DesignRender()
Descripción:
Método que muestra el objeto en modalidad design (diseño).
public virtual void SimulationRender()
Descripción:
Método que muestra el objeto en modalidad simulación.
public virtual void ToSource(StreamWriter writer)
Descripción:
Método que escribe el código fuente de un Objeto 3D de tipo Entity.
Requiere los parámetros:
writer: de tipo StreamWriter en cual se escribirá el código.
public double factor()
Descripción:
Calcula el factor de movimiento de los objetos para que se corresponda con el
del mouse.
public override void SaveToXML(XmlElement parent)
Descripción:
84
Método que guarda las propiedades de los objetos en el Xml.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
public override void LoadFromXML(XmlNode parent)
Descripción:
Método que carga las propiedades de los objetos desde el Xml.
Requiere los parámetros:
Parent: Tipo XmlNode, que contiene el nodo Xml padre.
public string replaceVar(string body)
Descripción:
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase Entity por el valor constante que tienen estas en
tiempo de ejecución.
Requiere los Parámetros:
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
8.2.2.3 Propiedades:
85
Public string Name: Obtiene o establece el nombre objeto de tipo Entity.
Public Trajectory Location: Obtiene o establece la posición del objeto tipo
Entity en el mundo 3D.
Public vector Scale: Obtiene o establece la escala del objeto tipo Entity en el
mundo 3D.
Public vector Rotation: Obtiene o establece la Rotación del objeto tipo Entity
en el mundo 3D.
Public bool PlaneQutX: Obtiene o establece el plano de corte con referencia
al plano X del objeto.
Public bool PlaneQutY: Obtiene o establece el plano de corte con referencia
al plano Y del objeto.
Public bool PlaneQutZ: Obtiene o establece el plano de corte con referencia
al plano Z del objeto.
Public int PrimaryKey: Obtiene o establece una llave primaria que identifica a
un Objeto de tipo Entity.
86
Public System.Drawing.Image Texture: Obtiene o establece la textura de la
entidad.
Public List<Entity> Entities: Obtiene o establece las entidades que contienen
la entidad.
Public List<Action> Actions: Obtiene o establece las acciones de la entidad.
Public Vector Color: Obtiene o establece el color de la entidad.
8.2.3 Class XMLConverter:
Es la encargada la guardar o cargar información de la escena además
hereda comportamientos, a las clases que hereden de ella para guardar o
cargar datos desde un Xml.
8.2.3.1 Miembros:
Modificador
acceso
Private
de Tipo
Nombre
XmlNode
Textura
Es un nodo Xml que guarda una textura.
8.2.3.2 Métodos:
87
Valor
public static XmlNode ImageToXMLNode(Image imagen)
Descripción:
Método que recibe una imagen, la codifica binariamente y la deja en un nodo
Xml.
Requiere los parámetros:
Imagen: de tipo Image, que contiene la imagen a codificar binariamente para
ser guardada en un nodo Xml.
public static XmlNode ImageToXMLNode(System.Drawing.Image imagen, string
nombre)
Descripción:(recarga)
Método que recibe una imagen, la codifica binariamente y la deja en un nodo
Xml.
Requiere los parámetros:
Imagen: de tipo Image, que contiene la imagen a codificar binariamente para
ser guarda en un nodo Xml.
Nombre: de tipo string, que contiene el nombre de la textura a codificar, el cual
igual se guardará en el Xml.
public static Image XMLNodeToImage(XmlNode Nodo)
Descripción:
88
Deserializa el XML y retorna la Imagen.
Requiere los parámetros:
Nodo: de tipo de XmlNode, que contiene la imagen deserializar.
public override void SaveToXML(XmlElement child,XmlElement parent,Entity
entity)
Descripción:
Método que guarda las propiedades de los objetos hijos de un objeto tipo
Custom en el Xml.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
child: Tipo XmlElement, que contiene el elemento Xml hijo.
Entity: Tipo Entity, que contiene el objeto hijo al cual se le guardarán las
propiedades en el Xml.
public void LoadFromXML(XmlNode xmlent, World world, Entity entity)
Descripción:
Método que carga las propiedades de los objetos hijos de un objeto tipo Custom
en el Xml.
Requiere los parámetros:
xmlent: Tipo XmlElement, que contiene el objeto hijo serializado.
89
world: Tipo World, que contiene los objetos del mundo.
Entity: Tipo Entity, que contiene el objeto hijo al cual se le cargarán las
propiedades desde el Xml.
8.2.4 Class GlPrimitives:
GlPrimitives es la clase que proporciona métodos para dibujar primitivas
3D mediante llamadas OpenGL, además proporciona métodos para manipular
las primitivas OpenGL.
8.2.4.1 Miembros:
Modificador
acceso
Private
de Tipo
Glu.GLUquadric
Nombre
Valor
Quadric
Variable de tipo GLUquadric necesaria para construir primitivas de tipo
Quádricas.
Private
Bool
Gotquadric
False
Sirve para verificar si la variable quadric ha sido asociada a un objeto
quádrico.
Private
double[]
clippingPlane1
Arreglo que guarda la representación del plano de corte x=0.
Private
double[]
clippingPlane2
Arreglo que guarda la representación del plano de corte y=0.
90
{ 1.0, 0.0, 0.0,
0.0}
{ 0.0, 1.0, 0.0,
0.0 }
Private
double[]
clippingPlane3
Arreglo que guarda la representación del plano de corte z=0.
{ 0.0, 0.0, 1.0,
0.0 }
8.2.4.2 Métodos:
public static void RenderSphere(double Radius,int slice,int stacks)
Descripción:
Método que construye la primitiva OpenGL esfera sólida.
Requiere los parámetros:
Radius: de tipo double, es el radio de la esfera.
Slice: de tipo Int, establece calidad del modelo de la primitiva.
Stacks: de tipo Int, establece calidad del modelo de la primitiva.
public static void RenderSphereWire(double Radius,int slice,int stacks)
Descripción:
Método que construye la primitiva OpenGL esfera cableada.
Requiere los parámetros:
Radius: de tipo double, es el radio de la esfera.
Slice: de tipo Int, establece calidad del modelo de la primitiva
Stacks: de tipo Int, establece calidad del modelo de la primitiva.
91
public static void RenderCylinder(double baseRadius,double topRadius,double
heigth, int slice, int stacks)
Descripción:
Método que construye la primitiva OpenGL cilindro sólido.
Requiere los parámetros:
baseRadius: de tipo double, es el radio basal del cilindro.
topRadius: de tipo double, es el radio superior del cilindro.
Heigth: de tipo double, es la altura del cilindro.
Slice: de tipo Int, establece calidad del modelo de la primitiva.
Stacks: de tipo Int, establece calidad del modelo de la primitiva.
public
static
void
RenderCylinderWire(double
baseRadius,double
topRadius,double heigth, int slice, int stacks)
Descripción:
Método que construye la primitiva OpenGL cilindro cableado.
Requiere los parámetros:
baseRadius: de tipo double, es el radio basal del cilindro.
topRadius: de tipo double, es el radio superior del cilindro.
Heigth: de tipo double, es la altura del cilindro.
Slice: de tipo Int establece calidad del modelo de la primitiva.
Stacks: de tipo Int establece calidad del modelo de la primitiva.
92
public static void RenderDisk(double innerRadius,double outerRadius, int slice,
int stacks)
Descripción:
Método que construye la primitiva OpenGL disco sólido.
Requiere los parámetros:
innerRadius: de tipo double, es el radio interior del cilindro.
outerRadius: de tipo double, es el radio externo del cilindro.
Slice: de tipo Int, establece calidad del modelo de la primitiva.
Stacks: de tipo Int, establece calidad del modelo de la primitiva.
public static void RenderDiskWire(double innerRadius,double outerRadius, int
slice, int stacks)
Descripción:
Método que construye la primitiva OpenGL disco cableado.
Requiere los parámetros:
innerRadius: de tipo double, es el radio interior del cilindro.
outerRadius: de tipo double, es el radio externo del cilindro.
Slice: de tipo Int, establece calidad del modelo del Objeto 3D.
Stacks: de tipo Int, establece calidad del modelo del Objeto 3D.
93
public static void RenderCube(double x)
Descripción:
Método que construye la primitiva OpenGL cubo sólido.
Requiere los parámetros:
x: de tipo double, es el tamaño del lado del cubo.
public static void RenderBox(double width, double height, double depth)
Descripción:
Método que construye la primitiva OpenGL Box sólido.
Requiere los parámetros:
Width: de tipo double, es el ancho de la caja.
Heigth: de tipo double, es la altura de la caja.
Depth: de tipo double, es el largo de la caja.
public static void RenderBoxWire(double width, double height, double depth)
Descripción:
Método que construye la primitiva OpenGL Box cableado.
Requiere los parámetros:
width: de tipo double, es el ancho de la caja.
Heigth: de tipo double, es la altura de la caja.
Depth: de tipo double, es el largo de la caja.
94
public static void RenderSquare(double x)
Descripción:
Método que construye la primitiva OpenGL cuadrado sólido.
Requiere los parámetros:
x: de tipo double, es el tamaño del lado del cuadrado.
public static void RenderSquareWire(double x)
Descripción:
Método que construye la primitiva OpenGL cuadrado cableado.
Requiere los parámetros:
x: de tipo double, es el tamaño del lado del cuadrado.
public static void RenderTriangle(double Sizesides)
Descripción:
Método que construye la primitiva OpenGL triángulo sólido.
Requiere los parámetros:
Sizesidez: de tipo double, es el tamaño del lado del triángulo equilátero.
public static void RenderPyramid(double x)
Descripción:
Método que construye la primitiva OpenGL Pirámide sólida.
95
Requiere los parámetros:
x: de tipo double, es la distancia del centro de la pirámide a sus vértices.
public static void RenderPyramidWire(double x)
Descripción:
Método que construye la primitiva OpenGL Pirámide cableado.
Requiere los parámetros:
x: de tipo double, es la distancia del centro de la pirámide a sus vértices.
public static void RenderCircle(float radius)
Descripción:
Método que construye la primitiva OpenGL Círculo cableado.
Requiere los parámetros:
radius: de tipo float, es el tamaño del radio del círculo.
public static void RenderCircleWire(float radius)
Descripción:
Método que construye la primitiva OpenGL Círculo cableado.
Requiere los parámetros:
radius: de tipo float, es el tamaño del radio del círculo.
96
public static void RenderPoligon(double Sizesides,int sides)
Descripción:
Método que construye la primitiva OpenGL Polígono sólido.
Requiere los parámetros:
Sizesidez: de tipo double, es el tamaño del lado del polígono.
Sides: de tipo int, es la cantidad de lados del polígono.
public static void RenderPoligonWire(double Sizesides,int sides)
Descripción:
Método que construye la primitiva OpenGL Polígono cableado.
Requiere los parámetros:
Sizesidez: de tipo double, es el tamaño del lado del polígono.
Sides: de tipo int, es la cantidad de lados del polígono.
public static void RenderPcBot()
Descripción:
Método que construye la primitiva OpenGL Tanque.
97
public static void postredisplay()
Descripción:
Método que llama a un postRediplay OpenGL.
public static void PushMatrix()
Descripción:
Método que llama a un PushMatrix OpenGL.
public static void LoadName(int name)
Descripción:
Método que asocia un identificador a una primitiva OpenGL.
Requiere los parámetros:
name:Tipo Int, contiene el identificador que se asociará a la primitiva.
public static void Traslate(double x,double y, double z)
Descripción:
Método que traslada las primitivas.
Requiere los parámetros:
x: de tipo double, contiene lo que se trasladará la primitiva en x.
y: de tipo double, contiene lo que se trasladará la primitiva en y.
z: de tipo double, contiene lo que se trasladará la primitiva en z.
98
public static void Scale(double x, double y, double z)
Descripción:
Método que escala las primitivas.
Requiere los parámetros:
x: de tipo double, contiene lo que se escalará la primitiva en x.
y: de tipo double, contiene lo que se escalará la primitiva en y.
z: de tipo double, contiene lo que se escalará la primitiva en z.
public static void Rotate(double x, double y, double z)
Descripción:
Método que rota las primitivas.
Requiere los parámetros:
x: de tipo double, contiene lo que se rotará la primitiva en x.
y: de tipo double, contiene lo que se rotará la primitiva en y.
z: de tipo double, contiene lo que se rotará la primitiva en z.
public static void Color(double r, double g, double b)
Descripción:
Método que colorea las primitivas.
Requiere los parámetros:
r: de tipo double, contiene el componente r del color de el objeto.
99
g: de tipo double, contiene el componente g del color del objeto.
b: de tipo double, contiene el componente b del color de el objeto.
public static void Onfocus(string name,double x,double y,double z)
Descripción:
Método que le da foco a la primitiva OpenGL.
Requiere los parámetros:
Name: de tipo string, contiene el nombre del objeto (no de la primitiva).
x: de tipo double, contiene la posición de la primitiva en x.
y: de tipo double, contiene la posición de la primitiva en y.
z: de tipo double, contiene la posición de la primitiva en z.
public static void plane()
Descripción:
Método que construye la primitiva OpenGL plano.
8.2.5 Class Sphere:
Clase que hereda de Entity la cual se encarga de construir un objeto de
tipo Sphere y además ofrecer las propiedades referentes a este tipo de objetos.
100
8.2.5.1 Miembros:
Modificador
acceso
Private
de Tipo
Double
Nombre
Valor
Radius
2
Radio de la esfera.
8.2.5.2 Métodos:
public override void NormalRender()
Descripción:
Método que muestra el objeto de tipo Sphere en modalidad render.
public override void DesignRender()
Descripción:
Método que muestra el objeto de tipo Sphere en modalidad design (diseño).
public override void SaveToXML(XmlElement parent)
Descripción:
Método que guarda las propiedades de los objetos tipo Sphere en el Xml.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
public override void LoadFromXML(XmlNode parent)
101
Descripción:
Método que carga las propiedades de los objetos tipo Sphere desde el Xml.
Requiere los parámetros:
Parent: Tipo XmlNode, que contiene el nodo Xml padre.
public virtual void ToSource(StreamWriter writer)
Descripción:
Método que escribe el código fuente de un objeto de tipo Sphere.
Requiere los parámetros:
writer: de tipo StreamWriter en cual se escribirá el código.
public string replaceVarSphere(string body)
Descripción:
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase Sphere, por el valor que estas tienen en tiempo de
ejecución.
Requiere los Parámetros:
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
102
8.2.5.3 Propiedades:
public double Radius: establece u obtiene el radio de la esfera.
8.2.6 Class Box:
Clase que hereda de Entity la cual está encargada de construir un objeto
de tipo Box y además ofrecer las propiedades referentes a este tipo de objetos.
8.2.6.1 Miembros:
Modificador
acceso
Private
de Tipo
Nombre
Double
Width
Double
Heigth
Double
Depth
Int
Text
Ancho de la caja.
Private
Altura de la caja.
Private
Largo de la caja.
Private
Dirección de memoria de la textura que cubre a la caja.
8.2.6.2 Métodos:
public override void NormalRender()
103
Valor
Descripción:
Método que muestra el objeto de tipo box en modalidad render.
public override void DesignRender()
Descripción:
Método que muestra el objeto de tipo box en modalidad design (diseño).
public override void SaveToXML(XmlElement parent)
Descripción:
Método que guarda las propiedades del objeto tipo Box en el Xml.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
public override void LoadFromXML(XmlNode parent)
Descripción:
Método que carga las propiedades del objeto tipo Box desde el Xml.
Requiere los parámetros:
Parent: Tipo XmlNode, que contiene el nodo Xml padre.
public override void ToSource(StreamWriter writer)
Descripción:
104
Método que escribe el código fuente de un Objeto 3D de tipo Box.
Requiere los parámetros:
writer: de tipo StreamWriter en el cual se escribirá el código.
public string replaceVarBox(string body)
Descripción:
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase Box por el valor que estas tienen en tiempo de
ejecución.
Requiere los Parámetros:
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
8.2.6.3 Propiedades:
public double Width: propiedad que obtiene o establece el ancho de la caja.
public double Heigth: propiedad que obtiene o establece la altura de la caja.
public double Depth: propiedad que obtiene o establece el largo de la caja.
105
8.2.7 Class Cylinder:
Clase que hereda de Entity la cual está encargada de construir un objeto
de tipo Cylinder y además ofrecer las propiedades referentes a este tipo de
objetos.
8.2.7.1 Miembros:
Modificador
acceso
Private
de Tipo
Double
Nombre
baseRadius
Radio basal del cilindro.
Private
Double
topRadius
Radio superior del cilindro.
Private
Double
Heigth
Int
Slice
Altura del cilindro.
Private
Detalle de Modelo del cilindro.
Private
Int
Stacks
Detalle de Modelo del cilindro.
8.2.7.2 Métodos:
public override void NormalRender()
Descripción:
106
Valor
Método que muestra el objeto de tipo Cylinder en modalidad render.
public override void DesignRender()
Descripción:
Método que muestra el objeto de tipo Cylinder en modalidad design (diseño).
public override void SaveToXML(XmlElement parent)
Descripción:
Método que guarda las propiedades de los objetos de tipo Cylinder en el Xml.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
public override void LoadFromXML(XmlNode parent)
Descripción:
Método que carga las propiedades de los objetos de tipo Cylinder desde el Xml.
Requiere los parámetros:
Parent: Tipo XmlNode, que contiene el nodo Xml padre.
public override void ToSource(StreamWriter writer)
Descripción:
Método que escribe el código fuente de un objeto de tipo Cylinder.
107
Requiere los parámetros:
writer: de tipo StreamWriter en cual la se escribirá el código.
public string replaceVarCylinder(string body)
Descripción:
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase Cylinder por el valor constante que tienen estas en
tiempo de ejecución.
Requiere los Parámetros:
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
8.2.7.3 Propiedades:
public double BaseRadius: propiedad que obtiene o establece el radio basal
del cilindro.
public double TopRadius: propiedad que obtiene o establece el radio superior
del cilindro.
public double Heigth: propiedad que obtiene o establece la altura del cilindro.
108
public int Slice: propiedad que obtiene o establece el detalle del modelo.
public int Stacks: propiedad que obtiene o establece el detalle del modelo.
8.2.8 Class Pyramid:
Clase que hereda de Entity la cual está encargada de construir un objeto
de tipo Pyramid y además ofrecer las propiedades referentes a este tipo de
objetos.
8.2.8.1 Miembros:
Modificador
acceso
Private
de Tipo
Double
Nombre
Valor
Size
Distancia desde el centro de la pirámide a sus vértices.
8.2.8.2 Métodos:
public override void NormalRender()
Descripción:
Método que muestra el objeto de tipo Pyramid en modalidad render.
public override void DesignRender()
Descripción:
109
Método que muestra el objeto de tipo Pyramid en modalidad design(diseño).
public override void SaveToXML(XmlElement parent)
Descripción:
Método que guarda las propiedades de los objetos de tipo Pyramid en el Xml.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
public override void LoadFromXML(XmlNode parent)
Descripción:
Método que carga las propiedades de los objetos de tipo Pyramid desde el Xml.
Requiere los parámetros:
Parent: Tipo XmlNode, que contiene el nodo Xml padre.
public override void ToSource(StreamWriter writer)
Descripción:
Método que escribe el código fuente de un Objeto 3D de tipo Pyramid.
Requiere los parámetros:
writer: de tipo StreamWriter en cual se escribirá el código.
110
public string replaceVarPyramid(string body)
Descripción:
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase Pyramid por el valor constante que tienen estas en
tiempo de ejecución.
Requiere los Parámetros:
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
8.2.8.3 Propiedades:
public double Size: propiedad que obtiene o establece el tamaño de la
Pirámide.
8.2.9
Class Disk:
Clase que hereda de Entity la cual está encargada de construir un objeto
de tipo Disk y además ofrecer las propiedades referentes a este tipo de objetos.
8.2.9.1 Miembros:
Modificador
acceso
Private
de Tipo
Double
Nombre
InnerRadius
Radio interior del disco.
111
Valor
Private
Double
OuterRadius
Radio exterior del disco.
Private
Int
Slice
Detalle de Modelo del Disco
Private
Int
Stacks
Detalle de Modelo del Disco.
8.2.9.2 Métodos:
public override void NormalRender()
Descripción:
Método que muestra el objeto de tipo disk en modalidad render.
public override void DesignRender()
Descripción:
Método que muestra el objeto de tipo disk en modalidad design (diseño).
public override void SaveToXML(XmlElement parent)
Descripción:
Método que guarda las propiedades de los objetos de tipo “disk” en el Xml.
Requiere los parámetros:
112
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
public override void LoadFromXML(XmlNode parent)
Descripción:
Método que carga las propiedades de los objetos de tipo disk desde el Xml.
Requiere los parámetros:
Parent: Tipo XmlNode, que contiene el nodo Xml padre.
public override void ToSource(StreamWriter writer)
Descripción:
Método que escribe el código fuente de un Objeto 3D de tipo disk.
Requiere los parámetros:
writer: de tipo StreamWriter en cual se escribirá el código.
public string replaceVarDisk(string body)
Descripción:
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase “Disk” por el valor constante que tienen estas en
tiempo de ejecución.
Requiere los Parámetros:
113
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
8.2.9.3 Propiedades:
public double InnerRadius: propiedad que obtiene o establece el radio interno
del disco.
public double OuterRadius: propiedad que obtiene o establece el radio
exterior del disco.
public int Slice: propiedad que obtiene o establece el detalle del modelo.
public int Stacks: propiedad que obtiene o establece el detalle del modelo.
8.2.10 Class Square:
Clase que hereda de Entity la cual está encargada de construir un objeto
de tipo Square y además ofrecer las propiedades referentes a este tipo de
objetos.
8.2.10.1 Miembros:
Modificador
acceso
de Tipo
Nombre
114
Valor
Private
Double
Size
Tamaño del cuadrado.
8.2.10.2 Métodos.
public override void NormalRender()
Descripción:
Método que muestra el objeto de tipo Square en modalidad render.
public override void DesignRender()
Descripción:
Método que muestra el objeto de tipo Square en modalidad design (diseño).
public override void SaveToXML(XmlElement parent)
Descripción:
Método que guarda las propiedades de los objetos de tipo square en el Xml.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
public override void LoadFromXML(XmlNode parent)
Descripción:
Método que carga las propiedades de los objetos de tipo square desde el Xml.
115
Requiere los parámetros:
Parent: Tipo XmlNode, que contiene el nodo Xml padre.
public override void ToSource(StreamWriter writer)
Descripción:
Método que escribe el código fuente de un Objeto 3D de tipo Square.
Requiere los parámetros:
writer: de tipo StreamWriter en cual se escribirá el código.
public string replaceVarSquare(string body)
Descripción:
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase Square por el valor constante que tienen estas en
tiempo de ejecución.
Requiere los Parámetros:
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
8.2.10.3 Propiedades:
public double Size: propiedad que obtiene o establece el tamaño del Objeto
3D Square.
116
8.2.11 Class Circle:
Clase que hereda de Entity la cual está encargada de construir un objeto
de tipo Circle y además ofrecer las propiedades referentes a este tipo de
objetos.
8.2.11.1 Miembros:
Modificador
acceso
Private
de Tipo
Double
Nombre
Valor
Radius
Radio del círculo.
8.2.11.2 Métodos:
public override void NormalRender()
Descripción:
Método que muestra el objeto de tipo Circle en modalidad render.
public override void DesignRender()
Descripción:
Método que muestra el objeto de tipo Circle en modalidad design (diseño).
public override void SaveToXML(XmlElement parent)
Descripción:
117
Método que guarda las propiedades de los objetos de tipo Circle en el Xml.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
public override void LoadFromXML(XmlNode parent)
Descripción:
Método que carga las propiedades de los objetos de tipo Circle desde el Xml.
Requiere los parámetros:
Parent: Tipo XmlNode, que contiene el nodo Xml padre.
public override void ToSource(StreamWriter writer)
Descripción:
Método que escribe el código fuente de un Objeto 3D de tipo Circle.
Requiere los parámetros:
writer: de tipo StreamWriter en cual se escribirá el código.
public string replaceVarCircle(string body)
Descripción:
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase Circle por el valor constante que tienen estas en
tiempo de ejecución.
118
Requiere los Parámetros:
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
8.2.11.3 Propiedades:
public double Radius: propiedad que obtiene o establece el radio del Objeto
3D de tipo Circle.
8.2.12 Class Poligon:
Clase que hereda de Entity la cual está encargada de construir un objeto
de tipo Poligon y además ofrecer las propiedades referentes a este tipo de
objetos.
8.2.12.1 Miembros:
Modificador
acceso
Private
de Tipo
Double
Nombre
Size
Tamaño del lado del polígono equilátero.
Private
Int
Sides
Cantidad de lados del polígono.
8.2.12.2 Métodos:
119
Valor
public override void NormalRender()
Descripción:
Método que muestra el objeto de tipo Poligon en modalidad render.
public override void DesignRender()
Descripción:
Método que muestra el objeto de tipo Poligon en modalidad design (diseño).
public override void SaveToXML(XmlElement parent)
Descripción:
Método que guarda las propiedades de los objetos de tipo Poligon en el Xml.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
public override void LoadFromXML(XmlNode parent)
Descripción:
Método que carga las propiedades de los objetos de tipo Poligon desde el Xml.
Requiere los parámetros:
Parent: Tipo XmlNode, que contiene el nodo Xml padre.
public override void ToSource(StreamWriter writer)
120
Descripción:
Método que escribe el código fuente de un objeto de tipo Poligon.
Requiere los parámetros:
writer: de tipo StreamWriter en cual se escribirá el código.
public string replaceVarPoligon(string body)
Descripción:
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase Poligon por el valor constante que tienen estas en
tiempo de ejecución.
Requiere los Parámetros:
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
8.2.12.3 Propiedades:
public double Size: Obtiene o establece el tamaño del lado del polígono
equilátero.
Public int sizes: Obtiene o establece la cantidad de lados del polígono
equilátero.
121
8.2.13 Class Triangle:
Clase que hereda de Entity la cual está encargada de construir un objeto
de tipo Triangle y además ofrecer las propiedades referentes a este tipo de
objetos.
8.2.13.1 Miembros:
Modificador
acceso
Private
de Tipo
Double
Nombre
Valor
Size
Tamaño del lado del triángulo equilátero.
8.2.13.2 Métodos:
Public override void NormalRender()
Descripción:
Método que muestra el objeto de tipo Triangle en modalidad render.
public override void DesignRender()
Descripción:
Método que muestra el objeto de tipo Triangle en modalidad design (diseño).
public override void SaveToXML(XmlElement parent)
122
Descripción:
Método que guarda las propiedades de los objetos de tipo Triangle en el Xml.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
public override void LoadFromXML(XmlNode parent)
Descripción:
Método que carga las propiedades de los objetos de tipo Triangle desde el Xml.
Requiere los parámetros:
Parent: Tipo XmlNode, que contiene el nodo Xml padre.
public override void ToSource(StreamWriter writer)
Descripción:
Método que escribe el código fuente de un objeto de tipo Triangle.
Requiere los parámetros:
writer: de tipo StreamWriter en cual se escribirá el código.
public string replaceVarTriangle(string body)
Descripción:
123
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase Triangle por el valor constante que tienen estas en
tiempo de ejecución.
Requiere los Parámetros:
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
8.2.13.3 Propiedades:
Public double Size: Obtiene o establece el tamaño del lado del triángulo
equilátero.
8.2.14 Class Tank:
Clase que hereda de Entity la cual está encargada de construir un objeto
de tipo Tank y además ofrecer las propiedades referentes a este tipo de
objetos.
8.2.14.1 Métodos:
public override void NormalRender()
Descripción:
Método que muestra el objeto de tipo Tank en modalidad render.
124
public override void DesignRender()
Descripción:
Método que muestra el objeto en de tipo Tank modalidad design (diseño).
public override void SaveToXML(XmlElement parent)
Descripción:
Método que guarda las propiedades de los objetos de tipo Tank en el Xml.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
public override void LoadFromXML(XmlNode parent)
Descripción:
Método que carga las propiedades de los objetos de tipo Tank desde el Xml.
Requiere los parámetros:
Parent: Tipo XmlNode, que contiene el nodo Xml padre.
public override void ToSource(StreamWriter writer)
Descripción:
Método que escribe el código fuente de un objeto de tipo Tank.
Requiere los parámetros:
writer: de tipo StreamWriter en cual se escribirá el código.
125
public string replaceVarTank(string body)
Descripción:
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase Tank por el valor constante que tienen estas en
tiempo de ejecución.
Requiere los Parámetros:
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
8.2.15 Class Ligth:
Clase que hereda de Entity la cual está encargada de construir una
fuente de luz y además ofrecer las propiedades referentes a esta.
8.2.15 .1 Miembros:
Modificador
acceso
Private
de Tipo
Int
Nombre
Valor
Ligth
Variable que identifica una fuente de luz.
Private
Vector
lightAmbientVector
Vector que sirve para cambiar la luz ambiente de una fuente de luz
dinámicamente.
Private
Vector
lightDiffuseVector
126
Vector que sirve para cambiar la difusión de una fuente de luz dinámicamente.
Private
float[]
LightAmbient
{ 0.0f, 0.0f, 0.0f,
0.0f }
LightDiffuse
{ 1f, 1f, 1f, 1f }
Ambiente de la fuente de luz.
Private
float[]
Difusión de la fuente de luz.
8.2.15.2 Métodos:
public override void NormalRender()
Descripción:
Método que muestra la luz sin mostrar la posición de la fuente.
public override void DesignRender()
Descripción:
Método que muestra la luz y la posición de la fuente.
public override void SaveToXML(XmlElement parent)
Descripción:
Método que guarda las propiedades de la luz en el Xml.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
127
public override void LoadFromXML(XmlNode parent)
Descripción:
Método que carga las propiedades de la luz desde el Xml.
Requiere los parámetros:
Parent: Tipo XmlNode, que contiene el nodo Xml padre.
public override void ToSource(StreamWriter writer)
Descripción:
Método que escribe el código fuente de un Objeto 3D de tipo Ligth.
Requiere los parámetros:
writer: de tipo StreamWriter en cual la se escribirá el código.
public string replaceVarLigth(string body)
Descripción:
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase Ligth por el valor constante que tienen estas en
tiempo de ejecución.
Requiere los Parámetros:
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
128
8.2.15.3 Propiedades:
public int Ligths: Obtiene o establece el identificador de la fuente de luz.
public Vector LightDiffuse: Obtiene o establece la difusión de la luz de una
fuente.
public Vector LightAmbient: Obtiene o establece la luz ambiente de una
fuente.
8.2.16 Class Custom:
Clase que hereda de Entity la cual está encargada de construir un objeto
de tipo Custom (objeto compuesto) y además ofrecer las propiedades
referentes a este tipo de objetos.
8.2.16.1 Métodos:
public override void NormalRender()
Descripción:
Método que muestra el objeto de tipo Custom en modalidad render.
public override void DesignRender()
129
Descripción:
Método que muestra el objeto de tipo Custom en modalidad design(diseño).
public override void SaveToXML(XmlElement parent)
Descripción:
Método que guarda las propiedades de los objetos de tipo Custom en el Xml.
Requiere los parámetros:
Parent: Tipo XmlElement, que contiene el elemento Xml padre.
public override void LoadFromXML(XmlNode parent)
Descripción:
Método que carga las propiedades de los objetos de tipo Custom desde el Xml.
Requiere los parámetros:
Parent: Tipo XmlNode, que contiene el nodo Xml padre.
public override void ToSource(StreamWriter writer)
Descripción:
Método que escribe el código fuente de un Objeto 3D de tipo Custom.
Requiere los parámetros:
writer: de tipo StreamWriter en cual se escribirá el código.
130
public string replaceVarCustom(string body)
Descripción:
Método que reemplaza las variables del código fuente desensamblado de un
método o field de la clase Custom por el valor constante que tienen estas en
tiempo de ejecución.
Requiere los Parámetros:
body: de tipo string, es el código fuente de un método desensamblado al cual se
le quiere reemplazar sus variables.
8.2.17
Class Action:
Clase encargada de construir una acción para un Objeto.
(Solo se propondrá una versión beta ya que el proyecto no contempla la
funcionalidad de animación avanzada)
8.2.17.1 Miembros.
Modificador
acceso
Private
de Tipo
Double
Nombre
target_x
Cantidad de movimiento x.
Private
Double
target_y
Cantidad de movimiento y.
Private
Double
target_z
131
Valor
Cantidad de movimiento z.
Private
Int
typeAction
Tipo de movimiento(traslación, rotación o escalamiento)
8.2.17.2 Propiedades:
public double TargetX: obtiene o establece la cantidad en x que el objeto se
moverá.
public double TargetY: obtiene o establece la cantidad en y que el objeto se
moverá.
public double TargetZ: obtiene o establece la cantidad en z que el objeto se
moverá.
public int TypeAction: obtiene o establece el tipo de acción.
8.2.18
Class Dissasembler:
Dissasembler es la clase encargada de desensamblar las clases del
proyecto para obtener el código fuente de ellas.
132
8.2.18.1 Métodos:
public static List<DissasemblerMethod> DissasemblerC(String Assembly,ref
List<DissasemblerClassField> Field)
Descripción:
Método que obtiene el código fuente de de todas la clases del proyecto y las
devuelve por medio de dos listas de objetos de tipo DissasemblerMethod y
DissasemblerClassField.
Requiere los parámetros:
Assembly: de tipo string, que en este caso es la ruta (“path”, ubicación) donde
está el proyecto al cual se le desensamblan sus clases.
Field: de tipo ref List<DissasemblerClassField> que es una lista en donde se
devolverán el código correspondiente a los campos de cada una de las clases
del proyecto.
8.2.19
Class ZeroFxInterface:
Clase encargada de ofrecer una interfaz visual para la manipulación del
mundo y sus objetos. Ofrece menús para cargar y guardar la escena; soporte
básico para creación y edición de objetos mediante menús, soporte avanzado
para manipulación de la cámara en la escena y configuraciones del Mundo 3D.
133
8.2.19.1 Miembros:
Modificador
acceso
Private
de Tipo
Nombre
World
World
Engine
Engine
Valor
Mundo 3D.
Private
Engine para manipular el mundo 3D.
Private
XmlDocument
Xml
Documento Xml usado para cargar o guardar la configuración de la interfaz
visual del software.
Private
(controles
win
forms)
Controles winforms y los métodos de esta clase, no se describirán en detalle
ya que sería muy extenso, el código se encuentra documentado igualmente.
8.2.20 SceneEditInterface:
Clase encargada de ofrecer una interfaz visual avanzada para la creación
y edición de Objetos (Entities) y el Mundo. Ofrece una interface visual para la
creación y edición de luces y ofrece una interface visual para la creación de
objetos de tipo compuesto (Custom).
8.2.20.1 Miembros:
Modificador
acceso
Private
de Tipo
World
Nombre
World
134
Valor
Mundo 3D.
Private
Engine
Engine
Engine para manipular el mundo 3D.
Private
(controles
win
forms)
Controles winforms y los métodos de esta clase, no se describirán en detalle
ya que sería muy extenso, el código se encuentra documentado igualmente.
8.2.21 Class Engine:
Engine es la clase encargada de proporcionar interfaces para manipular
el mundo y sus objetos, tales como teclado y mouse, además provee métodos
de creación de objetos y manipulación de cámaras.
8.2.21.1 Miembros:
Modificador
acceso
Private
de Tipo
List<World>
Nombre
list_world
Lista de Mundos 3D.
Private
Int
Camera
Identificador de la cámara activa.
135
Valor
8.2.21.2 Métodos:
public void CreateEntityWorld(World world, Entity entity, Double r, Double g,
Double b)
Descripción:
Método que agrega un objeto 3D a un mundo especificado.
Requiere los parámetros:
world: objeto de tipo World, donde se agregará el objeto 3D.
entity: objeto de tipo Entity, el cual se agregará al Mundo 3D (world).
r,g,b: parámetros de tipo double,los cuales establecerán el color del Objeto 3D.
public Entity EntitySearch(string name,World world)
Descripción:
Método que busca un objeto en el mundo.
Requiere los parámetros:
name: de tipo string, el cual es el nombre del objeto 3D a buscar.
world : de tipo world, es el mundo 3D donde se buscará el objeto 3D.
public void AddEntityToEntity(Entity custom, Entity child)
Descripción:
Método que le agrega un objeto 3D hijo a un objeto Custom (padre).
Requiere los parámetros:
136
Custom: de tipo Entity, objeto padre.
Child: de tipo Entity, objeto hijo.
public void MouseEngine(int x, int y, int oldX, int oldY, int Prkeyent, World world)
Descripción:
Método encargado de editar (escala, posición, rotación) el objeto seleccionado
mediante el mouse.
Requiere los parámetros:
x: de tipo int, es la posición en x del mouse.
Y: de tipo int, es la posición en y del mouse.
oldX: de tipo int, es la posición anterior en x del mouse.
oldY: de tipo int, es la posición anterior en y del mouse.
Prkeyent: de tipo int, es el id del objeto seleccionado actualmente.
world: de tipo World, el mundo 3D que está editando el mouse.
public void KeyboardEngine(int key,World world)
Descripción:
Método que está encargado de modificar el mundo y sus objetos mediante el
teclado, incluye el manejo para teclas especiales.
Requiere los parámetros:
key: de tipo entero, es el identificador de la tecla que ha sido presionada.
137
world: de tipo World, es el mundo que será manipulado con el teclado.
public void KeyboardEngine(byte key,World world) (sobrecarga)
Descripción:
Método que está encargado de modificar el mundo y sus objetos mediante el
teclado.
Requiere los parámetros:
key: de tipo byte, es el id de la tecla que ha sido presionada.
world: de tipo World, es el mundo que será manipulado con el teclado.
public void SelectCamera(int camera,World world)
Descripción:
Método que está encargado de seleccionar la cámara.
Requiere los parámetros:
camera: de tipo int, que identifica la cámara a seleccionar.
world: de tipo World, es el mundo 3D al cual se le establecerá una cámara.
public
void
SaveProyect(SaveFileDialog
saveFileDialog,
World
world,
XmlElement parent)
Descripción:
Método que está encargado de guardar el proyecto gráfico en un archivo XML.
138
Requiere los parámetros:
saveFileDialog: de tipo SaveFileDialog, el cual captura el path donde se
guardará el Xml del proyecto.
world: de tipo World, es el mundo 3D el cual se guardará en el Xml.
public void LoadProyect(OpenFileDialog openFileDialog,World
world,XmlElement parent)
Descripción:
Método que está encargado de restaurar el proyecto gráfico desde un archivo
XML.
Requiere los parámetros:
openFileDialog: de tipo OpenFileDialog, el cual captura el path de donde se
restaurará el documento XML del proyecto.
world: de tipo World, es el mundo 3D el cual se restaurará desde el XML.
public void CreateEntityCustomWorld(World world,Entity custom,String Name)
Descripción:
Método que agrega un objeto 3D de tipo “Custom” a un mundo especificado.
Requiere los parámetros:
world: objeto de tipo World donde se agregará el objeto 3D.
custom: objeto de tipo Custom, el cual se agregará al Mundo 3D (world).
139
public void DetailModel(int detail,World world)
Descripción:
Método que está encargado de aplicar el detalle de modelo al mundo.
Requiere los parámetros:
detail: de tipo int, que establece el grado de detalle.(mientras mayor más detalle
del modelo)
world: de tipo World, es el mundo 3D el cual se le aplicará el detalle de modelo.
8.2.21.3 Propiedades:
public List<World> ListWorld: obtiene o establece una lista de objetos de tipo
World.
public int Camera: obtiene o establece la cámara activa en el mundo.
8.2.22
Class
LanguageWriterConfiguration:(clase
de
apoyo
Dissasembler)
Es la clase encargada de configurar las partes de la clase que se
Desensamblarán.
140
de
8.2.23 Class CustomAssemblyResolver:(clase de apoyo de Dissasembler)
Es la clase encargada de cargar un ensamblado dado usando una
librería “reflector.dll” que sirve como clase de apoyo al desensamblador.
8.2.24 Class DissasemblerClassField:
Clase encargada de guardar el código de los campos de una clase
desensamblada.
8.2.24.1 Miembros:
Modificador
acceso
Private
de Tipo
Nombre
Double
class_name
Double
Body
Valor
Nombre de la clase.
Private
Código fuente de las fields de la clase.
8.2.24.2 Propiedades:
public string ClassName: obtiene o establece el nombre de la clase de donde
se obtendrán los fields .
141
public string Body: obtiene o establece el código de los fields de una clase.
public int Parameter: obtiene o establece el número de parámetros del método
desensamblado, sirve para distinguir métodos sobrecargados.
8.2.25 Class DissasemblerMethod:
Clase encargada de guardar el código de un método de una clase
desensamblada.
8.2.25.1 Miembros:
Modificador
acceso
Private
de Tipo
Nombre
Double
class_name
String
Body
Valor
Nombre de la clase.
Private
Código fuente del método desensamblado.
Private
String
Name
Nombre del método desensamblado.
Private
Int
Parameter
Número de parámetros del método desensamblado sirve para distinguir
métodos sobrecargados.
142
8.2.25.2 Propiedades:
public
string
Name:
obtiene
o
establece
el
nombre
del
método
desensamblado.
public string NameClass: obtiene o establece el nombre de la clase del
método desensamblado.
public string Body: obtiene o establece el cuerpo del método desensamblado.
public int Parameter: obtiene o establece el número de parámetros del método
desensamblado, sirve para distinguir métodos sobrecargados.
143
8.32 Casilla de Responsabilidades.
3
A continuación, se mostrará un diagrama resumen de la responsabilidad
de cada clase con el fin mostrar una visión global del rol que cumple cada clase
en el funcionamiento de la aplicación.
World
Entity
GlPrimitives
-Es la clase encargada de inicializar y deplegar
la ventana Glut por la que se muestra
el espacio 3D donde están contenidos
los objetos.
-Es la clase que reúne las características
en común de todos los objetos representables
por el software.
-Proporciona métodos
para dibujar primitivas 3D
mediante llamadas OpenGl.
-Es la encargada de definir acciones
para los objetos del mundo.
-Proporciona métodos para
manipular las primitivas OpenGl
Inputs
-Prorporciona métodos y propiedades
para controlar y mostrar el mundo 3D.
Action
-Es la encargada de definir Inputs
para los objetos del mundo.
Engine
-Contiene la colección de objetos presentes
en el mundo.
-Clase encargada de porporcionar
métodos de mainipulación del mundo
3D y sus Objtos, proporciona un nivel
más alto de abstracción que la clase World.
XmlConverter
-Proporciona métodos de manipulación
del mundo mediante el mouse y teclado.
-Es la clase encargada la guardar y cargar
información de la escena y heredar
comportamientos para guardar o cargar
datos desde un xml.
Outputs
Dissasembler
-Es la encargada de obtener
el código fuente de las clases
de la aplicación.
-Es la encargada de definir Outputs
para los objetos del mundo.
CustomAssemblyResolver
-Es la clase encargada de cargar un Asembly dado
usando la dll reflector, sirve como clase de apoyo
a dissasembler.
WorldUserInterface
Sphere
-Sphere es la clase encargada
de constuir objetos 3D de
tipo esfera.
Box
-Es la clase encargada
de construir y representar
objetos 3d de tipo Box.
Cylinder
-Cylinder es la clase encargada
de construir y representar
un objeto 3D de tipo cylinder.
-Clase encargada de ofrecer una interfaz visual
para la manipulación del mundo 3D.
LanguageWriterConfiguration
-Ofrece menus para cargar y guardar la escena.
-Es la clase encarda de configurar las partes de la clase que se
desensamblaran.
-Soporte básico para creación y edición de
objetos mediante menus.
-Soporte avanzado para manipulación de la
cámara en la escena y configuraciones del Mundo 3D.
Ligth
-Ligth es la clase encargada
de construir fuentes de luz.
DissasemblerMethod
-Clase encargada guardar el código de un método de una clase desensamblada.
EntityUserInterface
Pyramid
Square
-Clase encargada de ofrecer una interfaz visual
Avanzada para para la creación y edición
de Objetos(Entities).
-Es la encargada de construir
y representar Objetos de
tipo Pyramid.
-Es la encargada de construir
y representar Objetos de
tipo Square.
-Ofrece una interface visual para la creación y
edición de fuentes de luz.
DissasemblerClassField
-Clase encargada guardar el código de los fileds de una clase desensamblada.
-Ofrece una interface visual para la creación de
objetos de tipo compuesto(custom).
Circle
Poligon
-Es la encargada de construir
y representar Objetos de tipo
Circle.
-Es la encargada de construir
y representar Objetos de tipo
Poligon.
Custom
Triangle
Disk
Tank
-Es la encargada de construir
y representar Objetos de tipo
Triangle.
-Es la encargada de construir
y representar Objetos de tipo
Disk.
-Es la encargada de construir
y representar Objetos de tipo
Tank.
-Es la encargada de construir
y representar Objetos de tipo
custom los cuales están formados
a su vez por otros objetos.
Fi
Diagramas Casilla de Responsabilidades
144
8.4 Diagrama de Procesos.
A continuación se mostrará el diagrama de flujo de algunos de los
procesos más importantes de la aplicación, los cuales muestran la lógica de su
funcionamiento, estos diagramas suministran como producto la base lógica de
la programática de la aplicación.
8.4.1 Diagrama de Proceso Creación y edición de un Objeto 3D.
El siguiente diagrama (Figura 1) muestra la lógica con que se crea y edita
un objeto 3D, este diagrama se ha abordado desde el punto de vista de un
Objeto 3D genérico.
145
El usuario usa las interfaces
(Teclado o Formulario) para
crear un Objeto.
Se crea un objeto
3D.
Se agrega el
Objeto 3D a la
colección de
objetos del
mundo.
El usuario Selecciona como se
mostrará el Objeto.
El Objeto 3D se
muestra en
modalidad Design.
El usuario mediante las
interfaces (Teclado o
Formulario) Eliminar un
Objeto.
El usuario mediante
las interfaces
(Teclado o
Formulario) agrega
el Objeto 3D a un
Objeto compuesto.
Design
¿Que Modalidad
de despliegue del
Objeto 3D Render
o Design?
Render
El Objeto 3D se
muestra en
modalidad
Render.
Se Refresca la
ventana por donde
se muestra el
mundo.
El usuario mediante
las interfaces (Teclado
o Formulario) aplica
Planos de Corte.
El usuario mediante las
interfaces (Teclado o
Formulario) habilita
Traslación/Rotación/Escala
del Objeto 3D.
El usuario mediante
las interfaces (Teclado
o Formulario)
Selecciona una
textura para aplicar al
Objeto 3D
i
El Objeto 3D es
eliminado de la
colección de
Objetos del
Mundo o de un
Objeto
Compuesto.
Se agrega el
Objeto 3D a un
Objeto
compuesto.
Se aplica los
planos de corte
seleccionados por
el usuario al
Objeto 3D.
Traslada/Rota/
Escala el Objeto
3D como el
usuario requiera
mediante Mouse o
Teclado.
Se Aplica la
textura
seleccionada por
el usuario al
Objeto 3D.
Figura 1
Como se puede observar en el diagrama anterior, se muestra la
secuencia lógica para la creación y edición de un objeto, se puede observar
además, que este diagrama de proceso no posee un estado final, esto debido a
que después de que el usuario selecciona la modalidad de despliegue del
objeto, este entra en un ciclo iterativo de edición.
146
8.4.2 Diagrama de Proceso Guardar escena.
El siguiente diagrama (Figura 2), muestra la lógica de cómo se guardará
la escena en un archivo XML con el objetivo de guardar el trabajo realizado con
el Editor 3D, para posteriormente ser retomado, básicamente la lógica
programática se centra en la ejecución de un método llamado “SaveToXml” que
guarda las propiedades de las instancias (Objetos) actuales del Editor 3D en un
archivo Xml.
El usuario selecciona
guardar escena en el menú
principal de la aplicación.
Se ejecuta el método
SaveToXml de todas las
instancias que posean
este método.
La escena es guardada en el
Xml lista para ser cargada por
la aplicación cuando el usuario
lo requiera.
Figura 2
147
8.4.3 Diagrama de Proceso Cargar escena.
El siguiente diagrama (Figura 3), muestra la lógica de cómo se cargará la
escena desde archivo Xml con el objetivo de retomar el trabajo hecho con el
Editor 3D, básicamente la lógica programática se centra en la ejecución de dos
métodos llamados InitEntityFromXml y LoadFromXml, el primero se encarga de
crear las instancias necesarias y el segundo es encargado de asignarle las
propiedades a estas instancias, la información respecto a las instancias que se
deben crear y las propiedades que se les deben asignar vienen en el archivo
Xml.
El usuario selecciona Cargar
escena en el menú principal de
la aplicación.
Se ejecuta el método
InitEntityFromXml
para crear las
instancias necesarias
según la información
que trae el Xml.
Se ejecuta el método
LoadFromXml para cargar las
propiedades de las instancias
creadas en el proceso anterior
desde el Xml.
La escena es cargada por la
aplicación y queda lista para
seguir siendo editada por el
usuario.
Figura 3
148
Finalmente, una vez ejecutados todos los pasos lógicos del diagrama, la
escena queda restaurada totalmente lista para seguir siendo diseñada.
8.4.4 Diagrama de Proceso Generación código Fuente de la escena
Diseñada con el Editor 3D.
El siguiente diagrama (Figura 4) muestra la lógica de cómo se generará
el código fuente a partir de lo diseñado con el Editor 3D.
149
El usuario selecciona Exportar a
código C# la escena en el menú
principal de la aplicación.
Se desensamblan
las clases gráficas
de Editor 3D.
Se ejecuta el método
ToSource de todas las
instancias que posean
este método.
Se genera una clase C# que es
capas de desplegar la escena
diseñada anteriormente con el
Editor 3D.
La clase C# es agregada a un
proyecto Visual Studio.
El editor 3D ejecuta
automáticamente Visual Studio
con el proyecto ya cargado listo
para compilar y ejecutarse.
Figura 4
8.4.5 Diagrama de Proceso de Selección de objetos Mediante el Mouse.
El siguiente diagrama (Figura 5) muestra los pasos lógicos para realizar
la selección de objetos mediante el Mouse.
150
Cada vez que se crea un objeto se le asigna un
nombre (número entero).
Se obtienen las coordenadas de donde se
encuentra el cursor del Mouse en la ventana.
Se
habilita
el
modo
de
selección de OpenGL.
Se define el área de selección de modo que sólo una pequeña
parte de la ventana sea tomada en cuenta, esta debe ser en
donde está el cursor del Mouse.
Se llama al método que despliega la
escena a la cual se le seleccionaran los
objetos.
Se debe salir del modo de selección e
identificar los objetos que fueron
presionados en esa pequeña parte de
la pantalla.
Se establece en foco el objeto seleccionado
más cercano a la cámara y se le cargan sus
propiedades.
Figura 5
Este proceso (Figura 5), es uno de los más relevantes debido a que es
muy necesario para el funcionamiento del Editor 3D.
151
9. Construcción del Software
En este capítulo se abordará la construcción de la aplicación para esto,
se definieron dos versiones, una versión beta que tiene la funcionalidad de
editor 3D y una versión final que tendrá además la funcionalidad de generación
de código, por lo tanto la construcción se dividió en base a ésto, a continuación
se describirá en detalle de como se construyó cada funcionalidad.
9.1 Construcción Aplicación versión Beta (solo Funcionalidad de Editor
3D).
Esta versión de la aplicación fue obtenida mediante la construcción de
una lista de funcionalidades, éstas fueron construidas en base a los casos de
uso, diagramas de procesos y de clases abordados en capítulos anteriores. A
continuación se describirá la construcción de todas las funcionalidades más
relevantes para el funcionamiento del Editor 3D.
9.1.1 Construir una ventana que despliegue un Objeto en el mundo.
Para esta funcionalidad, se debió codificar una primera versión de una
clase llamada World que representa el mundo y además despliega la ventana
por donde se visualizará. También se construyó una clase llamada Entity, la que
152
construye un objeto 3D y además reúne las características (Propiedades,
métodos etc.) en común de todos los objetos 3D representables por el software,
posteriormente se crearon especializaciones de la clase Entity tales como
Sphere, Box entre otras, el detalle de estas clases (cantidad y tipos) se
abordarán más adelante dentro de la construcción de las clases especializadas
de Entity. A continuación (Figura 6) se muestra la ventana que despliega la
escena con una de las primeras versiones de la aplicación.
Figura 6
153
9.1.2 Capacidad de agregar en forma dinámica objetos al mundo y
además que se desplieguen.
Para esta funcionalidad se debió crear una colección de objetos de tipo
Entity llamada Entities, ésta es un miembro de la clase “World”; es aquí donde
los objetos se agregan en forma dinámica. Se usó una de las características de
la tecnología Reflection, la cual nos permite invocar métodos de un objeto sólo
sabiendo su tipo, y en este caso nos interesa llamar al método que muestra el
objeto de tipo Entity o que hereda de este tipo.
9.1.3 Crear una clase que ofrezca Primitivas OpenGL personalizadas.
Para esta funcionalidad se creó una clase Estática que ofrece primitivas
OpenGL personalizadas, esta clase se llama GlPrimitives, la cual encapsula las
llamadas nativas a OpenGL, además ofrece más de sesenta métodos para
desplegar y manipular primitivas OpenGL, éstos métodos son los que
finalmente se llaman en los métodos que despliegan los Objetos de tipo en
Entity y sus especializaciones. A continuación se presenta un método que
despliega la Primitiva OpenGL Sphere.
154
//método que construye la primitiva OpenGl esfera sólida
public static void RenderSphere(double Radius,int slice,int stacks)
{
CheckQuadric();
//se selecciona el estilo de despliegue.
Glu.gluQuadricDrawStyle(quadric, Glu.GLU_FILL);
//se despliega la primitiva sphere
Glu.gluSphere(quadric, Radius, slice, stacks);
}
Código Nº [1] Método que construye la primitiva OpenGL esfera sólida.
Como se puede apreciar en el método anterior, el cual está encargado de
construir una esfera 3D, esto se logra mediante el uso de primitivas OpenGL
como las que se ven en el trozo de código expuesto anteriormente.
9.1.4 Definir tipos Objetos que derivan de Entity.
Para la construcción de esta funcionalidad el cliente solicitó diez tipos de
especializaciones de Entity (Tipos de Objetos 3D), finalmente se construyeron
catorce con las cuales se puede construir escenarios de buena complejidad y
detalle, para esta funcionalidad se construyeron clases que derivan de “Entity”
las cuales son las siguientes:

Sphere

Box
155

Cylinder

Pyramid

Disk

Square

Triangle

Poligon

Circle

Camera

Tank

Custom

Cone

Ligth
Para más detalle, la descripción completa de estas clases se encuentra
en el diccionario de clases en el capítulo de diseño.
9.1.5 Crear interfaz visual y lógica para creación de Objetos.
Para la construcción de esta funcionalidad, en la parte visual se agregó
una paleta de objetos diseñada sobre un Formulario del tipo WinForm llamado
156
SceneEditInterface, con la cual mediante un click se crea un objeto en el
mundo.
Figura 7
En cuanto a la parte lógica para esta funcionalidad, se creó la clase
Engine con el método AddEntity, el cual agrega un Objeto de tipo Entity o que
hereda de Entity a un Objeto World.
A continuación se muestra un trozo de código, donde se crea un Objeto
de tipo Sphere y se agrega a un Objeto de tipo World.
Sphere sphere = new Sphere();
engine.AddEntity(world, sphere, colorR, colorG, colorB);
157
Se debe tomar en cuenta el método AddEntity sólo puede agregar
objetos de tipo Entity o que hereden de Entity a un objeto de tipo World.
9.1.6 Exhibir las propiedades del mundo y objetos en una paleta de
propiedades.
Para la construcción de esta funcionalidad se agregó un control de tipo
PropertyGrid a un formulario de tipo WinForm, este control se incluyó con el
objetivo de editar de forma dinámica las propiedades del mundo (World) y sus
Objetos, de manera que estas se visualicen inmediatamente en la ventana que
muestra el mundo, la paleta de propiedades sólo ofrece las propiedades del
objeto que está seleccionado o el mundo como se muestra en la Figura 8.
158
Figura 8
9.1.7 Seleccionar el mundo o los objetos desplegados en la ventana
mediante el Mouse.
Para esta funcionalidad se debió poner especial interés ya que fue una
de las más solicitadas por el cliente y ésta se obtuvo mediante las siguientes
consideraciones.
La API de OpenGL proporciona un mecanismo de selección de objetos
en una escena 3D para detectar los objetos que están bajo el Mouse en una
159
parte o región de la ventana. Los pasos involucrados en la selección de objetos
mediante el Mouse son los siguientes:
1. Obtener las coordenadas de donde se encuentra el puntero del Mouse
en la ventana.
2. Habilitar el modo de selección de OpenGL.
3. Definir el área de selección de modo que sólo una pequeña parte de la
ventana sea tomada en cuenta, ésta debe ser en donde está el cursor del
Mouse.
4. Llamar al método que despliega la escena a la cual se le seleccionaran los
objetos.
5. Se debe salir del modo de selección e identificar los objetos que fueron
presionados en esa pequeña parte de la pantalla.
Con el fin de identificar los objetos seleccionados utilizando la API de
OpenGL, se debe asignar un nombre a cada objeto en la escena, para esto la
API permite dar nombres a las primitivas o conjuntos de primitivas (objetos). El
modo de selección es un modo especial de la API OpenGL. En lugar de retornar
los nombres de los objetos, al seleccionarlos OpenGL devuelve la información
de selección en una matriz, la cual contiene información de todos los objetos
que fueron seleccionados.
160
Usando la terminología de OpenGL, cada vez que se presiona sobre una
primitiva en el modo de selección, el buffer de selección es modificado. Al salir
del modo de selección, OpenGL vuelve al modo normal, devolviendo en una
matriz la información del búffer de selección, OpenGL proporciona información
detallada acerca del objeto seleccionado, como por ejemplo a qué distancia se
encuentra de la cámara, lo cual se utiliza principalmente cuando dos objetos se
encuentran en el área de selección y se requiere seleccionar uno de los dos,
generalmente es elegido el más cercano a la cámara.
Los nombres que se asignaron a los objetos se almacenan en una pila,
los que en realidad no son nombres (cadena de texto) sino un número que
representa un identificador de la primitiva, a continuación se muestra el método
que despliega un objeto de tipo Sphere (Código Nº [2]) y se destacará en
donde se le asignó el nombre al objeto.
161
//método que muestra en modo render el Objeto tipo Sphere
public virtual void NormalRender(){
//se aplican las propiedades al objeto
GlPrimitives.PushMatrix();
GlPrimitives.Traslate(Location.Target.X, Location.Target.Y, Location.Target.Z);
GlPrimitives.Traslate(Location.Position.X, Location.Position.Y, Location.Position.Z);
GlPrimitives.Rotate(Rotation.X, Rotation.Y, Rotation.Z);
GlPrimitives.Scale(Scale.X, Scale.Y, Scale.Z);
//se le asigna el nombre para la selección OpenGL
Gl.glLoadName(PrimariKey);
GlPrimitives.Color(Color.X, Color.Y, Color.Z);
//se le asigna los planos de corte a la esfera.
GlPrimitives.Cutfigures(PlaneQutX, PlaneQutY, PlaneQutZ);
//se llama a la primitiva OpenGl RenderSphere
GlPrimitives.RenderSphere(Radius,Slice,Stacks, ITexture, Texture);
GlPrimitives.PopMatrix();
}
Código Nº [2] Método que Despliega un Objeto de Tipo Entity.
Como se explicó anteriormente se le asignó un nombre al Objeto, ahora
corresponde detectar cuando el objeto sea seleccionado con el mouse. A
continuación un trozo de código (Código Nº [3]) que realiza esta tarea.
162
//método que sirve para seleccionar los objetos
//presentes en el mundo mediante el uso del mouse
private void gl_select(int x, int y)
{
int[] buff = new int[1000];
float[] projection = new float[16];
int[] view = new int[4];
/*
designamos un array en el que OpenGl nos devuelva
la información de selección.
*/
Gl.glSelectBuffer(128, buff);
/*
Recuperamos informción con el siguiente método
acerca del wiew port que será requerido más adelante.
*/
Gl.glGetIntegerv(Gl.GL_VIEWPORT, view);
/*
Para realizar una selección se le debe indicar
a OpenGl que se trabajará en modo SELECT.
*/
Gl.glRenderMode(Gl.GL_SELECT);
/*
Inicialisamos la pila de nombres.
*/
Gl.glInitNames();
/*
Inicialisamos la pila de nombres en 0.
*/
Gl.glPushName(0);
/*
Fijamos la tranformación de proyección.
*/
Gl.glMatrixMode(Gl.GL_PROJECTION);
Gl.glPushMatrix();
Gl.glLoadIdentity();
/*
Restringimos el área de selección a la posición
del cursor con el siguiente método.
*/
Glu.gluPickMatrix(x, y, 1.0, 1.0, view);
Glu.gluPerspective(60, Aspect, 1, 2000);
/*
Redibujamos nuevamente los objetos en pantalla.
*/
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Glut.glutSwapBuffers();
/*
LLamamos al método que está asociado al manejador DisplayCallback
ya que sólo este nos devuelve información del bufer de selección.
*/
show();
/*
Preparamos para volver al Modo Render con las siguientes sentencias.
*/
Gl.glMatrixMode(Gl.GL_PROJECTION);
Gl.glPopMatrix();
/*
La siguiente sentencia obtiene la cantidad de objetos que se
seleccionó y además vuelve al modo RENDER.
*/
hits = Gl.glRenderMode(Gl.GL_RENDER);
163
/* procedemos a recorrer el arreglo que tiene los datos del bufer de
selección, en la posición 0 de este arreglo está el valor con que
inicialisamos la pila, en la 1 y 2 información no relevante para la selección
y en la posición 3 el nombre del objeto seleccionado, esto es en el caso que
bajo el puntero del mouse se encuentre solo un objeto, en caso contrario se
deben revisar todos lo objetos selecionados en las posiciones (2*i)+1 del
bufer,para esta implementación trabajaremos con el objeto que se encuentra
más cercano a la cámara, esta información se obtendrá de los elementos
(2*i)+2 y (2*i)+3 del bufer, una vez encontrado el objeto más cercano a la
cámara se asigna el valor(nombre) a la posición 3 del bufer, para no cambiar
el código respecto al caso de si se huviera seleccionado un solo objeto.
Posteriormente se busca el nombre que se encuentra en el bufer (buff[3]) en
la colección de objetos de tipo Entity del objeto World, mediante la
propiedad primarykey de los objetos de tipo Entity, ya que con este nombre(el
valor de la propiedad primarykey) fue guardado en la pila de nombres, una vez
encontrado el objeto de nombre buff[3] dentro de la colección de objetos de
tipo Entity del Mundo(World), la propiedad onfocus del objeto se establece en
true y posteriormente se cargan sus propiedades en el propertygrid. */
int i = 1;
if (hits > 1)
{
while (i < hits)
{
if (buff[i * 4 - 3] < buff[(i + 1) * 4 - 3])
{
buff[3] = buff[i * 4 - 1];
}
else
{
buff[3] = buff[(i + 1) * 4 - 1];
}
if (buff[3] == 1024)
{
buff[3] = buff[(i + 1) * 4 - 1];
}
i++;
}
}
//se procede a la busqueda del objeto mediante el nombre devuelto por la
//pila de nombres,una vez encontrado,se procede dando foco al objeto
//seleccionado y carga de sus propiedade en el propertygrid.
foreach (Entity entity in Entities)
{
if (string.Compare(entity.PrimariKey.ToString(), buff[3].ToString()) == 0)
{
entity.Onfocus = true;
selected_object = buff[3];
PropertyInterface.Show();
PropertyInterface.comboBoxObject.Text = entity.Name;
PropertyInterface.propertyGridObject.SelectedObject = entity;
Refresh();
}
else
{
entity.Onfocus = false;
}
}
Gl.glMatrixMode(Gl.GL_MODELVIEW);
}
164
Código Nº [3] Método que Selecciona un Objeto el Mundo mediante el
Mouse.
Finalmente teniendo esta funcionalidad se puede editar el mundo o los
objetos sólo haciendo un click sobre ellos.
9.1.8 Trasladar/Rotar/Escalar objetos en forma dinámica mediante el
Mouse y Paleta de Propiedades.
Para esta funcionalidad se debió crear un método manejador especial
llamado MouseEngine, el cual cumple la función de Trasladar, Rotar y Escalar
los objetos mediante el Mouse, éste se ubica en la clase Engine, la cual es la
clase encargada de proporcionar interfaces para manipular el mundo y sus
objetos, tales como teclado y mouse, además provee métodos de creación de
objetos y manipulación de cámaras.
El método manejador antes nombrado, recibe como parámetros las
coordenadas actuales del cursor del Mouse cuando el botón izquierdo del
Mouse se encuentra presionado, para obtener estos datos se usó el Callback
Motion de Glut, por tanto debemos suscribirnos a el de la siguiente forma.
Glut.glutMotionFunc(new Glut.MotionCallback(Motion));
165
La línea anterior suscribe el método Motion al MotionCallback de Glut
con el cual se obtiene la posición actual del cursor del Mouse mientras esté
presionado algún botón de éste.
Se definió el método Motion en la clase World con el objetivo de
suministrar los datos que necesita el método MouseEngine para editar los
objetos dinámicamente.
private void Motion(int x, int y)
{
//se suministran los parámatros al método MouseEngine para poder mover
//objetos dinámicamente mediante el Mouse.
engine.MouseEngine(x, y, oldX, oldY, selected_object, this);
}
Código Nº [4] Método Motion que captura la posición del Mouse mientras
el botón izquierdo del Mouse está presionado.
166
public void MouseEngine(int x, int y, int oldX, int oldY, int selected_object, World
world)
{
if (world.Entities.Count > selected_object)
{
Entity Entity = world.Entities[selected_object];
if (world.Lockworld == false)
{
//Si world está en modo de traslación el objeto seleccionado
//se moverá en concordancia con el Mouse.
if (world.TraslateModeMouse)
{
//Si world está en modo de traslación en el plano Z=0
// el objeto seleccionado se moverá en concordancia
// con el Mouse pero con referencia al plano Z=0.
if (world.TraslateModeMouseInZ)
{
Entity.Location.Position.X += (x - oldX) * Entity.factor();
Entity.Location.Position.Y += (y - oldY) * -Entity.factor();
b
}
//Si world está en modo de traslación en el plano Y=0
// el objeto seleccionado se moverá en concordancia
// con el Mouse pero con referencia al plano Y=0.
if (world.TraslateModeMouseInY)
{
Entity.Location.Position.X += (x - oldX) * Entity.factor();
Entity.Location.Position.Z += (y - oldY) * 0.03;
}
//Si world está en modo de traslación en el plano X=0
// el objeto seleccionado se moverá en concordancia
// con el Mouse pero con referencia al plano X=0.
if (world.TraslateModeMouseInX)
{
Entity.Location.Position.Z += (x - oldX) * Entity.factor();
Entity.Location.Position.Y += (y - oldY) * -0.03;
}
world.OldX = x;
world.OldY = y;
Glut.glutPostRedisplay();
}
}
Código Nº [5] sección del Método MouseEngine que traslada el objeto
mediante el Mouse.
En el código anterior (Código Nº [5]), se puede apreciar una pequeña
parte del método MouseEngine, específicamente la parte que traslada el objeto
seleccionado mediante el Mouse, este método también posee la lógica
167
programática para escalar y rotar objetos además trasladar y rotar la cámara.
Como se puede observar también, los parámetros recibidos por el método
MouseEngine modifican la posición del objeto seleccionado, no obstante esta
también depende de la función llamada Factor la cual calcula un factor de
movimiento del objeto esto dependiendo de la posición que tiene el objeto con
referencia a la cámara.
Por último se debió agregar al método base de la clase Entity que
despliega los objetos de tipo Entity, la lógica para que el objeto responda al
Mouse cuando éste se mueva ya sea trasladando, rotando o escalando.
A continuación el código (Código Nº [6]) del método que despliega una
entidad con la lógica antes descrita destacada, cabe mencionar que se conjugó
la lógica del método base que está en la clase Entity con el método que
reescribe de la clase derivada Sphere para que sea más entendible en el
ejemplo. En este método se puede apreciar como las propiedades Location,
Rotation y Scale de la clase Entity son aplicadas a la primitiva RenderSphere no
olvidar que estas mismas fueron modificadas en el método MouseEngine.
168
//método que muestra en modo render el Objeto tipo Sphere
public virtual void NormalRender(){
//se aplican las propiedades al objeto
GlPrimitives.PushMatrix();
GlPrimitives.Traslate(Location.Target.X, Location.Target.Y, Location.Target.Z);
GlPrimitives.Traslate(Location.Position.X, Location.Position.Y,
Location.Position.Z);
GlPrimitives.Rotate(Rotation.X, Rotation.Y, Rotation.Z);
GlPrimitives.Scale(Scale.X, Scale.Y, Scale.Z);
//se le asigna el nombre para la selección OpenGL
Gl.glLoadName(PrimariKey);
GlPrimitives.Color(Color.X, Color.Y, Color.Z);
//se le asigna los planos de corte a la esfera.
GlPrimitives.Cutfigures(PlaneQutX, PlaneQutY, PlaneQutZ);
//se llama a la primitiva OpenGl RenderSphere
GlPrimitives.RenderSphere(Radius,Slice,Stacks, ITexture, Texture);
GlPrimitives.PopMatrix();
}
Código Nº [6] Método que Despliega un Objeto de Tipo Sphere que
hereda de Entity.
9.1.9 Trasladar/Rotar la cámara en forma dinámica mediante el Mouse y
Paleta de Propiedades.
Para esta funcionalidad se debió agregar código al método manejador
para Trasladar, Rotar, Escalar objetos mediante el Mouse mencionado en la
funcionalidad anterior (MouseEngine), sólo que ahora se le agregó código para
que en lugar de trasladar un objeto lo realice con la cámara. Por último se debió
agregar al método que despliega el mundo de la clase World, la lógica para que
la cámara se Traslade o rote dinámicamente al mover el Mouse.
169
public void MouseEngine(int x, int y, int oldX, int oldY, int selected_object, World
world)
b{
//Se pregunta si el mundo está seleccionado.
if (selected_object == World.selected_world)
{
if (world.TraslateModeMouse)
{
//Si world está en modo de traslación de cámara en el plano Z=0
// el objeto seleccionado se moverá en concordancia
// con el Mouse pero con referencia al plano Z=0.
if (world.TraslateModeMouseInZ)
{
world.CameraPosition.Position.X += (x - oldX)*0.03 ;
world.CameraPosition.Position.Y -= (y - oldY)*0.03;
}
//Si world está en modo de traslación de cámara en el plano Y=0
// el objeto seleccionado se moverá en concordancia
// con el Mouse pero con referencia al plano Y=0.
if (world.TraslateModeMouseInY)
{
world.CameraPosition.Position.X += (x - oldX) *0.03 ;
world.CameraPosition.Position.Z += (y - oldY) * 0.03;
}
//Si world está en modo de traslación de cámara en el plano X=0
// el objeto seleccionado se moverá en concordancia
// con el Mouse pero con referencia al plano X=0.
if (world.TraslateModeMouseInX)
{
world.CameraPosition.Position.Z += (x - oldX) * 0.03;
world.CameraPosition.Position.Y += (y - oldY) * -0.03;
}
}
world.OldX = x;
world.OldY = y;
Glut.glutPostRedisplay();
}
Código Nº [7] sección del Método MouseEngine que traslada la cámara
mediante el Mouse.
9.1.10 Selección de cámaras.
Independiente de que la cámara se pueda trasladar o rotar mediante la
funcionalidad anterior, la aplicación igual debe ofrecer la funcionalidad de mover
la cámara a posiciones predeterminadas, para esto se construyó la lógica para
170
que el usuario pueda seleccionar cinco tipos o perspectivas de cámara las
cuales son:
a. Plano X=0.
b. Plano Y=0.
c. Plano Z=0.
d. Perspectiva.
e. Multi Cámaras.
En el caso de los tres primeros tipos de cámaras, la cámara está
orientada al plano coordenado mencionado en el nombre, en el caso de la
cámara de tipo Perspectiva, es aquella en que se distinguen todos los planos
coordenados, por último la cámara de tipo Multi Cámaras muestra todas las
cámaras anteriores en la misma ventana. Cabe mencionar que toda la lógica
respecto a la manipulación de cámaras se encuentra en la clase Engine.
9.1.11 Crear una interfaz visual para la aplicación.
Para esta funcionalidad se construyó dos formularios de tipo WinForm
que se agregan a la ventana Glut ya existente, uno para la creación y edición
del mundo (SceneEditInterface) y sus objetos y el otro para contener el menú
principal de la aplicación y accesos directos a los elementos más usados
171
(ZeroFxInterface), para el diseño de estos formularios se tomó en cuenta el
diseño de otras aplicaciones tales como 3D Studio Max y Maya.
Las interfaces visuales fueron creadas de manera que al usuario le
resulte intuitivo y fácil manipular la aplicación, una de las características que se
construyó para facilitar la manipulación de los objetos y el mundo, es la
configuración automática de traslación, rotación y escalado según la cámara
seleccionada por el usuario, esto ayuda a que la traslación, rotación y escalado
coincida con el movimiento del Mouse cualquiera sea la cámara seleccionada.
A continuación la pantalla (Figura 9) principal de la aplicación la cual
muestra una escena en modalidad Design.
172
Figura 9
Otra característica que se mencionó anteriormente es el uso de cámaras,
un ejemplo de esto es la misma escena de la figura anterior, pero visto desde la
cámara Y=0 que no es otra cosa que una cámara orientada hacia ese plano
(plano azul en la imagen Figura 10).
173
Figura 10
Otra de las características de la interfaz visual es la posibilidad elegir la
modalidad de despliegue de la escena. En las figuras anteriores se desplegó
ésta en modalidad Design. A continuación una escena (Figura 11) en modalidad
Render.
174
Figura 11
Como se puede observar en la Figura 11, los planos coordenados en la
modalidad Render han desaparecido y los objetos son sólidos (no cableados)
como en la modalidad Design.
Otra de las características de la interfaz visual es la posibilidad elegir la
modalidad multi cámaras como se muestra en la Figura 12, esta funcionalidad
se refiere a desplegar las cuatro cámaras que ofrece el Editor 3D al mismo
175
tiempo por la ventana de la escena, esto sirve para facilitar la visión espacial de
la escena.
Figura 12
Finalmente, hay otras funcionalidades que se encuentran en el menú de
la interfaz visual, tales como configuración de la creación y edición de objetos,
configuración de cámaras, configuración del detalle del modelo de la escena,
cargar y guardar una escena y generar código fuente de la escena.
176
9.1.12 Aplicar Texturas a Objetos de tipo Entity.
Para esta funcionalidad se construyó un método que carga una textura
en una posición de memoria (Código Nº [8]), posteriormente en el método que
despliega un objeto de tipo Entity se agregan las líneas de código necesarias
para asociar la textura a un Objeto de Tipo Entity en específico (Código Nº
[9]).
/// Método encargado de cargar una textura desde un archivo
/// y devuelve la posición de memoria donde se encuentra
public static int LoadTexture(string file,ref Bitmap bitmap)
{
int AuxTexture;
/// se crea un objeto bitmap cargado desde la ruta file
bitmap = new Bitmap(file);
bitmap.RotateFlip(RotateFlipType.Rotate270FlipX);
Rectangle Rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
/// se mapea la textura en un rectángulo
BitmapData BitmapData = bitmap.LockBits(Rect, ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
//Generamos el id de la textura en el contexto de OpenGL
Gl.glGenTextures(1, out AuxTexture);
Gl.glBindTexture(Gl.GL_TEXTURE_2D, AuxTexture);
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR);
Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGB8, BitmapData.Width,
BitmapData.Height, 0, Gl.GL_BGR_EXT, Gl.GL_UNSIGNED_BYTE, BitmapData.Scan0);
bitmap.UnlockBits(BitmapData);
//retornamos el id de la textura.
return (AuxTexture);
}
Código Nº [8] Método que carga una Textura en una posición de memoria.
177
//Seleccionamos la textura 0 para limpiar cualquier textura
//seleccionada anteriormente
Gl.glBindTexture(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE0);
// Seleccionamos nuestra nueva textura
Gl.glBindTexture(Gl.GL_TEXTURE_2D, ITexture);
//le asignamos el color blanco a nuestra primitiva para
// que la textura se vea en forma adecuada.
GlPrimitives.Color(1, 1, 1);
GlPrimitives.RenderBox(Width, Heigth, Depth);
Gl.glBindTexture(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE0);
Código Nº [9] Trozo de código que asocia la Textura cargada a un objeto
Entity en especifico.
En el trozo de código (Código Nº [9]) mostrado anteriormente, se puede
apreciar como la textura cargada en una posición de memoria es asociada a un
objeto de tipo Entity, la primera línea de código desasocia cualquier textura que
podría estar asociada anteriormente, la segunda línea asocia la textura a
cualquier primitiva OpenGL que se llame después de esta línea, en este caso la
primitiva llamada RenderBox, en la tercera línea le asignamos el color blanco a
la primitiva OpenGL de manera que esta primitiva despliegue la textura
asociada a ella de buena manera y no de un color que no corresponda a la
textura original, esto se valida principalmente debido a que el Objeto de tipo
Entity que se le asigna una textura puede tener un color asociado, la línea cinco
llama a la primitiva RenderBox a la cual se le asociará la textura, finalmente en
la última línea de código se desasocia la textura para que no tenga efecto sobre
ninguna primitiva que sea llamada posteriormente.
178
Finalmente, como producto de esta funcionalidad se puede ver como en
la pantalla del editor 3D (Figura 13) se visualiza un cubo con una textura.
Figura 13
179
9.1.13 Construir funcionalidad que permita crear Objetos Entity
compuestos de Otros.
Esta funcionalidad se llevó a cabo mediante la construcción de una clase
derivada de Entity llamada Custom, la cual permite que uno o más objetos
pertenezcan a un objeto Custom, con lo cual todos los objetos pertenecientes a
este objeto se trasladarán, rotarán y escalarán al mismo tiempo, como si se
tratara de un solo objeto. También fue necesario definir una colección de
objetos de tipo Entity en la clase Entity la cual permite que un objeto de tipo
Entity pueda tener objetos Entity hijos.
A continuación en la imagen (Figura 14) se puede apreciar el lugar
(elipse en la imagen) que ocupa la interfaz para crear objetos compuestos,
mediante un click del mouse se pueden agregar o quitar objetos de uno
compuesto. Una vez seleccionados los objetos que compondrán nuestro objeto
compuesto debemos presionar el botón “Create Custom Object” con el cual es
creado el objeto compuesto, el cual estará conformado por las tres esferas de la
imagen.
180
Figura 14
9.1.14 Construir Funcionalidad que permita aplicar planos de corte a
objetos de tipo Entity.
Esta funcionalidad se llevó a cabo mediante construcción de un método
que aplica planos de corte a un objeto en particular, para esto se definieron tres
planos de corte, Plano de Corte X=0, Y=0 y Z=0. Como parte de la
implementación de esta funcionalidad se definieron tres propiedades en la clase
181
Entity, que habilitan o deshabilitan los planos de corte antes mencionados para
un Objeto de tipo Entity en específico.
A continuación un ejemplo de la funcionalidad de planos de corte
aplicada al Editor 3D, se puede ver en la imagen (Figura 15) un disco con dos
planos de corte aplicados y una esfera con todos los planos de corte posible
aplicados, con lo cual la esfera queda reducida a una cuarta parte de lo que era.
Figura 15
182
9.1.15 Construir funcionalidad que permita crear y editar fuentes de Luz.
Esta funcionalidad se llevó a cabo mediante la construcción de una clase
derivada de Entity llamada Ligth, la cual proporciona mecanismos para crear y
editar Fuentes de luz, para esta clase se definieron propiedades tales como
LightDiffuse la cual configura la componente Difusa de la fuente de luz,
LightAmbient la cual configura la componente Ambiente de la fuente de luz,
estas componentes de una fuente de luz se tratan de lo siguiente;
Componente Difusa:

La luz viene de una dirección, pero cuando golpea una superficie se
esparce igualmente en todas las direcciones.

Una luz que proviene de una posición particular tiene una
componente difusa.
Componente Ambiente:

Es luz que ha sido esparcida por todo el ambiente y es imposible de
determinar su origen.

Cuando golpea una superficie se esparce igualmente en todas
direcciones.

Una sala iluminada tiene una gran componente ambiente.
183
Por lo anterior si el usuario quiere iluminar una parte de la escena con
una luz direccional se debe usar la componente Difusa, no obstante si se quiere
iluminar de forma homogénea toda la escena es necesario usar la componente
ambiente, cabe mencionar que también se puede usar una combinación de las
dos componentes.
Una característica de OpenGL con respecto al manejo de luces es que
soporta un máximo de ocho luces simultáneas en una escena, con lo cual la
aplicación soportará esta cantidad de luces como máximo.
Otra característica que incluye la construcción de esta funcionalidad es la
capacidad de trasladar dinámicamente una fuente de luz mediante el Mouse,
para esta característica se trató a la fuente de luz como un objeto Entity, más
aun Ligth es una clase que hereda de Entity y dentro de las características que
hereda Ligth de Entity es la propiedad que hace referencia a la posición, por lo
tanto ocupa el mismo método manejador que usan los Objetos de tipo Entity
para moverse, rotar y escalar mediante el Mouse. No obstante el objeto de tipo
light solo ocupa la característica de traslación.
En la siguiente imagen (Figura 16) se puede apreciar un ejemplo de una
luz con componente difusa, la cual viene de la posición de una pequeña esfera
184
de color naranja, la posición de la luz sólo es visible en modalidad design ya
que en modalidad render sólo se ve su efecto en la escena.
Figura 16
En la siguiente imagen (Figura 17) se puede apreciar un ejemplo de una
luz con componente Ambiente la cual tiene una posición, (pequeña esfera de
color naranja), el efecto de la luz en la escena es homogénea, por lo tanto no
distingue la posición, con lo cual, la posición de la luz no tiene mayor incidencia
en la iluminación de ésta.
185
Figura 17
Por último, cabe mencionar que para efecto de configuración inicial se
creó una luz por defecto, la cual está ubicada en el origen del sistema y además
tiene una mezcla de componentes difusa y ambiente, ya que de no ser por esta
luz la escena se vería opaca y obscura, no obstante al desplegarse la primera
luz creada por el usuario el efecto de esta luz por defecto desaparece.
9.1.16 Construir funcionalidad que permita editar el mundo y sus Objetos
mediante el teclado.
186
Para esta funcionalidad se creó un método llamado KeyboardHandler, el
cual recibe como parámetros las teclas que fueron presionadas, este método se
ubica en la clase Engine, y alguna de sus características y sus funcionalidades
especificas son:

Presionado [CTRL+E] se crea objeto de tipo Sphere.

Presionado [CTRL+Q] se habilita el traslado del objeto seleccionado.

Presionado [CTRL+R] se habilita el rotado del objeto seleccionado.

Presionado [CTRL+S] se habilita el escalado del objeto seleccionado.

Presionado [Supr] se elimina el objeto seleccionado.

Presionado las teclas direccionales se traslada la cámara.
Esta funcionalidad proporciona más de cuarenta accesos personalizados
por teclado, con lo cual involucra casi la mayoría de acciones sobre el mundo y
sus objetos pueden realizarse mediante teclado.
Para capturar las teclas presionadas por el usuario hay suscribirse al
KeyboardCallback de Glut mediante el siguiente código.
Glut.glutKeyboardFunc(new Glut.KeyboardCallback(KeyboardHandler));
187
Una vez suscritos al KeyboardCallback se creó un método manejador en
la clase World que se llamó KeyboardHandler el cual debió cumplir con una
firma preestablecida para poder suscribirse al KeyboardCallback de Glut; con
esto ya se puede realizar la captura de las teclas presionadas por el usuario.
Estas teclas serán manejadas en el método KeyboardHandler de la clase
Engine que no es el mismo método usado para capturar las teclas (de la clase
World) presionadas, ya que KeyboardHandler de la clase Engine realiza la
lógica que se desencadena al presionar el teclado, por ejemplo crear, editar
eliminar objetos y muchas otras acciones.
// Método que está encargado de capturar las teclas presiondas.
private void KeyboardHandler(byte key, int x, int y)
{
// se llama al método KeyboardHandler de la clase Engine
// la cual realiza la lógica cuando se presionan las teclas.
engine.KeyboardHandler(key,this);
e.Rotate = RotateModeMouse;
e.Traslate = TraslateModeMouse;
e.Scale = ScaleModeMouse;
worldChanged(this, e);
Glut.glutPostRedisplay();
}
Código Nº [10] Método suscrito al KeyboardCallback de Glut que captura
las teclas presionadas.
188
// Método que está encargado de modificar el mundo y sus objetos mediante el
//teclado.
public void KeyboardHandler(byte key,World world)
{
switch (key)
{
case 3: //key "ctlr+C" crear Cylinder
Cylinder cylinder = new Cylinder();
AddEntity(world,cylinder , 200, 100, 0);
break;
case 5: //key "ctlr+E" crear Sphere
Sphere sphere = new Sphere();
AddEntity(world, sphere, 200, 100, 0);
break;
case 2: //key "ctlr+B" crear Box
Box box = new Box();
AddEntity(world, box, 200, 100, 0);
break;
case 16: //key "ctlr+P" crear Pyramid
Pyramid pyramid = new Pyramid();
AddEntity(world, pyramid, 200, 100, 0);
break;
case 9: //key "ctlr+I" crear Circle
Circle circle = new Circle();
AddEntity(world, circle, 200, 100, 0);
break;
case 21: //key "ctlr+U" crear Square
Square square = new Square();
AddEntity(world, square, 200, 100, 0);
break;
case 15: //key "ctlr+O" crear Poligon
Poligon poligon = new Poligon();
AddEntity(world, poligon, 200, 100, 0);
break;
case 20: //key "ctlr+T" crear Triangle
Triangle triangle = new Triangle();
AddEntity(world, triangle, 200, 100, 0);
}
}
Código Nº [11] Trozo del método KeyboardHandler de la clase Engine.
En resumen, existen dos métodos con el mismo nombre pero de distintas
clases, uno de la clase World que está encargado sólo de capturar las teclas
que fueron presionadas y el otro de la clase Engine el cual toma los valores
entregados por el método de la clase World y ejecuta la lógica correspondiente,
189
por ejemplo crear una esfera, aplicar escala, rotación y muchas otras
funcionalidades.
9.1.17 Construir funcionalidad que permita revisar la escena mediante una
animación Básica que rote la cámara por la escena.
Para
esta
funcionalidad
se
creó
un
método
llamado
AnimationTimerEventHandler, el cual se encuentra en la clase World. Este
método despliega una animación básica la cual consiste en una rotación de la
cámara por toda la escena en 360 grados. A continuación, se mostrará el
método (Código [12]) manejador de la animación éste se encuentra en la clase
World y para activar la animación sólo basta cambiar la propiedad de la clase
World llamada Preview a True.
private void AnimationTimerEventHandler(object o, ElapsedEventArgs args)
{
//lógiga de animación de la cámara para la revisión de la escena(rotación en 360
//grados por la escena)
if (Preview)
{
Rotation = Rotation + 0.5;
}
Glut.glutPostRedisplay();
}
Código Nº [12] Método manejador que se encarga de la animación Básica.
190
9.1.18 Construir funcionalidad que permita guardar y cargar la escena
mediante el uso de la Tecnología Xml.
Para
esta
funcionalidad
se
creó
una
clase
abstracta
llamada
XmlConverter, la cual exige que todas las clases que heredan de ella
implementen los métodos SaveToXML y LoadFromXml. Además, la clase
posee métodos estáticos para guardar o cargar una imagen en el Xml, a
continuación el código fuente (Código Nº [13]) que implementa los métodos
SaveToXML y LoadFromXml de la la Clase Sphere.
// Método que guarda las propiedades de los objetos de tipo Sphere
en el Xml.
public override void SaveToXML(XmlElement parent)
{
parent.SetAttribute("Radius", Radius.ToString());
}
// Método que carga las propiedades de los objetos de tipo Sphere
desde el Xml.
public override void LoadFromXML(XmlNode parent)
{
Radius = double.Parse(parent.Attributes["Radius"].Value);
}
Código Nº [13] Métodos que cargan y guardan la propiedad especializada
Radius de la clase Sphere.
Para esta funcionalidad, además se construyó una interfaz de clase
llamada XMLstruct, la cual exige que las clases que firmen un contrato con ella
deben implementar los métodos SaveToXml y LoadFromXml, una de las clases
que están suscritas a este contrato es Entity, con lo cual se exige que Entity y
191
todas las clases que hereden de ésta deben implementar los métodos antes
nombrados.
El archivo Xml que guardará la escena tiene una estructura análoga al
diseño de clases del Editor 3D, a continuación se mostrara un archivo generado
por el Editor 3d el cual al cargarlo muestra la escena con un cubo y una esfera.
192
<?xml version="1.0" encoding="UTF-8"?>
<!-- Zero Fx 3d Studio File -->
<World>
<Modeview>0</Modeview>
<ModeRender>False</ModeRender>
<ModeCameraTraslateX>False</ModeCameraTraslateX>
<ModeCameraTraslateY>False</ModeCameraTraslateY>
<ModeCameraTraslateZ>True</ModeCameraTraslateZ>
<CameraPostionX>2</CameraPostionX>
<CameraPostionY>-3,03</CameraPostionY>
<CameraPostionZ>-20</CameraPostionZ>
<CameraRotationX>0</CameraRotationX>
<CameraRotationY>0</CameraRotationY>
<CameraRotationZ>0</CameraRotationZ>
<PlaneX>False</PlaneX>
<PlaneY>True</PlaneY>
<PlaneZ>False</PlaneZ>
<Name>World</Name>
<Entities>
<Sphere1 Radius="2">
<PrimaryKey>1</PrimaryKey>
<Type>0</Type>
<PositionX>-4,214</PositionX>
<PositionY>0,172</PositionY>
<PositionZ>0</PositionZ>
<ScaleX>1</ScaleX>
<ScaleY>1</ScaleY>
<ScaleZ>1</ScaleZ>
<RotationX>0</RotationX>
<RotationY>0</RotationY>
<RotationZ>0</RotationZ>
<ColorR>0,784313725490196</ColorR>
<ColorG>0,392156862745098</ColorG>
<ColorB>0</ColorB>
<PlaneQutX>False</PlaneQutX>
<PlaneQutY>False</PlaneQutY>
<PlaneQutZ>False</PlaneQutZ>
<Texture></Texture>
<Entities />
<TexturePath>
</TexturePath>
</Sphere1>
<Box1 Width="3" Heigth="3" Depth="3">
<PrimaryKey>2</PrimaryKey>
<Type>1</Type>
<PositionX>3,87</PositionX>
<PositionY>-0,043</PositionY>
<PositionZ>0</PositionZ>
<ScaleX>1</ScaleX>
<ScaleY>1</ScaleY>
<ScaleZ>1</ScaleZ>
<RotationX>0</RotationX>
<RotationY>0</RotationY>
<RotationZ>0</RotationZ>
<ColorR>0,784313725490196</ColorR>
<ColorG>0,392156862745098</ColorG>
<ColorB>0</ColorB>
<PlaneQutX>False</PlaneQutX>
<PlaneQutY>False</PlaneQutY>
<PlaneQutZ>False</PlaneQutZ>
<Texture></Texture>
<Entities />
<TexturePath>
</TexturePath>
</Box1>
</Entities>
</World>
Código Nº [14] sección de archivo Xml del Editor 3D.
193
En la sección archivo anterior también se pueden ver otras etiquetas
como por ejemplo “textura”, la cual guarda una textura en forma binaria, esta
codificación binaria se realizó mediante un método llamado ImageToXMLNode
de la clase XMLConverter, la cual básicamente toma una imagen y la codifica
en forma binaria usando el formato de codificación UTF8 y por último guarda
esta codificación en un nodo XML. A continuación, se mostrará el código
(Código Nº [15]) que realiza esta tarea.
194
//método que transforma una imagen en un nodo Xml
public static XmlNode ImageToXMLNode(Image imagen)
{
System.IO.MemoryStream oStream = new System.IO.MemoryStream();
XmlDocument oDom = new XmlDocument();
System.IO.MemoryStream mResult = new System.IO.MemoryStream();
long LenData = 0;
byte[] Buffer;
System.IO.BinaryReader oBinaryReader;
XmlTextWriter oXMLTextWriter;
System.IO.StreamReader oStreamReader;
string StrResult;
//Verifico si existe imagen a serializar
if ((imagen != null))
{
//Se graba en Stream para almacenar la imagen en formato
//binario se conserva el formato de la imagen
System.Drawing.Imaging.ImageFormat imgF;
imgF = ImageFormat.Png;
imagen.Save(oStream, imgF);
oStream.Position = 0;
LenData = oStream.Length - 1;
//Verifico la longitud de datos a serializar
if (LenData > 0)
{
Buffer = new byte[Convert.ToInt32(LenData) + 1];
//Genero Buffer y leo los datos binarios
oBinaryReader = new System.IO.BinaryReader(oStream,
System.Text.Encoding.UTF8);
oBinaryReader.Read(Buffer, 0, Buffer.Length);
//Creo XMLTextWriter y agrego nodo con la imagen
oXMLTextWriter = new XmlTextWriter(mResult,
System.Text.Encoding.UTF8);
oXMLTextWriter.WriteStartDocument();
oXMLTextWriter.WriteStartElement("BinaryTexture");
oXMLTextWriter.WriteBase64(Buffer, 0, Buffer.Length);
oXMLTextWriter.WriteEndElement();
oXMLTextWriter.WriteEndDocument();
oXMLTextWriter.Flush();
Código Nº [15] parte 1
195
//posiciono en 0 el resultado
mResult.Position = 0;
//Pasa el Stream a String y retorna
oStreamReader = new System.IO.StreamReader(mResult,
System.Text.Encoding.UTF8);
StrResult = oStreamReader.ReadToEnd();
oStreamReader.Close();
//Agrego Nuevo Nodo con imagen
oDom.LoadXml(StrResult);
return oDom.DocumentElement;
}
else
{
//En caso de no existir datos retorno el XML con
//formato vacio
oDom.LoadXml("<BinaryTexture/>");
return oDom.DocumentElement.CloneNode(true);
}
}
else
{
//no hay imagen devuelvo el XML Vacio
oDom.LoadXml("<BinaryData/>");
return oDom.DocumentElement.CloneNode(true);
}
}
Código Nº [15] parte 2
Para interpretar la información binaria que se encuentra en la etiqueta
texture y transformarla nuevamente en una imagen, se construyó un método
llamado XMLNodeToImage presente en la clase XMLConverter. A continuación
el código del método (Código Nº [16]).
196
//Método que recibe un nodo Xml y retorna una Imágen.
public static Image XMLNodeToImage(XmlNode Nodo)
{
int IntResult = 0;
int IntPosition = 0;
int LenBytes = 1024 * 1024;
//1024KB - 1MB Lee bloques de 1MB
byte[] myBytes = new byte[LenBytes];
System.IO.MemoryStream oMem = new System.IO.MemoryStream();
System.Xml.XmlTextReader oXMLTextReader;
bool NodeFound = false;
//Dim oStreamReader As IO.StreamReader
System.IO.StreamWriter oStreamWriter;
System.IO.MemoryStream oTempMem = new
System.IO.MemoryStream();
string nombre = "";
try
{
//Cargo nodo de texto en Memory Stream para almacenar
//la imagen temporalmente en bytes
oStreamWriter = new System.IO.StreamWriter(oTempMem,
System.Text.Encoding.UTF8);
oStreamWriter.Write(Nodo.OuterXml);
oStreamWriter.Flush();
oTempMem.Position = 0;
//Cargo un xmlReader con el Memory Stream para
//leer la imágen almacenada
oXMLTextReader = new System.Xml.XmlTextReader(oTempMem);
//Busco el Nodo en Binario
while (oXMLTextReader.Read())
{
if (oXMLTextReader.Name == "BinaryTexture")
{
NodeFound = true;
break;
}
NodeFound = true;
}
Código Nº [16] parte 1
197
//Verifico si se encontró el Nodo con la imagen
if (NodeFound)
{
if (oXMLTextReader.HasAttributes)
{
nombre = oXMLTextReader.GetAttribute("Nombre");
}
//Lo encontro, me muevo a la Posicion Inicial
//del Stream para leerlo
IntPosition = 0;
//Intento Leer
IntResult = oXMLTextReader.ReadBase64(myBytes, 0,
LenBytes);
while (IntResult > 0)
{
//Escribe datos
oMem.Write(myBytes, 0, IntResult);
//Limpio el array
Array.Clear(myBytes, 0, LenBytes);
//Leo nuevamente
IntResult = oXMLTextReader.ReadBase64(myBytes, 0,
LenBytes);
}
try
{
//Intento crear la Imagen y retornarla
//si no devuelvo Nothing
Image img;
img = Bitmap.FromStream(oMem, true, true);
if ((nombre != null) && (nombre.Length > 0))
{
img.Tag = nombre;
}
return img;
}
catch
{
return null;
}
}
else
{
//No encontró el nodo de imágen
return null;
}
}
catch (Exception ex)
{
//Ocurrio un error no contemplado Retorno Nothing
return null;
}
}
Código Nº [16] parte 2
198
Finalmente, la función antes descrita devuelve la imagen lista para ser
cargada por objeto de tipo Entity que lo requiera. Con los métodos antes
descritos se cumple una de la característica de guardar y cargar imágenes
desde el Xml completando así la funcionalidad total.
9.1.19 Integración de funcionalidades.
La construcción de esta funcionalidad se refiere a la reestructuración de
algunas de éstas con el objetivo de que funcionen correctamente al ir siendo
integradas a las demás, esta tarea se realizó recurrentemente debido a la
naturaleza del proyecto, una vez terminada las funcionalidades e iteraciones de
integración, se obtuvo como producto final el Editor 3D. A continuación una
imagen(Figura 18 y 19) mostrando la interfaz visual final del Editor 3D aplicando
algunas funcionalidades descritas anteriormente, como por ejemplo mostrar la
escena en modalidad Design o Render y también otras como aplicación de
Texturas y luces .
199
Figura 18(Escena en modalidad Render).
200
Figura 19(Escena en modalidad Design).
Las dos figuras (Figura 18 y 19) mostradas anteriormente son de la
interfaz gráfica de la aplicación final. Esta se ejecutó sobre la plataforma de
software y hardware mencionada en el capítulo de Hardware y Software.
201
9.2 Construcción aplicación versión Final (Editor 3D + Generador de
código Fuente).
Esta versión de la aplicación fue construida una vez terminado el editor 3D y
consiste en la construcción de una funcionalidad que genera el código fuente en
lenguaje C# de lo diseñado con el editor 3D, para que posteriormente sea
utilizado en lo que el usuario de la aplicación estime conveniente, esta
funcionalidad fue construida en varias subfuncionalidades tales como:

Generador de Clase C# que despliegue la escena.

Generador de Proyecto .Net con la Clase C# antes nombrada ya cargada
en el Proyecto.

Generador de Proyecto .Net con la Clase C# antes nombrada ya cargada
en el Proyecto, además levantando automáticamente Visual Studio.
A continuación el detalle de la construcción de la implementación.
9.2.1 Generador de clase que despliegue la escena diseñada con la
aplicación.
Para esta funcionalidad se construyó una clase llamada Dissasembler, la
cual implementa un método llamado DissasemblerC, el que desensambla el
código fuente de todas las clases de la aplicación y lo devuelve en forma de dos
202
tipos de objetos (DissasemblerClassField y DissasemblerMethod), en uno se
devuelven las field/campos de las clases y en el otro los métodos. La clase
Dissasembler se basó en el uso una librería llamada Reflector, que es una
implementación de la tecnología de .Net Reflection. La librería reflector es en
realidad una especialización de la clase Reflection de .Net, posee las mismas
funcionalidades de Reflection la cual es principalmente una vista administrada
de los campos, los métodos y los tipos cargados, con la posibilidad de crear e
invocar tipos dinámicamente, dentro de estas funcionalidades (de Reflection)
está la de obtener los métodos y tipos cargados, lo cual supone la solución de
esta funcionalidad, no obstante cabe mencionar que en el caso de la
visualización de métodos (obtener código fuente del método), sólo es capaz de
obtener el equivalente binario, es aquí donde reflector hace la diferencia, ya que
esta librería es capaz de llegar más allá, y es capaz de obtener el código MSIL
del método y además proporciona métodos adicionales para traducir lenguaje
MSIL al lenguaje administrado que se requiera, para el caso de esta
funcionalidad C#. A continuación un trozo de código (Código Nº [17]) que usa
reflector para la obtención del código de un método.
203
foreach (IMethodDeclaration methodDeclaration in typeDeclaration.Methods)
{
//se crea un método desensamblado
IMethodDeclaration methodDeclaration2 =
translatorManager.CreateDisassembler(null,_
null).TranslateMethodDeclaration(methodDeclaration);
eventReflection(CountTypesDissasembler);
//se crea un objeto de tipo DissasemblerMethod para guardar
//el método desensamblado
DissasemblerMethod method = new DissasemblerMethod();
//Se guarda el nombre,cuerpo, nombre de la clase
// y número de parámetros
method.Name = methodDeclaration2.Name;
method.Body = methodDeclaration2.Body.ToString();
method.NameClass=typeDeclaration.Name;
method.Parameter = methodDeclaration2.Parameters.Count;
//se agrega a la colección de métodos desensamblados.
Methods.Add(method);
}
Código Nº [17] Trozo de código del método DissaseblerC.
El trozo de código antes expuesto (Código Nº [17]) el cual obtiene el
código fuente de un método y lo guarda dentro de un objeto de tipo
DissasemblerMethod, además se almacena el nombre del método, nombre de
la clase y número de parámetros.
Con la librería Reflector como se abordó anteriormente, se puede
obtener el código de la mayor parte de una clase, pero éste código no es
utilizable directamente, ya que viene con algunos pequeños problemas de
sintaxis y nombres de variables cambiadas respecto al código original, y
además se deben aplicar el valor de la propiedades de cada uno de los objetos
204
3D desplegados actualmente por la aplicación, por lo tanto se crearon métodos
para la preparación de código fuente, a continuación se explicará paso a paso
como se obtuvo el código fuente de una escena diseñada con la aplicación.
Como primer paso se desensambló en su totalidad las clases que inciden
en el despliegue gráfico de la aplicación, posteriormente se construyó dos
clases para poder albergar el código fuente desensamblado, las cuales son
DissasemblerMethod y DissasemblerClassField, la primera es la encargada de
albergar el código fuente de los métodos de las clases desensambladas y la
segunda los field/campos de cada clase, posteriormente la clase Entity y todas
las clases que heredan de ella se les construyó el método llamado “ToSource”,
el cual construye el código fuente necesario para desplegar un objeto 3D o el
mundo, en esta oportunidad se abordará el caso de un objeto de tipo esfera que
hereda de la clase Entity, a continuación se creó un método en la clase Entity
que busca la posición del código fuente de un método dentro de la colección de
métodos desensamblados. Una vez encontrada esta posición, se hace
referencia a la colección con el índice encontrado, el cual posee un objeto de
tipo DissasemblerMethod. Este, posee como propiedades el nombre de la
clase, nombre del método y el cuerpo del método, teniendo el código del
método, se procedió a construir un método llamado ReplaceGlConst que aplica
las constantes OpenGL, ya que éstas se perdieron al ser desensambladas, un
ejemplo de esto a continuación.
205
//método que construye la primitiva OpenGl cilindro sólido
public static void RenderCylinder(double baseRadius,
double topRadius,double heigth, int slice, int stacks)
{
GlPrimitives.PushMatrix();
CheckQuadric();
Glu.gluQuadricDrawStyle(quadric, Glu.GLU_FILL);
//método OpenGL que despliega la primitiva Cylinder
Glu.gluCylinder(quadric, baseRadius,topRadius,heigth,slice,stacks);
GlPrimitives.PopMatrix();
}
//método que construye la primitiva OpenGl cilindro sólido
//(desensamblado)
public static void RenderCylinder(double baseRadius,
double topRadius,double heigth, int slice, int stacks)
{
GlPrimitives.PushMatrix();
CheckQuadric();
//linea de código desensamblada, la constante
// GLU_FILL fue devuelta en forma del número 6914
Glu.gluQuadricDrawStyle(quadric, 6914);
//método OpenGL que despliega la primitiva Cylinder
Glu.gluCylinder(quadric, baseRadius,topRadius,heigth,slice,stacks);
GlPrimitives.PopMatrix();
}
Código Nº [18] Trozo de código que muestra la diferencia entre el código
original y el desensamblado por la aplicación.
Como se pudo observar, el desensamblado devolvió la constante
Glu.GLU_FILL como un numero 6914, lo cual desde el punto de vista de la
compilación está correcto, no obstante para el programador que retome el
código es inentendible, por lo cual se construyó un método estático llamado
ReplaceGlConst de la clase GlConst, el cual toma las constantes tales como
6914 y los sustituye por su constante OpenGL en este caso Glu.GLU_FILL.
206
Una vez arreglado el código, se procedió a construir una función en la
clase Entity y World llamada ReplaceVar, la cual se preocupa de aplicar las
propiedades actuales de la clase World y Entity al código desensamblado,
además de aplicar indentación al código y algunas normas básicas de
programación.
Un ejemplo programático de la aplicación de los métodos antes descritos
sería el siguiente.
ReplaceVar(GlConst.ReplaceGlConst(Methods[SearchCode("RenderSphere", 5)].Body)));
Código
Nº [19] Trozo de código que busca y configura un fuente
desensamblado de un método.
Finalmente, se aplica el método ToSource a todas las instancias actuales
de la aplicación que posean este método, con lo cual se obtiene una clase C#
que es capaz de desplegar la escena tal cual como se ve en el Editor 3D. El
código fuente obtenido está listo para ser utilizado en la implementación que el
desarrollador estime conveniente.
9.2.2 Generador de Proyecto .Net que despliegue la escena diseñada con
la aplicación.
207
Para esta funcionalidad se tomó la clase C# generada en la funcionalidad
anterior y se agregó a un proyecto .Net. El detalle de esta implementación a
continuación.
En primer lugar se creó un proyecto plantilla, el cual posee las librerías
necesarias ya cargadas, después se copia el proyecto desde esta platilla donde
el usuario señale, posteriormente se agrega la clase C# antes nombrada al
proyecto .Net mediante las siguientes líneas de código (Código Nº [20]).
//cargamos el archivo del proyecto y le agregamos nuestra clase
xml.Load("C:/GlApplication/GlApplication.csproj");
XmlNode xmlm = xml.DocumentElement["ItemGroup"];
//Codigo que agrega clase(desensamblada) generada a un proyecto Vs2008.
XmlElement csElement = xml.CreateElement("Compile");
csElement =xml.CreateElement("Compile", _
"http://schemas.microsoft.com/developer/msbuild/2003");
csElement.SetAttribute("Include","OpenGl.cs");
if (xmlm.ChildNodes.Count == 9)
{
//cargamos
el archivo del proyecto y le agregamos nuestra clase.
xmlm.AppendChild(csElement);
}
xml.Save("C:/GlApplication/GlApplication.csproj");
Código Nº [20] Trozo de código que agrega la clase desensamblada en
proyecto .Net.
Una vez cargada la clase al proyecto, éste se encuentra listo para
compilar y ejecutarse.
208
10. Pruebas
En este capítulo se describirán las pruebas que se realizaron a las
distintas funcionalidades desarrolladas, ya sea en conjunto o modularizado,
esto con el fin de encontrar o detectar diferencias entre las condiciones
requeridas y las reales (fallas o defectos), y finalmente evaluar las
características de la aplicación.
10.1 Conceptos generales de las pruebas realizadas.
10.1.1 Pruebas de Unidad.
Las pruebas de unidad se realizaron sobre cada una de las
funcionalidades
codificadas
en
la
etapa
de
construcción
de
forma
independiente. Con esto se consigue comprobar que las funcionalidades, vistas
como unidades funcionales de programas autónomos están correctamente
codificadas.
Dichas funcionalidades fueron “testeadas”, bajo la técnica de prueba
llamada “caja blanca”.
10.1.2 Pruebas de Integración.
209
Estas pruebas se realizaron de forma incremental, es decir, a medida
que se desarrollaban las funcionalidades de la aplicación, se comprobara el
funcionamiento de la aplicación en su totalidad, cabe señalar que sólo al final
del último ciclo del proyecto se pudo comprobar que la aplicación funcionaba de
forma correcta y con la prestación necesaria para satisfacer los requerimientos
solicitados por el cliente.
10.1.3 Pruebas de Sistema y Evaluación.
Las
pruebas
de
caja
negra,
se
utilizaron
para
comprobar
el
comportamiento de la aplicación. Este tipo de pruebas se utilizaron para el
ingreso de valores máximos y mínimos para los dominios permitidos como
entradas. Bajo este análisis se pueden aplicar varios casos de pruebas tales
como:

Ingreso de valores máximos a propiedades del mundo y Objetos3D.

Creación de la máxima cantidad de Objetos en la escena antes de que
se vuelva inestable la aplicación.
Por último, las pruebas estéticas fueron evaluadas por el cliente, mediante
prototipos y versiones betas que fueron presentados en cada una de las
reuniones que se realizaron, en donde el cliente entregó su percepción de la
210
aplicación.
Los
comentarios
y
recomendaciones
fueron
recabados
e
implementados en las interfaces que componen la aplicación.
10.2 Plan de pruebas.
Con los antecedentes mencionados anteriormente se crea un plan de
pruebas que permite definir las actividades, planificar y estimar los esfuerzos,
condiciones y tiempos involucrados para la ejecución de las pruebas de la
aplicación. A continuación, se describe el plan de pruebas de forma general, de
acuerdo a los siguientes objetivos:

Identificar la información generada por el proyecto y los componentes de
software que deberán ser probados.

Establecer las actividades de prueba a ser realizadas.

Recomendar y describir la estrategia de pruebas a utilizar.
10.2.1 Pruebas Funcionales.
En este plan de Test se aplicarán técnicas de “Caja Negra”, las que
tendrán como objetivo principal verificar el comportamiento de la aplicación,
comparando el resultado esperado detallado en el caso de uso contra el
resultado obtenido en la ejecución de las pruebas.
211
Los datos de entrada serán los utilizados por las operaciones o uso
normal de la aplicación. Cada argumento de entrada puede seleccionar uno de
los siguientes datos de pruebas, dependiendo éste del resultado que se desea
obtener (esperado), verificando así el comportamiento del componente a
testear, usando los siguientes valores de entrada:

Valores normales para cada una de las propiedades de los objetos y el
mundo.

Valores límites para cada una de las propiedades de los objetos y el
mundo.

Cantidad normal de objetos (1 a 30 objetos).

Cantidad alta de objetos (31 -200).

Cargar archivos de Texturas inválidos y validos.

Cargar archivos de respaldo de la escena (Xml) inválidos y validos.
10.2.2 Estrategias de las Pruebas.
Las pruebas serán realizadas por funcionalidades, en la medida que
éstas sean entregadas al proceso de prueba, cada funcionalidad está asociada
a un caso de uso en particular por ende las pruebas velarán por que la
funcionalidad cumpla con el caso de uso.
212
10.2.3 Tipos de Pruebas.
Las pruebas funcionales se realizaron de acuerdo a la siguiente tabla.
Objetivo del Test:
Asegurar la funcionalidad del conjunto de casos
de prueba.
Que la navegación a través de los casos de
prueba refleje apropiadamente los resultados
esperados.
Que los objetos de las ventanas y sus
características, tales como menús, tamaño,
posición, estados y el foco, estén de acuerdo a los
estándares.
Técnica a Utilizar:
Criterio de Verificación:
Ejecutar cada Caso de Pruebas, su flujo y
funcionalidad usando tanto datos válidos como
inválidos para verificar lo siguiente:

Resultados esperados ocurren cuando los
datos válidos son utilizados.

El mensaje de error es el apropiado cuando se
utilizan datos inválidos.

Que todas las pruebas planificadas se
ejecuten correctamente y en forma empírica,
con lo cual este criterio de verificación se
encasilla dentro del tipo fuerte.
Tabla Nº [1]: Descripción de las Pruebas Funcionales.
213
Todas las pruebas mencionadas en este capítulo, tuvieron resultados
satisfactorios y cubren todos los requerimientos establecidos en la etapa de
análisis del proyecto.
Con estos antecedentes se puede asegurar que la aplicación ofrece una
prestación bastante aceptable y que cumple completamente lo requerido para el
proyecto.
214
11. Conclusiones y Recomendaciones
Una de la conclusiones que se obtuvo con la construcción de este tipo
aplicaciones, es que un buen diseño y construcción es especialmente
perceptible en el desempeño final de este tipo de aplicaciones, esto en base a
que las primeras versiones de la aplicación soportaba de 10 a 15 primitivas sin
texturas, a lo largo de las iteraciones de diseño y construcción como lo permite
la metodología Xp, las cantidades de primitivas fueron subiendo hasta llegar a
las 300 primitivas con texturas, aún cuando esto puede aumentar o disminuir
dependiendo del Computador usado.
Otro punto importante dentro del desarrollo de este seminario fue la
elección de la metodología de desarrollo, en un primer momento se estudiaron
diversas metodologías con el fin de obtener una variable aplicabilidad al
proyecto, se estudiaron algunas como Rup y Aup que si bien están
consideradas dentro las metodologías ágiles, éstas no consideran natural el
cambio de requisitos sobre la marcha, por contraparte XP propone que los
cambios de requisitos sobre la marcha son un aspecto natural, inevitable e
incluso deseable del desarrollo de proyectos, por otra parte XP ofrece un
soporte óptimo a juicio del alumno tesista, ya que el desarrollo de esta
aplicación tuvo un alto riesgo técnico y muchas veces se incurrió en desarrollar
215
desde cero algunas funcionalidades, ya que no cumplían a cabalidad los
requisitos o no cumplían algunas características de integración con el resto de
la aplicación.
Otra conclusión que se pudo obtener de la construcción de la aplicación
es que si bien la CPU de la computadora es parte importante en el rendimiento
de la aplicación, es más importante aún, la tarjeta gráfica del computador, a
continuación un benchmark (Prueba estática de rendimiento) de la aplicación
en el cual se basa esta conclusión, estas pruebas se realizaron con tres
configuraciones de hardware y software distintas las cuales son las siguientes.
Equipo 1:
Hardware
 CPU AMD Turion X2 de 2 GHZ.
 1 GB de RAM.
 Video 64 MB ATI X1200 DDR3 (Integrada).
 Disco duro de 120 GB.
Software
 Visual Studio 2005 ó 2008 bajo Windows XP y lenguaje C#.
 Librerías OpenGL en sistemas operativos Windows y Linux.
 Estándar XML versión 1.2.
 Mono/MonoDevelop en Linux para pruebas de códigos fuentes generados
por la aplicación.
Equipo 2:
Hardware
 CPU Intel Core 2 DUO 2.2 GHZ.
 1 GB de RAM.
 Video 256 MB Intel series DDR3 (Integrada).
216
 Disco duro de 320 GB.
Software
 Visual Studio 2005 ó 2008 bajo Windows Vista y lenguaje C#.
 Librerías OpenGL en sistemas operativos Windows y Linux.
 Estándar XML versión 1.2.
 Mono/MonoDevelop en Linux para pruebas de códigos fuentes generados
por la aplicación.
Equipo 3:
Hardware
 CPU Intel Core 2 Duo 2,2 GHZ.
 1 GB de RAM.
 512 MB Nvidia. 8600 GTS (Dedicada).
 Disco duro de 120 GB.
Software
 Visual Studio 2005 ó 2008 bajo Windows Vista y lenguaje C#.
 Librerías OpenGL en sistemas operativos Windows y Linux.
 Estándar XML versión 1.2.
 Mono/MonoDevelop en Linux para pruebas de códigos fuentes generados
por la aplicación.
Para esta prueba se tomó en cuenta la cantidad de frames por segundo
con una carga de 30 objetos, los parámetros de entrada son los siguientes:
 30 objetos en modalidad Render sin texturas.
 30 objetos en modalidad Render con texturas.
 30 objetos en modalidad Render con texturas, más una Luz con una
componente difusa.
217
350
300
250
200 Frames /
150 Segundo
100
50
0
30 objetos sin
Texturas.
30 objetos con
Texturas.
Equipo 1
30 objetos con
Texturas más una
Luz.
Equipo 2
Equipo 3
Con lo anterior se puede concluir además, que para el uso de
aplicaciones gráficas se hace fundamental un Computador con una tarjeta
gráfica dedicada (no integrada).
El desarrollo de esta aplicación proporcionó como producto un entorno
de diseño de escenarios en tres dimensiones, el cual puede ser utilizado en
entornos matemáticos, robótica y propósito general, con el cual el desarrollador
puede sin ser experto en OpenGL, diseñar modelos complejos, que sin la ayuda
de esta herramienta le sería muy arduo.
218
Otra conclusión que se obtuvo de la etapa de “Selección de Tecnologías
para el Desarrollo” es el caso especifico de la selección de la librería FreeGlut
la cual básicamente está encargada de la gestión de ventanas y de
comunicación del contexto OpenGL con periféricos tales como mouse y teclado,
esta librería no es la más actual ni la más desarrollada para realizar el trabajo
antes descrito, existen otras más actuales y ampliamente desarrolladas, tales
como Sdl entre otras, no obstante para este proyecto se requirió la generación
de código fuente y ésta se realiza mediante el uso de los fuentes de la
aplicación, con lo cual haber usado por ejemplo Sdl, el código fuente OpenGl
devuelto ya no hubiera sido puro, como si lo es con el uso de FreeGlut, ya que
esta librería es considerada como complemento natural de OpenGl no así Sdl,
con lo cual se puede concluir que la “Selección de Tecnologías para el
Desarrollo” es parte fundamental del desarrollo de una aplicación y se debe
tener en cuenta claramente el problema que desea solucionar y que el uso de la
herramienta ofrezca las características para solucionar este problema.
Otro
producto
obtenido
del
desarrollo
de
esta
aplicación,
fue
encapsulación de la dificultad del trabajo con OpenGL, ya que parte de esta
aplicación dió como producto una biblioteca de clases llamada ZeroFxCore, la
cual permite crear desde escenarios simples hasta complejos, esto sin
necesidad de usar la aplicación propiamente tal. Además, con el uso de
biblioteca antes mencionada, el diseño de las escenas en forma programática
219
reduce drásticamente la cantidad de líneas de código, a continuación se expone
el código que despliega una pirámide usando la biblioteca de Clases
ZeroFxCore (Código
Nº [21]) y otro usando directamente la API OpenGL
(Código Nº [22]).
//Código que construye la primitiva OpenGl pirámide sólida usando la
//Biblioteca de Clases ZeroFxCore
Pyramid pyramid = new Pyramid();
engine.AddEntity(world, pyramid, colorR, colorG, colorB);
Código Nº [21]
220
//método que construye la primitiva OpenGl pirámide sólida usando
//OpenGL
public static void RenderPyramid(double x)
{
//triángulo 1
Gl.glBegin(Gl.GL_TRIANGLES);
Gl.glTexCoord2d(1, 0.5);
Gl.glNormal3d(0f, x, 0f);
Gl.glVertex3d(0, x, 0);
Gl.glTexCoord2d(0, 1);
Gl.glNormal3d(-x, -x, x);
Gl.glVertex3d(-x, -x, x);
Gl.glTexCoord2d(0, 0);
Gl.glNormal3d(x, -x, x);
Gl.glVertex3d(x, -x, x);
//triángulo 2
Gl.glTexCoord2d(1, 0.5);
Gl.glNormal3d(0, x, 0);
Gl.glVertex3d(0, x, 0);
Gl.glTexCoord2d(0, 1);
Gl.glNormal3d(x, -x, x);
Gl.glVertex3d(x, -x, x);
Gl.glTexCoord2d(0, 0);
Gl.glNormal3d(x, -x, -x);
Gl.glVertex3d(x, -x, -x);
//triángulo 3
Gl.glTexCoord2d(1, 0.5);
Gl.glNormal3d(0, x,0);
Gl.glVertex3d(0, x,0);
Gl.glTexCoord2d(0, 1);
Gl.glNormal3d(x, -x, -x);
Gl.glVertex3d(x, -x, -x);
Gl.glTexCoord2d(0, 0);
Gl.glNormal3d(-x, -x, -x);
Gl.glVertex3d(-x, -x, -x);
//triángulo 4
Gl.glTexCoord2d(1, 0.5);
Gl.glNormal3d(0, x, 0);
Gl.glVertex3d(0, x, 0);
Gl.glTexCoord2d(0, 1);
Gl.glNormal3d(-x, -x, -x);
Gl.glVertex3d(-x, -x, -x);
Gl.glTexCoord2d(0, 0);
Gl.glNormal3d(-x, -x, x);
Gl.glVertex3d(-x, -x, x);
Gl.glEnd();
}
Código Nº [22].
221
Se puede concluir, que el uso de la librería ZeroFxCore dá como
resultado una disminución del código necesario para desplegar una primitiva, en
una escala promedio de 5 es a 1.
Otra conclusión que se puede obtener, es referente al uso de Reflection
de .Net, el cual básicamente es un mecanismo para examinar, manipular y
crear objetos en tiempo de ejecución, lo cual fue ampliamente utilizado para el
desarrollo de la aplicación, ya sea usado directamente para la generación de
entornos dinámicos o por medio de una implementación (Reflector) usada para
la generación de código fuente, con lo cual se puede concluir que la tecnología
reflection fue uno los pilares programáticos de la implementación de la
aplicación desarrollada.
Otra conclusión que puede obtener, es que si bien la aplicación es
portable a Linux, ésta no funciona completamente en forma adecuada, esto
principalmente a la diferencia en el esquema de trabajo con hilos que tiene
Linux con Windows, además los WinForms utilizados en la aplicación no son
completamente compatibles con Mono, con lo cual la aplicación funciona en
Linux de manera aceptable, pero en ningún caso como lo hace en Windows, no
obstante el código fuente generado por la aplicación es totalmente portable
entre Linux y Windows, con lo cual se puede concluir que la portabilidad de esta
aplicación no es total, lo cual no quiere decir que esta no pueda ser mejorada
222
en un futuro, esto en base a que la plataforma Mono de Linux avanza
rápidamente en la implementación análoga de la tecnologías .Net.
Junto con lo anterior, se puede establecer que los requerimientos y/o
funcionalidades
esperados
para
esta
aplicación
se
han
cumplido
satisfactoriamente de acuerdo a lo esperado por el cliente.
Finalmente, relacionada con la extensibilidad de la aplicación, queda
totalmente abierta agregar nuevas funcionalidades tales como aplicación de
Físicas, Animaciones avanzadas, aplicación de motor de partículas entre otras
muchas funcionalidades aplicables, por lo cual a juicio del alumno tesista es un
muy buen tema a retomar como parte una nueva tesis.
223
12. Bibliografía
[Autodesk2008] Autodesk, 3ds MAX Overview. Disponible en
http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=5659305
[Bateman2004] The Maya Exporter Factfile. Disponible en
http://www.robthebloke.org/research/index.htm
[CrytekGames2008] CrytekGames CrisisEngine2 Features. Disponible en
http://www.crytek.com/ .abril 2008
[EpicGames2008] EpicGames UnrealEngine3 Features. Disponible en
http://www.unrealtechnology.com/ .abril 2008
[Sinclair2008] GDC '08: Final Fantasy XIII powered by Crystal Tools. Disponible
en http://www.gamespot.com/news/6186627.html 22 .febrero 2008
[Edge2007] Unreal Engine 3 Vs CryEngine 2.Disponible en
http://www.nextgen.biz/index.php?option=com_content&task=view&id=6049&Itemid=2&li
mit=1&limitstart=0 .18 junio 2007
[Kyprianidis2007] Jan Eric Kyprianidis Lib3ds Features. Disponible en
http://lib3ds.sourceforge.net/
[Ogre3d2008] Ogre3d Feature, documentation. Disponible en
http://www.ogre3d.org/
224
[SerranoLobo2007] Iván Lobo y Francisco A. Serrano. Star Wars: The Force
Unleashed avance. Disponible en
http://www.meristation.com/v3/des_avances.php?pic=360&id=cw47c653f5
7508
1&idj=cw45d4689b5bed2&idp=&tipo=art&c=1&pos=0 .febrero 2008
[XtremePrograming2007] Xtreme Programing. XP Leasson. Disponible en
Http://www.extremeprogramming.org
[Flower2003] Martin Flower, La nueva Metodología. Disponible en
http://www.programacionextrema.org/articulos/newMethodology.es.html
febrero 2003
[UML2007] Tutorial de UML Diagrama de clases.
http://www.dcc.uchile.cl/~psalinas/uml/modelo.html
225
13. Anexo
Diagrama de clases Editor 3D
226
Descargar