Solvers — MRTK3
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 comXRNode
.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 comXRNode
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)
- Use a
- 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
- Use a
- 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
, GoalRotation
e 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.