현재 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);
}
}
}
}
}