2014-04-11 2 views
0

현재 Oculus Rift와 Kinect를 모두 사용하는 Unity3D 프로젝트를 개발 중입니다. 그러나 Kinect는 유창한 경험을 얻기 위해 프레임 속도를 30fps로 제한하고 리프트는 60fps를 필요로합니다. 나는 그것을 공식적으로 사용하고있다. 그것은 성능상의 문제가 아니다.Kinect가 Unity3D에서 프레임 속도 제한을 초래했습니다.

나는 공식 Kinect SDK와 함께 this 래퍼를 사용하고 있습니다.

나는이 코드 조각에 대한 원인을 좁혀 냈습니다. getSkeleton() 함수가 Kinect에서 데이터를 수신 할 때까지 주 스레드를 차단하고있는 것으로 의심됩니다. Kinect는 30fps에서만 실행되기 때문에 나머지 응용 프로그램은 이보다 더 빠르게 실행할 수 없습니다.

public bool pollSkeleton() { 
    if (!updatedSkeleton) 
    { 
     updatedSkeleton = true; 
     if (kinect.pollSkeleton()) 
     { 
      newSkeleton = true; 
      System.Int64 cur = kinect.getSkeleton().liTimeStamp; 
      System.Int64 diff = cur - ticks; 
      ticks = cur; 
      deltaTime = diff/(float)1000; 
      processSkeleton(); 
     } 
    } 
    return newSkeleton; 
} 

는 아마도 내가 별도의 스레드를 실행하지만, 수 나는 사람이 더 간단한 해결책이 있다면 멀티 스레드 프로그래밍 궁금와 경험이 없기 때문에?

내 생각 엔 많은 Oculus Rift 개발자들이 Kinect + Unity3D 콤보를 사용하고 있으므로 나와 같은 한계에 부딪 힐 것입니다. 어떤 도움이라도 대단히 감사하겠습니다!

EDIT : 변형 된 skeletonWrapper.cs에 대한 완전한 코드는 다음과 같습니다. 그것이 같은 이슈로 어려움을 겪고있는 여러분들을 도울 수 있기를 바랍니다.

using UnityEngine; 
using System.Collections; 
using Kinect; 
using System.Threading; 

public class SkeletonWrapper : MonoBehaviour { 

public DeviceOrEmulator devOrEmu; 
private Kinect.KinectInterface kinect; 

private bool updatedSkeleton = false; 
private bool newSkeleton = false; 

[HideInInspector] 
public Kinect.NuiSkeletonTrackingState[] players; 
[HideInInspector] 
public int[] trackedPlayers; 
[HideInInspector] 
public Vector3[,] bonePos; 
[HideInInspector] 
public Vector3[,] rawBonePos; 
[HideInInspector] 
public Vector3[,] boneVel; 
[HideInInspector] 
public Quaternion[,] boneLocalOrientation; 
[HideInInspector] 
public Quaternion[,] boneAbsoluteOrientation; 

public Kinect.NuiSkeletonPositionTrackingState[,] boneState;  
private System.Int64 ticks; 
private float deltaTime; 

private Matrix4x4 kinectToWorld; 
public Matrix4x4 flipMatrix; 

private Thread thread = null; 
private bool isThreadRunning = false; 

// Use this for initialization 
void Start() { 
    kinect = devOrEmu.getKinect(); 
    players = new Kinect.NuiSkeletonTrackingState[Kinect.Constants.NuiSkeletonCount]; 
    trackedPlayers = new int[Kinect.Constants.NuiSkeletonMaxTracked]; 
    trackedPlayers[0] = -1; 
    trackedPlayers[1] = -1; 
    bonePos = new Vector3[2,(int)Kinect.NuiSkeletonPositionIndex.Count]; 
    rawBonePos = new Vector3[2,(int)Kinect.NuiSkeletonPositionIndex.Count]; 
    boneVel = new Vector3[2,(int)Kinect.NuiSkeletonPositionIndex.Count]; 

    boneState = new Kinect.NuiSkeletonPositionTrackingState[2,(int)Kinect.NuiSkeletonPositionIndex.Count]; 
    boneLocalOrientation = new Quaternion[2, (int)Kinect.NuiSkeletonPositionIndex.Count]; 
    boneAbsoluteOrientation = new Quaternion[2, (int)Kinect.NuiSkeletonPositionIndex.Count]; 

    //create the transform matrix that converts from kinect-space to world-space 
    Matrix4x4 trans = new Matrix4x4(); 
    trans.SetTRS(new Vector3(-kinect.getKinectCenter().x, 
           kinect.getSensorHeight()-kinect.getKinectCenter().y, 
           -kinect.getKinectCenter().z), 
       Quaternion.identity, Vector3.one); 
    Matrix4x4 rot = new Matrix4x4(); 
    Quaternion quat = new Quaternion(); 
    double theta = Mathf.Atan((kinect.getLookAt().y+kinect.getKinectCenter().y-kinect.getSensorHeight())/(kinect.getLookAt().z + kinect.getKinectCenter().z)); 
    float kinectAngle = (float)(theta * (180/Mathf.PI)); 
    quat.eulerAngles = new Vector3(-kinectAngle, 0, 0); 
    rot.SetTRS(Vector3.zero, quat, Vector3.one); 

    //final transform matrix offsets the rotation of the kinect, then translates to a new center 
    kinectToWorld = flipMatrix*trans*rot; 

    thread = new Thread(ThreadUpdate); 
    thread.Start(); 
} 

void OnDestroy() 
{ 
    if (isThreadRunning) 
    { 
     isThreadRunning = false; 
     thread.Abort(); 
     thread = null; 
    } 
} 

// Update is called once per frame 
void Update() { 

} 

void LateUpdate() { 
    updatedSkeleton = false; 
    newSkeleton = false; 
} 

private void ThreadUpdate() 
{ 
    isThreadRunning = true; 

    while (isThreadRunning) 
    { 
     // This function is capping the FPS to 30. 
     if (kinect.pollSkeleton()) 
     { 
      System.Int64 cur = kinect.getSkeleton().liTimeStamp; 
      System.Int64 diff = cur - ticks; 
      ticks = cur; 
      deltaTime = diff/(float)1000; 
      processSkeleton(); 
      newSkeleton = true; 
     } 
    } 
} 

/// <summary> 
/// First call per frame checks if there is a new skeleton frame and updates, 
/// returns true if there is new data 
/// Subsequent calls do nothing have the same return as the first call. 
/// </summary> 
/// <returns> 
/// A <see cref="System.Boolean"/> 
/// </returns> 
public bool pollSkeleton() { 
    //if (!updatedSkeleton) 
    //{ 
    // updatedSkeleton = true; 
    // //this function is capping the FPS to 30. 
    // //It might be blocking the main thread because it waits for the kinects skeleton input which only runs 30 fps 
    // //possible solution: run function in seperate thread 
    // if (kinect.pollSkeleton()) 
    // { 
    //  newSkeleton = true; 
    //  System.Int64 cur = kinect.getSkeleton().liTimeStamp; 
    //  System.Int64 diff = cur - ticks; 
    //  ticks = cur; 
    //  deltaTime = diff/(float)1000; 
    //  processSkeleton(); 
    // } 
    //} 
    return newSkeleton; 
} 

private void processSkeleton() { 
    int[] tracked = new int[Kinect.Constants.NuiSkeletonMaxTracked]; 
    tracked[0] = -1; 
    tracked[1] = -1; 
    int trackedCount = 0; 
    //update players 
    for (int ii = 0; ii < Kinect.Constants.NuiSkeletonCount; ii++) 
    { 
     players[ii] = kinect.getSkeleton().SkeletonData[ii].eTrackingState; 
     if (players[ii] == Kinect.NuiSkeletonTrackingState.SkeletonTracked) 
     { 
      tracked[trackedCount] = ii; 
      trackedCount++; 
     } 
    } 
    //this should really use trackingID instead of index, but for now this is fine 
    switch (trackedCount) 
    { 
    case 0: 
     trackedPlayers[0] = -1; 
     trackedPlayers[1] = -1; 
     break; 
    case 1: 
     //last frame there were no players: assign new player to p1 
     if (trackedPlayers[0] < 0 && trackedPlayers[1] < 0) 
      trackedPlayers[0] = tracked[0]; 
     //last frame there was one player, keep that player in the same spot 
     else if (trackedPlayers[0] < 0) 
      trackedPlayers[1] = tracked[0]; 
     else if (trackedPlayers[1] < 0) 
      trackedPlayers[0] = tracked[0]; 
     //there were two players, keep the one with the same index (if possible) 
     else 
     { 
      if (tracked[0] == trackedPlayers[0]) 
       trackedPlayers[1] = -1; 
      else if (tracked[0] == trackedPlayers[1]) 
       trackedPlayers[0] = -1; 
      else 
      { 
       trackedPlayers[0] = tracked[0]; 
       trackedPlayers[1] = -1; 
      } 
     } 
     break; 
    case 2: 
     //last frame there were no players: assign new players to p1 and p2 
     if (trackedPlayers[0] < 0 && trackedPlayers[1] < 0) 
     { 
      trackedPlayers[0] = tracked[0]; 
      trackedPlayers[1] = tracked[1]; 
     } 
     //last frame there was one player, keep that player in the same spot 
     else if (trackedPlayers[0] < 0) 
     { 
      if (trackedPlayers[1] == tracked[0]) 
       trackedPlayers[0] = tracked[1]; 
      else{ 
       trackedPlayers[0] = tracked[0]; 
       trackedPlayers[1] = tracked[1]; 
      } 
     } 
     else if (trackedPlayers[1] < 0) 
     { 
      if (trackedPlayers[0] == tracked[1]) 
       trackedPlayers[1] = tracked[0]; 
      else{ 
       trackedPlayers[0] = tracked[0]; 
       trackedPlayers[1] = tracked[1]; 
      } 
     } 
     //there were two players, keep the one with the same index (if possible) 
     else 
     { 
      if (trackedPlayers[0] == tracked[1] || trackedPlayers[1] == tracked[0]) 
      { 
       trackedPlayers[0] = tracked[1]; 
       trackedPlayers[1] = tracked[0]; 
      } 
      else 
      { 
       trackedPlayers[0] = tracked[0]; 
       trackedPlayers[1] = tracked[1]; 
      } 
     } 
     break; 
    } 

    //update the bone positions, velocities, and tracking states) 
    for (int player = 0; player < 2; player++) 
    { 
     //print(player + ", " +trackedPlayers[player]); 
     if (trackedPlayers[player] >= 0) 
     { 
      for (int bone = 0; bone < (int)Kinect.NuiSkeletonPositionIndex.Count; bone++) 
      { 
       Vector3 oldpos = bonePos[player,bone]; 

       bonePos[player,bone] = kinectToWorld.MultiplyPoint3x4(kinect.getSkeleton().SkeletonData[trackedPlayers[player]].SkeletonPositions[bone]); 
       //bonePos[player,bone] = kinectToWorld.MultiplyPoint3x4(bonePos[player, bone]); 
       rawBonePos[player, bone] = kinect.getSkeleton().SkeletonData[trackedPlayers[player]].SkeletonPositions[bone]; 


       Kinect.NuiSkeletonBoneOrientation[] or = kinect.getBoneOrientations(kinect.getSkeleton().SkeletonData[trackedPlayers[player]]); 
       boneLocalOrientation[player,bone] = or[bone].hierarchicalRotation.rotationQuaternion.GetQuaternion(); 
       boneAbsoluteOrientation[player,bone] = or[bone].absoluteRotation.rotationQuaternion.GetQuaternion(); 

       //print("index " + bone + ", start" + (int)or[bone].startJoint + ", end" + (int)or[bone].endJoint); 

       boneVel[player,bone] = (bonePos[player,bone] - oldpos)/deltaTime; 
       boneState[player,bone] = kinect.getSkeleton().SkeletonData[trackedPlayers[player]].eSkeletonPositionTrackingState[bone]; 
       //print(kinect.getSkeleton().SkeletonData[player].Position.z); 
      } 
     } 
    } 
} 

}

답변

1

나는 키 넥트 SDK가 작동하는 방법에 대해 잘 모른다. 그것은 이미 골격 추적을하고있는 백그라운드 스레드를 관리하고 있고 pollSkeleton 메서드는 다음 프레임이 사용 가능해질 때까지 차단합니다.

SDK는 폴링 및 이벤트 기반 알림을 모두 지원하므로 합리적인 가정처럼 보입니다. 폴링하지 않으면 다른 프레임을 가져오고 이벤트를 보냅니다. 이 경우 문제가 해결되지 않으면

, 당신은 대부분 다음 ... 단순히 스레드에서 사용할 수 골격 데이터에 타임 스탬프를 스캔하여

System.Int64 lastSkeletonTime = 0; 
public bool pollSkeleton() 
{ 
    if (kinect.getSkeleton().liTimeStamp > lastSkeletonTime) { 
    updatedSkeleton = true; 
    newSkeleton = true; 
    System.Int64 cur = kinect.getSkeleton().liTimeStamp; 
    System.Int64 diff = cur - lastSkeletonTime; 
    deltaTime = diff/(float)1000; 
    lastSkeletonTime = cur; 
    processSkeleton(); 
    } 
    return newSkeleton; 
} 

당신의 문제를 해결할 수 백그라운드 스레드를 시작하거나 이벤트 처리로 전환해야합니다.

관련 문제