I want to keep a score or a health bar always visible in a react-vr app.
I could use VrHeadModel - rotation, yawPitchRoll and position, but having to calculate it just to keep it fixed... seems like I am missing something.
How do I do this?
The answer is to use multiple surfaces: one that isn't headlocked and another that is headlocked.
See "Using Multiple Surfaces" here: Surfaces - React 360
To get yours working, paste the missing code from the example into your client.js and index.js files respectively:
Here is a link to a working example (partially pasted below): Headlocked Surfaces
import { Math as VRMath, ReactInstance, Surface } from "react-360-web";
function init(bundle, parent, options = {}) {
const horizontalPanel = new Surface(300, 300, Surface.SurfaceShape.Flat);
const hvPanel = new Surface(300, 300, Surface.SurfaceShape.Flat);
horizontalPanel.setAngle(0, -0.5);
const cameraDirection = [0, 0, -1];
const r360 = new ReactInstance(bundle, parent, {
fullScreen: true,
frame: () => {
const cameraQuat = r360.getCameraQuaternion();
cameraDirection[0] = 0;
cameraDirection[1] = 0;
cameraDirection[2] = -1;
// cameraDirection will point out from the view of the camera,
// we can use it to compute surface angles
VRMath.rotateByQuaternion(cameraDirection, cameraQuat);
const cx = cameraDirection[0];
const cy = cameraDirection[1];
const cz = cameraDirection[2];
const horizAngle = Math.atan2(cx, -cz);
const vertAngle = Math.asin(cy / Math.sqrt(cx * cx + cy * cy + cz * cz));
horizontalPanel.setAngle(horizAngle, -0.5);
hvPanel.setAngle(horizAngle, vertAngle);
},
...options
});
r360.renderToSurface(r360.createRoot("HorizontalPanel"), horizontalPanel);
r360.renderToSurface(r360.createRoot("HVPanel"), hvPanel);
}
window.React360 = { init };
In your client.js:
Inside the frame
property of the ReactInstance
constructor, set the surface angle to match the camera: either horizontally, or both horizontally and vertically.
In your index.js:
Remember to register a React component to the new headlocked surface.
Updated gist which has less delay as it's subscribed to the HM:
https://gist.github.com/cidicles/b4e978d3f3e2de8b359bdc51b5fb3261
This is how I am currently doing this. It has visual lag and sets state in a loop but achieves the goal.
Create a state for the VrheadModel.rotation() array
constructor(props) {
super(props);
this.state = {
hmRot: VrHeadModel.rotation()
}
}
Start a timer
componentDidMount(){
this.timer = setInterval(()=>{this.tick()}, 50);
}
componentWillUnmount(){
clearInterval(this.timer);
}
tick(){
this.setState({
hmRot: VrHeadModel.rotation()
});
}
Create a view at 0/0/0 and position your fixed object in the scene as you normally world. Set the rotation on the master view to match the rotation of the camera.
render(){
let {hmRot} = this.state;
return (
<View
style={{
position: 'absolute',
layoutOrigin: [0.5, 0.5],
transform: [
{translate: [0, 0, 0]},
{rotateX: hmRot[0]},
{rotateY: hmRot[1]},
{rotateZ: hmRot[2]}
]
}}>
<Text
style={{
position: 'absolute',
layoutOrigin: [0.5, 0.5],
backgroundColor: '#f00',
transform: [
{translate: [0, 0, -2]},
]
}}>
Fixed
</Text>
</View>
);
}
There is a relevant post around this issue from the React VR team here: https://github.com/facebook/react-vr/issues/261
来源:https://stackoverflow.com/questions/45859098/how-do-i-keep-some-element-fixed-on-the-screen-in-react-vr