8 using System.Collections;
9 using System.Runtime.InteropServices;
12 public static class SteamVR_Utils
15 public static Quaternion Slerp(Quaternion A, Quaternion B,
float t)
17 var cosom = Mathf.Clamp(A.x * B.x + A.y * B.y + A.z * B.z + A.w * B.w, -1.0f, 1.0f);
20 B =
new Quaternion(-B.x, -B.y, -B.z, -B.w);
25 if ((1.0f - cosom) > 0.0001f)
27 var omega = Mathf.Acos(cosom);
28 var sinom = Mathf.Sin(omega);
29 sclp = Mathf.Sin((1.0f - t) * omega) / sinom;
30 sclq = Mathf.Sin(t * omega) / sinom;
39 return new Quaternion(
40 sclp * A.x + sclq * B.x,
41 sclp * A.y + sclq * B.y,
42 sclp * A.z + sclq * B.z,
43 sclp * A.w + sclq * B.w);
46 public static Vector3 Lerp(Vector3 A, Vector3 B,
float t)
54 public static float Lerp(
float A,
float B,
float t)
56 return A + (B - A) * t;
59 public static double Lerp(
double A,
double B,
double t)
61 return A + (B - A) * t;
64 public static float InverseLerp(Vector3 A, Vector3 B, Vector3 result)
66 return Vector3.Dot(result - A, B - A);
69 public static float InverseLerp(
float A,
float B,
float result)
71 return (result - A) / (B - A);
74 public static double InverseLerp(
double A,
double B,
double result)
76 return (result - A) / (B - A);
79 public static float Saturate(
float A)
81 return (A < 0) ? 0 : (A > 1) ? 1 : A;
84 public static Vector2 Saturate(Vector2 A)
86 return new Vector2(Saturate(A.x), Saturate(A.y));
89 public static float Abs(
float A)
91 return (A < 0) ? -A : A;
94 public static Vector2 Abs(Vector2 A)
96 return new Vector2(Abs(A.x), Abs(A.y));
99 private static float _copysign(
float sizeval,
float signval)
101 return Mathf.Sign(signval) == 1 ? Mathf.Abs(sizeval) : -Mathf.Abs(sizeval);
104 public static Quaternion GetRotation(
this Matrix4x4 matrix)
106 Quaternion q =
new Quaternion();
107 q.w = Mathf.Sqrt(Mathf.Max(0, 1 + matrix.m00 + matrix.m11 + matrix.m22)) / 2;
108 q.x = Mathf.Sqrt(Mathf.Max(0, 1 + matrix.m00 - matrix.m11 - matrix.m22)) / 2;
109 q.y = Mathf.Sqrt(Mathf.Max(0, 1 - matrix.m00 + matrix.m11 - matrix.m22)) / 2;
110 q.z = Mathf.Sqrt(Mathf.Max(0, 1 - matrix.m00 - matrix.m11 + matrix.m22)) / 2;
111 q.x = _copysign(q.x, matrix.m21 - matrix.m12);
112 q.y = _copysign(q.y, matrix.m02 - matrix.m20);
113 q.z = _copysign(q.z, matrix.m10 - matrix.m01);
117 public static Vector3 GetPosition(
this Matrix4x4 matrix)
123 return new Vector3(x, y, z);
126 public static Vector3 GetScale(
this Matrix4x4 m)
128 var x = Mathf.Sqrt(m.m00 * m.m00 + m.m01 * m.m01 + m.m02 * m.m02);
129 var y = Mathf.Sqrt(m.m10 * m.m10 + m.m11 * m.m11 + m.m12 * m.m12);
130 var z = Mathf.Sqrt(m.m20 * m.m20 + m.m21 * m.m21 + m.m22 * m.m22);
132 return new Vector3(x, y, z);
135 [System.Serializable]
139 public Quaternion rot;
143 get {
return new RigidTransform(Vector3.zero, Quaternion.identity); }
159 this.pos = t.position;
160 this.rot = t.rotation;
165 var inv = Quaternion.Inverse(from.rotation);
166 rot = inv * to.rotation;
167 pos = inv * (to.position - from.position);
172 var m = Matrix4x4.identity;
189 this.pos = m.GetPosition();
190 this.rot = m.GetRotation();
195 var m = Matrix4x4.identity;
217 this.pos = m.GetPosition();
218 this.rot = m.GetRotation();
223 var m = Matrix4x4.TRS(pos, rot, Vector3.one);
251 var m = Matrix4x4.TRS(pos, rot, Vector3.one);
272 public override bool Equals(
object o)
276 RigidTransform t = (RigidTransform)o;
277 return pos == t.pos && rot == t.rot;
282 public override int GetHashCode()
284 return pos.GetHashCode() ^ rot.GetHashCode();
289 return a.pos == b.pos && a.rot == b.rot;
294 return a.pos != b.pos || a.rot != b.rot;
302 pos = a.pos + a.rot * b.pos
306 public void Inverse()
308 rot = Quaternion.Inverse(rot);
322 pos = a.pos + a.rot * b.pos;
325 public Vector3 InverseTransformPoint(Vector3 point)
327 return Quaternion.Inverse(rot) * (point - pos);
330 public Vector3 TransformPoint(Vector3 point)
332 return pos + (rot * point);
337 return t.TransformPoint(v);
342 return new RigidTransform(Vector3.Lerp(a.pos, b.pos, t), Quaternion.Slerp(a.rot, b.rot, t));
347 pos = SteamVR_Utils.Lerp(pos, to.pos, t);
348 rot = SteamVR_Utils.Slerp(rot, to.rot, t);
352 public delegate
object SystemFn(
CVRSystem system, params
object[] args);
354 public static object CallSystemFn(SystemFn fn, params
object[] args)
356 var initOpenVR = (!SteamVR.active && !SteamVR.usingNativeSupport);
359 var error = EVRInitError.None;
360 OpenVR.Init(ref error, EVRApplicationType.VRApplication_Utility);
363 var system = OpenVR.System;
364 var result = (system != null) ? fn(system, args) : null;
372 public static void TakeStereoScreenshot(uint screenshotHandle, GameObject target,
int cellSize,
float ipd, ref
string previewFilename, ref
string VRFilename)
374 const int width = 4096;
375 const int height = width / 2;
376 const int halfHeight = height / 2;
378 var texture =
new Texture2D(width, height * 2, TextureFormat.ARGB32,
false);
380 var timer =
new System.Diagnostics.Stopwatch();
382 Camera tempCamera = null;
386 var camera = target.GetComponent<Camera>();
389 if (tempCamera == null)
390 tempCamera =
new GameObject().AddComponent<Camera>();
395 const int previewWidth = 2048;
396 const int previewHeight = 2048;
397 var previewTexture =
new Texture2D(previewWidth, previewHeight, TextureFormat.ARGB32,
false);
398 var targetPreviewTexture =
new RenderTexture(previewWidth, previewHeight, 24);
400 var oldTargetTexture = camera.targetTexture;
401 var oldOrthographic = camera.orthographic;
402 var oldFieldOfView = camera.fieldOfView;
403 var oldAspect = camera.aspect;
404 var oldstereoTargetEye = camera.stereoTargetEye;
405 camera.stereoTargetEye = StereoTargetEyeMask.None;
406 camera.fieldOfView = 60.0f;
407 camera.orthographic =
false;
408 camera.targetTexture = targetPreviewTexture;
409 camera.aspect = 1.0f;
413 RenderTexture.active = targetPreviewTexture;
414 previewTexture.ReadPixels(
new Rect(0, 0, targetPreviewTexture.width, targetPreviewTexture.height), 0, 0);
415 RenderTexture.active = null;
416 camera.targetTexture = null;
417 Object.DestroyImmediate(targetPreviewTexture);
421 var oldPosition = target.transform.localPosition;
422 var oldRotation = target.transform.localRotation;
423 var basePosition = target.transform.position;
424 var baseRotation = Quaternion.Euler(0, target.transform.rotation.eulerAngles.y, 0);
426 var transform = camera.transform;
428 int vTotal = halfHeight / cellSize;
429 float dv = 90.0f / vTotal;
430 float dvHalf = dv / 2.0f;
432 var targetTexture =
new RenderTexture(cellSize, cellSize, 24);
433 targetTexture.wrapMode = TextureWrapMode.Clamp;
434 targetTexture.antiAliasing = 8;
436 camera.fieldOfView = dv;
437 camera.orthographic =
false;
438 camera.targetTexture = targetTexture;
439 camera.aspect = oldAspect;
440 camera.stereoTargetEye = StereoTargetEyeMask.None;
448 for (
int v = 0; v < vTotal; v++)
450 var pitch = 90.0f - (v * dv) - dvHalf;
451 var uTotal = width / targetTexture.width;
452 var du = 360.0f / uTotal;
453 var duHalf = du / 2.0f;
455 var vTarget = v * halfHeight / vTotal;
457 for (
int i = 0; i < 2; i++)
462 vTarget = height - vTarget - cellSize;
465 for (
int u = 0; u < uTotal; u++)
467 var yaw = -180.0f + (u * du) + duHalf;
469 var uTarget = u * width / uTotal;
471 var vTargetOffset = 0;
472 var xOffset = -ipd / 2 * Mathf.Cos(pitch * Mathf.Deg2Rad);
474 for (
int j = 0; j < 2; j++)
478 vTargetOffset = height;
482 var offset = baseRotation * Quaternion.Euler(0, yaw, 0) *
new Vector3(xOffset, 0, 0);
483 transform.position = basePosition + offset;
485 var direction = Quaternion.Euler(pitch, yaw, 0.0f);
486 transform.rotation = baseRotation * direction;
489 var N = direction * Vector3.forward;
492 var phi0 = yaw - (du / 2);
493 var phi1 = phi0 + du;
496 var theta0 = pitch + (dv / 2);
497 var theta1 = theta0 - dv;
499 var midPhi = (phi0 + phi1) / 2;
500 var baseTheta = Mathf.Abs(theta0) < Mathf.Abs(theta1) ? theta0 : theta1;
503 var V00 = Quaternion.Euler(baseTheta, phi0, 0.0f) * Vector3.forward;
504 var V01 = Quaternion.Euler(baseTheta, phi1, 0.0f) * Vector3.forward;
507 var V0M = Quaternion.Euler(theta0, midPhi, 0.0f) * Vector3.forward;
508 var V1M = Quaternion.Euler(theta1, midPhi, 0.0f) * Vector3.forward;
511 var P00 = V00 / Vector3.Dot(V00, N);
512 var P01 = V01 / Vector3.Dot(V01, N);
513 var P0M = V0M / Vector3.Dot(V0M, N);
514 var P1M = V1M / Vector3.Dot(V1M, N);
517 var P00_P01 = P01 - P00;
518 var P0M_P1M = P1M - P0M;
520 var uMag = P00_P01.magnitude;
521 var vMag = P0M_P1M.magnitude;
523 var uScale = 1.0f / uMag;
524 var vScale = 1.0f / vMag;
526 var uAxis = P00_P01 * uScale;
527 var vAxis = P0M_P1M * vScale;
530 fx.Set(N, phi0, phi1, theta0, theta1,
534 camera.aspect = uMag / vMag;
537 RenderTexture.active = targetTexture;
538 texture.ReadPixels(
new Rect(0, 0, targetTexture.width, targetTexture.height), uTarget, vTarget + vTargetOffset);
539 RenderTexture.active = null;
543 var progress = (float)( v * ( uTotal * 2.0f ) + u + i*uTotal) / (
float)(vTotal * ( uTotal * 2.0f ) );
544 OpenVR.Screenshots.UpdateScreenshotProgress(screenshotHandle, progress);
550 OpenVR.Screenshots.UpdateScreenshotProgress(screenshotHandle, 1.0f);
554 previewFilename +=
".png";
555 VRFilename +=
".png";
558 previewTexture.Apply();
559 System.IO.File.WriteAllBytes(previewFilename, previewTexture.EncodeToPNG());
563 System.IO.File.WriteAllBytes(VRFilename, texture.EncodeToPNG());
566 if (camera != tempCamera)
568 camera.targetTexture = oldTargetTexture;
569 camera.orthographic = oldOrthographic;
570 camera.fieldOfView = oldFieldOfView;
571 camera.aspect = oldAspect;
572 camera.stereoTargetEye = oldstereoTargetEye;
574 target.transform.localPosition = oldPosition;
575 target.transform.localRotation = oldRotation;
579 tempCamera.targetTexture = null;
582 Object.DestroyImmediate(targetTexture);
583 Object.DestroyImmediate(fx);
586 Debug.Log(string.Format(
"Screenshot took {0} seconds.", timer.Elapsed));
588 if (tempCamera != null)
590 Object.DestroyImmediate(tempCamera.gameObject);
593 Object.DestroyImmediate(previewTexture);
594 Object.DestroyImmediate(texture);