El concepto
Fundamentalmente, un gráfico de escena no es más que un gráfico acíclico bidireccional que sirve para representar un conjunto jerárquicamente estructurado de relaciones espaciales.
Los motores en la naturaleza tienden a incluir otras cosas buenas en el gráfico de la escena, como se señaló. Si lo ves como la carne o la vaca probablemente depende de tu experiencia con motores y bibliotecas.
Manteniéndolo ligero
Estoy a favor del estilo Unity3D de tener su nodo de gráfico de escena (que en esencia es una estructura topológica en lugar de una estructura espacial / topográfica) inherentemente incluye parámetros espaciales y funcionalidad. En mi motor, mis nodos son incluso más livianos que Unity3D, donde heredan muchos miembros basura innecesarios de superclases / interfaces implementadas: esto es lo que tengo, lo más ligero que puedes obtener:
- miembros punteros padre / hijo.
- miembros de parámetros espaciales pretransformados: posición xyz, cabeceo, guiñada y balanceo.
- una matriz de transformación; las matrices en una cadena jerárquica pueden multiplicarse rápida y fácilmente caminando recursivamente hacia arriba / abajo del árbol, brindándole las transformaciones espaciales jerárquicas que son la característica principal de un gráfico de escena;
- un
updateLocal()
método que actualiza solo las matrices de transformación de este nodo
- un
updateAll()
método que actualiza esta y todas las matrices de transformación de nodos descendientes
... También incluyo la lógica de ecuaciones de movimiento y, por lo tanto, miembros de velocidad / aceleración (lineal y angular) en mi clase de nodo. Puede renunciar a eso y manejarlo en su controlador principal si lo desea. Pero eso es todo, muy ligero. Recuerde, podría tenerlos en miles de entidades. Entonces, como has sugerido, mantenlo ligero.
Construyendo Jerarquías
Lo que dices sobre un gráfico de escena que hace referencia a otros gráficos de escena ... ¿Estoy esperando el remate? Por supuesto que lo hacen. Ese es su uso principal. Puede agregar cualquier nodo a cualquier otro nodo, y las transformaciones deben ocurrir automáticamente dentro del espacio local de la nueva transformación. Todo lo que está haciendo es cambiar un puntero, ¡no es como si estuviera copiando datos! Al cambiar un puntero, tiene un gráfico de escena más profundo. Si usar Proxies hace las cosas más eficientes, entonces, por supuesto, pero nunca he visto la necesidad.
Evita la lógica relacionada con el renderizado
Olvídate de renderizar mientras escribes tu clase de nodo de gráfico de escena, o confundirás las cosas por ti mismo. Lo único que importa es que tenga un modelo de datos, ya sea que sea el gráfico de escena o no, y que algún renderizador inspeccionará ese modelo de datos y renderizará los objetos en el mundo en consecuencia, ya sea en 1, 2 , 3 o 7 dimensiones. El punto que estoy haciendo es: No contamine su gráfico de escena con la lógica de renderizado. Un gráfico de escena trata sobre topología y topografía, es decir, conectividad y características espaciales. Este es el verdadero estado de la simulación y existe incluso en ausencia de renderizado (que puede tomar cualquier forma bajo el sol desde una vista en primera persona a un gráfico estadístico a una descripción textual). Los nodos no apuntan a objetos relacionados con la representación; sin embargo, lo contrario puede ser cierto. Considere también esto: No todos los nodos de gráficos de escena en todo su árbol serán renderizables. Muchos serán solo contenedores. Entonces, ¿por qué incluso asignar memoria para un puntero a objeto de renderizado? Incluso un miembro de puntero que nunca se usa, todavía está ocupando memoria. Por lo tanto, invierta la dirección del puntero: la instancia relacionada con el renderizado hace referencia al modelo de datos (que podría ser, o incluir, su nodo de gráfico de escena), NO viceversa. Y si desea una manera fácil de ejecutar su lista de controladores y obtener acceso a la vista relacionada, utilice un diccionario / tabla hash, que se acerca al tiempo de acceso de lectura O (1). De esa manera no hay contaminación, y su lógica de simulación no le importa qué procesadores están en su lugar, lo que hace que sus días y noches de codificación Entonces, ¿por qué incluso asignar memoria para un puntero a objeto de renderizado? Incluso un miembro de puntero que nunca se usa, todavía está ocupando memoria. Por lo tanto, invierta la dirección del puntero: la instancia relacionada con el renderizado hace referencia al modelo de datos (que podría ser, o incluir, su nodo de gráfico de escena), NO viceversa. Y si desea una manera fácil de ejecutar su lista de controladores y obtener acceso a la vista relacionada, utilice un diccionario / tabla hash, que se acerca al tiempo de acceso de lectura O (1). De esa manera no hay contaminación, y su lógica de simulación no le importa qué procesadores están en su lugar, lo que hace que sus días y noches de codificación Entonces, ¿por qué incluso asignar memoria para un puntero a objeto de renderizado? Incluso un miembro de puntero que nunca se usa, todavía está ocupando memoria. Por lo tanto, invierta la dirección del puntero: la instancia relacionada con el renderizado hace referencia al modelo de datos (que podría ser, o incluir, su nodo de gráfico de escena), NO viceversa. Y si desea una manera fácil de ejecutar su lista de controladores y obtener acceso a la vista relacionada, use un diccionario / tabla hash, que se acerca al tiempo de acceso de lectura O (1). De esa manera no hay contaminación, y su lógica de simulación no le importa qué procesadores están en su lugar, lo que hace que sus días y noches de codificación Y si desea una manera fácil de ejecutar su lista de controladores y obtener acceso a la vista relacionada, use un diccionario / tabla hash, que se acerca al tiempo de acceso de lectura O (1). De esa manera no hay contaminación, y su lógica de simulación no le importa qué procesadores están en su lugar, lo que hace que sus días y noches de codificación Y si desea una manera fácil de ejecutar su lista de controladores y obtener acceso a la vista relacionada, use un diccionario / tabla hash, que se acerca al tiempo de acceso de lectura O (1). De esa manera no hay contaminación, y su lógica de simulación no le importa qué procesadores están en su lugar, lo que hace que sus días y noches de codificaciónmundos más fáciles.
En cuanto al sacrificio, refiérase a lo anterior. El sacrificio de área de interés es un concepto de lógica de simulación. Es decir, no se procesa el mundo fuera de esta área (generalmente en caja, circular o esférica). Esto tiene lugar en el controlador principal / bucle del juego, antes de que se produzca el renderizado. Por otro lado, el sacrificio de frustum está puramente relacionado con el render. Así que olvídate de sacrificar ahora mismo. No tiene nada que ver con los gráficos de escena, y al enfocarse en él, ocultará el verdadero propósito de lo que está tratando de lograr.
Una nota final ...
Tengo la fuerte sensación de que proviene de un fondo Flash (específicamente AS3), dados todos los detalles sobre la representación incluidos aquí. Sí, el paradigma Flash Stage / DisplayObject incluye toda la lógica de renderizado como parte de la escena. Pero Flash hace muchas suposiciones que no necesariamente quieres hacer. Para un motor de juego completo, es mejor no mezclar los dos, por razones de rendimiento, conveniencia y control de la complejidad del código a través del SoC adecuado .
Renderable
s (que es una interfaz o clase abstracta) internamente en esos objetos de controlador de modelo centrales. Buenos ejemplos de esto son entidades o elementos de la interfaz de usuario. Por lo tanto, puede acceder rápidamente solo a los renderizadores pertinentes a ese objeto central en particular, sin detalles de implementación que contaminen la clase de entidad, de ahí el uso de interfaces.Renderer
.