既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
// create and configure three.js renderer with XR support
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
autoClear: true,
context: gl,
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.xr.enabled = true;
renderer.xr.setReferenceSpaceType('local');
renderer.xr.setSession(session);
// simple sprite to indicate detected surfaces
reticle = new THREE.Mesh(
new THREE.RingBufferGeometry(0.12, 0.15, 20).rotateX(-Math.PI / 2),
new THREE.MeshPhongMaterial({ color: 0x0fff00 }),
);
// we will update it's matrix later using WebXR hit test pose matrix
reticle.matrixAutoUpdate = false;
reticle.visible = false;
scene.add(reticle);
}
// closing intiScene
在上面的代码中,我们添加了矩形对象,这将有助于识别我们指向相机的表面区域。
reticle image
在 initScene 中设置完所有 threejs 之后,我们现在将开始做与 webxrSession 相关的事情,我们称之为 initScene。
如果没有用户交互,我们将无法启动 webxrSession 我们将首先在我们的 jsx 返回中添加一个按钮
const xrButton = useRef(null);
return (
// id xrOverlay will be used later
<div id="xrOverlay">
<button id="xrbutton" ref={xrButton} onClick={onXRButtonClick}>
Start experience
</button>
</div> )
function checkXR() {
if (!window.isSecureContext) {
// show message to use secure connection,
// webXR need https for giving device permission
}
if (navigator.xr) {
xrButton?.current?.disabled = false;
} else {
xrButton?.current?.disabled = true
// show message that this device or browser does not support webXR
}
}
React.useEffect(() => {
checkXR();
}, []);
我们添加了检查是否支持 XR 的功能。现在我们将处理启动 webXR 会话的主要部分,其中包含我们需要的命中和放置功能所需的功能。
我们将要求immersive session提供dom-overlay, local, and hit-test功能。
- dom-overlay:它允许我们在会话时在屏幕上添加 html DOM 内容。
- local:在会话开始时启用您的设备作为视图位置。
- hit-test:它提供了我们击中并想要放置我们的 3D 模型的表面信息。
我们可以根据我们的需要请求更多功能,例如hand-tracking, depth sensing等。
let xrSession = null;
let xrRefSpace = null;
let xrHitTestSource = null;
function onXRButtonClick() {
if (!xrSession) {
navigator.xr
.requestSession('immersive-ar', {
optionalFeatures: ['dom-overlay'],
requiredFeatures: ['local', 'hit-test'],
domOverlay: { root: document.getElementById('xrOverlay') },
})
.then(onSessionStarted, onRequestSessionError);
} else {
xrSession.end();
}
}
我们已经通过document.getElementById(‘xrOverlay’)了,任何对此 DOM 的输入和交互都只能用于 xrSession 操作。
function onSessionStarted(session) {
setIsWebXRStarted(true);
xrSession = session;
// create a canvas element and WebGL context for rendering
session.addEventListener('end', onSessionEnded);
let canvas = document.createElement('canvas');
gl = canvas.getContext('webgl', { xrCompatible: true });
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
// here we have register source from where we want to get hit test result in surronding
space
session.requestReferenceSpace('viewer').then(refSpace => {
session.requestHitTestSource({ space: refSpace }).then(hitTestSource => {
xrHitTestSource = hitTestSource;
});
});
session.requestReferenceSpace('local').then(refSpace => {
xrRefSpace = refSpace;
session.requestAnimationFrame(onXRFrame);
});
// we have added click listner once session is started to place object once we have
// surface information after hit-test result.
document.getElementById('arOverlay').addEventListener('click', placeObject);
// initialize three.js scene
initScene(gl, session);
}
现在,我们必须添加最后一个主函数来处理会话中每个更新的帧。正如我们在上面的代码中的 session.requestAnimationFrame() 中注册 onXRFrame 一样。
function onXRFrame(t, frame) {
let session = frame.session;
// calling it recursively to get current updated frame information
session.requestAnimationFrame(onXRFrame);
if (xrHitTestSource) {
// obtain hit test results by casting a ray from the centre of device screen
// into AR view. Results indicate that ray intersected with one or more detected surfaces
const hitTestResults = frame.getHitTestResults(xrHitTestSource);
if (hitTestResults.length) {
// obtain a local pose at the intersection point
const pose = hitTestResults[0].getPose(xrRefSpace);
// we are changing reticle position and view at the intersection
point to get visible feedback on which surface the hit result is in this frame.
reticle.matrix.fromArray(pose.transform.matrix);
reticle.visible = true;
}
} else {
// do not show a reticle if no surfaces are intersected
reticle.visible = false;
}
// update object animation if your model contains animation
updateAnimation();
// bind our gl context that was created with WebXR to threejs renderer
gl.bindFramebuffer(
gl.FRAMEBUFFER,
session.renderState.baseLayer.framebuffer,
);
// render the scene
renderer.render(scene, camera);
}
在每个帧更新中为模型动画添加这个
function updateAnimation() {
![img](https://img-blog.csdnimg.cn/img_convert/6a1a6a511945259d44cd7a3aa941d95c.png)
![img](https://img-blog.csdnimg.cn/img_convert/74e1d8a4667447e2314420dd67b8fdbb.png)
![img](https://img-blog.csdnimg.cn/img_convert/e49ce7aa4626073026ae0ce2b3933e40.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**
9729)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**