Partilhar via


Visão geral do Solver — MRTK2

Solver Principal

Solvers são componentes que facilitam os meios de calcular a posição e orientação de um objeto de acordo com um algoritmo predefinido. Um exemplo pode ser colocar um objeto na superfície que o raycast do olhar do usuário atinge atualmente.

Além disso, 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 a um objeto para fazer com que o objeto acompanhe o controlador. Todos os solvers podem ser empilhados com segurança, por exemplo, um comportamento tag-along + magnetismo de superfície + momento.

Como usar um solucionador

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

  • Solver: A classe abstrata base 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 objeto de referência para rastrear (por 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 adequada.

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 alinhar 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: Restringe o objeto a seguir as 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 IMixedRealityHand, mas também funciona com IMixedRealityController.
  • 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 controladores IMixedRealityHand , com outros tipos de controladores este solucionador se comportará exatamente como sua classe base.

Para usar o sistema Solver, basta adicionar 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 raycast 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âmara 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, Esquerda, Direita, Ambas)
  • 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, Esquerda, Direita, Ambas)
    • Use a TrackedHandJoint propriedade para determinar a transformação conjunta a ser utilizada
  • CustomOverride: Ponto de referência do atribuído TransformOverride

Nota

Para ambos os tipos ControllerRay e HandJoint , o manipulador 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.

Objeto rastreado do SolverExemplo de várias propriedades associadas a cada TrackedTargetType

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 que aponta para cima através da palma da mão (ou seja, vetor verde está para cima, vetor azul é para frente).

Vetor Forward Up

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

Rotação adicional

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 calculada, orientação, escala & para 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 são capazes de realizar seus cálculos a partir da variável intermediária. Isso ocorre porque o Unity não permite que as atualizações para 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 GoalPositionGoalRotation e GoalScale as propriedades para os valores desejados. Além disso, é geralmente 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 2m na frente do SolverHandler.TransformTarget. Se o SolverHandler.TrackedTargetType é definido pelo consumidor como Head, então o SolverHandler.TransformTarget será a câmera transformar e, portanto, este Solver colocará o GameObject anexado 2m 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 básico 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 velocidade dessa alteração é determinada pela propriedade LerpTime de cada componente de transformaçã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.

Propriedades do Core Solver
Propriedades comuns herdadas por todos os componentes do Solver

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 na cintura, etc., ao redor de um usuário. Isso é feito modificando as propriedades Local Offset e World Offset . A propriedade Tipo de Orientação determina a rotação aplicada ao objeto se ele deve manter sua rotação original ou sempre de frente para a câmera ou face qualquer transformação que esteja dirigindo sua posição, etc.

Exemplo orbital
Exemplo orbital

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 o tamanho de uma parte do GameObject que 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 1m empurrará o GameObject para longe para garantir que ele nunca esteja mais perto do que 1m do usuário.

Geralmente, o é usado em conjunto 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.

Exemplo de RadialView
Exemplo de RadialView

Seguir

A Follow classe posiciona um elemento na frente do alvo 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 ou Vertical View Degrees, e mecanismos para alterar a orientação do objeto.

Seguir propriedades
Seguir propriedades

Seguir cena de exemplo
Siga a cena de exemplo (Assets/MRTK/Examples/Demos/Solvers/Scenes/FollowSolverExample.unity)

Entre

A InBetween classe manterá o GameObject anexado entre duas transformações. Esses dois pontos de extremidade de transformação são definidos pelo próprio SolverHandler Tipo de Destino Rastreado do GameObject e pela InBetween propriedade Segundo Tipo de Destino Rastreado do componente. Geralmente, ambos os tipos serão definidos como e os valores resultantes SolverHandler.TransformOverride serão InBetween.SecondTransformOverride definidos para CustomOverride os dois pontos de extremidade rastreados.

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

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

Exemplo InBetween
Exemplo de uso do solucionador InBetween para manter o objeto entre duas transformações

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, então 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 totalmente orientada pelo modo TrackedTarget e um valor de 1,0 terá orientação conduzida inteiramente por SurfaceNormal.

Exemplo de SurfaceMagnetism

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 executando vários tipos de raycasts para determinar qual superfície se "ímã" contra. Se o solucionador GameObject tiver um colisor em uma das camadas listadas na MagneticSurfaces propriedade de , então o raycast provavelmente atingirá a si mesmo, resultando no GameObject anexado ao seu próprio ponto de SurfaceMagnetismcolisão. Esse comportamento estranho pode ser evitado definindo o GameObject principal e todas as crianças para a camada Ignore Raycast ou modificando a MagneticSurfaces matriz LayerMask apropriadamente.

Por outro lado, um SurfaceMagnetism GameObject não colidirá com superfícies em uma camada não listada MagneticSurfaces na propriedade. Geralmente recomenda-se colocar todas as superfícies desejadas em uma camada dedicada (ou seja , superfícies) e definir 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 de um ponto desejado no espaço.

Mais comumente usado quando o SolverHandler Tipo de Destino Rastreado do 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.

O ponto desejado no espaço é determinado através da propriedade Directional Target .

Se o destino direcional for visível pelo usuário, ou qualquer quadro de referência definido no SolverHandler, então 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, a câmera possivelmente), esta propriedade define a distância na direção do indicador que o objeto deve estar do centro do visor.

Propriedades do indicador direcional
Propriedades do indicador direcional

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

Menu de mãos com HandConstraint e HandConstraintPalmUp

Exemplo de UX do menu manual

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 do solucionador quando a palma está voltada para o usuário.

Consulte a página Menu de mão para obter exemplos de como usar o solucionador de restrições de mão para criar menus de mãos.

Consulte também