Visão geral do Solver — MRTK2
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)
- 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, Esquerda, Direita, Ambas) - 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 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.
Exemplo 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).
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.
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 GoalPosition
GoalRotation
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 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
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
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
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 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.
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 SurfaceMagnetism
colisã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
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 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.