Entrada MR 213: Comandos de movimento
Nota
Os tutoriais Mixed Reality Academy foram concebidos com o HoloLens (1.ª geração) e Mixed Reality Headsets Envolventes em mente. Como tal, consideramos importante deixar estes tutoriais em vigor para os programadores que ainda estão à procura de orientação no desenvolvimento desses dispositivos. Estes tutoriais não serão atualizados com os conjuntos de ferramentas ou interações mais recentes que estão a ser utilizados para HoloLens 2. Serão mantidas para continuarem a trabalhar nos dispositivos suportados. Foi publicada uma nova série de tutoriais para HoloLens 2.
Os comandos de movimento no mundo da realidade mista adicionam outro nível de interatividade. Com os comandos de movimento, podemos interagir diretamente com objetos de uma forma mais natural, semelhante às nossas interações físicas na vida real, aumentando a imersão e o prazer na sua experiência de aplicação.
No MR Input 213, vamos explorar os eventos de entrada do controlador de movimento criando uma experiência de pintura espacial simples. Com esta aplicação, os utilizadores podem pintar num espaço tridimensional com vários tipos de pincéis e cores.
Tópicos abordados neste tutorial
Visualização do controlador | Eventos de entrada do controlador | Controlador personalizado e IU |
Saiba como compor modelos de comando de movimento no modo de jogo e runtime do Unity. | Compreenda os diferentes tipos de eventos de botões e as respetivas aplicações. | Saiba como sobrepor elementos da IU na parte superior do controlador ou personalizá-los completamente. |
Suporte de dispositivos
Curso | HoloLens | Headsets envolventes |
---|---|---|
Entrada MR 213: Comandos de movimento | ✔️ |
Antes de começar
Pré-requisitos
Veja a lista de verificação de instalação para auscultadores envolventes nesta página.
- Este tutorial requer o Unity 2017.2.1p2
Ficheiros de projeto
- Transfira os ficheiros necessários para o projeto e extraia os ficheiros para o Ambiente de Trabalho.
Nota
Se quiser ver o código fonte antes de transferir, este estará disponível no GitHub.
Configuração do Unity
Objetivos
- Otimizar o Unity para desenvolvimento de Windows Mixed Reality
- Configurar a Câmara Mixed Reality
- Ambiente de configuração
Instruções
Inicie o Unity.
Selecione Abrir.
Navegue para o seu Ambiente de Trabalho e localize a pasta mestra MixedReality213 que ansiou anteriormente.
Clique em Selecionar Pasta.
Assim que o Unity concluir o carregamento de ficheiros do projeto, poderá ver o editor do Unity.
No Unity, selecione Definições de Compilação de Ficheiros>.
Selecione Plataforma Universal do Windows na lista Plataforma e clique no botão Mudar de Plataforma.
Definir Dispositivo de Destino como Qualquer dispositivo
Definir o Tipo de Compilação como D3D
Definir o SDK como Instalado Mais Recente
Verificar Projetos C# do Unity
- Isto permite-lhe modificar ficheiros de script no projeto do Visual Studio sem reconstruir o projeto do Unity.
Clique em Definições do Leitor.
No painel Inspetor , desloque-se para baixo até à parte inferior
Nas Definições XR, verifique a Realidade Virtual Suportada
Em SDKs de Realidade Virtual, selecione Windows Mixed Reality
Feche a janela Definições de Compilação .
Estrutura do projeto
Este tutorial utiliza Mixed Reality Toolkit – Unity. Pode encontrar as versões nesta página.
Cenas concluídas para referência
- Encontrará duas cenas do Unity concluídas na pasta Cenas .
- MixedReality213: Cena concluída com pincel único
- MixedReality213Advanced: cenário concluído para design avançado com vários pincéis
Configuração de Nova Cena para o tutorial
No Unity, clique em Arquivar > Nova Cena
Eliminar Câmara Principal e Luz Direcional
No painel Projeto, pesquise e arraste as seguintes prefabs para o painel Hierarquia :
- Assets/HoloToolkit/Input/Prefabs/MixedRealityCamera
- Recursos/AppPrefabs/Ambiente
Existem duas pré-tarefas de câmara no Mixed Reality Toolkit:
- MixedRealityCamera.prefab: Apenas câmara
- MixedRealityCameraParent.prefab: Câmara + Teletransporte + Limite
- Neste tutorial, vamos utilizar a funcionalidade MixedRealityCamera sem teletransporte. Por este motivo, adicionámos uma prefab ambiente simples que contém um piso básico para fazer com que o utilizador se sinta de castigo.
- Para saber mais sobre a teletransporte com MixedRealityCameraParent, veja Advanced design - Teleportation and locomotion (Design avançado – Teleportação e locomoção)
Configuração do Skybox
Clique em Definições de Iluminação > da Janela >
Clique no círculo no lado direito do campo Material do Skybox
Escreva "cinzento" e selecione SkyboxGray (Assets/AppPrefabs/Support/Materials/SkyboxGray.mat)
Selecione a opção Skybox para ver o skybox de gradação cinzento atribuído
A cena com MixedRealityCamera, Ambiente e skybox cinzento terá este aspeto.
Clique em Cena guardar ficheiro > como
Guardar a cena na pasta Cenas com qualquer nome
Capítulo 1 - Visualização do controlador
Objetivos
- Saiba como compor modelos de comando de movimento no modo de jogo do Unity e no runtime.
Windows Mixed Reality fornece um modelo de controlador animado para a visualização do controlador. Existem várias abordagens que pode adotar para a visualização do controlador na sua aplicação:
- Predefinição – utilizar o controlador predefinido sem modificação
- Híbrido – utilizar o controlador predefinido, mas personalizar alguns dos respetivos elementos ou sobrepor componentes da IU
- Substituição – utilizar o seu próprio modelo 3D personalizado para o controlador
Neste capítulo, vamos saber mais sobre os exemplos destas personalizações do controlador.
Instruções
- No painel Projeto , escreva MotionControllers na caixa de pesquisa . Também pode encontrá-lo em Assets/HoloToolkit/Input/Prefabs/.
- Arraste a prefab MotionControllers para o painel Hierarquia .
- Clique na prefab MotionControllers no painel Hierarquia .
Pré-criação de MotionControllers
O motionControllers prefab tem um script MotionControllerVisualizer que fornece os blocos para modelos de controlador alternativos. Se atribuir os seus próprios modelos 3D personalizados, como uma mão ou uma espada, e verificar "Utilizar Sempre Modelo Alternativo à Esquerda/Direita", irá vê-los em vez do modelo predefinido. Vamos utilizar este bloco no Capítulo 4 para substituir o modelo do controlador por um pincel.
Instruções
- No painel Inspetor , faça duplo clique em MotionControllerVisualizer script para ver o código no Visual Studio
Script MotionControllerVisualizer
As classes MotionControllerVisualizer e MotionControllerInfo fornecem os meios para aceder & modificar os modelos de controlador predefinidos. MotionControllerVisualizer subscreve o evento InteractionSourceDetected do Unity e instancia automaticamente os modelos de controlador quando são encontrados.
protected override void Awake()
{
...
InteractionManager.InteractionSourceDetected += InteractionManager_InteractionSourceDetected;
InteractionManager.InteractionSourceLost += InteractionManager_InteractionSourceLost;
...
}
Os modelos de controlador são fornecidos de acordo com a especificação glTF. Este formato foi criado para fornecer um formato comum, ao mesmo tempo que melhora o processo subjacente à transmissão e desempacotamento de recursos 3D. Neste caso, precisamos de obter e carregar os modelos de controlador no runtime, pois queremos tornar a experiência do utilizador o mais perfeita possível e não é garantido qual a versão dos controladores de movimento que o utilizador poderá estar a utilizar. Este curso, através do Mixed Reality Toolkit, utiliza uma versão do projeto UnityGLTF do Grupo Khronos.
Depois de o controlador ser entregue, os scripts podem utilizar MotionControllerInfo para encontrar as transformações para elementos específicos do controlador para que possam posicionar-se corretamente.
Num capítulo posterior, vamos aprender a utilizar estes scripts para anexar elementos de IU aos controladores.
Em alguns scripts, encontrará blocos de código com #if ! UNITY_EDITOR ou UNITY_WSA. Estes blocos de código são executados apenas no runtime UWP quando implementa no Windows. Isto deve-se ao facto de o conjunto de APIs utilizado pelo editor do Unity e o runtime da aplicação UWP serem diferentes.
- Guarde a cena e clique no botão reproduzir .
Poderá ver a cena com comandos de movimento nos auscultadores. Pode ver animações detalhadas para cliques de botões, movimento de manípulo e realce do toque do touchpad.
Capítulo 2 – Anexar elementos da IU ao controlador
Objetivos
- Saiba mais sobre os elementos dos comandos de movimento
- Saiba como anexar objetos a partes específicas dos controladores
Neste capítulo, irá aprender a adicionar elementos de interface de utilizador ao controlador aos quais o utilizador pode aceder e manipular facilmente em qualquer altura. Também irá aprender a adicionar uma IU do seletor de cores simples com a entrada do touchpad.
Instruções
- No painel Projeto , procure script MotionControllerInfo .
- No resultado da pesquisa, faça duplo clique no script MotionControllerInfo para ver o código no Visual Studio.
Script MotionControllerInfo
O primeiro passo é escolher o elemento do controlador ao qual pretende anexar a IU. Estes elementos são definidos em ControllerElementEnum em MotionControllerInfo.cs.
- Base
- Menu
- Compreender
- Manípulo
- Selecionar
- Touchpad
- Pose a apontar – este elemento representa a ponta do controlador que aponta para a direção para a frente.
Instruções
- No painel Projeto , procure script AttachToController .
- No resultado da pesquisa, faça duplo clique no script AttachToController para ver o código no Visual Studio.
Script AttachToController
O script AttachToController fornece uma forma simples de anexar quaisquer objetos a um elemento e entrega de controladores especificados.
Em AttachElementToController(),
- Verificar a entrega com MotionControllerInfo.Handedness
- Obter um elemento específico do controlador com MotionControllerInfo.TryGetElement()
- Depois de obter a transformação do elemento do modelo de controlador, coloque o objeto principal por baixo do mesmo e defina a posição local do objeto & rotação como zero.
public MotionControllerInfo.ControllerElementEnum Element { get { return element; } }
private void AttachElementToController(MotionControllerInfo newController)
{
if (!IsAttached && newController.Handedness == handedness)
{
if (!newController.TryGetElement(element, out elementTransform))
{
Debug.LogError("Unable to find element of type " + element + " under controller " + newController.ControllerParent.name + "; not attaching.");
return;
}
controller = newController;
SetChildrenActive(true);
// Parent ourselves under the element and set our offsets
transform.parent = elementTransform;
transform.localPosition = positionOffset;
transform.localEulerAngles = rotationOffset;
if (setScaleOnAttach)
{
transform.localScale = scale;
}
// Announce that we're attached
OnAttachToController();
IsAttached = true;
}
}
A forma mais simples de utilizar o script AttachToController é herdar do mesmo, como fizemos no caso do ColorPickerWheel. Basta substituir as funções OnAttachToController e OnDetachFromController para efetuar a configuração/divisão quando o controlador for detetado/desligado.
Instruções
- No painel Projeto , escreva na caixa de pesquisa ColorPickerWheel. Também pode encontrá-lo em Ativos/AppPrefabs/.
- Arraste ColorPickerWheel prefab para o painel Hierarquia .
- Clique na prefab ColorPickerWheel no painel Hierarquia .
- No painel Inspetor , faça duplo clique em ColorPickerWheel Script para ver o código no Visual Studio.
Script ColorPickerWheel
Uma vez que ColorPickerWheel herda AttachToController, mostra Handedness e Element no painel Inspetor . Vamos anexar a IU ao elemento Touchpad no controlador esquerdo.
ColorPickerWheel substitui OnAttachToController e OnDetachFromController para subscrever o evento de entrada que será utilizado no próximo capítulo para seleção de cores com entrada do touchpad.
public class ColorPickerWheel : AttachToController, IPointerTarget
{
protected override void OnAttachToController()
{
// Subscribe to input now that we're parented under the controller
InteractionManager.InteractionSourceUpdated += InteractionSourceUpdated;
}
protected override void OnDetachFromController()
{
Visible = false;
// Unsubscribe from input now that we've detached from the controller
InteractionManager.InteractionSourceUpdated -= InteractionSourceUpdated;
}
...
}
- Guarde a cena e clique no botão reproduzir .
Método alternativo para anexar objetos aos controladores
Recomendamos que os scripts herdem de AttachToController e substituam OnAttachToController. No entanto, isto pode nem sempre ser possível. Uma alternativa é utilizá-lo como um componente autónomo. Isto pode ser útil quando quer anexar uma pré-base existente a um controlador sem refatorizar os scripts. Basta que a sua turma aguarde que IsAttached seja definido como verdadeiro antes de efetuar qualquer configuração. A forma mais simples de o fazer é utilizando um coroutine para "Iniciar".
private IEnumerator Start() {
AttachToController attach = gameObject.GetComponent<AttachToController>();
while (!attach.IsAttached) {
yield return null;
}
// Perform setup here
}
Capítulo 3 - Trabalhar com a entrada do touchpad
Objetivos
- Saiba como obter eventos de dados de entrada do touchpad
- Saiba como utilizar as informações de posição do eixo do touchpad para a sua experiência de aplicação
Instruções
- No painel Hierarquia , clique em ColorPickerWheel
- No painel Inspetor , em Animator, faça duplo clique em ColorPickerWheelController
- Poderá ver o separador Animator aberto
Mostrar/ocultar a IU com o controlador de Animação do Unity
Para mostrar e ocultar a IU colorPickerWheel com animação, estamos a utilizar o sistema de animação do Unity. Definir a propriedade Visível de ColorPickerWheel como acionadores verdadeiros ou falsos Mostrar e Ocultar acionadores de animação. Os parâmetros Mostrar e Ocultar são definidos no controlador de animação ColorPickerWheelController .
Instruções
- No painel Hierarquia , selecione ColorPickerWheel prefab
- No painel Inspetor , faça duplo clique em ColorPickerWheel script para ver o código no Visual Studio
Script ColorPickerWheel
ColorPickerWheel subscreve o evento InteractionSourceUpdated do Unity para escutar eventos do touchpad.
Em InteractionSourceUpdated(), o script verifica primeiro para garantir que:
- é, na verdade, um evento do touchpad (obj.state.touchpadTouched)
- tem origem no controlador esquerdo (obj.state.source.mão de mão)
Se ambos forem verdadeiros, a posição do touchpad (obj.state.touchpadPosition) é atribuído a selectorPosition.
private void InteractionSourceUpdated(InteractionSourceUpdatedEventArgs obj)
{
if (obj.state.source.handedness == handedness && obj.state.touchpadTouched)
{
Visible = true;
selectorPosition = obj.state.touchpadPosition;
}
}
Em Update(), com base na propriedade visível , aciona acionadores Mostrar e Ocultar animações no componente de animador do selecionador de cores
if (visible != visibleLastFrame)
{
if (visible)
{
animator.SetTrigger("Show");
}
else
{
animator.SetTrigger("Hide");
}
}
Em Update(), selectorPosition é utilizado para lançar um raio no colisor de malha da roda de cores, que devolve uma posição UV. Esta posição pode então ser utilizada para encontrar a coordenada de píxel e o valor de cor da textura da roda de cor. Este valor é acessível a outros scripts através da propriedade SelectedColor .
...
// Clamp selector position to a radius of 1
Vector3 localPosition = new Vector3(selectorPosition.x * inputScale, 0.15f, selectorPosition.y * inputScale);
if (localPosition.magnitude > 1)
{
localPosition = localPosition.normalized;
}
selectorTransform.localPosition = localPosition;
// Raycast the wheel mesh and get its UV coordinates
Vector3 raycastStart = selectorTransform.position + selectorTransform.up * 0.15f;
RaycastHit hit;
Debug.DrawLine(raycastStart, raycastStart - (selectorTransform.up * 0.25f));
if (Physics.Raycast(raycastStart, -selectorTransform.up, out hit, 0.25f, 1 << colorWheelObject.layer, QueryTriggerInteraction.Ignore))
{
// Get pixel from the color wheel texture using UV coordinates
Vector2 uv = hit.textureCoord;
int pixelX = Mathf.FloorToInt(colorWheelTexture.width * uv.x);
int pixelY = Mathf.FloorToInt(colorWheelTexture.height * uv.y);
selectedColor = colorWheelTexture.GetPixel(pixelX, pixelY);
selectedColor.a = 1f;
}
// Set the selector's color and blend it with white to make it visible on top of the wheel
selectorRenderer.material.color = Color.Lerp (selectedColor, Color.white, 0.5f);
}
Capítulo 4 – Substituir o modelo de controlador
Objetivos
- Saiba como substituir o modelo de controlador por um modelo 3D personalizado.
Instruções
- Clique em MotionControllers no painel Hierarquia .
- Clique no círculo no lado direito do campo Comando Alternativo à Direita .
- Escreva "BrushController" e selecione a pré-fab no resultado. Pode encontrá-la em Assets/AppPrefabs/BrushController.
- Verificar utilizar sempre o modelo alternativo à direita
A prefab BrushController não tem de ser incluída no painel Hierarquia . No entanto, para dar saída dos componentes subordinados:
- No painel Projeto , escreva BrushController e arraste BrushController prefab para o painel Hierarquia .
Encontrará o componente Sugestão em BrushController. Vamos utilizar a sua transformação para iniciar/parar linhas de desenho.
- Elimine o BrushController do painel Hierarquia .
- Guarde a cena e clique no botão reproduzir . Poderá ver que o modelo do pincel substituiu o comando de movimento do lado direito.
Capítulo 5 - Pintar com Selecionar entrada
Objetivos
- Saiba como utilizar o evento do botão Selecionar para iniciar e parar um desenho de linha
Instruções
- Pesquise brushController prefab no painel Projeto .
- No painel Inspetor , faça duplo clique em BrushController Script para ver o código no Visual Studio
Script BrushController
BrushController subscreve os eventos InteractionSourcePressed e InteractionSourceReleased do InteractionManager. Quando o evento InteractionSourcePressed é acionado, a propriedade Desenhar do pincel é definida como verdadeira; quando o evento InteractionSourceReleased é acionado , a propriedade Desenhar do pincel é definida como falsa.
private void InteractionSourcePressed(InteractionSourcePressedEventArgs obj)
{
if (obj.state.source.handedness == InteractionSourceHandedness.Right && obj.pressType == InteractionSourcePressType.Select)
{
Draw = true;
}
}
private void InteractionSourceReleased(InteractionSourceReleasedEventArgs obj)
{
if (obj.state.source.handedness == InteractionSourceHandedness.Right && obj.pressType == InteractionSourcePressType.Select)
{
Draw = false;
}
}
Enquanto Desenhar está definido como verdadeiro, o pincel irá gerar pontos num LineRenderer do Unity instanciado. Uma referência a esta pré-fab é mantida no campo Prefab de Traço do pincel.
private IEnumerator DrawOverTime()
{
// Get the position of the tip
Vector3 lastPointPosition = tip.position;
...
// Create a new brush stroke
GameObject newStroke = Instantiate(strokePrefab);
LineRenderer line = newStroke.GetComponent<LineRenderer>();
newStroke.transform.position = startPosition;
line.SetPosition(0, tip.position);
float initialWidth = line.widthMultiplier;
// Generate points in an instantiated Unity LineRenderer
while (draw)
{
// Move the last point to the draw point position
line.SetPosition(line.positionCount - 1, tip.position);
line.material.color = colorPicker.SelectedColor;
brushRenderer.material.color = colorPicker.SelectedColor;
lastPointAddedTime = Time.unscaledTime;
// Adjust the width between 1x and 2x width based on strength of trigger pull
line.widthMultiplier = Mathf.Lerp(initialWidth, initialWidth * 2, width);
if (Vector3.Distance(lastPointPosition, tip.position) > minPositionDelta || Time.unscaledTime > lastPointAddedTime + maxTimeDelta)
{
// Spawn a new point
lastPointAddedTime = Time.unscaledTime;
lastPointPosition = tip.position;
line.positionCount += 1;
line.SetPosition(line.positionCount - 1, lastPointPosition);
}
yield return null;
}
}
Para utilizar a cor atualmente selecionada da IU da roda do selecionador de cores, BrushController tem de ter uma referência ao objeto ColorPickerWheel . Uma vez que a prefab BrushController é instanciada no runtime como um controlador de substituição, todas as referências aos objetos na cena terão de ser definidas no runtime. Neste caso, utilizamos GameObject.FindObjectOfType para localizar o ColorPickerWheel:
private void OnEnable()
{
// Locate the ColorPickerWheel
colorPicker = FindObjectOfType<ColorPickerWheel>();
// Assign currently selected color to the brush’s material color
brushRenderer.material.color = colorPicker.SelectedColor;
...
}
- Guarde a cena e clique no botão reproduzir . Poderá desenhar as linhas e pintar com o botão selecionar no comando direito.
Capítulo 6 – Desova de objetos com Selecionar entrada
Objetivos
- Saiba como utilizar eventos de entrada do botão Selecionar e Agarrar
- Saiba como instanciar objetos
Instruções
No painel Projeto , escreva ObjectSpawner na caixa de pesquisa. Também pode encontrá-lo em Ativos/AppPrefabs/
Arraste a prefab ObjectSpawner para o painel Hierarquia .
Clique em ObjectSpawner no painel Hierarquia .
ObjectSpawner tem um campo denominado Origem da Cor.
No painel Hierarquia , arraste a referência ColorPickerWheel para este campo.
Clique na prefab ObjectSpawner no painel Hierarquia .
No painel Inspetor , faça duplo clique em ObjectSpawner Script para ver o código no Visual Studio.
Script ObjectSpawner
O ObjectSpawner instancia cópias de uma malha primitiva (cubo, esfera, cilindro) para o espaço. Quando é detetada uma InteractionSourcePressed , verifica a entrega e se é um evento InteractionSourcePressType.Grasp ou InteractionSourcePressType.Select .
Para um evento do Grasp , incrementa o índice do tipo de malha atual (esfera, cubo, cilindro)
private void InteractionSourcePressed(InteractionSourcePressedEventArgs obj)
{
// Check handedness, see if it is left controller
if (obj.state.source.handedness == handedness)
{
switch (obj.pressType)
{
// If it is Select button event, spawn object
case InteractionSourcePressType.Select:
if (state == StateEnum.Idle)
{
// We've pressed the grasp - enter spawning state
state = StateEnum.Spawning;
SpawnObject();
}
break;
// If it is Grasp button event
case InteractionSourcePressType.Grasp:
// Increment the index of current mesh type (sphere, cube, cylinder)
meshIndex++;
if (meshIndex >= NumAvailableMeshes)
{
meshIndex = 0;
}
break;
default:
break;
}
}
}
Para um evento Select , em SpawnObject(), um novo objeto é instanciado, não parentado e lançado no mundo.
private void SpawnObject()
{
// Instantiate the spawned object
GameObject newObject = Instantiate(displayObject.gameObject, spawnParent);
// Detach the newly spawned object
newObject.transform.parent = null;
// Reset the scale transform to 1
scaleParent.localScale = Vector3.one;
// Set its material color so its material gets instantiated
newObject.GetComponent<Renderer>().material.color = colorSource.SelectedColor;
}
O ObjectSpawner utiliza o ColorPickerWheel para definir a cor do material do objeto de apresentação. Os objetos gerados recebem uma instância deste material para que estes mantenham a cor.
- Guarde a cena e clique no botão reproduzir .
Poderá alterar os objetos com o botão Agarrar e gerar objetos com o botão Selecionar.
Criar e implementar aplicações no Portal do Mixed Reality
- No Unity, selecione Definições de Compilação de Ficheiros>.
- Clique em Adicionar Cenas Abertas para adicionar a cena atual às Cenas na Compilação.
- Clique em Compilar.
- Crie uma Nova Pasta com o nome "Aplicação".
- Clique apenas na pasta Aplicação .
- Clique em Selecionar Pasta.
- Quando o Unity estiver concluído, será apresentada uma janela de Explorador de Ficheiros.
- Abra a pasta Aplicação .
- Faça duplo clique no ficheiro YourSceneName.sln Visual Studio Solution.
- Com a barra de ferramentas superior no Visual Studio, altere o destino de Depuração para Versão e de ARM para X64.
- Clique na seta pendente junto ao botão Dispositivo e selecione Máquina Local.
- Clique em Depurar –> Iniciar Sem depuração no menu ou prima Ctrl + F5.
Agora, a aplicação foi criada e instalada no Portal do Mixed Reality. Pode iniciá-la novamente através do menu Iniciar no Portal do Mixed Reality.
Design avançado - Ferramentas de pincel com esquema radial
Neste capítulo, irá aprender a substituir o modelo de controlador de movimento predefinido por uma coleção personalizada de ferramentas de pincel. Para sua referência, pode encontrar a cena concluída MixedReality213Adicionada na pasta Cenas .
Instruções
No painel Projeto , escreva BrushSelector na caixa de pesquisa . Também pode encontrá-lo em Ativos/AppPrefabs/
Arraste a pré-base BrushSelector para o painel Hierarquia .
Para a organização, crie um GameObject vazio chamado Brushes
Arraste as seguintes pré-tarefas do painel Project para Brushes
- Recursos/AppPrefabs/BrushFat
- Recursos/AppPrefabs/BrushThin
- Recursos/AppPrefabs/Borracha
- Assets/AppPrefabs/MarkerFat
- Recursos/AppPrefabs/MarkerThin
- Recursos/AppPrefabs/Pencil
Clique em MotionControllers prefab no painel Hierarquia .
No painel Inspetor , desmarque Utilizar Sempre Modelo Alternativo à Direita no Visualizador do Controlador de Movimento
No painel Hierarquia , clique em PincelEletor
BrushSelector tem um campo chamado ColorPicker
No painel Hierarquia , arraste ColorPickerWheel para o campo ColorPicker no painel Inspetor .
No painel Hierarquia , em BrushSelector prefab, selecione o objeto Menu .
No painel Inspetor , no componente LineObjectCollection , abra a lista pendente Matriz de objetos . Verá 6 blocos vazios.
No painel Hierarquia , arraste cada um dos pré-fabricados parentados por baixo de Brushes GameObject para estes blocos por qualquer ordem. (Certifique-se de que está a arrastar os pré-fabricados do local, não os pré-fabricados na pasta do projeto.)
BrushSelector prefab
Uma vez que BrushSelector herda AttachToController, mostra as opções Handedness e Element no painel Inspetor . Selecionámos Right e Pointing Pose para anexar as ferramentas de pincel ao comando do lado direito com a direção para a frente.
O BrushSelector utiliza dois utilitários:
- Reticências: utilizada para gerar pontos no espaço ao longo de uma forma de reticências.
- LineObjectCollection: distribui objetos com os pontos gerados por qualquer classe de Linha (por exemplo, Reticências). Isto é o que vamos utilizar para colocar os nossos pincéis ao longo da forma de Elipse.
Quando combinados, estes utilitários podem ser utilizados para criar um menu radial.
Script LineObjectCollection
LineObjectCollection tem controlos para o tamanho, posição e rotação de objetos distribuídos ao longo da linha. Isto é útil para criar menus radiais como o seletor de pincel. Para criar o aspeto dos pincéis que se aproximam do nada à medida que se aproximam da posição selecionada pelo centro, a curva ObjectScale atinge o pico no centro e os tapers desativados nas margens.
Script BrushSelector
No caso do BrushSelector, optámos por utilizar animações processuais. Primeiro, os modelos de pincel são distribuídos numa reticência pelo script LineObjectCollection . Em seguida, cada pincel é responsável por manter a sua posição na mão do utilizador com base no respetivo valor DisplayMode , que é alterado com base na seleção. Escolhemos uma abordagem processual devido à elevada probabilidade de as transições de posição do pincel serem interrompidas à medida que o utilizador seleciona pincéis. As animações mecanim podem processar as interrupções corretamente, mas tendem a ser mais complicadas do que uma simples operação Lerp.
BrushSelector utiliza uma combinação de ambos. Quando a entrada do touchpad é detetada, as opções do pincel ficam visíveis e verticalmente ao longo do menu radial. Após um período de tempo limite (que indica que o utilizador fez uma seleção), as opções do pincel voltam a reduzir verticalmente, deixando apenas o pincel selecionado.
Visualizar a entrada do touchpad
Mesmo nos casos em que o modelo do controlador foi completamente substituído, pode ser útil mostrar entradas nas entradas do modelo original. Isto ajuda a basear as ações do utilizador na realidade. Para o BrushSelector , optámos por tornar o touchpad brevemente visível quando a entrada é recebida. Isto foi feito ao obter o elemento Touchpad do controlador, substituindo o respetivo material por um material personalizado e, em seguida, aplicando uma gradação à cor desse material com base na última vez que a entrada do touchpad foi recebida.
protected override void OnAttachToController()
{
// Turn off the default controller's renderers
controller.SetRenderersVisible(false);
// Get the touchpad and assign our custom material to it
Transform touchpad;
if (controller.TryGetElement(MotionControllerInfo.ControllerElementEnum.Touchpad, out touchpad))
{
touchpadRenderer = touchpad.GetComponentInChildren<MeshRenderer>();
originalTouchpadMaterial = touchpadRenderer.material;
touchpadRenderer.material = touchpadMaterial;
touchpadRenderer.enabled = true;
}
// Subscribe to input now that we're parented under the controller
InteractionManager.InteractionSourceUpdated += InteractionSourceUpdated;
}
private void Update()
{
...
// Update our touchpad material
Color glowColor = touchpadColor.Evaluate((Time.unscaledTime - touchpadTouchTime) / touchpadGlowLossTime);
touchpadMaterial.SetColor("_EmissionColor", glowColor);
touchpadMaterial.SetColor("_Color", glowColor);
...
}
Seleção de ferramentas de pincel com entrada do touchpad
Quando o seletor de pincel deteta a entrada premida do touchpad, verifica a posição da entrada para determinar se se encontrava à esquerda ou à direita.
Espessura do traço com selectPressedAmount
Em vez do evento InteractionSourcePressType.Select no InteractionSourcePressed(), pode obter o valor analógico da quantidade premida através de selectPressedAmount. Este valor pode ser obtido em InteractionSourceUpdated().
private void InteractionSourceUpdated(InteractionSourceUpdatedEventArgs obj)
{
if (obj.state.source.handedness == handedness)
{
if (obj.state.touchpadPressed)
{
// Check which side we clicked
if (obj.state.touchpadPosition.x < 0)
{
currentAction = SwipeEnum.Left;
}
else
{
currentAction = SwipeEnum.Right;
}
// Ping the touchpad material so it gets bright
touchpadTouchTime = Time.unscaledTime;
}
if (activeBrush != null)
{
// If the pressed amount is greater than our threshold, draw
if (obj.state.selectPressedAmount >= selectPressedDrawThreshold)
{
activeBrush.Draw = true;
activeBrush.Width = ProcessSelectPressedAmount(obj.state.selectPressedAmount);
}
else
{
// Otherwise, stop drawing
activeBrush.Draw = false;
selectPressedSmooth = 0f;
}
}
}
}
Script de borracha
Borracha é um tipo especial de pincel que substitui a função DrawOverTime() do Pincel base. Enquanto Desenhar é verdadeiro, a borracha verifica se a ponta se cruza com traços de pincel existentes. Se for o caso, são adicionados a uma fila para serem reduzidas e eliminadas.
Design avançado - Teletransportação e locomoção
Se quiser permitir que o utilizador se mova na cena com teletransporte com o thumbstick, utilize MixedRealityCameraParent em vez de MixedRealityCamera. Também tem de adicionar InputManager e DefaultCursor. Uma vez que MixedRealityCameraParent já inclui MotionControllers e Boundary como componentes subordinados, deve remover motionControllers e Environment prefab existentes.
Instruções
No painel Hierarquia , elimine MixedRealityCamera, Environment e MotionControllers
No painel Projeto, pesquise e arraste as seguintes prefabs para o painel Hierarquia :
- Assets/AppPrefabs/Input/Prefabs/MixedRealityCameraParent
- Recursos/AppPrefabs/Input/Prefabs/InputManager
- Recursos/AppPrefabs/Input/Prefabs/Cursor/DefaultCursor
No painel Hierarquia , clique em Gestor de Entradas
No painel Inspetor, desloque-se para baixo até à secção Seletor de Ponteiro Único Simples
No painel Hierarquia, arraste DefaultCursor para o campo Cursor
Guarde a cena e clique no botão reproduzir . Poderá utilizar o manípulo para rodar para a esquerda/direita ou teletransportar.
O fim
E é o fim deste tutorial! Aprendeu:
- Como trabalhar com modelos de comando de movimento no modo de jogo e runtime do Unity.
- Como utilizar diferentes tipos de eventos de botão e respetivas aplicações.
- Como sobrepor elementos da IU na parte superior do controlador ou personalizá-los completamente.
Agora está pronto para começar a criar a sua própria experiência envolvente com comandos de movimento!
Cenas concluídas
- No painel Projeto do Unity, clique na pasta Cenas .
- Encontrará duas cenas do Unity MixedReality213 e MixedReality213Advanced.
- MixedReality213: Cena concluída com pincel único
- MixedReality213Advanced: Cena concluída com vários pincel com exemplo de quantidade de imprensa do botão selecionar