Move.me (PS Move API) - Unity

Por: Daniel Robledo

Descripción

Con esta demo se quiere demostrar como el PS Move, a través de la consola Playstation 3, nos permite capturar sus datos de forma clara y como podemos utilizar los mismos para implementar aplicaciones en las cuales nos podamos mover en 3 dimensiones y recibir respuesta haptica entre otras, en este caso con la ayuda del motor de videojuegos Unity.

Objetivos

  1. Implementar una interfaz de comunicación entre el PS Move y Unity.
  2. Interpretar correctamente los datos que recibimos del PS3.
  3. Visualizar en una aplicación tridimensional estos datos en forma de manipulación de posición y rotación de un objeto 3D. Así mismo manipular estos datos para obtener un respuesta haptica, en forma de vibración o cambio de color del LED.

Requermientos

PS3

Consola PS3 con la aplicación Move.Me (descargada de PSN)

PS Move (Motion Controller) & Playstation Eye

Tener un PS Move Motion Controller y un Playstation Eye

Unity

Tener un PC con la ultima version de Unity o mínimo la 3.5 y con conexión a internet: http://unity3d.com/unity/download/

Acerca del Move.me

El Move.me es un servidor de aplicaciones que utiliza el control PS Move con un input device. En otras palabras, permite al PS3 actuar como intermediario entre el PS Move y el PC.

Demo

Como se dijo anteriormente, el principal objetivo de este proyecto era encontrar una forma adecuada de conectar el Move.me con el motor de juegos Unity3D. Esto se logro mediante la implementación de un wrapper que nos permite la comunicación entre el motor y la aplicación cliente que por defecto podemos encontrar con el Move.me.

Básicamente este nos permite obtener los datos (como bytes) del cliente, transformarlos para su correcta interpretación y utilizarlos:

1. Cuando se esta conectado, el cliente PSMoveClient obtiene los datos

 public void FillFromNetworkBuffer(ref Byte[] buffer, int i)
        {
            int offset = 104 + i * 176;
            pos = NetworkReaderHelper.ReadFloat4(ref buffer, offset);
            vel = NetworkReaderHelper.ReadFloat4(ref buffer, offset + 16);
            accel = NetworkReaderHelper.ReadFloat4(ref buffer, offset + 32);
            quat = NetworkReaderHelper.ReadFloat4(ref buffer, offset + 48);
            angvel = NetworkReaderHelper.ReadFloat4(ref buffer, offset + 64);
            angaccel = NetworkReaderHelper.ReadFloat4(ref buffer, offset + 80);
            handle_pos = NetworkReaderHelper.ReadFloat4(ref buffer, offset + 96);
            handle_vel = NetworkReaderHelper.ReadFloat4(ref buffer, offset + 112);
            handle_accel = NetworkReaderHelper.ReadFloat4(ref buffer, offset + 128);
            pad.FillFromNetworkBuffer(ref buffer, i);
            timestamp = NetworkReaderHelper.ReadInt64(ref buffer, offset + 152);
            temperature = NetworkReaderHelper.ReadFloat(ref buffer, offset + 160);
            camera_pitch_angle = NetworkReaderHelper.ReadFloat(ref buffer, offset + 164);
            tracking_flags = NetworkReaderHelper.ReadUint32(ref buffer, offset + 168);
        }

2. Después la clase PSMoveWrapper nos ayuda con las transformaciones correspondientes a posición, rotación y orientación entre otras.

private void UpdateGemState(int num)
    { 
       	bool selected_move_connected = (state.gemStatus[num].connected == 1);
        PSMoveSharpGemState selected_gem = state.gemStates[num];
		position[num].x = (float)Convert.ToInt32(selected_gem.pos.x)/100;
		position[num].y = (float)Convert.ToInt32(selected_gem.pos.y)/100;
		position[num].z = (float)Convert.ToInt32(selected_gem.pos.z)/100;
		velocity[num].x = (float)Convert.ToInt32(selected_gem.vel.x)/100;
		velocity[num].y = (float)Convert.ToInt32(selected_gem.vel.y)/100;
		velocity[num].z = (float)Convert.ToInt32(selected_gem.vel.z)/100;
		acceleration[num].x = (float)Convert.ToInt32(selected_gem.accel.x)/100;
		acceleration[num].y = (float)Convert.ToInt32(selected_gem.accel.y)/100;
		acceleration[num].z = (float)Convert.ToInt32(selected_gem.accel.z)/100;
		
		Quaternion rotation = new Quaternion(selected_gem.quat.x, selected_gem.quat.y, selected_gem.quat.z, selected_gem.quat.w);
		orientation[num] = rotation.eulerAngles;
		qOrientation[num] = rotation;
		
		angularVelocity[num].x = Convert.ToInt32((180.0 / Math.PI) * selected_gem.angvel.x);
		angularVelocity[num].y = Convert.ToInt32((180.0 / Math.PI) * selected_gem.angvel.y);
		angularVelocity[num].z = Convert.ToInt32((180.0 / Math.PI) * selected_gem.angvel.z);
		angularAcceleration[num].x = Convert.ToInt32((180.0 / Math.PI) * selected_gem.angaccel.x);
		angularAcceleration[num].y = Convert.ToInt32((180.0 / Math.PI) * selected_gem.angaccel.y);
		angularAcceleration[num].z = Convert.ToInt32((180.0 / Math.PI) * selected_gem.angaccel.z);
		
		handlePosition[num].x = (float)Convert.ToInt32(selected_gem.handle_pos.x)/100;
		handlePosition[num].y = (float)Convert.ToInt32(selected_gem.handle_pos.y)/100;
		handlePosition[num].z = (float)Convert.ToInt32(selected_gem.handle_pos.z)/100;
		handleVelocity[num].x = (float)Convert.ToInt32(selected_gem.handle_vel.x)/100;
		handleVelocity[num].y = (float)Convert.ToInt32(selected_gem.handle_vel.y)/100;
		handleVelocity[num].z = (float)Convert.ToInt32(selected_gem.handle_vel.z)/100;
		handleAcceleration[num].x = (float)Convert.ToInt32(selected_gem.handle_accel.x)/100;
		handleAcceleration[num].y = (float)Convert.ToInt32(selected_gem.handle_accel.y)/100;
		handleAcceleration[num].z = (float)Convert.ToInt32(selected_gem.handle_accel.z)/100;
}

3. Luego podemos utlizar los datos para por ejemplo, mover un objeto basandonos en los datos del PS Move.

void FixedUpdate () {
	
		Vector3 gemPos, handlePos;
		gemPos = psMoveWrapper.position[0];
		handlePos = psMoveWrapper.handlePosition[0];
		if(isMirror) {
			gem.transform.localPosition = gemPos;
			handle.transform.localPosition = handlePos;
			handle.transform.localRotation = Quaternion.Euler(psMoveWrapper.orientation[0]);
		}
		else {
			gemPos.z = -gemPos.z + zOffset;
			handlePos.z = -handlePos.z + zOffset;
			gem.transform.localPosition = gemPos;
			handle.transform.localPosition = handlePos;
			handle.transform.localRotation = Quaternion.LookRotation(gemPos - handlePos);
		}
	}

*Este wrapper esta basado en la solución dada por Xun Zhang

Procedimiento

  1. Conectar el PS Move, el PS Eye y ejecutar la aplicación Move.me en el PS3.
  2. Cuando vea en la pantalla las imágenes de la cámara, encienda el PS Move (si no esta encendido).
  3. Ubíquese de tal forma que en el televisor usted vea el control aproximadamente en la esquina inferior izquierda, apunte hacia la cámara y mantenga oprimido el botón “MOVE” del control hasta que el LED encienda permanentemente y en la pantalla vea un modelo 3D de una espada.
  4. Ejecute la aplicación del demo.
  5. Ingrese la dirección IP y el puerto que aparecen en la esquina inferior izquierda de la pantalla y presione el botón Conectar.
  6. Interactue con la aplicación.
  7. Cuando desee salir de la aplicación oprima el botón Desconectar en la pantalla y luego “SELECT” en el control para apagar el LED.
  8. Para volver a ejecutar la aplicación repita desde el tercer paso.
  9. Observaciones:
  • No oprima el botón “SELECT” en el control del PS Move ya que esto causa que el LED se apague y la cámara deje de rastrear el control.
  • Si tuvo problemas y la aplicación no inicia, y en el numero de conexiones en la pantalla le aparece 0, deshabilite el firewall o configurelo para permitirle el acceso a esta aplicación.

Descargas y Videos

move.me_ps_move_api_-_unity.txt · Última modificación: 2012/06/26 07:08 por d.robledo61
Departamento de Ingeniería de Sistemas y Computación - Facultad de Ingeniería - Universidad de los Andes
CC Attribution-Noncommercial-Share Alike 3.0 Unported
Valid CSS Driven by DokuWiki Recent changes RSS feed Valid XHTML 1.0