O conceito
Fundamentalmente, um gráfico de cena nada mais é do que um gráfico acíclico bidirecional que serve para representar um conjunto hierárquico de relações espaciais.
Os motores em estado selvagem tendem a incluir outros itens no gráfico da cena, conforme observado. Se você vê isso como a carne ou a vaca provavelmente depende da sua experiência com motores e bibliotecas por aí.
Mantendo o peso leve
Eu sou a favor do estilo Unity3D de ter o nó do gráfico de cena (que no fundo é uma estrutura topológica e não espacial / topográfica) inclui inerentemente parâmetros e funcionalidades espaciais. No meu mecanismo, meus nós são ainda mais leves que o Unity3D, onde herdam muitos membros indesejados de superclasses / interfaces implementadas: Aqui está o que eu tenho - o mais leve possível:
- membros de ponteiro pai / filho.
- membros do parâmetro espacial de pré-transformação: posição xyz, pitch, yaw e roll.
- uma matriz de transformação; as matrizes em uma cadeia hierárquica podem multiplicar-se de maneira muito rápida e fácil, caminhando recursivamente para cima / para baixo na árvore, fornecendo as transformações espaciais hierárquicas que são a principal característica de um gráfico de cena;
- um
updateLocal()
método que atualiza apenas as matrizes de transformação desse nó
- um
updateAll()
método que atualiza esta e todas as matrizes de transformação de nós descendentes
... Também incluo lógica de equações de movimento e, portanto, membros de velocidade / aceleração (lineares e angulares) na minha classe de nós. Você pode renunciar a isso e manipulá-lo em seu controlador principal, se desejar. Mas é isso - muito leve mesmo. Lembre-se, você pode tê-los em milhares de entidades. Então, como você sugeriu, mantenha a luz.
Construindo hierarquias
O que você diz sobre um gráfico de cena que faz referência a outros gráficos de cena ... Estou esperando a linha de argumento? Claro que sim. Esse é o uso principal deles. Você pode adicionar qualquer nó a qualquer outro nó, e as transformações devem ocorrer automaticamente no espaço local da nova transformação. Tudo o que você está fazendo é mudar um ponteiro, não é como se você estivesse copiando dados! Ao alterar um ponteiro, você tem um gráfico de cena mais profundo. Se o uso de Proxies torna as coisas mais eficientes, é claro, mas nunca vi a necessidade.
Evitar lógica relacionada à renderização
Esqueça a renderização enquanto escreve sua classe de nó do gráfico de cena, ou você confunde tudo. O que importa é que você tenha um modelo de dados - seja o gráfico da cena ou não, não importa - e que algum representante irá inspecionar esse modelo de dados e renderizar objetos no mundo de acordo, seja em 1, 2 , 3 ou 7 dimensões. O que estou dizendo é: Não contamine seu gráfico de cena com a lógica de renderização. Um gráfico de cena é sobre topologia e topografia - isto é, conectividade e características espaciais. Esse é o verdadeiro estado da simulação e existe mesmo na ausência de renderização (que pode assumir qualquer forma sob o sol, desde a visualização em primeira pessoa até o gráfico estatístico e a descrição textual). Os nós não apontam para objetos relacionados à renderização - no entanto, o contrário pode ser verdadeiro. Considere também isso: Nem todo nó do gráfico de cena em sua árvore inteira será renderizável. Muitos serão apenas contêineres. Então, por que alocar memória para um ponteiro para renderizar objeto? Mesmo um membro ponteiro que nunca é usado, ainda está ocupando memória. Portanto, inverta a direção do ponteiro: a instância relacionada à renderização faz referência ao modelo de dados (que pode ser, ou incluir, o nó do gráfico de cena), NÃO vice-versa. E se você deseja uma maneira fácil de percorrer sua lista de controladores e ainda obter acesso à visualização relacionada, use um dicionário / hashtable, que se aproxime de O (1) tempo de acesso de leitura. Dessa forma, não há contaminação, e sua lógica de simulação não se importa com os renderizadores, o que torna seus dias e noites de codificação Então, por que alocar memória para um ponteiro para renderizar objeto? Mesmo um membro ponteiro que nunca é usado, ainda está ocupando memória. Portanto, inverta a direção do ponteiro: a instância relacionada à renderização faz referência ao modelo de dados (que pode ser, ou incluir, o nó do gráfico de cena), NÃO vice-versa. E se você deseja uma maneira fácil de percorrer sua lista de controladores e ainda obter acesso à visualização relacionada, use um dicionário / hashtable, que se aproxime de O (1) tempo de acesso de leitura. Dessa forma, não há contaminação, e sua lógica de simulação não se importa com os renderizadores, o que torna seus dias e noites de codificação Então, por que alocar memória para um ponteiro para renderizar objeto? Mesmo um membro ponteiro que nunca é usado, ainda está ocupando memória. Portanto, inverta a direção do ponteiro: a instância relacionada à renderização faz referência ao modelo de dados (que pode ser, ou incluir, o nó do gráfico de cena), NÃO vice-versa. E se você deseja uma maneira fácil de percorrer sua lista de controladores e ainda obter acesso à visualização relacionada, use um dicionário / hashtable, que se aproxime de O (1) tempo de acesso de leitura. Dessa forma, não há contaminação, e sua lógica de simulação não se importa com os renderizadores, o que torna seus dias e noites de codificação E se você deseja uma maneira fácil de percorrer sua lista de controladores e ainda obter acesso à visualização relacionada, use um dicionário / hashtable, que se aproxime de O (1) tempo de acesso de leitura. Dessa forma, não há contaminação, e sua lógica de simulação não se importa com os renderizadores, o que torna seus dias e noites de codificação E se você deseja uma maneira fácil de percorrer sua lista de controladores e ainda obter acesso à visualização relacionada, use um dicionário / hashtable, que se aproxime de O (1) tempo de acesso de leitura. Dessa forma, não há contaminação, e sua lógica de simulação não se importa com os renderizadores, o que torna seus dias e noites de codificaçãomundos mais fáceis.
Quanto ao descarte, consulte o item acima. A seleção por área de interesse é um conceito de lógica de simulação. Ou seja, você não processa o mundo fora desta área (geralmente em caixas, circular ou esférica). Isso ocorre no loop principal do controlador / jogo, antes da renderização. Por outro lado, o descarte de frustum é puramente relacionado à renderização. Então esqueça a seleção agora. Não tem nada a ver com gráficos de cenas e, ao focar neles, você estará obscurecendo o verdadeiro propósito do que está tentando alcançar.
Uma nota final ...
Tenho a forte sensação de que você é proveniente de um background em Flash (especificamente AS3), considerando todos os detalhes sobre a renderização incluídos aqui. Sim, o paradigma Flash Stage / DisplayObject inclui toda a lógica de renderização como parte do gráfico de cenário. Mas o Flash faz muitas suposições que você não necessariamente quer fazer. Para um mecanismo de jogo completo, é melhor não misturar os dois, por razões de desempenho, conveniência e controle da complexidade do código por meio do SoC adequado .
Renderable
s (que é uma classe de interface ou abstrata) internamente para esses objetos principais de controlador de modelo. Bons exemplos disso são entidades ou elementos da interface do usuário. Assim, você pode acessar rapidamente apenas os renderizadores pertinentes a esse objeto principal em particular - sem especificações de implementação que contaminariam a classe de entidade, daí o uso de interfaces.Renderer
.