프로젝트

일반

사용자정보

통계
| 개정판:

t1 / TFDContents / Assets / KinectDemos / VisualizerDemo / Scripts / SceneMeshVisualizer.cs @ 3

이력 | 보기 | 이력해설 | 다운로드 (10.6 KB)

1
using UnityEngine;
2
using System.Collections;
3

    
4

    
5
public class SceneMeshVisualizer : MonoBehaviour
6
{
7
	[Tooltip("Minimum tracked distance from the sensor, in meters.")]
8
	public float minDistance = 1f;
9
	
10
	[Tooltip("Maximum tracked distance from the sensor, in meters.")]
11
	public float maxDistance = 3f;
12
	
13
	[Tooltip("Maximum left and right distance from the sensor, in meters.")]
14
	public float maxLeftRight = 2f;
15
	
16
	[Tooltip("Whether to include players to the scene mesh or not.")]
17
	public bool includePlayers = false;
18

    
19
	[Tooltip("Time interval between scene mesh updates, in seconds.")]
20
	public float updateMeshInterval = 0.1f;
21

    
22
	[Tooltip("Whether to update the mesh, only when there are no players detected.")]
23
	public bool updateWhenNoPlayers = false;
24

    
25
	[Tooltip("Whether the mesh is facing the player or not.")]
26
	private bool mirroredScene = true;
27
	
28
	[Tooltip("Camera that may be used to overlay the mesh over the color background.")]
29
	public Camera foregroundCamera;
30

    
31
	[Tooltip("Whether to update the mesh collider as well, when the user mesh changes.")]
32
	public bool updateMeshCollider = false;
33

    
34
	[Tooltip("Number of pixels per direction in a sample.")]
35
	private const int sampleSize = 2;
36
	
37

    
38
    private Mesh mesh;
39
    private Vector3[] vertices;
40
    private Vector2[] uvs;
41
    private int[] triangles;
42

    
43
	private KinectManager manager = null;
44

    
45
	private KinectInterop.SensorData sensorData = null;
46
	//private Vector3[] spaceCoords = null;
47
	private Matrix4x4 kinectToWorld = Matrix4x4.identity;
48

    
49
	private float lastMeshUpdateTime = 0f;
50

    
51
	private int colorWidth = 0;
52
	private int colorHeight = 0;
53
	
54
	private int depthWidth = 0;
55
	private int depthHeight = 0;
56

    
57
	private int sampledWidth = 0;
58
	private int sampledHeight = 0;
59

    
60
	private int minDepth = 0;
61
	private int maxDepth = 0;
62

    
63
	private Vector3 sceneMeshPos = Vector3.zero;
64

    
65
	private byte[] vertexType;
66
	private int[] vertexIndex;
67

    
68

    
69
    void Start()
70
    {
71
		if (foregroundCamera == null) 
72
		{
73
			foregroundCamera = Camera.main;
74
		}
75

    
76
		manager = KinectManager.Instance;
77
		if (manager != null && manager.IsInitialized())
78
        {
79
			sensorData = manager.GetSensorData();
80

    
81
			minDepth = Mathf.RoundToInt(minDistance * 1000f);
82
			maxDepth = Mathf.RoundToInt(maxDistance * 1000f);
83

    
84
			colorWidth = manager.GetColorImageWidth();
85
			colorHeight = manager.GetColorImageHeight();
86
			
87
			depthWidth = manager.GetDepthImageWidth();
88
			depthHeight = manager.GetDepthImageHeight();
89
			
90
			sampledWidth = depthWidth / sampleSize;
91
			sampledHeight = depthHeight / sampleSize;
92

    
93
			if(sensorData.depth2SpaceCoords == null)
94
			{
95
				sensorData.depth2SpaceCoords = new Vector3[depthWidth * depthHeight];
96
			}
97

    
98
			sceneMeshPos = transform.position;
99
			if(!mirroredScene)
100
			{
101
				sceneMeshPos.x = -sceneMeshPos.x;
102
			}
103

    
104
			vertexType = new byte[sampledWidth * sampledHeight];
105
			vertexIndex = new int[sampledWidth * sampledHeight];
106

    
107
			CreateMesh(sampledWidth, sampledHeight);
108
        }
109
    }
110

    
111
    private void CreateMesh(int width, int height)
112
    {
113
        mesh = new Mesh();
114
		mesh.name = "SceneMesh";
115

    
116
        GetComponent<MeshFilter>().mesh = mesh;
117
    }
118
    
119
    void Update()
120
    {
121
		if (manager == null || !manager.IsInitialized())
122
			return;
123

    
124
		// get user texture
125
		Renderer renderer = GetComponent<Renderer>();
126
		if(renderer && renderer.material && renderer.material.mainTexture == null)
127
		{
128
			renderer.material.mainTexture = manager.GetUsersClrTex();
129
		}
130

    
131
		// update the mesh position
132
		sceneMeshPos = transform.position;
133
		if(!mirroredScene)
134
		{
135
			sceneMeshPos.x = -sceneMeshPos.x;
136
		}
137

    
138
		// get kinect-to-world matrix
139
		kinectToWorld = manager.GetKinectToWorldMatrix();
140

    
141
		// update the mesh
142
		UpdateMesh();
143
    }
144
    
145
    private void UpdateMesh()
146
    {
147
		if(sensorData.depthImage != null && sensorData.depth2ColorCoords != null && 
148
			sensorData.depth2SpaceCoords != null && sensorData.spaceCoordsBufferReady)
149
		{
150
			if ((Time.time - lastMeshUpdateTime) >= updateMeshInterval &&
151
				(!updateWhenNoPlayers || !manager.IsUserDetected())) 
152
			{
153
				int vCount = 0, tCount = 0;
154
				EstimateSceneVertices(out vCount, out tCount);
155

    
156
				vertices = new Vector3[vCount];
157
				uvs = new Vector2[vCount];
158
				triangles = new int[6 * tCount];
159

    
160
				int index = 0, vIndex = 0, tIndex = 0, xyIndex = 0;
161
				for (int y = 0; y < depthHeight; y += sampleSize)
162
				{
163
					int xyStartIndex = xyIndex;
164

    
165
					for (int x = 0; x < depthWidth; x += sampleSize)
166
					{
167
						Vector3 vSpacePos = sensorData.depth2SpaceCoords[xyIndex];
168

    
169
						if(vertexType[index] != 0 &&
170
							!float.IsInfinity(vSpacePos.x) && !float.IsInfinity(vSpacePos.y) && !float.IsInfinity(vSpacePos.z))
171
						{
172
							Vector2 vColorPos = sensorData.depth2ColorCoords[xyIndex];
173
							if(!float.IsInfinity(vColorPos.x) && !float.IsInfinity(vColorPos.y))
174
							{
175
								uvs[vIndex] = new Vector2(Mathf.Clamp01(vColorPos.x / colorWidth), Mathf.Clamp01(vColorPos.y / colorHeight));
176
							}
177

    
178
							// check for color overlay
179
							if (foregroundCamera) 
180
							{
181
								// get the background rectangle (use the portrait background, if available)
182
								Rect backgroundRect = foregroundCamera.pixelRect;
183
								PortraitBackground portraitBack = PortraitBackground.Instance;
184

    
185
								if(portraitBack && portraitBack.enabled)
186
								{
187
									backgroundRect = portraitBack.GetBackgroundRect();
188
								}
189

    
190
								ushort depthValue = sensorData.depthImage[xyIndex];
191

    
192
								if(!float.IsInfinity(vColorPos.x) && !float.IsInfinity(vColorPos.y) && depthValue > 0)
193
								{
194
									float xScaled = (float)vColorPos.x * backgroundRect.width / sensorData.colorImageWidth;
195
									float yScaled = (float)vColorPos.y * backgroundRect.height / sensorData.colorImageHeight;
196

    
197
									float xScreen = backgroundRect.x + xScaled;
198
									float yScreen = backgroundRect.y + backgroundRect.height - yScaled;
199
									float zDistance = (float)depthValue / 1000f;
200

    
201
									vSpacePos = foregroundCamera.ScreenToWorldPoint(new Vector3(xScreen, yScreen, zDistance));
202
								}
203
							}
204

    
205
							if(!mirroredScene)
206
							{
207
								vSpacePos.x = -vSpacePos.x;
208
							}
209

    
210
							if(foregroundCamera == null) 
211
							{
212
								// convert space to world coords, when there is no color overlay
213
								vSpacePos = kinectToWorld.MultiplyPoint3x4(vSpacePos);
214
							}
215

    
216
							vertices[vIndex] = vSpacePos - sceneMeshPos;
217
							vIndex++;
218

    
219
							if(vertexType[index] == 3)
220
							{
221
								if(mirroredScene)
222
								{
223
									triangles[tIndex++] = vertexIndex[index];  // top left
224
									triangles[tIndex++] = vertexIndex[index + 1];  // top right
225
									triangles[tIndex++] = vertexIndex[index + sampledWidth];  // bottom left
226

    
227
									triangles[tIndex++] = vertexIndex[index + sampledWidth];  // bottom left
228
									triangles[tIndex++] = vertexIndex[index + 1];  // top right
229
									triangles[tIndex++] = vertexIndex[index + sampledWidth + 1];  // bottom right
230
								}
231
								else
232
								{
233
									triangles[tIndex++] = vertexIndex[index + 1];  // top left
234
									triangles[tIndex++] = vertexIndex[index];  // top right
235
									triangles[tIndex++] = vertexIndex[index + sampledWidth + 1];  // bottom left
236

    
237
									triangles[tIndex++] = vertexIndex[index + sampledWidth + 1];  // bottom left
238
									triangles[tIndex++] = vertexIndex[index];  // top right
239
									triangles[tIndex++] = vertexIndex[index + sampledWidth];  // bottom right
240
								}
241
							}
242
						}
243

    
244
						index++;
245
						xyIndex += sampleSize;
246
					}
247

    
248
					xyIndex = xyStartIndex + sampleSize * depthWidth;
249
				}
250

    
251
				// update the mesh
252
				mesh.Clear();
253
				mesh.vertices = vertices;
254
				mesh.uv = uvs;
255
				//mesh.normals = normals;
256
				mesh.triangles = triangles;
257
				mesh.RecalculateNormals();
258
				mesh.RecalculateBounds();
259

    
260
				if (updateMeshCollider) 
261
				{
262
					MeshCollider meshCollider = GetComponent<MeshCollider>();
263

    
264
					if (meshCollider) 
265
					{
266
						meshCollider.sharedMesh = null;
267
						meshCollider.sharedMesh = mesh;
268
					}
269
				}
270

    
271
				// save update time
272
				lastMeshUpdateTime = Time.time;
273
			}
274

    
275
			// buffer is released
276
			lock(sensorData.spaceCoordsBufferLock)
277
			{
278
				sensorData.spaceCoordsBufferReady = false;
279
			}
280
		}
281
    }
282

    
283
	// estimates which and how many sampled vertices are valid
284
	private void EstimateSceneVertices(out int count1, out int count3)
285
	{
286
		System.Array.Clear(vertexType, 0, vertexType.Length);
287

    
288
		Vector3[] vSpacePos = new Vector3[4];
289
		int rowIndex = 0;
290

    
291
		for (int y = 0; y < sampledHeight - 1; y++)
292
		{
293
			int pixIndex = rowIndex;
294

    
295
			for (int x = 0; x < sampledWidth - 1; x++)
296
			{
297
				if(IsSceneSampleValid(x, y, ref vSpacePos[0]) && IsSceneSampleValid(x + 1, y, ref vSpacePos[1]) &&
298
				   IsSceneSampleValid(x, y + 1, ref vSpacePos[2]) && IsSceneSampleValid(x + 1, y + 1, ref vSpacePos[3]))
299
				{
300
					if(IsSpacePointsClose(vSpacePos, 0.01f))
301
					{
302
						vertexType[pixIndex] = 3;
303
						
304
						vertexType[pixIndex + 1] = 1;
305
						vertexType[pixIndex + sampledWidth] = 1;
306
						vertexType[pixIndex + sampledWidth + 1] = 1;
307
					}
308
				}
309

    
310
				pixIndex++;
311
			}
312

    
313
			rowIndex += sampledWidth;
314
		}
315

    
316
		// estimate counts
317
		count1 = 0;
318
		count3 = 0;
319
		
320
		for(int i = 0; i < vertexType.Length; i++)
321
		{
322
			if(vertexType[i] != 0)
323
			{
324
				vertexIndex[i] = count1;
325
				count1++;
326
			}
327
			else
328
			{
329
				vertexIndex[i] = 0;
330
			}
331

    
332
			if(vertexType[i] == 3)
333
			{
334
				count3++;
335
			}
336
		}
337
	}
338

    
339
	// checks if the space points are closer to each other than the minimum squared distance
340
	private bool IsSpacePointsClose(Vector3[] vSpacePos, float fMinDistSquared)
341
	{
342
		int iPosLength = vSpacePos.Length;
343

    
344
		for(int i = 0; i < iPosLength; i++)
345
		{
346
			for(int j = i + 1; j < iPosLength; j++)
347
			{
348
				Vector3 vDist = vSpacePos[j] - vSpacePos[i];
349
				if(vDist.sqrMagnitude > fMinDistSquared)
350
					return false;
351
			}
352
		}
353

    
354
		return true;
355
	}
356

    
357
	// checks whether this sample block is valid for the scene
358
	private bool IsSceneSampleValid(int x, int y, ref Vector3 vSpacePos)
359
	{
360
		int pixelIndex = y * sampleSize * depthWidth + x * sampleSize;
361

    
362
		int depth = sensorData.depthImage[pixelIndex];
363
		vSpacePos = sensorData.depth2SpaceCoords[pixelIndex];
364

    
365
		// check for valid scene or body pixel
366
		bool isValidScenePixel = !includePlayers ? sensorData.bodyIndexImage[pixelIndex] == 255 : true;
367

    
368
		if(isValidScenePixel && depth >= minDepth && depth <= maxDepth &&
369
		   !float.IsInfinity(vSpacePos.x) && !float.IsInfinity(vSpacePos.y) && !float.IsInfinity(vSpacePos.z) &&
370
		   (maxLeftRight < 0f || (vSpacePos.x >= -maxLeftRight && vSpacePos.x <= maxLeftRight)))
371
		{
372
			return true;
373
		} 
374

    
375
		return false;
376
	}
377

    
378
}