Flutuar, dobrar ou ambos para classe Vector 2D?

11

Atualmente, estou escrevendo um pequeno mecanismo de jogo 2D baseado em OpenGL de plataforma cruzada para o nosso estúdio. Quando pesquisei qual classe de vetor 2D usar, me deparei com três paradigmas de design diferentes:

  • Flutuar e chamar por valor, como neste artigo do Gamasutra . Parece ser rápido, mas oferece pouca precisão (consulte também este tópico ). Pro: Rápido, portátil e compatível com a maioria das bibliotecas.

  • Duplo e Chamada por Referência. Se eu entendi direito o artigo acima, também poderia usar 2 variáveis ​​de precisão dupla em vez dos 4 números flutuantes. De acordo com o segmento acima, o duplo ainda é mais lento que o flutuador.

  • Modelo para double e float: o livro amplamente popular " Game Engine Architecture " usa modelos para possibilitar o uso de float e double conforme necessário. A desvantagem óbvia é o inchaço do código. Além disso, duvido que o código possa ser otimizado sem basicamente escrever duas classes.

Gostaria de saber quais são as soluções que você está usando em seus mecanismos internos e quão precisas, por exemplo, os mecanismos de jogos populares são, para que eu possa decidir qual solução implementarei em nosso mecanismo. No momento, estou pensando em simplesmente usar a precisão de flutuação e conviver com ela.

martinpi
fonte
Mais devagar onde ? Você não pode falar sobre velocidade se isso não estiver vinculado a uma arquitetura específica.
o0 '.
2
@ Lo'oris: Não conheço nenhuma arquitetura em que o dobro seja mais rápido que o float.
Em vez de escrever sua própria classe de vetor, considere o uso da Sony ( bulletphysics.org/Bullet/phpBB3/… ). É uma "biblioteca" fácil de usar somente cabeçalho que já foi micro otimizada e todas as bibliotecas de vetores são basicamente a mesma interface externa.
@ Joe: 2 duplos em vez de 4 carros alegóricos?
o0 '.
@ Lo'oris: A pergunta está um pouco estranha, não sei se o interlocutor está confuso ou apenas você - você usa dois duplos "em vez de" quatro carros alegóricos ao lidar com o SIMD, porque o registro tem 128 bits de largura. Você ainda precisa processar um número igual de números e está fazendo a meia velocidade.

Respostas:

9

Eu sempre uso float, a menos que tenha um motivo para usar o dobro, da mesma forma que uso int, a menos que tenha um motivo para usar int64_t.

Os carros alegóricos não têm problemas ao fazer aritmética inteira precisa até 2 24 , que é o que a maioria das pessoas tem medo (principalmente irracionalmente). As duplas não resolvem exatamente o problema de os valores comuns não serem representáveis ​​- se você obtém 0.10000001 ou 0.10000000000000001, você ainda deve garantir que seu código considere "igual" a 0,09999999.

As duplas são mais lentas em todas as plataformas em que você se preocupa em escrever jogos, consome o dobro da largura de banda da memória e tem menos instruções especializadas da CPU disponíveis.

Flutuadores de precisão única continuam sendo o padrão para interfaces gráficas de hardware, tanto no lado C / C ++ quanto dentro de shaders.

Você provavelmente precisará de um vetor duplo em algum momento, mas ele deve ser usado quando necessário, não por padrão.

Quanto à modelagem - você está certo, para obter o desempenho máximo, você deverá especializar os modelos manualmente de qualquer maneira. Além disso, executei alguns testes para código de modelo no fim de semana (criando um IntRect e FloatRect de 4 ple) e descobri que a versão do modelo demorava cerca de 20 vezes mais para compilar do que apenas repetir o código, que totalizava cerca de 15 linhas . A repetição é uma porcaria, mas esperar por compilações é uma porcaria mais - e não é como se eu fosse precisar de um StringRect ou FooRect.


fonte
"Os duplos são mais lentos em todas as plataformas [...] " - citação necessária.
zenith
3

A estrutura de jogo do Microsoft XNA possui uma classe Vector2 que usa carros alegóricos. Essa seria minha maior razão pessoal para ir com carros alegóricos, pois confio que a sabedoria e a experiência da equipe do XNA sejam muito maiores que as minhas.

Achei bastante interessante ler a resposta nesta pergunta de estouro de pilha: "Desempenho flutuante versus duplo" . Há também um tópico gamedev.net com algumas discussões sobre desempenho duplo em GPUs. Eu acho que é seguro supor que as duplas são mais lentas que as flutuantes, pelo menos em muitas GPUs, e eu sempre usei as funções OpenGL flutuantes sobre suas contrapartes duplas. Isso pode não se aplicar atualmente, mas se você considerar que nem todo mundo que executa seu jogo tem a GPU mais recente com suporte duplo nativo, acho que isso é motivo suficiente para usar carros alegóricos e obter um pouco mais de desempenho.

Ricket
fonte
1
Da pergunta do SO: "Nos processadores x86, pelo menos, float e double serão convertidos em um real de 10 bytes pela FPU para processamento". Embora isso seja verdade, ele negligencia as instruções SIMD e os requisitos de memória adicional (= pior coerência do cache, mais largura de banda da memória) de dobras, os quais continuam a torná-lo mais lento do que flutuar nos testes do mundo real.
Imaginei que havia um problema. Você deve comentar que, para a resposta SO, eu a votaria.
Ricket 01/10/10
Já está lá como um comentário.
1
Desde que você criou o XNA, devo salientar que o Direct2D também usa flutuadores de precisão única.
Mike Strobel
E, para ser completo, o OpenGL possui versões flutuante e dupla de seus métodos, por isso é neutro nesse sentido.
Ricket 2/10/10