Skip to content
This repository was archived by the owner on Dec 15, 2020. It is now read-only.

Commit 448ba23

Browse files
Environment facing camera displayed full screen
Summary: A simple component that when dropped into the scene displaces the environment facing camera Reviewed By: amberroy Differential Revision: D5144803 fbshipit-source-id: 2175809
1 parent 06eec59 commit 448ba23

5 files changed

Lines changed: 241 additions & 0 deletions

File tree

Libraries/Camera/LiveEnvCamera.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
* @providesModule LiveEnvCamera
10+
*/
11+
'use strict';
12+
13+
const NativeMethodsMixin = require('NativeMethodsMixin');
14+
const React = require('React');
15+
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
16+
const View = require('View');
17+
const requireNativeComponent = require('requireNativeComponent');
18+
const StyleSheetPropType = require('StyleSheetPropType');
19+
const LayoutAndTransformPropTypes = require('LayoutAndTransformPropTypes');
20+
21+
/**
22+
* Displays the environment facing camera. By default the camera is position:'absolute'
23+
* `<LiveEnvCamera />`
24+
* The camera image is displayed on geometry that is 1000m away from the viewer
25+
*/
26+
const LiveEnvCamera = React.createClass({
27+
mixins: [NativeMethodsMixin],
28+
29+
propTypes: {
30+
...View.propTypes,
31+
style: StyleSheetPropType(LayoutAndTransformPropTypes),
32+
},
33+
34+
viewConfig: {
35+
uiViewClassName: 'LiveEnvCamera',
36+
validAttributes: {
37+
...ReactNativeViewAttributes.RCTView,
38+
},
39+
},
40+
41+
getDefaultProps: function() {
42+
return {};
43+
},
44+
45+
render: function() {
46+
const props = {...this.props} || {};
47+
props.style = props.style || {};
48+
if (!props.style.position) {
49+
props.style.position = 'absolute';
50+
}
51+
// default panos to being a render group
52+
if (!props.style.renderGroup) {
53+
props.style.renderGroup = true;
54+
}
55+
56+
return (
57+
<RKLiveEnvCamera
58+
{...props}
59+
testID={this.props.testID}
60+
onStartShouldSetResponder={() => true}
61+
onResponderTerminationRequest={() => false}>
62+
{this.props.children}
63+
</RKLiveEnvCamera>
64+
);
65+
},
66+
});
67+
68+
const RKLiveEnvCamera = requireNativeComponent('LiveEnvCamera', LiveEnvCamera, {
69+
nativeOnly: {},
70+
});
71+
72+
module.exports = LiveEnvCamera;

Libraries/react-vr.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ const ReactVR = {
2828
get Box() {
2929
return require('Box');
3030
},
31+
get LiveEnvCamera() {
32+
return require('LiveEnvCamera');
33+
},
3134
get Cylinder() {
3235
return require('Cylinder');
3336
},

ReactVR/js/Modules/UIManager.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import RCTSphere from '../Views/Sphere';
1616
import RCTImage from '../Views/Image';
1717
import RCTView from '../Views/View';
1818
import RCTPano from '../Views/Pano';
19+
import RCTLiveEnvCamera from '../Views/LiveEnvCamera';
1920
import RCTModel from '../Views/Model';
2021
import RCTScene from '../Views/Scene';
2122
import RCTSound from '../Views/Sound';
@@ -177,6 +178,9 @@ export default class UIManager extends Module {
177178
this.registerViewType('RCTView', RCTView.describe(), function() {
178179
return new RCTView(guiSys);
179180
});
181+
this.registerViewType('LiveEnvCamera', RCTLiveEnvCamera.describe(), function() {
182+
return new RCTLiveEnvCamera(guiSys);
183+
});
180184
this.registerViewType('RCTImageView', RCTImage.describe(), function() {
181185
return new RCTImage(guiSys, rnctx);
182186
});

ReactVR/js/Views/LiveEnvCamera.js

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
/**
11+
* RCTLiveEnvCamera
12+
* Displays the environment facing camera on a sphere
13+
* @class RCTLiveEnvCamera
14+
* @extends RCTBaseView
15+
*/
16+
17+
import RCTBaseView from './BaseView';
18+
import merge from '../Utils/merge';
19+
import * as OVRUI from 'ovrui';
20+
import * as THREE from 'three';
21+
import * as Yoga from '../Utils/Yoga.bundle';
22+
23+
// display texture always infront of the camera
24+
const basic_vert = `
25+
varying highp vec4 vUv;
26+
void main()
27+
{
28+
vUv = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
29+
vUv.xy = (vUv.xy + vec2(vUv.w)) * 0.5;
30+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
31+
}
32+
`;
33+
34+
const basic_frag = `
35+
uniform sampler2D map;
36+
varying highp vec4 vUv;
37+
void main()
38+
{
39+
gl_FragColor = texture2DProj( map, vUv );
40+
}
41+
`;
42+
43+
const SPHERE_RADIUS = 1000;
44+
45+
const sphereRayCast = (function() {
46+
// avoid create temp objects;
47+
const inverseMatrix = new THREE.Matrix4();
48+
const ray = new THREE.Ray();
49+
const sphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0), SPHERE_RADIUS);
50+
const intersectionPoint = new THREE.Vector3();
51+
const intersectionPointWorld = new THREE.Vector3();
52+
return function(raycaster, intersects) {
53+
// transform the ray into the space of the sphere
54+
inverseMatrix.getInverse(this.matrixWorld);
55+
ray.copy(raycaster.ray).applyMatrix4(inverseMatrix);
56+
const intersect = ray.intersectSphere(sphere, intersectionPoint);
57+
if (intersect === null) {
58+
return;
59+
}
60+
61+
// determine hit location in world space
62+
intersectionPointWorld.copy(intersectionPoint);
63+
intersectionPointWorld.applyMatrix4(this.matrixWorld);
64+
65+
const distance = raycaster.ray.origin.distanceTo(intersectionPointWorld);
66+
if (distance < raycaster.near || distance > raycaster.far) {
67+
return;
68+
}
69+
70+
intersects.push({
71+
distance: distance,
72+
point: intersectionPointWorld.clone(),
73+
object: this,
74+
});
75+
};
76+
})();
77+
78+
export default class RCTLiveEnvCamera extends RCTBaseView {
79+
/**
80+
* constructor: allocates the required resources and sets defaults
81+
*/
82+
constructor(guiSys, rnctx) {
83+
super();
84+
85+
navigator.getUserMedia =
86+
navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
87+
88+
const constraints = {
89+
video: {facingMode: {exact: 'environment'}},
90+
};
91+
const video = document.createElement('video');
92+
const videoTexture = new THREE.Texture(video);
93+
videoTexture.minFilter = THREE.LinearFilter;
94+
this._video = video;
95+
this._videoTexture = videoTexture;
96+
navigator.getUserMedia(
97+
constraints,
98+
stream => {
99+
video.src = window.URL.createObjectURL(stream);
100+
},
101+
error => {
102+
console.log('navigator.getUserMedia error: ', error);
103+
}
104+
);
105+
106+
this._sphereGeometry = new THREE.SphereGeometry(SPHERE_RADIUS, 5, 5);
107+
this._material = new THREE.ShaderMaterial({
108+
uniforms: {
109+
map: {
110+
value: videoTexture,
111+
type: 't',
112+
},
113+
},
114+
vertexShader: basic_vert,
115+
fragmentShader: basic_frag,
116+
side: THREE.DoubleSide,
117+
});
118+
119+
this._onUpdate = this._onUpdate.bind(this);
120+
121+
this._globe = new THREE.Mesh(this._sphereGeometry, this._material);
122+
this._globe.raycast = sphereRayCast.bind(this._globe);
123+
this._globe.rotation.y = -Math.PI / 2;
124+
this._globe.onUpdate = this._onUpdate;
125+
126+
this.view = new OVRUI.UIView(guiSys);
127+
this.view.add(this._globe);
128+
}
129+
130+
_onUpdate(scene, camera) {
131+
if (this._video.readyState === this._video.HAVE_ENOUGH_DATA) {
132+
this._videoTexture.needsUpdate = true;
133+
}
134+
}
135+
136+
presentLayout() {
137+
super.presentLayout();
138+
this._globe.visible = this.YGNode.getDisplay() !== Yoga.DISPLAY_NONE;
139+
}
140+
141+
/**
142+
* Dispose of any associated resources
143+
*/
144+
dispose() {
145+
if (this._localResource) {
146+
this._localResource.dispose();
147+
}
148+
super.dispose();
149+
}
150+
151+
/**
152+
* Describes the properties representable by this view type and merges
153+
* with super type
154+
*/
155+
static describe() {
156+
return merge(super.describe(), {
157+
// declare the native props sent from react to runtime
158+
NativeProps: {},
159+
});
160+
}
161+
}

website/server/docsList.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ path.join(rn, 'Libraries/Text/Text.js'),
2121
const components = [
2222
'../Libraries/Lights/AmbientLight.js',
2323
'../Libraries/Mesh/Box.js',
24+
'../Libraries/Camera/LiveEnvCamera.js',
2425
'../Libraries/Mesh/Cylinder.js',
2526
'../Libraries/VRLayers/CylindricalPanel.js',
2627
'../Libraries/Lights/DirectionalLight.js',

0 commit comments

Comments
 (0)