Open Inventor Object-Oriented Computer Graphics Herling Gonzalez Alvarez Instituto Colombiano del Petroleo 3 de octubre de 2018 Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 1 / 29 Introducción OpenInventor fue creado para simplificar el desarrollo de aplicaciones gráficas. OpenInventor incluye un conjunto de objetos como cubos, polı́gonos, textos, materiales, cámaras, luces, trackballs, visualizadores, etc. ¿Que se pueden hacer con los objetos? Definir y manipular formas, tamaños, texturas, materiales etc. Aplicar y manipular transformaciones de tipo espacial. Add y remover objetos o sub-conjuntos de objetos. Representar, salvar, cargar e imprimir objetos. Permitir el procesamiento entre objetos. Animar objetos con motores (Engines) Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 2 / 29 OpenInventor utiliza OpenGL como estándar a nivel de hardware para el renderizado de gráficos. Sin embargo, el desarrollo de OpenInventor es cercano al usuario o de alto nivel. El modelo de programación de OpenInventor esta basado en objetos, donde una escena 3D está representada por nodos-objeto (3D scene database). Cada nodo mantiene una parte de la información y está compuesto por un conjunto de elementos-dato, llamados campos (fields), que describen las propiedades del nodo. Un conjunto de nodos representa una escena gráfica [Wernecke, 1994]. Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 3 / 29 Scene Graph Una escena en OpenInventor esta organizada en estructuras (Scene Graph). Una escena gráfica esta hecha de nodos los cuales representa los objetos 3D a ser graficados. Las propiedades de los objetos son también nodos con una determinada jerarquı́a y agrupación. Group node Group node Camera node Light node Appearance node Shape node Es decir, los objetos en la escena gráfica forman una estructura de árbol cuyos objetos son nodos. Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 4 / 29 Otro tipo de objeto llamado acción recorre el árbol de la escena gráfica, con el propósito de revisar cada nodo y ejecutar alguna acción sobre uno nodo especifico. Donde: Group node Un conjunto de objetos-nodos tiene una estructura jerárquica. Su recorrido tiene el propósito de actuar para: I I I I I Renderizar (draw) Escocer (select) Buscar Escribir etc... Group node Camera node OpenInventor tiene una: I I Optima y adecuada estrategia de renderización. Capacidad de manejar grandes volúmenes de datos. Light node Appearance node Shape node Que tipo de Acción? Renderizar y dibujar una escena. Seleccionar un objeto o geometrı́a de interés, buscar objetos-nodos, etc. Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 5 / 29 Nodes Objetos escena gráfica I I I I I Group - Organiza la escena. Data - Coordenadas, volumen,.. Transform - Posición, rotación,.. Property - Color, textura,.. Shape - Geometrı́a Position Direction Propiedades - fields I Light node Camera node Función miembro “publica” de la clase (C++). Que define las propiedades o estados de cada nodo. Intensity Direction Fields Creacion de un nodo: SoSphere * ptrNode = new SoSphere () ; No es necesario una explicita liberación de memoria de los nodos con delete []. Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 6 / 29 Cada nodo contiene uno o mas campos para almacenar información. Por ejemplo el nodo SoSphere contiene el campo radius, para definir el radio de la esfera. SoExaminerViewer SoSeparator SoScale SoGroup SoText3 SoSphere SoTranslation SoCube Los nodos conectados en la escena gráfica pueden ser objetos o propiedades dentro de una jerarquı́a que cumple un propósito de mayor complejidad. Los objetos son instancias de las clases Sb* y So* [Reference-Manual, 1994]. Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 7 / 29 SoExaminerViewer SoGroup SoSeparator SoScale SoText3 SoSphere SoTranslation SoCube Esta figura muestra la relación parental o jerarquı́a de los objetos. Iniciando en el nodo raı́z, de arriba hacia abajo, y de izquierda a derecha. De manera consecutiva los nodo-objetos heredan los estado y propiedades de los nodos en jerarquı́as superiores [Wernecke, 1994]. Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 8 / 29 SoExaminerViewer SoGroup SoCone SoTranslation SoCube SoXtExaminerViewer *myViewer = new SoXtExaminerViewer(myWindow); SoGroup *root = new SoGroup; SoCone *Cone = new SoCone; SoCube *Cube = new SoCube; SoTranslation *Move = new SoTranslation; Move->translation.setValue(4,0,0); //4 units x-direction root->ref(); //scene root node root->addChild(Cone); //append first child object root->addChild(Move); //append second object root->addChild(Cube); //append third object myViewer->setSceneGraph(root); Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 9 / 29 SoExaminerViewer SoGroup SoCube SoTranslation SoCone SoXtExaminerViewer *myViewer = new SoXtExaminerViewer(myWindow); SoGroup *root = new SoGroup; SoCone *Cone = new SoCone; SoCube *Cube = new SoCube; SoTranslation *Move = new SoTranslation; Move->translation.setValue(4,0,0);//4 units x-direction root->ref(); //scene root node root->addChild(Cube); //append first child object root->addChild(Move); //append second object root->addChild(Cone); //append third object myViewer->setSceneGraph(root); Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 10 / 29 Object-Oriented Constructor Transform Camera Light Manipulator Appearance Timer Shape Selection Separator Group Engine Switch Callback Metric Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 11 / 29 File: code-iv-01.cc #include #include #include #include #include #include #include <cstdlib> <Inventor/Xt/SoXt.h> <Inventor/nodes/SoCone.h> <Inventor/nodes/SoCube.h> <Inventor/nodes/SoGroup.h> <Inventor/nodes/SoTranslation.h> <Inventor/Xt/viewers/SoXtExaminerViewer.h> int main(int argc, char* argv[]) { Widget myWindow = SoXt::init(argv[0]); if (myWindow == NULL) exit(1); SoXtExaminerViewer *myViewer = new SoXtExaminerViewer(myWindow); SoGroup *root = new SoGroup; SoCone *Cone = new SoCone; SoCube *Cube = new SoCube; SoTranslation *Move = new SoTranslation; ... Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 12 / 29 File: code-iv-01.cc ... Move->translation.setValue(4,0,0); //4 units x-direction root->ref(); root->addChild(Cone); root->addChild(Move); root->addChild(Cube); //scene root node //append first child object //append second object //append third object myViewer->setSceneGraph(root); myViewer->show(); SoXt::show(myWindow); SoXt::mainLoop(); } Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 13 / 29 File: SConstruct import os env = Environment(CPPFLAGS=['-Wall','-g'], LIBPATH=['/usr/lib'], CPPPATH=['/usr/include'], LIBS=['Inventor','InventorXt']) progs=''' code-iv-01 code-iv-02 ''' mains = Split(progs) for prog in mains: env.Program( target=prog, source=[prog+'.cc'] ) Para compilar solo basta ejecutar: scons -c; scons Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 14 / 29 Haciendo para aprender!!: 1 Escriba un código basado en el manual pagina 220 [Reference-Manual, 1994], la siguiente escena gráfica: SoExaminerViewer SoGroup SoDirectionalLightManip SoCone 2 ¿Que sucede a la escena si intercambiamos la jerarquı́a de la fuente de luz y cono? 3 ¿Como cambiar los campos por defecto de on, color e intensity, en la instancia de la clase SoDirectionalLightManip? Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 15 / 29 Resumen: OpenInventor tiene diferentes tipos de nodos que se pueden poner en escena. Un tipo de nodo es usado para describir un cono, cubo, esfera, etc. Otros tipos de nodos son usados para describir la apariencias superficial de los objetos, etc. Cada uno de estos nodos-objeto son instancias de una clase. Todos los nodos en una clase particular tienen el mismo tipo de propiedades, como altura, dimensión, posición. Durante el recorrido de las estructura jerarquı́a de la escena gráfica cada nodo depende de la modificación de sus campos. Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 16 / 29 DB y la Escena Gráfica: Una escena gráfica en OpenInventor es una colección ordenada de objetos-nodos almacenada en una base de datos interna (DB). Un nodo en OpenInventor es un bloque de construcción básico usado para generar una escena 3D. Cada nodo especifica un conjunto de campos que definen una instancia de un objeto como por ejemplo, formas geométricas, atributos, cámaras, luces, transformaciones, etc. Nodos especiales responden directamente a eventos del usuario y son utilizados para manipular la escena. Los nodos pueden tener nombres y sus campos pueden estar conectados a campos de otros nodos. Dentro DB de los nodos base hay: Formas geométricas (shapes nodes): esferas, cubos, cilindros y mallas. Propiedades (property nodes): material, modelo de iluminacion, texturas. Grupos (group nodes): separador, nivel de detalles y decisión. Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 17 / 29 DB y la Escena Grafica: Hay otros nodos-objeto de OpenInventor como los motores (engines) que se conectan a otros nodos-objeto para realizar animaciones o imponer restricciones a partes de la escena. También tenemos los nodos-objeto como los sensores, que detectan cambios en la base de datos (DB) y activan alguna función definida por el usuario. Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 18 / 29 Mas ejemplos de escenas graficas Basado en el siguiente esquema construiremos una escena de un cilindro (SoCylinder), donde aplicaremos de manera incremental la instanciación del objeto geométrico, transformaciones, agrupaciones de objetos, definición de propiedades objetos de tipo engines y manipuladores. root myCamera Cylinder dirLight myMaterial Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 19 / 29 File: code-iv-04.cc #include <cstdlib> #include <Inventor/Xt/SoXt.h> #include <Inventor/Xt/SoXtRenderArea.h> #include <Inventor/nodes/SoCylinder.h> #include <Inventor/nodes/SoSeparator.h> #include <Inventor/nodes/SoMaterial.h> #include <Inventor/nodes/SoSeparator.h> #include <Inventor/nodes/SoDirectionalLight.h> #include <Inventor/nodes/SoPerspectiveCamera.h> int main(int argc, char* argv[]) { Widget myWindow = SoXt::init(argv[0]); //window name if (myWindow == NULL) exit(1); //successfully //initialization ... Como podemos observar el código incluye los prototipos de la clases de OpenInventor y bibliotecas auxiliares necesarias para este ejemplo. Si la creación de la ventana es fallida (NULL) da salida y se cierra el programa. Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 20 / 29 File: code-iv-04.cc ... SoSeparator *root SoPerspectiveCamera *myCamera SoDirectionalLight *dirLight SoMaterial *myMaterial = = = = new new new new SoSeparator; SoPerspectiveCamera; SoDirectionalLight; SoMaterial; myMaterial->diffuseColor.setValue(0.0,1.0,1.0); //RGB root->ref(); root->addChild(myCamera); root->addChild(dirLight); root->addChild(myMaterial); root->addChild(new SoCylinder); ... Se crea el grupo raı́z, cámara, luz direccional, apariencia del nodo-objeto (material) y el cilindro. Con lo anterior la escena gráfica queda definida. Ahora hay que crear un area de renderización para mostrar la escena y ponerla en la ventana de despliegue gráfico. Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 21 / 29 File: code-iv-04.cc ... SoXtRenderArea *myRenderArea = new SoXtRenderArea(myWindow); myCamera->viewAll(root, myRenderArea->getViewportRegion()); myRenderArea->setSceneGraph(root); myRenderArea->setTitle("My Cylinder GraphScene"); myRenderArea->show(); SoXt::show(myWindow); SoXt::mainLoop(); } Crea la instancia del area de renderización. Ajusta la cámara para visualizar la escena entera. Coloca la escena (root) en el área de renderización y altera su titulo. Muestra la ventana principal y llama el explorador de eventos SoXt::mainLoop(). Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 22 / 29 Un Cilindro en Rotación (Animación): Vamos hacer que el Cilindro rote de manera continua en la escena, haciendo uso de los engines. Esto se consigue a través de un enlace entre el engine con el campo angle de la instancia de la clase SoRotationXYZ en la escena. El engine cambia el campo angle por cada cambio en clock. root myCamera myMaterial dirLight myRotXYZ Cylinder Real Time myCounter Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 23 / 29 File: code-iv-05.cc #include <cstdlib> #include <Inventor/Xt/SoXt.h> #include <Inventor/Xt/SoXtRenderArea.h> #include <Inventor/nodes/SoCylinder.h> #include <Inventor/nodes/SoSeparator.h> #include <Inventor/nodes/SoMaterial.h> #include <Inventor/nodes/SoSeparator.h> #include <Inventor/nodes/SoRotationXYZ.h> //added #include <Inventor/engines/SoElapsedTime.h> //added #include <Inventor/nodes/SoDirectionalLight.h> #include <Inventor/nodes/SoPerspectiveCamera.h> int main(int argc, char* argv[]) { Widget myWindow = SoXt::init(argv[0]); //window name if (myWindow == NULL) exit(1); //successfully //initialization SoSeparator *root = new SoSeparator; SoPerspectiveCamera *myCamera = new SoPerspectiveCamera; SoDirectionalLight *dirLight = new SoDirectionalLight; SoMaterial *myMaterial = new SoMaterial; SoRotationXYZ *myRotXYZ = new SoRotationXYZ; ... Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 24 / 29 File: code-iv-05.cc ... myMaterial->diffuseColor.setValue(0.0,1.0,1.0); //RGB root->ref(); root->addChild(myCamera); root->addChild(dirLight); root->addChild(myRotXYZ); //Preserving the hierarchy of the scene. root->addChild(myMaterial); root->addChild(new SoCylinder); myRotXYZ->axis = SoRotationXYZ::X; //Rotation around X-axis SoElapsedTime *myCounter = new SoElapsedTime; //engine myRotXYZ->angle.connectFrom(&myCounter->timeOut); //on seconds ... La instancia “myCounter” de la clase engine SoElapsedTime hacer rotar el objeto que se conecta al campo angle de la instancia “myRotXYZ” del la clase SoRotationXYZ. La variable miembro (campo) timeOut de la clase SoElapsedTime retorna un valor flotante (SoSFFloat) en segundos. Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 25 / 29 Reto para aprender!!: 1 2 ¿Como puede modificar la velocidad de rotacion del cilindro ? Pista: Revisar en “Open Inventor C++ Reference Manual” la clase engine SoElapsedTime. Use las siguientes lineas para generar una función callback e interactuar con la escena. Por ejemplo, acelerar o disminuir la velocidad de rotacion con las teclas UP ARROW y DOWN ARROW de SoKeyboardEvent. // Implementation of the callback function void myKeyPressCB(void *userData, SoEventCallback *eventCB) { const SoEvent* event = eventCB->getEvent(); // SoKeyboardEvent if (SO_KEY_PRESS_EVENT(event,Q)) exit(0); } ... // Declaration of a callback function SoEventCallback *myEventCB = new SoEventCallback; myEventCB->addEventCallback(SoKeyboardEvent::getClassTypeId(), myKeyPressCB,NULL); root->addChild(myEventCB); ... Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 26 / 29 Agrupación de nodos y jerarquı́as: SoSeparator Comunmente usado para agrupar nodos: I Child 0 I Child 1 Child 2 Children (Descendientes) I I Es implicito, sin ningun campo (field). Atraviesa los nodos en sequencia. SoSeparator: Encapsula propiedades y transformaciones. SoSwitch: Atraviesa a uno, a ninguno o a todos los descendientes. Por ejemplo, el campo whichChild toma un entero, para seleccionar un nodo 1 en especifico y tornarlo visible o invisible. pGroup->addChild( pNode ); pGroup->insertChild( pNode, index ); 1 Pag. 616, from [Reference-Manual, 1994]. Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 27 / 29 Agrupación de nodos y jerarquı́as: Relative to the previous transform SoSeparator RED -1,-1,0 Red Cone at -1,-1,0 2,2,0 Red Cone at 1,1,0 "Inherits" red color Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 28 / 29 Reference-Manual (1994). Open Inventor C++ Reference Manual: The Official Reference Document for Open Inventor, Release 2. Adsison Wesley (Open Inventor Architecture Group). Wernecke, J. (1994). The Inventor Mentor: Programming Object-Oriented 3D Graphics with Open Inventor, Release 2. Adsison Wesley (Open Inventor Architecture Group). Herling G. A. (ICP-Ecopetrol-Geofı́sica) Open Inventor - Tutorial 3 de octubre de 2018 29 / 29