Espelhos rotativos slerping

9

Giro meu personagem do jogo para assistir ao alvo usando o seguinte código:

        transform.rotation = Quaternion.Slerp(startQuaternion, lookQuaternion, turningNormalizer*turningSpeed/10f)

startQuaternion é a rotação atual do personagem quando um novo alvo é dado.

lookQuaternion é a direção que o personagem deve olhar e está definido assim:

    destinationVector = currentWaypoint.transform.position - transform.position;
    lookQuaternion = Quaternion.LookRotation(destinationVector, Vector3.up);

TurnNormalizer é apenas Time.deltaTimeincrementado e turningSpeedé um valor estático fornecido no editor.

O problema é que, embora o personagem gire como deveria na maioria das vezes, ele tem problemas quando precisa fazer perto de 180 graus. Às vezes, ele se agita e reflete a rotação:

insira a descrição da imagem aqui

Nesta imagem mal desenhada, o personagem (à direita) começa a girar em direção ao círculo à esquerda. Em vez de apenas virar pela esquerda ou direita, inicia esta "dança do espelho":

  1. Começa a girar em direção ao novo revestimento
  2. De repente, ele se encaixa no mesmo ângulo, mas do outro lado e continua girando

Faz esse "espelhamento" por tanto tempo até olhar para o alvo. Isso é uma coisa com quaternions, slerping / lerping ou algo mais?

EDIT1: Aparentemente, o problema não surge da própria rotação. O problema mais provável é que o personagem se mova na direção do rosto enquanto gira. Como limitar o ângulo, entre o rosto e o alvo, quando o personagem pode se mover, reduz e às vezes elimina a rotação de tremulação / espelhamento.

É claro que isso levanta mais questões: por que o personagem não pode se mover e girar ao mesmo tempo sem problemas? Código usado para o movimento:

transform.Translate(Vector3.forward * runningSpeed/10f * Time.deltaTime);
Esa
fonte
O 'lookQuaternion' está sendo atualizado a cada quadro? Em caso afirmativo, minha presunção seria que algumas pequenas imprecisões estão levando a uma espécie de instabilidade, em que o jogador 'ultrapassa' a rotação de olhar e, portanto, a nova direção a olhar fica do outro lado de 'diretamente atrás' ... .
Steven Stadnicki

Respostas:

5

Cada orientação no espaço 3D pode ser representada por 2 quaterniões de unidades distintas qe -q(negadas por componentes q). Por exemplo, a orientação representada pela matriz de identidade 3x3 Ipode ser representada por 2 quaternions:

 q:  { 0,  0,  0},  1
-q:  {-0, -0, -0}, -1

Ambos representam a mesma orientação no espaço 3D, seu produto pontual é exatamente -1, cada um deles no outro hemisfério, exatamente nos lados opostos da hiperesfera.

O resultado que você observa quando o slerp leva o arco mais longo para girar é quando desliza entre 2 quaternions que não estão no mesmo hemisfério. Se isso acontecer, basta negar um deles antes de slerpá-los, então o slerp assumirá o arco mais curto.

O produto escalar é uma ferramenta fácil para descobrir se isso acontece. Se o produto escalar de ambos os quaternions for menor que 0, eles não estarão no mesmo hemisfério. Portanto, se o produto escalar de ambos for menor que 0, apenas em termos de componentes, anule o outro quaternário antes de cortá-los.

Maik Semder
fonte
Gostaria de saber se eu entendi você corretamente, como eu tentei com isso if(Quaternion.Dot (lookQuaternion, startQuaternion) < 0) { startQuaternion = Quaternion.Inverse(startQuaternion); } Mas isso não corrigiu o problema. Desculpe pela má formatação, não consigo domar esta seção de comentários.
Esa
Quase, mas não Inverse, é uma operação diferente da Negate. if(Quaternion.Dot (lookQuaternion, q) < 0) { q.x = -q.x; q.y = -q.y; q.z = -q.z; q.w = -q.w; }Eu não uso C #, mas pela aparência do documento, parece que você também pode usar a Função Negar diretamente.
Maik Semder
if(Quaternion.Dot (lookQuaternion, startQuaternion) < 0) { startQuaternion = Quaternion.Negate(startQuaternion); }
Maik Semder
Receio que estes não tenham corrigido o problema. Eu atualizei a pergunta.
Esa
Sim, isso é provavelmente uma mistura de bugs diferentes. Simplifique sua configuração de teste, teste uma coisa de cada vez, não a tradução e a rotação ao mesmo tempo. Primeiro, verifique se um funciona, depois o outro e depois os dois juntos. Concentre-se apenas na rotação primeiro, use alguns valores de orientação conhecidos, como começar a 170 graus, descer para zero, ver onde está errado e postar aqui
Maik Semder
1

Bem, o seu problema é porque esses dois vetores que formam seus quaternions fazem 180 graus, então a pergunta que deve ser feita ao interpolar qual arco ele deve assumir? o arco superior ou o inferior ??

Isso é o que basicamente causa o espelhamento, cada vez que você interpola, é o contrário, mantendo o ângulo.

De acordo com este link .

Quando teta é de 180 graus, o resultado é indefinido porque não há uma direção mais curta para girar. Acho que essa situação ainda não foi tratada corretamente. Seria melhor se escolhêssemos algum eixo arbitrário normal para qa ou qb. aprecie as idéias para a melhor maneira de fazer isso.

O que você precisa fazer é interpolar seu quaternion inicial com um quaternion intermediário (para determinar qual arco tomar) e, quando atingido, use o quaternion intermediário para continuar com o quaternion alvo real.

concept3d
fonte
1

O problema que suspeito que você está vendo não tem nada a ver com seu código, mas é um problema fundamental com a interpolação na superfície de uma esfera (neste caso, para o viewDirection). Entre (quase) dois pontos em uma esfera, há um único grande círculo - por exemplo, arbitrariamente fixando nosso ponto de 'início' no polo norte, o grande círculo seria o meridiano em que o ponto final se encontra. A interpolação de um ponto para o outro se move ao longo deste grande círculo.

Agora, para a maioria dos pontos em uma esfera, pontos próximos correspondem a grandes círculos próximos; por exemplo, os meridianos em que Los Angeles e Phoenix se encontram são bastante próximos um do outro. Mas quando o ponto de destino é o antípoda do ponto original - o polo sul ao polo norte do ponto inicial - não há mais um único grande círculo entre os dois, mas todos os grandes círculos através de um passam pelo outro. O que é pior, isso significa que os pontos próximos ao polo sul não são 'a maioria dos pontos'; dois pontos próximos um do outro e ambos próximos ao pólo sul podem ter meridianos bastante divergentes.

Eu suspeito que o que você está vendo é uma manifestação dessa instabilidade no meridiano - ou em outras palavras, o arco de interpolação. Quando o alvo da aparência está diretamente atrás do personagem, coisas como a imprecisão de primeira ordem na sua 'integração Euler' da posição do personagem e a maneira que muda a direção da aparência, quadro a quadro, vão levar a isso descontroladamente. interpolações diferentes arqueiam de um quadro para o outro, e isso provavelmente levará ao 'cambalear' que você está vendo.

Quanto ao que fazer com isso, a melhor coisa que vem à mente é não recalcular o "alvo" na direção de cada quadro; em vez disso, use o mesmo para um intervalo de vários quadros, calcule um novo e use-o para vários quadros etc. Se necessário, você pode até interpolar de um destino para o próximo ao longo de alguns quadros, para que a direção do movimento não muda muito abruptamente.

Steven Stadnicki
fonte