X3D: X de eXtensible

X3D no sólo es extensible porque exista una implementación libre y abierta de referencia que puede ser fácilmente modificada y adaptada por cualquiera. El propio lenguaje X3D también brinda herramientas para crear nuevos nodos a partir de los existentes mediante el mecanismo de los protos.

Básicamente, se trata de crear la definición de un nuevo nodo (el prototipo), con todos los campos que necesitamos en una cabecera, y luego un cuerpo que contiene los elementos X3D (nodos, rutas, etc) que forman su implementación. Una vez declarado, incluyéndolo en cualquier escena lo podremos utilizar como si de un nodo más se tratara.

Empecé a prestar atención a este mecanismo cuando, escribiendo una clase en Java para implementar mi envoltorio de objetos en la escena (el wrapper), me dí cuenta de que estaba construyendo un sistema de paso de mensajes que duplicaba el mecanismo de eventos de que ya dispone X3D: se podría acceder cómodamente a toda esa funcionalidad ya definida usando un nodo proto de X3D que encapsulara toda la funcionalidad que necesito de un wrapper. El resultado es que el wrapper se pasa a implementar mediante un proto como éste:

        <ProtoDeclare name='Wrapper' documentation='Wrapper object for easy editing.'>
            <ProtoInterface>
                <field name='size' accessType='inputOutput' type='SFVec3f' value='1 1 1' />
                <field name='translation' accessType='inputOnly' type='SFVec3f' value='0 0 0' />
                <field name='rotation' accessType='inputOutput' type='SFRotation' value='0 0 0 0' />
                <field name='color' accessType='inputOutput' type='SFColor' value='1 0 0' />
                <field name='addChildren' accessType='inputOnly' type='MFNode' />
                <field name='content' accessType='inputOutput' type='MFNode' />
                <field name='enabled' accessType='inputOnly' type='SFBool'  value='true'/>
                <field  name='whichChoice' accessType='outputOnly' type='SFInt32' />

            </ProtoInterface>   
            <ProtoBody>
                <Group DEF='WrapperGroup'>
                    <Switch DEF='WrapperSwitch' whichChoice='0'>
                        <Transform DEF='WrapperTrans'>
                            <IS>
                                <connect protoField='translation' nodeField='translation' />
                                <connect protoField='rotation' nodeField='rotation' />
                                <connect protoField='addChildren' nodeField='addChildren' />
                            </IS>

                            <Transform DEF="CubeTrans">
                                <IS><connect protoField='size' nodeField='scale'/></IS>
                                <Shape>
                                    <Box>
                                    </Box>
                                    <Appearance>
                                        <Material DEF='CubeMaterial' transparency='0.5'>
                                            <IS><connect protoField='color' nodeField='emissiveColor' /></IS>
                                        </Material>
                                    </Appearance>              
                                </Shape>        
                            </Transform>
                            <Group DEF="EntityTransform">
                                <IS><connect protoField='content' nodeField='children' /> </IS>
                            </Group>
                         </Transform>
                        <Script DEF='Enabler'>
                            <field name='enabled' accessType='inputOnly' type='SFBool' />
                            <field  name='whichChoice' accessType='outputOnly' type='SFInt32' />
                            <IS>
                                <connect protoField='enabled' nodeField='enabled' />
                                <connect protoField='whichChoice' nodeField='whichChoice' />
                            </IS>
                            <![CDATA[ecmascript:
                                function enable (value) {
                                    enabled = value;
                                    if (enabled) {
                                        whichChoice = 0;
                                    }
                                    else {
                                        whichChoice = -1;
                                    }                 
                                }
                            ]]>
                        </Script>
                        <Script DEF='relativeTranslation' directOutput='true'>
                            <field name='wrapperTransform'  accessType='inputOutput' type='SFNode' >
                                <Transform USE='WrapperTrans' />
                            </field>
                            <field name='relativeTranslation' accessType='inputOnly' type='SFVec3f' />
                            <field name='translationCorrected' accessType='outputOnly' type='SFVec3f' />
                            <field name='size'  accessType='inputOutput' type='SFVec3f' />

                            <IS>
                                <connect  protoField='size' nodeField='size' />
                            </IS>

                            <![CDATA[ecmascript:
                                function relativeTranslation (value) {
                                    sensed = value;
                                    currentX = wrapperTransform.translation.x;
                                    currentY = wrapperTransform.translation.y;
                                    currentZ = wrapperTransform.translation.z;
                                    translationCorrected = wrapperTransform.translation;

                                    // If the new relative translation is inside the wrapper cube, correct it
                                    if ( Math.abs ( sensed.x - currentX ) < (size.x/2) ) {
                                        translationCorrected.x = sensed.x;
                                    }

                                    if ( Math.abs ( sensed.y - currentY ) < (size.y/2) ) {
                                        translationCorrected.y = sensed.y;                                    
                                    }
                                    if ( Math.abs ( sensed.z - currentZ ) < (size.z/2) ) {
                                        translationCorrected.z = sensed.z;                                    
                                    }
                                }
                              ]]>
                        </Script>

                        <!--
                        <Script DEF='absoluteTranslation' directOutput='true'>
                            <field name='absoluteTranslation' accessType='inputOnly' type='SFVec3f' />
                            <field name='translationCorrected' accessType='outputOnly' type='SFVec3f' />

                            <IS>
                                <connect protoField='translation' nodeField='absoluteTranslation' />
                            </IS>
                            <![CDATA[ecmascript:

                            function absoluteTranslation(value) {

                                translationCorrected = value;

                            }
                              ]]>                            
                        </Script>
                        -->
                    </Switch>
                    <TouchSensor DEF="WrapperInnerSensor"/>
                </Group>

                <ROUTE fromNode='WrapperInnerSensor' fromField='hitPoint_changed' toNode='relativeTranslation' toField='relativeTranslation' />
                <ROUTE fromNode='relativeTranslation' fromField='translationCorrected' toNode='WrapperTrans' toField='translation' />

            </ProtoBody>
        </ProtoDeclare>

1 comment so far

  1. juaxix on

    Un Wrapper entonces es como un contenedor que define como se trata un objeto y donde se le pueden incrustar definiciones de funciones con las que alterar dicho objeto ,por ejemplo,la forma de rotar…
    lo que me causa un poco de confusión es que he visto que hay varios tipos de scripts,…no se si esto es mejor o peor ,pero si que es interesante, mezclar varios lenguajes permite más libertad, sin embargo, no se hasta que punto sería eficiente construir árboles XML para objetos ya que puede haber muchos en pantalla…entonces, ya puedes acceder a los objetos clickando en ellos?
    Saludos!


Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: