IMHOTEP Framework
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Pages
SteamVR_ExternalCamera.cs
1 //======= Copyright (c) Valve Corporation, All rights reserved. ===============
2 //
3 // Purpose: Used to render an external camera of vr player (split front/back).
4 //
5 //=============================================================================
6 
7 using UnityEngine;
8 using UnityEngine.Rendering;
9 using Valve.VR;
10 
11 public class SteamVR_ExternalCamera : MonoBehaviour
12 {
13  [System.Serializable]
14  public struct Config
15  {
16  public float x, y, z;
17  public float rx, ry, rz;
18  public float fov;
19  public float near, far;
20  public float sceneResolutionScale;
21  public float frameSkip;
22  public float nearOffset, farOffset;
23  public float hmdOffset;
24  public float r, g, b, a; // chroma key override
25  public bool disableStandardAssets;
26  }
27 
28  public Config config;
29  public string configPath;
30 
31  public void ReadConfig()
32  {
33  try
34  {
35  var mCam = new HmdMatrix34_t();
36  var readCamMatrix = false;
37 
38  object c = config; // box
39  var lines = System.IO.File.ReadAllLines(configPath);
40  foreach (var line in lines)
41  {
42  var split = line.Split('=');
43  if (split.Length == 2)
44  {
45  var key = split[0];
46  if (key == "m")
47  {
48  var values = split[1].Split(',');
49  if (values.Length == 12)
50  {
51  mCam.m0 = float.Parse(values[0]);
52  mCam.m1 = float.Parse(values[1]);
53  mCam.m2 = float.Parse(values[2]);
54  mCam.m3 = float.Parse(values[3]);
55  mCam.m4 = float.Parse(values[4]);
56  mCam.m5 = float.Parse(values[5]);
57  mCam.m6 = float.Parse(values[6]);
58  mCam.m7 = float.Parse(values[7]);
59  mCam.m8 = float.Parse(values[8]);
60  mCam.m9 = float.Parse(values[9]);
61  mCam.m10 = float.Parse(values[10]);
62  mCam.m11 = float.Parse(values[11]);
63  readCamMatrix = true;
64  }
65  }
66 #if !UNITY_METRO
67  else if (key == "disableStandardAssets")
68  {
69  var field = c.GetType().GetField(key);
70  if (field != null)
71  field.SetValue(c, bool.Parse(split[1]));
72  }
73  else
74  {
75  var field = c.GetType().GetField(key);
76  if (field != null)
77  field.SetValue(c, float.Parse(split[1]));
78  }
79 #endif
80  }
81  }
82  config = (Config)c; //unbox
83 
84  // Convert calibrated camera matrix settings.
85  if (readCamMatrix)
86  {
87  var t = new SteamVR_Utils.RigidTransform(mCam);
88  config.x = t.pos.x;
89  config.y = t.pos.y;
90  config.z = t.pos.z;
91  var angles = t.rot.eulerAngles;
92  config.rx = angles.x;
93  config.ry = angles.y;
94  config.rz = angles.z;
95  }
96  }
97  catch { }
98 
99  // Clear target so AttachToCamera gets called to pick up any changes.
100  target = null;
101 #if !UNITY_METRO
102  // Listen for changes.
103  if (watcher == null)
104  {
105  var fi = new System.IO.FileInfo(configPath);
106  watcher = new System.IO.FileSystemWatcher(fi.DirectoryName, fi.Name);
107  watcher.NotifyFilter = System.IO.NotifyFilters.LastWrite;
108  watcher.Changed += new System.IO.FileSystemEventHandler(OnChanged);
109  watcher.EnableRaisingEvents = true;
110  }
111  }
112 
113  void OnChanged(object source, System.IO.FileSystemEventArgs e)
114  {
115  ReadConfig();
116  }
117 
118  System.IO.FileSystemWatcher watcher;
119 #else
120  }
121 #endif
122  Camera cam;
123  Transform target;
124  GameObject clipQuad;
125  Material clipMaterial;
126 
127  public void AttachToCamera(SteamVR_Camera vrcam)
128  {
129  if (target == vrcam.head)
130  return;
131 
132  target = vrcam.head;
133 
134  var root = transform.parent;
135  var origin = vrcam.head.parent;
136  root.parent = origin;
137  root.localPosition = Vector3.zero;
138  root.localRotation = Quaternion.identity;
139  root.localScale = Vector3.one;
140 
141  // Make a copy of the eye camera to pick up any camera fx.
142  vrcam.enabled = false;
143  var go = Instantiate(vrcam.gameObject);
144  vrcam.enabled = true;
145  go.name = "camera";
146 
147  DestroyImmediate(go.GetComponent<SteamVR_Camera>());
148  DestroyImmediate(go.GetComponent<SteamVR_Fade>());
149 
150  cam = go.GetComponent<Camera>();
151  cam.stereoTargetEye = StereoTargetEyeMask.None;
152  cam.fieldOfView = config.fov;
153  cam.useOcclusionCulling = false;
154  cam.enabled = false; // manually rendered
155 
156  colorMat = new Material(Shader.Find("Custom/SteamVR_ColorOut"));
157  alphaMat = new Material(Shader.Find("Custom/SteamVR_AlphaOut"));
158  clipMaterial = new Material(Shader.Find("Custom/SteamVR_ClearAll"));
159 
160  var offset = go.transform;
161  offset.parent = transform;
162  offset.localPosition = new Vector3(config.x, config.y, config.z);
163  offset.localRotation = Quaternion.Euler(config.rx, config.ry, config.rz);
164  offset.localScale = Vector3.one;
165 
166  // Strip children of cloned object (AudioListener in particular).
167  while (offset.childCount > 0)
168  DestroyImmediate(offset.GetChild(0).gameObject);
169 
170  // Setup clipping quad (using camera clip causes problems with shadows).
171  clipQuad = GameObject.CreatePrimitive(PrimitiveType.Quad);
172  clipQuad.name = "ClipQuad";
173  DestroyImmediate(clipQuad.GetComponent<MeshCollider>());
174 
175  var clipRenderer = clipQuad.GetComponent<MeshRenderer>();
176  clipRenderer.material = clipMaterial;
177  clipRenderer.shadowCastingMode = ShadowCastingMode.Off;
178  clipRenderer.receiveShadows = false;
179  clipRenderer.lightProbeUsage = LightProbeUsage.Off;
180  clipRenderer.reflectionProbeUsage = ReflectionProbeUsage.Off;
181 
182  var clipTransform = clipQuad.transform;
183  clipTransform.parent = offset;
184  clipTransform.localScale = new Vector3(1000.0f, 1000.0f, 1.0f);
185  clipTransform.localRotation = Quaternion.identity;
186 
187  clipQuad.SetActive(false);
188  }
189 
190  public float GetTargetDistance()
191  {
192  if (target == null)
193  return config.near + 0.01f;
194 
195  var offset = cam.transform;
196  var forward = new Vector3(offset.forward.x, 0.0f, offset.forward.z).normalized;
197  var targetPos = target.position + new Vector3(target.forward.x, 0.0f, target.forward.z).normalized * config.hmdOffset;
198 
199  var distance = -(new Plane(forward, targetPos)).GetDistanceToPoint(offset.position);
200  return Mathf.Clamp(distance, config.near + 0.01f, config.far - 0.01f);
201  }
202 
203  Material colorMat, alphaMat;
204 
205  public void RenderNear()
206  {
207  var w = Screen.width / 2;
208  var h = Screen.height / 2;
209 
210  if (cam.targetTexture == null || cam.targetTexture.width != w || cam.targetTexture.height != h)
211  {
212  var tex = new RenderTexture(w, h, 24, RenderTextureFormat.ARGB32);
213  tex.antiAliasing = QualitySettings.antiAliasing == 0 ? 1 : QualitySettings.antiAliasing;
214  cam.targetTexture = tex;
215  }
216 
217  cam.nearClipPlane = config.near;
218  cam.farClipPlane = config.far;
219 
220  var clearFlags = cam.clearFlags;
221  var backgroundColor = cam.backgroundColor;
222 
223  cam.clearFlags = CameraClearFlags.Color;
224  cam.backgroundColor = Color.clear;
225 
226  clipMaterial.color = new Color(config.r, config.g, config.b, config.a);
227 
228  float dist = Mathf.Clamp(GetTargetDistance() + config.nearOffset, config.near, config.far);
229  var clipParent = clipQuad.transform.parent;
230  clipQuad.transform.position = clipParent.position + clipParent.forward * dist;
231 
232  MonoBehaviour[] behaviours = null;
233  bool[] wasEnabled = null;
234  if (config.disableStandardAssets)
235  {
236  behaviours = cam.gameObject.GetComponents<MonoBehaviour>();
237  wasEnabled = new bool[behaviours.Length];
238  for (int i = 0; i < behaviours.Length; i++)
239  {
240  var behaviour = behaviours[i];
241  if (behaviour.enabled && behaviour.GetType().ToString().StartsWith("UnityStandardAssets."))
242  {
243  behaviour.enabled = false;
244  wasEnabled[i] = true;
245  }
246  }
247  }
248 
249  clipQuad.SetActive(true);
250 
251  cam.Render();
252 
253  Graphics.DrawTexture(new Rect(0, 0, w, h), cam.targetTexture, colorMat);
254 
255  // Re-render scene with post-processing fx disabled (if necessary) since they override alpha.
256  var pp = cam.gameObject.GetComponent("PostProcessingBehaviour") as MonoBehaviour;
257  if ((pp != null) && pp.enabled)
258  {
259  pp.enabled = false;
260  cam.Render();
261  pp.enabled = true;
262  }
263 
264  Graphics.DrawTexture(new Rect(w, 0, w, h), cam.targetTexture, alphaMat);
265 
266  // Restore settings.
267  clipQuad.SetActive(false);
268 
269  if (behaviours != null)
270  {
271  for (int i = 0; i < behaviours.Length; i++)
272  {
273  if (wasEnabled[i])
274  {
275  behaviours[i].enabled = true;
276  }
277  }
278  }
279 
280  cam.clearFlags = clearFlags;
281  cam.backgroundColor = backgroundColor;
282  }
283 
284  public void RenderFar()
285  {
286  cam.nearClipPlane = config.near;
287  cam.farClipPlane = config.far;
288  cam.Render();
289 
290  var w = Screen.width / 2;
291  var h = Screen.height / 2;
292  Graphics.DrawTexture(new Rect(0, h, w, h), cam.targetTexture, colorMat);
293  }
294 
295  void OnGUI()
296  {
297  // Necessary for Graphics.DrawTexture to work even though we don't do anything here.
298  }
299 
300  Camera[] cameras;
301  Rect[] cameraRects;
302  float sceneResolutionScale;
303 
304  void OnEnable()
305  {
306  // Move game view cameras to lower-right quadrant.
307  cameras = FindObjectsOfType<Camera>() as Camera[];
308  if (cameras != null)
309  {
310  var numCameras = cameras.Length;
311  cameraRects = new Rect[numCameras];
312  for (int i = 0; i < numCameras; i++)
313  {
314  var cam = cameras[i];
315  cameraRects[i] = cam.rect;
316 
317  if (cam == this.cam)
318  continue;
319 
320  if (cam.targetTexture != null)
321  continue;
322 
323  if (cam.GetComponent<SteamVR_Camera>() != null)
324  continue;
325 
326  cam.rect = new Rect(0.5f, 0.0f, 0.5f, 0.5f);
327  }
328  }
329 
330  if (config.sceneResolutionScale > 0.0f)
331  {
332  sceneResolutionScale = SteamVR_Camera.sceneResolutionScale;
333  SteamVR_Camera.sceneResolutionScale = config.sceneResolutionScale;
334  }
335  }
336 
337  void OnDisable()
338  {
339  // Restore game view cameras.
340  if (cameras != null)
341  {
342  var numCameras = cameras.Length;
343  for (int i = 0; i < numCameras; i++)
344  {
345  var cam = cameras[i];
346  if (cam != null)
347  cam.rect = cameraRects[i];
348  }
349  cameras = null;
350  cameraRects = null;
351  }
352 
353  if (config.sceneResolutionScale > 0.0f)
354  {
355  SteamVR_Camera.sceneResolutionScale = sceneResolutionScale;
356  }
357  }
358 }
359 
Definition: Config.cs:4