Como animar dinamicamente uma parte de um modelo 3D em direção a algo

8

Estou curioso para saber como esse tipo de animação geralmente é feito em código.

Alguns exemplos:

Gerstmann
fonte

Respostas:

4

Isso é chamado de cinemática inversa. O Google provavelmente é seu melhor amigo, pois pode ficar complexo.

n3XusSLO
fonte
Entendi, tenho que calcular os movimentos necessários para alcançar a posição desejada. Nesse caso, eu calcularia apenas os movimentos para o osso desejado.
Gerstmann
De fato, a descrição do vídeo diz "... um sistema de animação baseado inteiramente em cinemática inversa ..."
MichaelHouse
0

Artigo Original: Como codificar um sistema IK

Às vezes, o IK incorporado ao Unity não é suficiente. Vou mostrar como criar seu próprio script IK para o Unity. Você pode aplicar este IK a qualquer corpo articulado - dedos, mãos ou pés. O IK que vou revisar é atualmente usado pelo Unity, Unreal, Panda e vários outros mecanismos de jogos. É chamado FABRIK.

O FABRIK é um método iterativo. Um método iterativo é um método que não obtém a solução imediatamente. Um método iterativo se aproxima cada vez mais da solução correta com mais iterações do método - em outras palavras, iterações de um loop.

Qualquer problema de CI tem um determinado corpo articulado (um conjunto de membros conectados com comprimentos e ângulos). O efetor final (a posição do ponto final do membro final) tem uma posição inicial com uma posição de meta. Pode ter outros objetivos, como ângulos.

Cada iteração do FABRIK possui duas partes principais.

void FABRIK() {
    while( abs(endEffectorPosition  goalPosition) > EPS ) {
        FinalToRoot(); // PartOne
        RootToFinal(); // PartTwo
    }
}

A primeira parte itera do membro final para o membro raiz. Para o membro final, é necessário alterar o ângulo / rotação do membro para apontar para a posição do objetivo (mantendo a posição interna ancorada e permitindo que a posição externa seja traduzida pela alteração do ângulo). Em seguida, você converte o membro final ao longo do ângulo atualizado em direção à posição do objetivo, até que a posição externa do membro seja igual à posição do objetivo (mantendo o ângulo, mas deixando a posição interna do membro mudar). É basicamente isso para o membro final, exceto que agora você precisa atualizar a posição atual do objetivo. A posição atual do objetivo agora está definida para a posição interna atualizada do membro final.

Para cada membro interno consecutivo, você faz a mesma coisa. Para ser claro, vou descrevê-lo. Para o membro atual, você precisa alterar o ângulo / rotação do membro para apontar para a posição atual do objetivo. Em seguida, você converte o membro atual ao longo do ângulo atualizado em direção à posição atual do objetivo, até que a posição externa do membro seja igual à posição atual do objetivo. Finalmente, você atualiza a posição atual da meta para ser igual à posição interna atualizada do membro atual.

Repita essas operações até concluir essas operações no ramo raiz. Depois disso, a primeira parte foi concluída.

/* Part One */
void FinalToRoot() {
    currentGoal = goalPosition;
    currentLimb = finalLimb;
    while (currentLimb != NULL) {
        currentLimb.rotation = RotFromTo(Vector.UP,
            currentGoal  currentLimb.inboardPosition);
        currentGoal = currentLimb.inboardPosition;
        currentLimb = currentLimb->inboardLimb;
    }
}

A segunda parte itera na direção inversa: do membro raiz ao membro final. Para o membro raiz, você precisa atualizar sua posição interna para a posição raiz. Isso deve traduzir o membro inteiro (sem alongamento). É basicamente isso para o membro raiz, exceto que agora você precisa atualizar a posição atual interna. A posição atual do interior agora está definida para a posição atualizada do membro raiz. Para cada membro externo consecutivo, você faz a mesma coisa. Para ser claro, vou descrevê-lo. Para o membro atual, é necessário atualizar sua posição interna para a atual posição interna. Isso deve traduzir o membro inteiro. É praticamente isso para o membro atual, exceto que agora você precisa atualizar a posição atual interna. A posição atual do interior está agora definida como a posição externa atualizada do membro atual.

Repita essas operações até concluir essas operações no membro final. Depois disso, a segunda parte foi concluída.

/* Part Two */
void RootToFinal() {
    currentInboardPosition = rootLimb.inboardPosition;
    currentLimb = rootLimb;
    while (currentLimb != NULL) {
        currentLimb.inboardPosition = currentInboardPosition;
        currentInboardPosition = currentLimb.outboardPosition;
        currentLimb = currentLimb->inboardLimb;
    }
}

Após a conclusão da primeira e da segunda parte, você conclui a primeira iteração do método FABRIK. Continue iterando as partes um e dois até que o efetor final esteja o mais próximo possível da posição da meta, definida por algum EPS (valor epsilon).

É isso aí! Esse é o método FABRIK. A Parte Um itera para trás a partir do membro final. Parte dois itera para frente a partir do membro raiz. O método FABRIK itera a Parte Um e a Parte Dois até que o efetor final esteja próximo o suficiente da posição do gol.

Luis B
fonte