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.deltaTime
incrementado 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:
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":
- Começa a girar em direção ao novo revestimento
- 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);
Respostas:
Cada orientação no espaço 3D pode ser representada por 2 quaterniões de unidades distintas
q
e-q
(negadas por componentesq
). Por exemplo, a orientação representada pela matriz de identidade 3x3I
pode ser representada por 2 quaternions: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 que0
, apenas em termos de componentes, anule o outro quaternário antes de cortá-los.fonte
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.Inverse
, é uma operação diferente daNegate
.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.if(Quaternion.Dot (lookQuaternion, startQuaternion) < 0) { startQuaternion = Quaternion.Negate(startQuaternion); }
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 .
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.
fonte
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.
fonte