Skip to content

Commit 2df4199

Browse files
committed
WIP - Mixed Reality Capture
1 parent a3eb20f commit 2df4199

File tree

9 files changed

+425
-0
lines changed

9 files changed

+425
-0
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
%YAML 1.1
2+
%TAG !u! tag:unity3d.com,2011:
3+
--- !u!21 &2100000
4+
Material:
5+
serializedVersion: 6
6+
m_ObjectHideFlags: 0
7+
m_CorrespondingSourceObject: {fileID: 0}
8+
m_PrefabInstance: {fileID: 0}
9+
m_PrefabAsset: {fileID: 0}
10+
m_Name: ChromaKeyDiffuse
11+
m_Shader: {fileID: 4800000, guid: a49075226332e334b8532c2d2e37aed2, type: 3}
12+
m_ShaderKeywords:
13+
m_LightmapFlags: 4
14+
m_EnableInstancingVariants: 0
15+
m_DoubleSidedGI: 0
16+
m_CustomRenderQueue: -1
17+
stringTagMap: {}
18+
disabledShaderPasses: []
19+
m_SavedProperties:
20+
serializedVersion: 3
21+
m_TexEnvs:
22+
- _MainTex:
23+
m_Texture: {fileID: 0}
24+
m_Scale: {x: 1, y: 1}
25+
m_Offset: {x: 0, y: 0}
26+
m_Floats: []
27+
m_Colors:
28+
- _Color: {r: 1, g: 1, b: 1, a: 1}
29+
- _ThresholdMax: {r: 0.23, g: 1, b: 0.23, a: 1}
30+
- _ThresholdMin: {r: 0, g: 0.39, b: 0, a: 1}
31+
m_BuildTextureStacks: []

Packages/webxr-interactions/Runtime/Materials/ChromaKeyDiffuse.mat.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
using System.Collections;
2+
using UnityEngine;
3+
4+
namespace WebXR.Interactions
5+
{
6+
public class MixedRealityCaptureController : MonoBehaviour
7+
{
8+
private enum ControllerState
9+
{
10+
None,
11+
SetCameraPoint,
12+
SetTopPoint,
13+
SetBottomPoint,
14+
Confirm,
15+
CalcAndSet,
16+
Playing,
17+
Ended
18+
}
19+
20+
private const float WEBCAM_DISTANCE_CALIBRATION = 0.5f;
21+
private const float WEBCAM_SIZE_CALIBRATION = 0.25f;
22+
private const float WEBCAM_MIN_SIZE = 0.001f;
23+
private readonly Quaternion LEFT_STEP_ROTATION = Quaternion.Euler(0, -90, 0);
24+
25+
[SerializeField]
26+
private bool enableInXR = false;
27+
private WebXRState currentXRState = WebXRState.NORMAL;
28+
29+
[SerializeField]
30+
private Transform camerasBase;
31+
[SerializeField]
32+
private Transform cameraFollower;
33+
[SerializeField]
34+
private Camera spectatorCamera;
35+
[SerializeField]
36+
private Transform spectatorCameraTransform;
37+
[SerializeField]
38+
private Transform spectatorCameraParent;
39+
[SerializeField]
40+
private Transform webcamParent;
41+
[SerializeField]
42+
private Transform calibrationPointCamera;
43+
[SerializeField]
44+
private Transform calibrationPointTop;
45+
[SerializeField]
46+
private Transform calibrationPointBottom;
47+
[SerializeField]
48+
private GameObject calibrationHintCamera;
49+
[SerializeField]
50+
private GameObject calibrationHintTop;
51+
[SerializeField]
52+
private GameObject calibrationHintBottom;
53+
[SerializeField]
54+
private WebXRController webxrController;
55+
56+
private ControllerState state = ControllerState.None;
57+
private float webcamBaseSize = 1f;
58+
59+
private void OnEnable()
60+
{
61+
WebXRManager.OnXRChange += HandleOnXRChange;
62+
currentXRState = WebXRManager.Instance.XRState;
63+
TryUpdateControllerState();
64+
}
65+
66+
private void OnDisable()
67+
{
68+
StopAllCoroutines();
69+
WebXRManager.OnXRChange -= HandleOnXRChange;
70+
Ended();
71+
}
72+
73+
private void HandleOnXRChange(WebXRState state, int viewsCount, Rect leftRect, Rect rightRect)
74+
{
75+
currentXRState = state;
76+
TryUpdateControllerState();
77+
}
78+
79+
public void EnableInXR(bool value)
80+
{
81+
enableInXR = value;
82+
TryUpdateControllerState();
83+
}
84+
85+
private void TryUpdateControllerState()
86+
{
87+
bool enableState = enableInXR && currentXRState != WebXRState.NORMAL;
88+
if (enableState && (state == ControllerState.None || state == ControllerState.Ended))
89+
{
90+
StartController();
91+
}
92+
else if (!enableState && state != ControllerState.Ended)
93+
{
94+
state = ControllerState.Ended;
95+
}
96+
}
97+
98+
private void StartController()
99+
{
100+
StartCoroutine(ControllerProcess());
101+
}
102+
103+
private IEnumerator ControllerProcess()
104+
{
105+
state = ControllerState.None;
106+
calibrationPointCamera.gameObject.SetActive(false);
107+
calibrationPointTop.gameObject.SetActive(false);
108+
calibrationPointBottom.gameObject.SetActive(false);
109+
calibrationHintCamera.SetActive(true);
110+
calibrationHintTop.SetActive(false);
111+
calibrationHintBottom.SetActive(false);
112+
webcamParent.localScale = Vector3.one * WEBCAM_SIZE_CALIBRATION;
113+
webcamParent.gameObject.SetActive(true);
114+
spectatorCameraParent.SetPositionAndRotation(camerasBase.position, camerasBase.rotation);
115+
state = ControllerState.SetCameraPoint;
116+
while (state != ControllerState.Ended)
117+
{
118+
switch (state)
119+
{
120+
case ControllerState.SetCameraPoint:
121+
WhileCalibrating();
122+
SetPoint(calibrationPointCamera, calibrationHintCamera, ControllerState.SetTopPoint, calibrationHintTop);
123+
break;
124+
case ControllerState.SetTopPoint:
125+
WhileCalibrating();
126+
SetPoint(calibrationPointTop, calibrationHintTop, ControllerState.SetBottomPoint, calibrationHintBottom);
127+
break;
128+
case ControllerState.SetBottomPoint:
129+
WhileCalibrating();
130+
SetBottomPoint();
131+
break;
132+
case ControllerState.Confirm:
133+
WhileCalibrating();
134+
Confirm();
135+
break;
136+
case ControllerState.CalcAndSet:
137+
CalcAndSet();
138+
state = ControllerState.Playing;
139+
break;
140+
case ControllerState.Playing:
141+
Playing();
142+
break;
143+
}
144+
yield return null;
145+
}
146+
Ended();
147+
}
148+
149+
private void Ended()
150+
{
151+
calibrationPointCamera.gameObject.SetActive(false);
152+
calibrationPointTop.gameObject.SetActive(false);
153+
calibrationPointBottom.gameObject.SetActive(false);
154+
webcamParent.gameObject.SetActive(false);
155+
}
156+
157+
private void SetPoint(Transform point, GameObject hint, ControllerState nextState, GameObject nextHint)
158+
{
159+
if (GetControllersButtonDown())
160+
{
161+
point.position = webxrController.transform.position;
162+
point.gameObject.SetActive(true);
163+
hint.SetActive(false);
164+
nextHint.SetActive(true);
165+
state = nextState;
166+
}
167+
}
168+
169+
private void SetBottomPoint()
170+
{
171+
if (GetControllersButtonDown())
172+
{
173+
float cameraToTopDistance = Vector3.Distance(calibrationPointCamera.position, calibrationPointTop.position);
174+
Vector3 cameraToBottomDirection = (webxrController.transform.position - calibrationPointCamera.position).normalized;
175+
calibrationPointBottom.position = calibrationPointCamera.position + cameraToBottomDirection * cameraToTopDistance;
176+
calibrationPointBottom.gameObject.SetActive(true);
177+
calibrationHintBottom.SetActive(false);
178+
state = ControllerState.Confirm;
179+
}
180+
}
181+
182+
private void Confirm()
183+
{
184+
if (GetControllersButtonDown())
185+
{
186+
calibrationPointCamera.gameObject.SetActive(false);
187+
calibrationPointTop.gameObject.SetActive(false);
188+
calibrationPointBottom.gameObject.SetActive(false);
189+
state = ControllerState.CalcAndSet;
190+
}
191+
}
192+
193+
private void CalcAndSet()
194+
{
195+
SetCameraVerticalFOV();
196+
SetCameraPositionRotation();
197+
}
198+
199+
private void WhileCalibrating()
200+
{
201+
spectatorCameraTransform.SetPositionAndRotation(cameraFollower.position, cameraFollower.rotation);
202+
webcamParent.SetPositionAndRotation(cameraFollower.position + cameraFollower.forward * WEBCAM_DISTANCE_CALIBRATION, cameraFollower.rotation);
203+
}
204+
205+
private void Playing()
206+
{
207+
var headPosition = spectatorCameraTransform.InverseTransformPoint(cameraFollower.position);
208+
var newWebcamPosition = spectatorCameraTransform.TransformPoint(new Vector3(0, 0, headPosition.z));
209+
webcamParent.SetPositionAndRotation(newWebcamPosition, spectatorCameraTransform.rotation);
210+
float webcamSize = Mathf.Max(Mathf.LerpUnclamped(0f, webcamBaseSize, headPosition.z), WEBCAM_MIN_SIZE);
211+
webcamParent.localScale = Vector3.one * webcamSize;
212+
}
213+
214+
private void SetCameraVerticalFOV()
215+
{
216+
float distanceA = Vector3.Distance(calibrationPointTop.position, calibrationPointBottom.position);
217+
float distanceB = Vector3.Distance(calibrationPointCamera.position, calibrationPointTop.position);
218+
float distanceC = Vector3.Distance(calibrationPointCamera.position, calibrationPointBottom.position);
219+
float A = Mathf.Acos((distanceB * distanceB + distanceC * distanceC - distanceA * distanceA) / (2 * distanceB * distanceC));
220+
spectatorCamera.fieldOfView = Mathf.Rad2Deg * A;
221+
webcamBaseSize = Mathf.Tan(A * 0.5f) * 2f; // Half of FOV as direction * 2
222+
}
223+
224+
private void SetCameraPositionRotation()
225+
{
226+
Plane plane = new Plane(calibrationPointCamera.position, calibrationPointTop.position, calibrationPointBottom.position);
227+
Vector3 up = (calibrationPointTop.position - calibrationPointBottom.position).normalized;
228+
spectatorCameraTransform.SetPositionAndRotation(calibrationPointCamera.position, Quaternion.LookRotation(plane.normal, up) * LEFT_STEP_ROTATION);
229+
}
230+
231+
bool GetControllersButtonDown()
232+
{
233+
return (webxrController.isHandActive || webxrController.isControllerActive)
234+
&& (webxrController.GetButtonDown(WebXRController.ButtonTypes.Trigger));
235+
}
236+
}
237+
}

Packages/webxr-interactions/Runtime/Scripts/MixedRealityCaptureController.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using System.Collections;
2+
using UnityEngine;
3+
4+
public class PlayWebcam : MonoBehaviour
5+
{
6+
private WebCamTexture webcamTexture;
7+
private Renderer _renderer;
8+
private bool started = false;
9+
10+
private int defaultWidth = 1280;
11+
private int defaultHeight = 720;
12+
13+
void Awake()
14+
{
15+
_renderer = GetComponent<Renderer>();
16+
}
17+
18+
void Start()
19+
{
20+
started = true;
21+
Play();
22+
}
23+
24+
void Play()
25+
{
26+
if (webcamTexture == null)
27+
{
28+
var devices = WebCamTexture.devices;
29+
var device = devices[0];
30+
var resolutions = device.availableResolutions;
31+
if (resolutions?.Length > 0)
32+
{
33+
webcamTexture = new WebCamTexture(device.name, resolutions[0].width, resolutions[0].height, resolutions[0].refreshRate);
34+
}
35+
else
36+
{
37+
webcamTexture = new WebCamTexture(device.name, defaultWidth, defaultHeight);
38+
}
39+
float ratio = (float)defaultWidth / (float)defaultHeight;
40+
transform.localScale = new Vector3(ratio, 1f, 1f);
41+
_renderer.material.mainTexture = webcamTexture;
42+
}
43+
webcamTexture.Play();
44+
StartCoroutine(SetScale());
45+
}
46+
47+
IEnumerator SetScale()
48+
{
49+
while (!webcamTexture.isPlaying || webcamTexture.height == 16)
50+
{
51+
yield return null;
52+
}
53+
float ratio = (float)webcamTexture.width / (float)webcamTexture.height;
54+
transform.localScale = new Vector3(ratio, 1f, 1f);
55+
}
56+
57+
void OnEnable()
58+
{
59+
if (started)
60+
{
61+
Play();
62+
}
63+
}
64+
65+
void OnDisable()
66+
{
67+
StopAllCoroutines();
68+
webcamTexture.Stop();
69+
}
70+
}

Packages/webxr-interactions/Runtime/Scripts/PlayWebcam.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Packages/webxr-interactions/Runtime/Shaders.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)