Partilhar via


Solvers — MRTK3

Solver Principal

Solvers são componentes que facilitam o cálculo da posição e orientação de um objeto de acordo com um algoritmo predefinido. Exemplo: colocar um objeto na superfície com o qual o raio de olhar do usuário se cruza.

O sistema Solver define deterministicamente uma ordem de operações para esses cálculos de transformação, pois não há uma maneira confiável de especificar ao Unity a ordem de atualização dos componentes.

Os solvers oferecem uma variedade de comportamentos para anexar objetos a outros objetos ou sistemas. Um outro exemplo seria um objeto tag-along que paira na frente do usuário com base na câmera. Um solucionador também pode ser anexado a um controlador e um objeto para fazer a tag do objeto ao longo do controlador. Todos os solucionadores podem ser empilhados com segurança - por exemplo, um comportamento de tag-along mais magnetismo de superfície mais momento.

Como utilizar

O sistema Solver consiste em três categorias de scripts:

  • Solver: A classe base abstrata da qual todos os solvers derivam. Ele fornece rastreamento de estado, suavização de parâmetros e implementação, integração automática do sistema de resolução e ordem de atualização.
  • SolverHandler: Define o rastreamento do objeto de referência contra (exemplo: a transformação da câmera principal, raio de mão, etc.), lida com a coleta de componentes do solucionador e executa a atualização deles na ordem correta.

A terceira categoria é o próprio solucionador. Os seguintes solvers fornecem os blocos de construção para o comportamento básico:

  • Orbital: Bloqueia para uma posição especificada e desloca do objeto referenciado.
  • ConstantViewSize: Escala para manter um tamanho constante em relação à exibição do objeto referenciado.
  • RadialView: Mantém o objeto dentro de um cone de exibição convertido pelo objeto referenciado.
  • Follow: Mantém o objeto dentro de um conjunto de limites definidos pelo usuário do objeto referenciado.
  • InBetween: Mantém um objeto entre dois objetos rastreados.
  • SurfaceMagnetism: lança raios para superfícies no mundo e alinha o objeto a essa superfície.
  • DirectionalIndicator: Determina a posição e orientação de um objeto como um indicador direcional. Do ponto de referência do SolverHandler Tracked Target, este indicador orientar-se-á para o DirectionalTarget fornecido.
  • Momentum: Aplica aceleração/velocidade/atrito para simular o momento e a elasticidade de um objeto que está sendo movido por outros solvers/componentes.
  • HandConstraint: Constraints object para seguir mãos em uma região que não cruza o GameObject com as mãos. Útil para conteúdo interativo restrito à mão, como menus, etc. Este solucionador destina-se a trabalhar com XRNode.
  • HandConstraintPalmUp: Deriva de HandConstraint, mas inclui lógica para testar se a palma está voltada para o usuário antes da ativação. Este solucionador só funciona com XRNode controladores e irá comportar-se como a sua classe base com outros tipos de controladores.
  • Overlap: Sobrepõe-se ao objeto rastreado.

Para usar o sistema Solver, adicione um dos componentes listados acima a um GameObject. Como todos os Solvers requerem um SolverHandler, um será criado automaticamente por Unity.

Nota

Exemplos de como usar o sistema Solvers podem ser encontrados no arquivo SolverExamples.scene .

Como alterar a referência de acompanhamento

A propriedade Tracked Target Type do componente define o SolverHandler ponto de referência que todos os solucionadores usarão para calcular seus algoritmos. Por exemplo, um tipo de valor com Head um componente simples SurfaceMagnetism resultará em um raio lançado da cabeça e na direção do olhar do usuário para resolver qual superfície é atingida. Os valores potenciais para o TrackedTargetType imóvel são:

  • *Cabeça: Ponto de referência é a transformação da câmera principal
  • ControllerRay: Ponto de referência é a transformação em um controlador (ou seja, origem LinePointer do ponteiro em um controlador de movimento ou controlador manual) apontando na direção do raio de linha
    • Use a TrackedHandedness propriedade para selecionar a preferência handedness (ou seja, Left, Right, Both)
  • HandJoint: Ponto de referência é a transformação de uma junta de mão específica
    • Use a TrackedHandedness propriedade para selecionar a preferência handedness (ou seja, Left, Right, Both)
    • Use a TrackedHandJoint propriedade para determinar a transformação conjunta a ser utilizada
  • CustomOverride: Ponto de referência do atribuído TransformOverride

Nota

Para os tipos ControllerRay e HandJoint , o manipulador de solver tentará fornecer a transformação controlador/mão esquerda primeiro e depois a direita se a primeira não estiver disponível ou a menos que a TrackedHandedness propriedade especifique o contrário.

Importante

A maioria dos solvers usa o vetor forward do alvo de transformação rastreado fornecido pelo SolverHandler. Ao usar um tipo de alvo rastreado Hand Joint , o vetor para frente da articulação da palma pode apontar através dos dedos e não através da palma. Isso depende da plataforma que fornece os dados da junta manual. Para simulação de entrada e Windows Mixed Reality, o vetor para cima aponta para cima através da palma da mão (em outras palavras, vetor verde está para cima, vetor azul é para frente).

Para superar isso, atualize a propriedade Rotação adicional no SolverHandler para <90, 0, 0>. Isso garante que o vetor avançado fornecido aos solucionadores esteja apontando através da palma e para fora da mão.

Como alternativa, use o tipo de alvo rastreado Controller Ray para obter um comportamento semelhante ao apontar com as mãos.

Como encadear solvers

É possível adicionar vários Solver componentes ao mesmo GameObject, encadeando assim os seus algoritmos. Os SolverHandler componentes lidam com a atualização de todos os solvers no mesmo GameObject. Por padrão, as SolverHandler chamadas GetComponents<Solver>() em Start, que retornarão os Solvers na ordem em que aparecem no inspetor.

Além disso, definir a propriedade Updated Linked Transform como true instruirá que Solver salvar sua posição, orientação e escala calculadas em uma variável intermediária acessível por todos os Solvers (ou seja, GoalPosition). Quando false, o Solver irá atualizar a transformação do GameObject diretamente. Ao salvar as propriedades de transformação em um local intermediário, outros Solvers podem executar seus cálculos a partir da variável intermediária. Isso ocorre porque o Unity não permite que as atualizações de gameObject.transform sejam empilhadas dentro do mesmo quadro.

Nota

Os desenvolvedores podem modificar a ordem de execução de Solvers definindo a SolverHandler.Solvers propriedade diretamente.

Como criar um novo solucionador

Todos os solvers devem herdar da classe base abstrata, Solver. Os principais requisitos de uma extensão do Solver envolvem a substituição do SolverUpdate método. Nesse método, os desenvolvedores devem atualizar as propriedades herdadas GoalPosition, GoalRotatione GoalScale para os valores desejados. Além disso, é valioso alavancar SolverHandler.TransformTarget como o quadro de referência desejado pelo consumidor.

O código fornecido abaixo dá um exemplo de um novo componente Solver chamado InFront que coloca o objeto anexado 2 m na frente do SolverHandler.TransformTarget. O consumidor define SolverHandler.TrackedTargetType como Head, então o SolverHandler.TransformTarget será a transformação da câmera, e, assim, este Solver colocará o GameObject anexado 2 m na frente do olhar dos usuários a cada quadro.

/// <summary>
/// InFront solver positions an object 2m in front of the tracked transform target
/// </summary>
public class InFront : Solver
{
    ...

    public override void SolverUpdate()
    {
        if (SolverHandler != null && SolverHandler.TransformTarget != null)
        {
            var target = SolverHandler.TransformTarget;
            GoalPosition = target.position + target.forward * 2.0f;
        }
    }
}

Guias de implementação do Solver

Propriedades comuns do solucionador

Cada componente do Solver tem um conjunto principal de propriedades idênticas que controlam o comportamento principal do Solver.

Se a Suavização estiver ativada , o Solver atualizará gradualmente a transformação do GameObject ao longo do tempo para os valores calculados. A propriedade LerpTime de cada componente de transformação determina a velocidade dessa alteração. Por exemplo, um valor MoveLerpTime mais alto resultará em incrementos mais lentos no movimento entre quadros.

Se MaintainScale estiver habilitado, o Solver utilizará a escala local padrão do GameObject.

Orbital

A Orbital classe é um componente tag-along que se comporta como planetas em um sistema solar. Este Solver garantirá que o GameObject anexado orbite em torno da transformação rastreada. Assim, se o Tipo de Alvo Rastreado do estiver definido como Head, então o GameObject orbitará em torno da cabeça do usuário com um deslocamento fixo SolverHandler aplicado.

Os desenvolvedores podem modificar esse deslocamento fixo para manter os menus ou outros componentes de cena na altura dos olhos ou da cintura, etc., ao redor de um usuário. Isso é feito alterando as propriedades Local Offset e World Offset . A propriedade Orientation Type determina a rotação aplicada ao objeto se ele deve manter sua rotação original ou sempre de frente para a câmera ou qualquer transformação que esteja impulsionando sua posição.

Vista Radial

O RadialView é outro componente de tag-along que mantém uma parte específica de um GameObject dentro do frustum da visualização do usuário.

As propriedades Min & Max View Degrees determinam quanto de uma parte do GameObject deve estar sempre em exibição.

As propriedades Min & Max Distance determinam a distância que o GameObject deve manter do usuário. Por exemplo, caminhar em direção ao GameObject com uma distância mínima de 1 m empurrará o GameObject para longe para garantir que ele nunca esteja mais perto do que 1 m do usuário.

Geralmente, o é usado com o RadialView Tipo de Destino Rastreado definido para Head que o componente siga o olhar do usuário. No entanto, este componente pode funcionar para ser mantido em "vista" de qualquer tipo de alvo rastreado.

Seguir

A Follow classe posiciona um elemento na frente do destino rastreado em relação ao seu eixo de avanço local. O elemento pode ser vagamente restrito (também conhecido como "tag-along") para que não siga até que o destino rastreado ultrapasse os limites definidos pelo usuário.

Ele funciona de forma semelhante ao solucionador RadialView, com controles adicionais para gerenciar Max Horizontal & Vertical View Degrees e mecanismos para alterar a orientação do objeto.

Entre

A InBetween classe manterá o GameObject anexado entre duas transformações. O próprio SolverHandler Tracked Target Type do GameObject e a InBetween propriedade Second Tracked Target Type do componente definem esses dois pontos de extremidade de transformação. Geralmente, ambos os tipos serão definidos como CustomOverride e os valores e SolverHandler.TransformOverride InBetween.SecondTransformOverride resultantes serão definidos para os dois pontos de extremidade controlados.

O InBetween componente criará outro SolverHandler componente em tempo de execução com base nas propriedades Second Tracked Target Type e Second Transform Override .

Ao longo da linha entre duas transformações, a PartwayOffset define onde o objeto será colocado com 0,5 na metade, 1,0 na primeira transformação e 0,0 na segunda transformação.

SuperfícieMagnetismo

O SurfaceMagnetism funciona executando um raycast contra um conjunto LayerMask de superfícies e colocando o GameObject nesse ponto de contato.

O Deslocamento Normal de Superfície colocará o GameObject a uma distância definida em metros de distância da superfície na direção do normal no ponto de acerto na superfície.

Por outro lado, o Surface Ray Offset colocará o GameObject a uma distância definida em metros de distância da superfície, mas na direção oposta ao raycast realizado. Assim, se o raycast é o olhar do usuário, o GameObject se aproximará ao longo da linha do ponto de acerto na superfície para a câmera.

O Modo de Orientação determina o tipo de rotação a aplicar em relação ao normal na superfície.

  • Nenhum - Sem rotação aplicada
  • TrackedTarget - O objeto enfrentará a transformação rastreada conduzindo o raycast
  • SurfaceNormal - O objeto será alinhado com base no normal no ponto de acerto na superfície
  • Misturado - O objeto será alinhado com base no normal no ponto de acerto na superfície E com base na face da transformação rastreada.

Para forçar o GameObject associado a permanecer vertical em qualquer modo que não seja Nenhum, ative Manter Orientação Vertical.

Nota

Use a propriedade Orientation Blend para controlar o equilíbrio entre os fatores de rotação quando o Modo de Orientação estiver definido como Blended. Um valor de 0,0 terá orientação inteiramente orientada pelo modo TrackedTarget , e um valor de 1,0 terá orientação conduzida inteiramente por SurfaceNormal.

Sobreposição

O Overlap é um solucionador simples que manterá a transformação do objeto na mesma posição e rotação que o destino da SolverHandler's transformação.

Determinar quais superfícies podem ser atingidas

Ao adicionar um SurfaceMagnetism componente a um GameObject, é importante considerar a camada do GameObject e seus filhos, se algum tiver colisores. O componente funciona através da realização de vários raycasts para determinar qual superfície "ímã" se "ímã" contra. Suponha que o solucionador GameObject tenha um colisor em uma das camadas listadas na MagneticSurfaces propriedade de SurfaceMagnetism. Nesse caso, o raycast provavelmente atingirá a si mesmo, resultando no GameObject anexado ao seu próprio ponto de colisão. Esse comportamento estranho pode ser evitado definindo o GameObject principal e todas as crianças para a camada Ignore Ray cast ou modificando a MagneticSurfaces matriz LayerMask adequadamente.

Por outro lado, um SurfaceMagnetism GameObject não colide com superfícies em uma camada não listada MagneticSurfaces na propriedade. Recomendamos que você coloque todas as superfícies desejadas em uma camada dedicada (ou seja, Superfícies) e defina a MagneticSurfaces propriedade apenas para essa camada. Usar o padrão ou tudo pode resultar em componentes ou cursores da interface do usuário contribuindo para o solucionador.

Finalmente, superfícies mais distantes do que a configuração da MaxRaycastDistance propriedade serão ignoradas SurfaceMagnetism pelos raycasts.

Indicador Direcional

A DirectionalIndicator classe é um componente tag-along que se orienta para a direção do ponto desejado no espaço. É mais comumente usado quando o Tipo de Destino Rastreado do SolverHandler está definido como Head. Desta forma, um componente UX com o solucionador DirectionalIndicator direcionará o usuário a olhar para o ponto desejado no espaço. Este ponto é determinado pela propriedade Directional Target .

Se o destino direcional for visível pelo usuário ou qualquer quadro de referência definido no SolverHandler, esse solucionador desativará todos os Renderer componentes abaixo dele. Se não for visível, tudo será ativado no indicador.

O tamanho do indicador diminuirá quanto mais próximo o usuário estiver de capturar o Alvo Direcional em seu FOV.

  • Min Indicator Scale - A escala mínima para o objeto indicador

  • Max Indicator Scale - A escala máxima para o objeto indicador

  • Fator de Escala de Visibilidade - Multiplicador para aumentar ou diminuir o FOV que determina se o ponto de Destino Direcional é visível ou não

  • Deslocamento da visão - Do ponto de vista do quadro de referência (ou seja, câmera possivelmente) e na direção do indicador, essa propriedade define a distância que o objeto está do centro do visor.

Cena de exemplo de indicador direcional (Assets/MRTK/Examples/Demos/Solvers/Scenes/DirectionalIndicatorSolverExample.unity)

Menu de mãos com HandConstraint e HandConstraintPalmUp

O HandConstraint comportamento fornece um solucionador que restringe o objeto rastreado a uma região segura para conteúdo restrito à mão (como interface do usuário manual, menus, etc.) Regiões seguras são consideradas áreas que não se cruzam com a mão. Uma classe derivada de HandConstraint chamada HandConstraintPalmUp também é incluída para demonstrar um comportamento comum de ativação do objeto rastreado pelo solucionador quando a palma está voltada para o usuário.

Consulte a documentação do Menu de mão para obter exemplos de como usar o solucionador de restrições de mão para criar menus de mão.