1 Star 0 Fork 0

刘政杨/cesium-demo

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
index.html 7.80 KB
一键复制 编辑 原始数据 按行查看 历史
刘政杨 提交于 2024-03-13 16:33 . 13213141
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Use correct character set. -->
<meta charset="utf-8" />
<!-- Tell IE to use the latest, best version. -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
<meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<title>Hello World!</title>
<script src="./Cesium/Cesium.js"></script>
<style>
@import url(./Cesium/Widgets/widgets.css);
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.cesium-viewer-vrContainer {
z-index: 10000;
}
</style>
</head>
<body>
<div id="cesiumContainer"></div>
</body>
</html>
<script>
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI3OTg1YjA4My01ZjhkLTQyOTEtYWEzYS04NTdhYzM2ZjZlMWYiLCJpZCI6MTA0NzQ0LCJpYXQiOjE2OTUxMDgxMzR9._hH8LKO8eZGALIytyypkpA7TYM1PJam6IGraUYqjkPQ';
var viewer = new Cesium.Viewer("cesiumContainer", {
vrButton: true,
enableXR: true,
animation: false, //动画控制不显示
timeline: false, //时间线不显示
shouldAnimate: true,
});
viewer._cesiumWidget._creditContainer.style.display = "none";
var imgLayer = new Cesium.UrlTemplateImageryProvider({
url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}",
minimumLevel: 3,
maximumLevel: 18
})
viewer.imageryLayers.addImageryProvider(imgLayer);
addGLTF()
// 添加gltf模型
function addGLTF() {
var entity = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(116.39780659888075, 39.90739653376521, 0.0),
model: {
uri: './porsche_918_free/scene.gltf',
}
});
}
let gl = '';
let refSpace = '';
let xrSession = '';
let animationFrameRequestID = '';
let originalDirection = ''; // 进入VR模式前的场景相机信息
// console.log("🚀 ~ sessionStarted ~ gl:",viewer.scene.canvas.getContext('webgl2'))
// vrButton设置监听事件,进入vr模式后检测vr设备
viewer.vrButton.viewModel.command.afterExecute.addEventListener(() => {
// 刚进入VR模式
if (viewer.vrButton.viewModel.isVRMode) {
setTimeout(() => {
// 检查当前环境
if (navigator.xr) {
// 检查是否支持 immersive-vr 模式
navigator.xr.isSessionSupported('immersive-vr').then((supported) => {
if (supported) {
// 请求VR会话
navigator.xr.requestSession('immersive-vr').then(sessionStarted);
originalDirection = viewer.camera.direction;
viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(116.397805, 39.90735, 1),
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(0.0),
roll: 0.0
}
});
} else {
alert("未检测到VR设备");
}
}).catch(() => {
alert("检测失败");
});
} else {
alert("当前浏览器不支持 WebXR");
}
}, 200);
} else {
// 刚退出VR模式
if (xrSession) xrSession.end();
}
});
/**
* VR会话开始
* @param {*} session
*/
function sessionStarted(session) {
xrSession = session;
// 监听会话结束事件
xrSession.addEventListener("end", sessionEnded);
// 与普通 WebGL 不同,这里需要设置 xrCompatible 参数
gl = viewer.scene.canvas.getContext('webgl2', { xrCompatible: true });
// gl.makeXRCompatible();
// 更新会话的渲染层,后续渲染会渲染在该层上
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
// session.updateRenderState({ baseLayer: new XRWebGLLayer() });
// 请求 local 空间,跟踪用户头部旋转
session.requestReferenceSpace('local').then(s => {
refSpace = s
session.requestAnimationFrame(onXRFrame); // 开始渲染
})
}
/**
* VR会话结束
*/
function sessionEnded() {
// If we have a pending animation request, cancel it; this
// will stop processing the animation of the scene.
if (animationFrameRequestID) {
xrSession.cancelAnimationFrame(animationFrameRequestID);
animationFrameRequestID = 0;
}
xrSession = null;
}
let lastTransMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1];
/**
* 设备渲染帧
* @param {*} time
* @param {*} frame
*/
function onXRFrame(time, frame) {
const session = frame.session;
animationFrameRequestID = session.requestAnimationFrame(onXRFrame);
// viewer.scene.render()
const pose = frame.getViewerPose(refSpace)
// 获取旋转和视图信息
if (pose) {
let glLayer = frame.session.renderState.baseLayer;
// Bind the WebGL layer's framebuffer to the renderer
gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
// Clear the GL context in preparation to render the new frame
gl.clearColor(0, 0, 0, 1.0);
gl.clearDepth(1.0); // Clear everything
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
pose.views.forEach(view => {
let viewport = glLayer.getViewport(view);
gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
gl.canvas.width = viewport.width * pose.views.length;
gl.canvas.height = viewport.height;
// 视角映射
if (view.eye == 'left') {
// let matrix = Cesium.Matrix4.fromRowMajorArray(view.transform.inverse.matrix, new Cesium.Matrix4());
// let result = Cesium.Matrix4.multiplyByPoint(matrix, originalDirection, new Cesium.Cartesian3());
// 矩阵应该使用上次变换的矩阵,而不是从刚进入VR模式后整个过程中的总矩阵
let mergedTransMatrix = Cesium.Matrix4.fromRowMajorArray(view.transform.inverse.matrix, new Cesium.Matrix4());
let realTransMatrix = Cesium.Matrix4.multiply(Cesium.Matrix4.fromRowMajorArray(lastTransMatrix, new Cesium.Matrix4()),
mergedTransMatrix, new Cesium.Matrix4());
let result = Cesium.Matrix4.multiplyByPoint(realTransMatrix, viewer.camera.direction, new Cesium.Cartesian3());
viewer.camera.direction = result;
viewer.scene.render();
lastTransMatrix = view.transform.matrix; // 矩阵的逆,作为下次计算基础
}
})
}
}
// XXX:
// 1. 【view.transform.inverse.matrix】矩阵中既包括了头盔旋转变换,也包含了位置平移变换(针对有距离传感器的VR设备),
// 最终将整个矩阵应用到了Cesium场景的【camera.direction】,逻辑是不合理的,【camera.direction】应该只对应头盔旋转变换。
// The transform property describes the position and orientation of the eye or camera represented by the XRView,
// given in that reference space.
// 2. 根据[WebXR基础介绍](https://developer.mozilla.org/en-US/docs/Web/API/WebXR_Device_API/Fundamentals#field_of_view),
// 左右两只眼看到的应该是有细微差别的。在官方示例中[如https://webxr-experiment.glitch.me/]可以看出,都是将一个canvas分成了
// 左右两块区域,然后根据XRView中的左右眼信息分别在两块区域绘制,但是Cesium未暴露出类似【gl.drawElements】的接口,只有
// 【scene.render】,调用后只会在整个canvas区域上进行绘制,没有左右分区的效果,所以借助了Cesium自带的VRButton,在进入Cesium
// 的VrMode后,再调用WebXR接口连接设备,同时XRView也只处理左眼,利用Cesium自身的左右同步。隐患未知。
</script>
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/xiyang6/cesium-demo.git
git@gitee.com:xiyang6/cesium-demo.git
xiyang6
cesium-demo
cesium-demo
master

搜索帮助

0d507c66 1850385 C8b1a773 1850385