Descrição geral do Solver – MRTK2

Solver Main

Os resolvedores são componentes que facilitam o cálculo da posição de um objeto & orientação de acordo com um algoritmo predefinido. Um exemplo pode estar a colocar um objeto na superfície que o raycast de mira do utilizador atinge atualmente.

Além disso, o sistema Solver define deterministicamente uma ordem de operações para estes cálculos de transformação, uma vez que não existe uma forma fiável de especificar para o Unity a ordem de atualização dos componentes.

Os resolvedores oferecem vários comportamentos para anexar objetos a outros objetos ou sistemas. Um outro exemplo seria um objeto de tag-along que paira sobre a frente do utilizador (com base na câmara). Também pode ser anexado um solver a um controlador e a um objeto para tornar o objeto etiquetado ao longo do controlador. Todos os solucionadores podem ser empilhados com segurança, por exemplo, um comportamento de tag-along + magnetismo da superfície + impulso.

Como utilizar um solver

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

  • Solver: a classe abstrata base da qual todos os resolvedores derivam. Fornece monitorização de estado, suavização de parâmetros e implementação, integração automática do sistema solver e ordem de atualização.
  • SolverHandler: define o objeto de referência para controlar (por exemplo, a transformação da câmara principal, o raio da mão, etc.), processa a recolha de componentes solver e executa a atualização pela ordem adequada.

A terceira categoria é o solver propriamente dito. Os seguintes solucionadores fornecem os blocos modulares para o comportamento básico:

  • Orbital: bloqueia para uma posição especificada e deslocamento do objeto referenciado.
  • ConstantViewSize: dimensiona para manter um tamanho constante em relação à vista do objeto referenciado.
  • RadialView: mantém o objeto dentro de um cone de vista fundido pelo objeto referenciado.
  • Follow: mantém o objeto dentro de um conjunto de limites definidos pelo utilizador do objeto referenciado.
  • InBetween: mantém um objeto entre dois objetos controlados.
  • SurfaceMagnetism: lança raios para superfícies no mundo e alinha o objeto com essa superfície.
  • DirectionalIndicator: determina a posição e a orientação de um objeto como um indicador direcional. A partir do ponto de referência do SolverHandler Tracked Target, este indicador irá orientar-se para o DirectionalTarget fornecido.
  • Momentum: aplica aceleração/velocidade/fricção para simular o impulso e o acionador para um objeto que está a ser movido por outros solucionadores/componentes.
  • HandConstraint: restringe o objeto para seguir as mãos numa região que não intercala o GameObject com as mãos. Útil para conteúdo interativo restrito à mão, como menus, etc. Este solver 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 da mão está virada para o utilizador antes da ativação. Este solver só funciona com controladores IMixedRealityHand , com outros tipos de controlador que este solver irá comportar tal como a sua classe base.

Para utilizar o sistema Solver, basta adicionar um dos componentes listados acima a um GameObject. Uma vez que todos os Solvers necessitam de um SolverHandler, um será criado automaticamente pelo Unity.

Nota

Pode encontrar exemplos de como utilizar o sistema Solvers no ficheiro SolverExamples.scene .

Como alterar a referência de controlo

A propriedade Tipo de Destino Controlado do SolverHandler componente define o ponto de referência que todos os resolvedores utilizarão para calcular os respetivos algoritmos. Por exemplo, um tipo de valor de Head com um componente simples SurfaceMagnetism resultará num raycast da cabeça e na direção do olhar do utilizador para resolver que superfície é atingida. Os valores potenciais da TrackedTargetType propriedade são:

  • Cabeçalho : ponto de referência é a transformação da câmara principal
  • ControllerRay: o ponto de referência é a LinePointer transformação num controlador (ou seja, a origem do ponteiro num controlador de movimento ou controlador manual) que aponta na direção do raio de linha
    • Utilize a TrackedHandedness propriedade para selecionar a preferência de entrega (ou seja, Esquerda, Direita, Ambos)
  • HandJoint: ponto de referência é a transformação de uma articulação manual específica
    • Utilize a TrackedHandedness propriedade para selecionar a preferência de entrega (ou seja, Esquerda, Direita, Ambos)
    • Utilizar a TrackedHandJoint propriedade para determinar a transformação conjunta a utilizar
  • CustomOverride: ponto de referência do atribuído TransformOverride

Nota

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

Solver Tracked ObjectExample of various properties associated with each TrackedTargetType (Exemplo de Objeto Controlado do Solver de várias propriedades associadas a cada TrackedTargetType)

Importante

A maioria dos solucionadores utiliza o vetor de reencaminhamento do destino de transformação controlado fornecido pelo SolverHandler. Ao utilizar um tipo de destino controlado hand joint , o vetor para a frente da articulação da palma da mão pode apontar através dos dedos e não através da palma da mão. Isto depende da plataforma que fornece os dados conjuntos de mãos. Para simulação de entrada e Windows Mixed Reality, é o vetor para cima que aponta para cima através da palma (ou seja, vetor verde está para cima, vetor azul é para a frente).

Vetor Reencaminhar Para Cima

Para ultrapassar esta situação, atualize a propriedade Rotação Adicional no SolverHandler para <90, 0, 0>. Isto garantirá que o vetor de reencaminhamento fornecido aos solucionadores está a apontar através da palma da mão e para fora da mão.

Rotação Adicional

Em alternativa, utilize o tipo de destino controlado pelo Controller Ray para obter um comportamento semelhante para apontar com as mãos.

Como encadear solucionadores

É possível adicionar múltiplos Solver componentes ao mesmo GameObject, encadeando assim os respetivos algoritmos. Os SolverHandler componentes processam a atualização de todos os resolvedores no mesmo GameObject. Por predefinição, as SolverHandler chamadas GetComponents<Solver>() em Início, que devolverão os Solvers pela ordem em que aparecem no inspetor.

Além disso, definir a propriedade Transformação Ligada Atualizada como verdadeira irá instruir que Solver para guardar a sua posição calculada, orientação & dimensionar para uma variável intermediária acessível por todos os Solvers (ou seja GoalPosition, ). Quando for falso, o Solver atualizará diretamente a transformação do GameObject. Ao guardar as propriedades de transformação numa localização intermediária, outros Solvadores são capazes de efetuar os cálculos a partir da variável intermediária. Isto acontece porque o Unity não permite que as atualizações para gameObject.transform se empilhem dentro da mesma moldura.

Nota

Os programadores podem modificar a ordem de execução dos Solvers ao definir a SolverHandler.Solvers propriedade diretamente.

Como criar um novo solver

Todos os solucionadores têm de herdar da classe base abstrata, Solver. Os principais requisitos de uma extensão solver envolvem substituir o SolverUpdate método . Neste método, os programadores devem atualizar as propriedades herdadas GoalPositionGoalRotation e GoalScale para os valores pretendidos. Além disso, é geralmente importante tirar partido SolverHandler.TransformTarget do quadro de referência pretendido pelo consumidor.

O código fornecido abaixo dá um exemplo de um novo componente solver chamado InFront que coloca o objeto anexado 2 m à frente do SolverHandler.TransformTarget. Se o SolverHandler.TrackedTargetType for definido pelo consumidor como Head, será a SolverHandler.TransformTarget transformação da câmara e, portanto, este Solver colocará o GameObject ligado 2 m à frente do olhar dos utilizadores em cada frame.

/// <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 solver

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

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

Se a opção ManterEscala estiver ativada, o Solver utilizará a escala local predefinida do GameObject.

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

Orbital

A Orbital classe é um componente de tag-along que se comporta como planetas num sistema solar. Este Solver irá garantir que o GameObject ligado orbita em torno da transformação registada. Assim, se o Tipo de Destino Controlado do SolverHandler estiver definido como Head, o GameObject irá orbitar à volta da cabeça do utilizador com um desvio fixo aplicado.

Os programadores podem modificar este deslocamento fixo para manter menus ou outros componentes de cena ao nível dos olhos ou ao nível da cintura, etc. em torno de um utilizador. Isto é feito ao modificar as propriedades Desvio Local e Deslocamento Mundial . A propriedade Tipo de Orientação determina a rotação aplicada ao objeto se este deve manter a rotação original ou sempre face à câmara ou face a qualquer transformação que esteja a conduzir a sua posição, etc.

Exemplo Orbital
Exemplo orbital

RadialView

O RadialView é outro componente de tag-along que mantém uma parte específica de um GameObject dentro do resumo da vista do utilizador.

As propriedades Min & Max View Degrees determinam o tamanho de uma parte do GameObject que tem de estar sempre à vista.

As propriedades Distância Máx. & Determina até que ponto o GameObject deve ser mantido do utilizador. Por exemplo, caminhar em direção ao GameObject com uma Distância Mínima de 1 m irá afastar o GameObject para garantir que nunca está mais perto de 1 m para o utilizador.

Geralmente, o RadialView é utilizado em conjunto com o Tipo de Destino Controlado definido para Head que o componente siga o olhar do utilizador. No entanto, este componente pode funcionar para ser mantido na "vista" de qualquer Tipo de Destino Controlado.

Exemplo radialView
Exemplo radialView

Seguir

A Follow classe posiciona um elemento à frente do destino controlado em relação ao eixo de reencaminhamento local. O elemento pode ser limitado vagamente (também conhecido como tag-along) para que não se siga até que o destino controlado se mova para além dos limites definidos pelo utilizador.

Funciona de forma semelhante ao solver RadialView, com controlos adicionais para gerir Os Graus de Vista Horizontal Máxima & Vertical e mecanismos para alterar a Orientação do objeto.

Seguir propriedades
Seguir propriedades

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

InBetween

A InBetween classe manterá o GameObject anexado entre duas transformações. Estes dois pontos finais de transformação são definidos pela propriedade Tipo de Destino Controlado do GameObject SolverHandler e InBetweeno Segundo Tipo de Destino Controlado do componente. Geralmente, ambos os tipos serão definidos como CustomOverride e os valores SolverHandler.TransformOverride resultantes e InBetween.SecondTransformOverride definidos para os dois pontos finais controlados.

No runtime, o InBetween componente irá criar outro SolverHandler componente com base nas propriedades Segundo Tipo de Destino Controlado e Segunda Substituição de Transformação .

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

Exemplo InBetween
Exemplo de utilização do Solver InBetween para manter o objeto entre duas transformações

SurfaceMagnetismo

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

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

Por outro lado, o Surface Ray Offset colocará o GameObject a uma distância definida a metros da superfície, mas na direção oposta do raycast realizado. Assim, se o raycast for o olhar do utilizador, o GameObject irá aproximar-se ao longo da linha do ponto de acesso da superfície para a câmara.

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

  • Nenhum - Nenhuma rotação aplicada
  • TrackedTarget - O objeto enfrentará a transformação registada que conduz o raycast
  • SurfaceNormal – o objeto será alinhado com base no normal no ponto de acesso à superfície
  • Blended - O objeto será alinhado com base no normal no ponto de impacto na superfície E com base na transformação registada.

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

Nota

Utilize a propriedade Mistura de Orientação para controlar o equilíbrio entre fatores de rotação quando o Modo de Orientação está definido como Misturado. Um valor de 0,0 terá uma orientação totalmente orientada pelo modo TrackedTarget e um valor de 1,0 terá orientação totalmente orientada pelo SurfaceNormal.

Exemplo de SurfaceMagnetism

Determinar que superfícies podem ser atingidas

Ao adicionar um SurfaceMagnetism componente a um GameObject, é importante considerar a camada do GameObject e dos respetivos filhos, caso existam colisões. O componente funciona ao executar vários tipos de raycasts para determinar em que superfície se deve "íman". Se o solver GameObject tiver um colisor numa das camadas listadas na MagneticSurfaces propriedade de SurfaceMagnetism, o raycast provavelmente irá atingir-se a si próprio, resultando na anexação do GameObject ao seu próprio ponto de colisão. Este comportamento estranho pode ser evitado ao definir o GameObject principal e todas as crianças para a camada Ignorar Raycast ou modificar adequadamente a MagneticSurfaces matriz LayerMask.

Por outro lado, um SurfaceMagnetism GameObject não irá colidir com superfícies numa camada não listada na MagneticSurfaces propriedade. Geralmente, é recomendado colocar todas as superfícies pretendidas numa camada dedicada (ou seja , Surfaces) e definir a MagneticSurfaces propriedade como apenas esta camada. A utilização predefinida ou tudo pode resultar na contribuição de componentes ou cursores de IU para o solver.

Por fim, as superfícies mais distantes do que a definição da MaxRaycastDistance propriedade serão ignoradas pelos SurfaceMagnetism raycasts.

DirectionalIndicator

A DirectionalIndicator classe é um componente de tag-along que se orienta para a direção de um ponto no espaço pretendido.

Mais frequentemente utilizado quando o Tipo de Destino Controlado do SolverHandler está definido como Head. Desta forma, um componente UX com o DirectionalIndicator solver irá direcionar um utilizador para olhar para o ponto no espaço pretendido.

O ponto pretendido no espaço é determinado através da propriedade Destino Direcional .

Se o destino direcional for visualizável pelo utilizador ou se o fotograma de referência estiver definido no SolverHandler, este solver desativará todos os Renderer componentes por baixo do mesmo. Se não for visualizável, tudo será ativado no indicador.

O tamanho do indicador diminuirá quanto mais próximo o utilizador estiver de capturar o Destino Direcional no respetivo FOV.

  • Escala mínima de Indicadores – a escala mínima para o objeto indicador

  • Escala Máxima de Indicadores - 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 é visualizável ou não

  • Desvio de Vista – do ponto de vista da moldura de referência (ou seja, câmara possivelmente), esta propriedade define a distância na direção do indicador se o objeto estiver no centro do viewport.

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 manual com HandConstraint e HandConstraintPalmUp

Exemplo de UX do Menu Manual

O HandConstraint comportamento fornece um solver que restringe o objeto controlado a uma região segura para conteúdo restrito à mão (como IU manual, menus, etc.). As 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 ativar o objeto controlado pelo solver quando a palma da mão está virada para o utilizador.

Veja a página Menu Manual para obter os exemplos de utilização do solver Hand Constraint para criar menus mano.

Ver também