@realsee/five 5.0.0-alpha.14 → 5.0.0-alpha.142
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -11
- package/docs/.nojekyll +1 -0
- package/docs/assets/highlight.css +134 -0
- package/docs/assets/icons.css +1043 -0
- package/docs/assets/{images/icons.png → icons.png} +0 -0
- package/docs/assets/{images/icons@2x.png → icons@2x.png} +0 -0
- package/docs/assets/main.js +52 -0
- package/docs/assets/search.js +1 -0
- package/docs/assets/style.css +1413 -0
- package/docs/assets/{images/widgets.png → widgets.png} +0 -0
- package/docs/assets/{images/widgets@2x.png → widgets@2x.png} +0 -0
- package/docs/classes/five.AnimationFrameLoop.html +15 -0
- package/docs/classes/five.BVH.html +10 -0
- package/docs/classes/five.BVHIntersect.html +1 -0
- package/docs/classes/five.BVHNode.html +7 -0
- package/docs/classes/five.BVHVector3.html +1 -0
- package/docs/classes/five.Camera.html +11 -0
- package/docs/classes/five.Five.html +310 -0
- package/docs/classes/five.InternalWebGLRenderer.html +1 -0
- package/docs/classes/five.IntersectMesh.html +1 -0
- package/docs/classes/five.LegacyPanoCircleMesh.html +5 -0
- package/docs/classes/five.Model.html +87 -0
- package/docs/classes/five.NetworkSubscribe.html +50 -0
- package/docs/classes/five.PBMContainer.html +17 -0
- package/docs/classes/five.PBMGroup.html +19 -0
- package/docs/classes/five.PBMMaterial.html +19 -0
- package/docs/classes/five.PBMMesh.html +7 -0
- package/docs/classes/five.PanoCircleMesh.html +7 -0
- package/docs/classes/five.Scene.html +3 -0
- package/docs/classes/five.Subscribe.html +56 -0
- package/docs/classes/five.Tile3D.html +34 -0
- package/docs/classes/five.Tile3DModel.html +15 -0
- package/docs/classes/five.TileBoundingSphere.html +1 -0
- package/docs/classes/five.TileCacheNode.html +1 -0
- package/docs/classes/five.TileCullingVolume.html +1 -0
- package/docs/classes/five.TileOrientedBoundingBox.html +1 -0
- package/docs/classes/five.TilePlane.html +1 -0
- package/docs/classes/five.TileRequestScheduler.html +16 -0
- package/docs/classes/five.Tileset3D.html +11 -0
- package/docs/classes/five.Tileset3DTraverser.html +1 -0
- package/docs/classes/five.TilesetCache.html +1 -0
- package/docs/classes/five.Work.html +30 -0
- package/docs/classes/five.XRButton.html +1 -0
- package/docs/classes/gltf_loader.GLTFLoader.html +17 -0
- package/docs/classes/gltf_loader.GLTFObject.html +7 -0
- package/docs/classes/line.Line.html +1 -0
- package/docs/classes/line.LineGeometry.html +1 -0
- package/docs/classes/line.LineMaterial.html +1 -0
- package/docs/classes/line.LineSegmentsGeometry.html +1 -0
- package/docs/classes/line.THREE_Line2.html +1 -0
- package/docs/classes/line.THREE_LineSegments2.html +1 -0
- package/docs/classes/react.Store.html +29 -0
- package/docs/classes/server.BVH.html +10 -0
- package/docs/classes/server.BVHIntersect.html +1 -0
- package/docs/classes/server.BVHNode.html +7 -0
- package/docs/classes/server.BVHVector3.html +1 -0
- package/docs/classes/server.Model.html +63 -0
- package/docs/classes/server.PBMGroup.html +9 -0
- package/docs/classes/server.PBMMesh.html +7 -0
- package/docs/classes/sticker.Sticker.html +32 -0
- package/docs/index.html +166 -422
- package/docs/interfaces/five.AddableObject.html +1 -0
- package/docs/interfaces/five.AnimationFrame.html +1 -0
- package/docs/interfaces/five.CameraPose.html +1 -0
- package/docs/interfaces/five.DepthPanoramaControllerCustomInitArgs.html +28 -0
- package/docs/interfaces/five.EventCallback.html +399 -0
- package/docs/interfaces/five.FiveInitArgs.html +107 -0
- package/docs/interfaces/five.FloorplanControllerCustomInitArgs.html +15 -0
- package/docs/interfaces/five.ImageOptions.html +18 -0
- package/docs/interfaces/five.ImageURLMappings.html +1 -0
- package/docs/interfaces/five.ImageURLOptions.html +17 -0
- package/docs/interfaces/five.IntersectMeshInterface.html +3 -0
- package/docs/interfaces/five.Intersection.html +7 -0
- package/docs/interfaces/five.MapviewControllerCustomInitArgs.html +15 -0
- package/docs/interfaces/five.ModelControllerCustomInitArgs.html +20 -0
- package/docs/interfaces/five.ModelEventCallback.html +22 -0
- package/docs/interfaces/five.MovePanoOptions.html +42 -0
- package/docs/interfaces/five.PBMPanoPicture.html +7 -0
- package/docs/interfaces/five.PBMParameters.html +19 -0
- package/docs/interfaces/five.PanoCircleMeshInterface.html +19 -0
- package/docs/interfaces/five.PanoramaControllerCustomInitArgs.html +33 -0
- package/docs/interfaces/five.PanoramaLikeControllerCustomInitArgs.html +20 -0
- package/docs/interfaces/five.Pose.html +37 -0
- package/docs/interfaces/five.Scissor.html +14 -0
- package/docs/interfaces/five.State.html +21 -0
- package/docs/interfaces/five.SubscribeMixinType.emit.html +1 -0
- package/docs/interfaces/five.SubscribeMixinType.hasListener.html +1 -0
- package/docs/interfaces/five.SubscribeMixinType.off.html +1 -0
- package/docs/interfaces/five.SubscribeMixinType.on.html +1 -0
- package/docs/interfaces/five.SubscribeMixinType.once.html +1 -0
- package/docs/interfaces/five.TextureOptions.html +20 -0
- package/docs/interfaces/five.Tile3DModelLoaderOptions.html +3 -0
- package/docs/interfaces/five.TileBoundingVolume.html +19 -0
- package/docs/interfaces/five.TileContent.html +1 -0
- package/docs/interfaces/five.Tileset3dOptions.html +1 -0
- package/docs/interfaces/five.TilesetJSON.html +1 -0
- package/docs/interfaces/five.TilesetJSONNode.html +1 -0
- package/docs/interfaces/five.TopviewControllerCustomInitArgs.html +7 -0
- package/docs/interfaces/five.VRPanoramaControllerCustomInitArgs.html +29 -0
- package/docs/interfaces/five.WorkCubeImage.html +13 -0
- package/docs/interfaces/five.WorkImage.html +21 -0
- package/docs/interfaces/five.WorkInitial.html +13 -0
- package/docs/interfaces/five.WorkModel.html +11 -0
- package/docs/interfaces/five.WorkModelTiles.html +3 -0
- package/docs/interfaces/five.WorkObserver.html +25 -0
- package/docs/interfaces/five.WorkTile.html +1 -0
- package/docs/interfaces/five.WorkVideo.html +9 -0
- package/docs/interfaces/five.XRPanoramaControllerCustomInitArgs.html +29 -0
- package/docs/interfaces/gltf_loader.GLTF.html +7 -0
- package/docs/interfaces/react.FiveActionReactCallbacks.html +62 -0
- package/docs/interfaces/react.FiveInjectionTypes.html +191 -0
- package/docs/interfaces/react.PropTypeOfFiveFeatures.html +1 -0
- package/docs/interfaces/server.Intersection.html +7 -0
- package/docs/interfaces/server.ModelEventCallback.html +18 -0
- package/docs/interfaces/sticker.IntersectionLike.html +8 -0
- package/docs/interfaces/vue.FiveActionVueCallbacks.html +62 -0
- package/docs/modules/five.SubscribeMixinType.html +1 -0
- package/docs/modules/five.html +496 -0
- package/docs/modules/gltf_loader.html +1 -0
- package/docs/modules/line.html +1 -0
- package/docs/modules/react.html +130 -1374
- package/docs/modules/server.html +18 -0
- package/docs/modules/sticker.html +1 -0
- package/docs/modules/vue.html +112 -0
- package/docs/modules.html +1 -120
- package/exporters/staticify.js +210 -0
- package/{index.d.ts → five/index.d.ts} +1211 -331
- package/five/index.js +372 -0
- package/gltf-loader/index.d.ts +76 -0
- package/gltf-loader/index.js +260 -0
- package/line/index.d.ts +69 -0
- package/line/index.js +260 -0
- package/package.json +25 -17
- package/react/index.d.ts +86 -24
- package/react/index.js +260 -1
- package/resource/{basis_transcoder.js → basis/basis_transcoder.js} +0 -0
- package/resource/{basis_transcoder.wasm → basis/basis_transcoder.wasm} +0 -0
- package/resource/gltf/draco_decoder.js +31 -0
- package/resource/gltf/draco_decoder.wasm +0 -0
- package/resource/gltf/draco_wasm_wrapper.js +119 -0
- package/scripts/five-staticify.js +26 -0
- package/server/index.d.ts +197 -26
- package/server/index.js +367 -1
- package/sticker/index.d.ts +71 -0
- package/sticker/index.js +260 -0
- package/templates/quick-start/README.md +1 -1
- package/templates/quick-start/package.json +1 -1
- package/templates/react-component/lib/index.tsx +3 -3
- package/umd/five-gltf-loader.js +2 -0
- package/umd/five-gltf-loader.js.LICENSE.txt +14 -0
- package/umd/five-line.js +2 -0
- package/umd/five-line.js.LICENSE.txt +14 -0
- package/umd/five-react.js +2 -0
- package/umd/five-react.js.LICENSE.txt +14 -0
- package/umd/five-sticker.js +2 -0
- package/umd/five-sticker.js.LICENSE.txt +14 -0
- package/umd/five-vue.js +1 -0
- package/umd/five.js +2 -0
- package/umd/five.js.LICENSE.txt +116 -0
- package/vue/index.d.ts +433 -0
- package/vue/index.js +260 -0
- package/bundles/five.js +0 -2
- package/bundles/five.js.LICENSE.txt +0 -160
- package/docs/assets/css/main.css +0 -2660
- package/docs/assets/js/main.js +0 -248
- package/docs/assets/js/search.js +0 -1
- package/docs/classes/index.five.html +0 -2498
- package/docs/classes/index.fivecamera.html +0 -311
- package/docs/classes/index.fivehashcubetexture.html +0 -240
- package/docs/classes/index.fiveline.html +0 -342
- package/docs/classes/index.fivelinegeometry.html +0 -500
- package/docs/classes/index.fivelinematerial.html +0 -276
- package/docs/classes/index.fivelinesegmentsgeometry.html +0 -447
- package/docs/classes/index.fivescene.html +0 -186
- package/docs/classes/index.internalwebglrenderer.html +0 -200
- package/docs/classes/index.model.html +0 -883
- package/docs/classes/index.pbmgroup.html +0 -415
- package/docs/classes/index.pbmmaterial.html +0 -521
- package/docs/classes/index.pbmmesh.html +0 -242
- package/docs/classes/index.subscribe.html +0 -556
- package/docs/classes/react.store.html +0 -584
- package/docs/interfaces/index.depthpanoramacontrollercustominitargs.html +0 -408
- package/docs/interfaces/index.eventcallback.html +0 -2452
- package/docs/interfaces/index.fiveinitargs.html +0 -695
- package/docs/interfaces/index.floorplancontrollercustominitargs.html +0 -283
- package/docs/interfaces/index.imageoptions.html +0 -320
- package/docs/interfaces/index.intersection.html +0 -215
- package/docs/interfaces/index.intersectmeshinterface.html +0 -176
- package/docs/interfaces/index.modelcontrollercustominitargs.html +0 -354
- package/docs/interfaces/index.modeleventcallback.html +0 -316
- package/docs/interfaces/index.movepanooptions.html +0 -457
- package/docs/interfaces/index.panocirclemeshinterface.html +0 -349
- package/docs/interfaces/index.panoramacontrollercustominitargs.html +0 -433
- package/docs/interfaces/index.panoramalikecontrollercustominitargs.html +0 -352
- package/docs/interfaces/index.pbmparameters.html +0 -462
- package/docs/interfaces/index.pose.html +0 -258
- package/docs/interfaces/index.scissor.html +0 -240
- package/docs/interfaces/index.state.html +0 -288
- package/docs/interfaces/index.subscribemixintype.emit.html +0 -180
- package/docs/interfaces/index.subscribemixintype.haslistener.html +0 -171
- package/docs/interfaces/index.subscribemixintype.off.html +0 -198
- package/docs/interfaces/index.subscribemixintype.on.html +0 -213
- package/docs/interfaces/index.subscribemixintype.once.html +0 -210
- package/docs/interfaces/index.topviewcontrollercustominitargs.html +0 -214
- package/docs/interfaces/index.vrpanoramacontrollercustominitargs.html +0 -420
- package/docs/interfaces/react.fiveactionreactcallbacks.html +0 -559
- package/docs/interfaces/react.fiveinjectiontypes.html +0 -1473
- package/docs/interfaces/react.injectfivetoprops.html +0 -259
- package/docs/modules/index.html +0 -3027
- package/docs/modules/index.subscribemixintype.html +0 -143
- package/five.js.LICENSE.txt +0 -160
- package/index.js +0 -1
- package/scripts/export-five-resource/chfs.exe +0 -0
- package/scripts/export-five-resource/fileify.js +0 -192
- package/scripts/export-five-resource/format-work.js +0 -71
- package/scripts/export-five-resource/staticify.js +0 -327
- package/scripts/transcode-model/BufferGeometryUtils.js +0 -832
- package/scripts/transcode-model/LoaderSupport.js +0 -1545
- package/scripts/transcode-model/MTLLoader.js +0 -602
- package/scripts/transcode-model/OBJLoader2.js +0 -1470
- package/scripts/transcode-model/obj2pbm.js +0 -65
|
Binary file
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const http = require("http");
|
|
4
|
-
const mkdirp = require("mkdirp");
|
|
5
|
-
const crypto = require("crypto");
|
|
6
|
-
const formatWork = require("./format-work");
|
|
7
|
-
|
|
8
|
-
const [
|
|
9
|
-
__command__,
|
|
10
|
-
__scriptPath__,
|
|
11
|
-
workPath,
|
|
12
|
-
exportPath,
|
|
13
|
-
] = process.argv;
|
|
14
|
-
|
|
15
|
-
const work = JSON.parse(fs.readFileSync(workPath));
|
|
16
|
-
|
|
17
|
-
if (!fs.existsSync(exportPath)) fs.mkdirSync(exportPath);
|
|
18
|
-
|
|
19
|
-
function md5(contents) {
|
|
20
|
-
const md5 = crypto.createHash("md5");
|
|
21
|
-
md5.update(contents);
|
|
22
|
-
return md5.digest("hex");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function shortPath(path) {
|
|
26
|
-
const array = path.split("/");
|
|
27
|
-
if (array.length < 3) return path;
|
|
28
|
-
const start = array.shift();
|
|
29
|
-
const end = array.pop();
|
|
30
|
-
return [start, md5(array.join("/")), end].join("/");
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function imageURL(url, options = {}) {
|
|
34
|
-
if (typeof options.transform === "function") {
|
|
35
|
-
return options.transform(url, options);
|
|
36
|
-
}
|
|
37
|
-
if (url.indexOf("//vrlab-public.ljcdn.com") >= 0) {
|
|
38
|
-
if (/\.basis(\?|$)/.test(url) && options.basisLoaderInitialized !== true) {
|
|
39
|
-
url = url.replace(/\.basis(\?|$)/, ".jpg$1");
|
|
40
|
-
}
|
|
41
|
-
if (/\.jpg$/.test(url)) {
|
|
42
|
-
const { size, quality, format } = options;
|
|
43
|
-
if (size || quality || format) {
|
|
44
|
-
let suffix = "?imageMogr2";
|
|
45
|
-
if (quality) suffix += "/quality/" + quality;
|
|
46
|
-
if (size) suffix += "/thumbnail/" + size + "x";
|
|
47
|
-
if (format) suffix += "/format/" + format;
|
|
48
|
-
url = url.replace("//vrlab-public.ljcdn.com", "//vrlab-image4.ljcdn.com") + suffix;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return url
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function downloadAsDataURL(url, filename, handleKey) {
|
|
56
|
-
filename = path.resolve(filename);
|
|
57
|
-
mkdirp.sync(path.dirname(filename));
|
|
58
|
-
return new Promise(resolve => {
|
|
59
|
-
http.get(url.replace(/^https\:/, "http:"), res => {
|
|
60
|
-
const mime = res.headers["content-type"];
|
|
61
|
-
const buffers = [];
|
|
62
|
-
|
|
63
|
-
res.on("data", chunk => buffers.push(chunk));
|
|
64
|
-
res.on("end", () => {
|
|
65
|
-
const dataURL = `data:${mime};base64,${Buffer.concat(buffers).toString("base64")}`;
|
|
66
|
-
const contents = `window[${JSON.stringify(handleKey)}] && window[${JSON.stringify(handleKey)}](${JSON.stringify(dataURL)})`;
|
|
67
|
-
fs.writeFileSync(filename, contents, "utf8");
|
|
68
|
-
resolve();
|
|
69
|
-
})
|
|
70
|
-
})
|
|
71
|
-
})
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function traverse(json, callback, keyPath = "") {
|
|
75
|
-
json = callback(json, keyPath);
|
|
76
|
-
if (json) {
|
|
77
|
-
if (typeof json === "array") {
|
|
78
|
-
for (let i = 0; i < json.length; i++) {
|
|
79
|
-
json[i] = traverse(json[i], callback, keyPath + "." + i);
|
|
80
|
-
}
|
|
81
|
-
} else if (typeof json === "object") {
|
|
82
|
-
for (let i = 0, keys = Object.keys(json); i < keys.length; i++) {
|
|
83
|
-
const key = keys[i];
|
|
84
|
-
json[key] = traverse(json[key], callback, keyPath + "." + key);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return json;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const urlRegExp = /^https?:\/\/(?:[\w-]+\.)*[\w-]{1,63}(?:\.(?:\w+))(?:$|\/)/i;
|
|
92
|
-
const fileRegExp = /\.[a-z0-9]{1,6}$/;
|
|
93
|
-
|
|
94
|
-
const htmlExample = (work) => `
|
|
95
|
-
<!DOCTYPE html>
|
|
96
|
-
<html lang="en">
|
|
97
|
-
<head>
|
|
98
|
-
<meta charset="UTF-8">
|
|
99
|
-
<title>如视 VR SDK 调用实例</title>
|
|
100
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
101
|
-
<style>
|
|
102
|
-
html, body { height: 100%; width: 100%; overflow: hidden; }
|
|
103
|
-
* { margin: 0; padding: 0 }
|
|
104
|
-
#app { position: fixed; top: 0; left: 0; right: 0; bottom: 0; overflow: hidden; }
|
|
105
|
-
.buttons { position: fixed; top: 10px; left: 10px; }
|
|
106
|
-
.buttons button { display: block; margin-top: 10px; }
|
|
107
|
-
</style>
|
|
108
|
-
</head>
|
|
109
|
-
<body>
|
|
110
|
-
<!-- 试图渲染容器 -->
|
|
111
|
-
<div id="app"></div>
|
|
112
|
-
|
|
113
|
-
<!-- 简易空间按钮 -->
|
|
114
|
-
<div class="buttons">
|
|
115
|
-
<!-- 点击进入相机全景模式 -->
|
|
116
|
-
<button onclick="five.changeMode(Five.Mode.Panorama)">全景模式(Panorama)</button>
|
|
117
|
-
<!-- 点击进入相机模型自由模式 -->
|
|
118
|
-
<button onclick="five.changeMode(Five.Mode.Floorplan, {latitude: Math.PI / 4, longitude: Math.PI / 4})">模型自由模式(Floorplan)</button>
|
|
119
|
-
<!-- 点击进入相机模型垂直模式 -->
|
|
120
|
-
<button onclick="five.changeMode(Five.Mode.Topview)">模型垂直模式(Topview)</button>
|
|
121
|
-
<!-- 点击进入相机VR眼睛模式 -->
|
|
122
|
-
<button onclick="five.changeMode(Five.Mode.VRPanorama)">眼睛模式(VRPanorama)</button>
|
|
123
|
-
<!-- 点击进入相机模型漫游模式 -->
|
|
124
|
-
<button onclick="five.changeMode(Five.Mode.Model)">模型漫游模式(Model)</button>
|
|
125
|
-
</div>
|
|
126
|
-
|
|
127
|
-
<script>${fs.readFileSync(path.join(__dirname, "../bundles/five.js"), "utf8")}</script>
|
|
128
|
-
<script>
|
|
129
|
-
// Five 是 如视 VR 视图渲染库的构造函数,通过 new 关键字产生实例。
|
|
130
|
-
// 构造函数的具体参数见文档,这边仅配置常用的几项
|
|
131
|
-
var five = new Five({
|
|
132
|
-
// 初始化为全景观测状态状态
|
|
133
|
-
mode: Five.Mode.Panorama,
|
|
134
|
-
// 初始化为摄像机位于第 0 个观测点的位置
|
|
135
|
-
panoIndex: 0,
|
|
136
|
-
// 初始化为摄像机水平角度为 0
|
|
137
|
-
longitude: 0,
|
|
138
|
-
// 初始化为摄像机俯仰角度为 0
|
|
139
|
-
latitude: 0,
|
|
140
|
-
// 取消初始化镜头过度动画
|
|
141
|
-
initWithTransition: false,
|
|
142
|
-
// 按需渲染
|
|
143
|
-
onlyRenderIfNeeds: true,
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
// 将渲染视图的 canvas 添加到 DOM 中
|
|
147
|
-
five.appendTo(document.getElementById("app"))
|
|
148
|
-
|
|
149
|
-
// 如果显示区域需要变动,在变动时请调用 refresh 重置显示参数
|
|
150
|
-
window.addEventListener("resize", function () {
|
|
151
|
-
five.refresh()
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
five.load(${JSON.stringify(work, "", " ")});
|
|
155
|
-
</script>
|
|
156
|
-
</body>
|
|
157
|
-
</html>
|
|
158
|
-
`;
|
|
159
|
-
|
|
160
|
-
let downloadQueue = Promise.resolve();
|
|
161
|
-
|
|
162
|
-
function main(work, exportPath) {
|
|
163
|
-
|
|
164
|
-
// 生成输出目录
|
|
165
|
-
mkdirp(path.resolve(exportPath));
|
|
166
|
-
|
|
167
|
-
// 修改work
|
|
168
|
-
traverse(work, (value, keyPath) => {
|
|
169
|
-
if (typeof value === "string" && urlRegExp.test(value) && fileRegExp.test(value)) {
|
|
170
|
-
const handleKey = "jsonp_" + md5(value);
|
|
171
|
-
const relativeValue = value.replace(urlRegExp, match => "downloads/" + md5(match) + "/") + "." + handleKey;
|
|
172
|
-
const filename = shortPath(path.resolve(exportPath, relativeValue));
|
|
173
|
-
downloadQueue = downloadQueue.then(() => {
|
|
174
|
-
if (keyPath.indexOf("model.material_textures") >= 0) {
|
|
175
|
-
value = imageURL(value, { size: 512 });
|
|
176
|
-
}
|
|
177
|
-
return downloadAsDataURL(value, filename, handleKey)
|
|
178
|
-
.then(() => console.log(`success ${value} => ${filename}`))
|
|
179
|
-
.catch(() => console.log(`error ${value} => ${filename}`));
|
|
180
|
-
})
|
|
181
|
-
return relativeValue;
|
|
182
|
-
}
|
|
183
|
-
return value;
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
work.base_url = "./";
|
|
187
|
-
|
|
188
|
-
// 输出 html
|
|
189
|
-
fs.writeFileSync(path.resolve(exportPath, "index.html"), htmlExample(work), "utf-8");
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
main(formatWork(work), exportPath);
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
function objectGet(obj, pathArray, defaultValue) {
|
|
2
|
-
try {
|
|
3
|
-
for (let i = 0; i < pathArray.length; i++) {
|
|
4
|
-
obj = obj[pathArray[i]];
|
|
5
|
-
}
|
|
6
|
-
return obj === undefined ? defaultValue : obj;
|
|
7
|
-
} catch (error) {
|
|
8
|
-
return defaultValue;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
module.exports = function parse(input) {
|
|
13
|
-
|
|
14
|
-
const work = {};
|
|
15
|
-
|
|
16
|
-
const base_url = objectGet(input, "base_url", "");
|
|
17
|
-
|
|
18
|
-
work.project_id = objectGet(input, ["project_id"]);
|
|
19
|
-
work.work_code = objectGet(input, ["work_code"]);
|
|
20
|
-
|
|
21
|
-
work.initial = {
|
|
22
|
-
pano_index: objectGet(input, ["initial", "pano_index"], objectGet(input, ["initial", "pano"], 0)),
|
|
23
|
-
latitude: objectGet(input, ["initial", "latitude"], 0),
|
|
24
|
-
longitude: objectGet(input, ["initial", "longitude"], 0),
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
work.model = {
|
|
28
|
-
file_url: base_url + objectGet(input, ["model", "file_url"], ""),
|
|
29
|
-
material_textures: objectGet(input, ["model", "material_textures"], []).map(url => {
|
|
30
|
-
if (/^https?:/.test(url)) return url;
|
|
31
|
-
return base_url + url;
|
|
32
|
-
}),
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
work.observers = objectGet(input, ["observers"], []).map(one => {
|
|
36
|
-
return {
|
|
37
|
-
visible_nodes: one.visible_nodes,
|
|
38
|
-
accessible_nodes: one.accessible_nodes,
|
|
39
|
-
index: one.index,
|
|
40
|
-
quaternion: one.quaternion,
|
|
41
|
-
standing_position: one.standing_position,
|
|
42
|
-
position: one.position,
|
|
43
|
-
floor_index: one.floor_index,
|
|
44
|
-
};
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
work.panorama = {
|
|
48
|
-
count: objectGet(input, ["panorama", "count"], 0),
|
|
49
|
-
list: objectGet(input, ["panorama", "list"], []).map((_, index) => {
|
|
50
|
-
const parseURL = (url) => {
|
|
51
|
-
const panoCubeBaseURL = objectGet(input, ["panorama", "base_url"], "");
|
|
52
|
-
const panoCubePath = objectGet(input, ["panorama", "pano_high_cube_base_url"], "");
|
|
53
|
-
if (panoCubePath || panoCubeBaseURL) {
|
|
54
|
-
return base_url + panoCubeBaseURL + panoCubePath + index + "/" + url;
|
|
55
|
-
} else {
|
|
56
|
-
return base_url + url;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return {
|
|
60
|
-
index: objectGet(input, ["panorama", "list", index, "index"], 0),
|
|
61
|
-
up: parseURL(objectGet(input, ["panorama", "list", index, "up"], objectGet(input, ["panorama", "info", index, "up"], ""))),
|
|
62
|
-
down: parseURL(objectGet(input, ["panorama", "list", index, "down"], objectGet(input, ["panorama", "info", index, "down"], ""))),
|
|
63
|
-
left: parseURL(objectGet(input, ["panorama", "list", index, "left"], objectGet(input, ["panorama", "info", index, "left"], ""))),
|
|
64
|
-
right: parseURL(objectGet(input, ["panorama", "list", index, "right"], objectGet(input, ["panorama", "info", index, "right"], ""))),
|
|
65
|
-
front: parseURL(objectGet(input, ["panorama", "list", index, "front"], objectGet(input, ["panorama", "info", index, "front"], ""))),
|
|
66
|
-
back: parseURL(objectGet(input, ["panorama", "list", index, "back"], objectGet(input, ["panorama", "info", index, "back"], ""))),
|
|
67
|
-
};
|
|
68
|
-
}),
|
|
69
|
-
}
|
|
70
|
-
return work;
|
|
71
|
-
};
|
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const http = require("http");
|
|
4
|
-
const mkdirp = require("mkdirp");
|
|
5
|
-
const crypto = require("crypto");
|
|
6
|
-
const formatWork = require("./format-work");
|
|
7
|
-
|
|
8
|
-
const [
|
|
9
|
-
__command__,
|
|
10
|
-
__scriptPath__,
|
|
11
|
-
workPath,
|
|
12
|
-
exportPath,
|
|
13
|
-
] = process.argv;
|
|
14
|
-
|
|
15
|
-
const work = JSON.parse(fs.readFileSync(workPath));
|
|
16
|
-
|
|
17
|
-
if (!fs.existsSync(exportPath)) fs.mkdirSync(exportPath);
|
|
18
|
-
|
|
19
|
-
function md5(contents) {
|
|
20
|
-
const md5 = crypto.createHash("md5");
|
|
21
|
-
md5.update(contents);
|
|
22
|
-
return md5.digest("hex");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function shortPath(path) {
|
|
26
|
-
const array = path.split("/");
|
|
27
|
-
if (array.length < 3) return path;
|
|
28
|
-
const start = array.shift();
|
|
29
|
-
const end = array.pop();
|
|
30
|
-
return [start, md5(array.join("/")), end].join("/");
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
function imageURL(url, options = {}) {
|
|
35
|
-
if (typeof options.transform === "function") {
|
|
36
|
-
return options.transform(url, options)
|
|
37
|
-
}
|
|
38
|
-
if (url.indexOf("//vrlab-public.ljcdn.com") >= 0) {
|
|
39
|
-
if (/\.basis(\?|$)/.test(url) && options.basisLoaderInitialized !== true) {
|
|
40
|
-
url = url.replace(/\.basis(\?|$)/, ".jpg$1");
|
|
41
|
-
}
|
|
42
|
-
if (/\.jpg$/.test(url)) {
|
|
43
|
-
const { size, quality, format } = options;
|
|
44
|
-
if (size || quality || format) {
|
|
45
|
-
let suffix = "?imageMogr2";
|
|
46
|
-
if (quality) suffix += "/quality/" + quality;
|
|
47
|
-
if (size) suffix += "/thumbnail/" + size + "x";
|
|
48
|
-
if (format) suffix += "/format/" + format;
|
|
49
|
-
url = url.replace("//vrlab-public.ljcdn.com", "//vrlab-image4.ljcdn.com") + suffix;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return url;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function download(url, filename) {
|
|
57
|
-
filename = path.resolve(filename);
|
|
58
|
-
mkdirp.sync(path.dirname(filename));
|
|
59
|
-
return new Promise(resolve => {
|
|
60
|
-
http.get(url.replace(/^https\:/, "http:"), res => {
|
|
61
|
-
const writeStream = fs.createWriteStream(filename);
|
|
62
|
-
res.pipe(writeStream);
|
|
63
|
-
res.on("end", resolve);
|
|
64
|
-
})
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function traverse(json, callback, keyPath = "") {
|
|
69
|
-
json = callback(json, keyPath);
|
|
70
|
-
if (json) {
|
|
71
|
-
if (typeof json === "array") {
|
|
72
|
-
for (let i = 0; i < json.length; i++) {
|
|
73
|
-
json[i] = traverse(json[i], callback, keyPath + "." + i);
|
|
74
|
-
}
|
|
75
|
-
} else if (typeof json === "object") {
|
|
76
|
-
for (let i = 0, keys = Object.keys(json); i < keys.length; i++) {
|
|
77
|
-
const key = keys[i];
|
|
78
|
-
json[key] = traverse(json[key], callback, keyPath + "." + key);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return json;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const urlRegExp = /^https?:\/\/(?:[\w-]+\.)*[\w-]{1,63}(?:\.(?:\w+))(?:$|\/)/i;
|
|
86
|
-
const fileRegExp = /\.[a-z0-9]{1,6}$/i;
|
|
87
|
-
|
|
88
|
-
const htmlExample = `
|
|
89
|
-
<!DOCTYPE html>
|
|
90
|
-
<html lang="en">
|
|
91
|
-
<head>
|
|
92
|
-
<meta charset="UTF-8">
|
|
93
|
-
<title>如视 VR SDK 调用实例</title>
|
|
94
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
95
|
-
<style>
|
|
96
|
-
html, body { height: 100%; width: 100%; overflow: hidden; }
|
|
97
|
-
* { margin: 0; padding: 0 }
|
|
98
|
-
#app { position: fixed; top: 0; left: 0; right: 0; bottom: 0; overflow: hidden; }
|
|
99
|
-
.buttons { position: fixed; top: 10px; left: 10px; }
|
|
100
|
-
.buttons button { display: block; margin-top: 10px; }
|
|
101
|
-
</style>
|
|
102
|
-
</head>
|
|
103
|
-
<body>
|
|
104
|
-
<script>
|
|
105
|
-
if (location.href.indexOf("file:") === 0) {
|
|
106
|
-
alert("Please follow the README.md file to run the project.\n请根据README.md文件来启动项目。")
|
|
107
|
-
}
|
|
108
|
-
</script>
|
|
109
|
-
<!-- 试图渲染容器 -->
|
|
110
|
-
<div id="app"></div>
|
|
111
|
-
|
|
112
|
-
<!-- 简易空间按钮 -->
|
|
113
|
-
<div class="buttons">
|
|
114
|
-
<!-- 点击进入相机全景模式 -->
|
|
115
|
-
<button onclick="five.changeMode(Five.Mode.Panorama)">全景模式(Panorama)</button>
|
|
116
|
-
<!-- 点击进入相机模型自由模式 -->
|
|
117
|
-
<button onclick="five.changeMode(Five.Mode.Floorplan, {latitude: Math.PI / 4, longitude: Math.PI / 4})">模型自由模式(Floorplan)</button>
|
|
118
|
-
<!-- 点击进入相机模型垂直模式 -->
|
|
119
|
-
<button onclick="five.changeMode(Five.Mode.Topview)">模型垂直模式(Topview)</button>
|
|
120
|
-
<!-- 点击进入相机VR眼睛模式 -->
|
|
121
|
-
<button onclick="five.changeMode(Five.Mode.VRPanorama)">眼睛模式(VRPanorama)</button>
|
|
122
|
-
<!-- 点击进入相机模型漫游模式 -->
|
|
123
|
-
<button onclick="five.changeMode(Five.Mode.Model)">模型漫游模式(Model)</button>
|
|
124
|
-
</div>
|
|
125
|
-
|
|
126
|
-
<script src="./five.js"></script>
|
|
127
|
-
<script>
|
|
128
|
-
// Five 是 如视 VR 视图渲染库的构造函数,通过 new 关键字产生实例。
|
|
129
|
-
// 构造函数的具体参数见文档,这边仅配置常用的几项
|
|
130
|
-
var five = new Five({
|
|
131
|
-
// 初始化为全景观测状态状态
|
|
132
|
-
mode: Five.Mode.Panorama,
|
|
133
|
-
// 初始化为摄像机位于第 0 个观测点的位置
|
|
134
|
-
panoIndex: 0,
|
|
135
|
-
// 初始化为摄像机水平角度为 0
|
|
136
|
-
longitude: 0,
|
|
137
|
-
// 初始化为摄像机俯仰角度为 0
|
|
138
|
-
latitude: 0,
|
|
139
|
-
// 取消初始化镜头过度动画
|
|
140
|
-
initWithTransition: false,
|
|
141
|
-
// 按需渲染
|
|
142
|
-
onlyRenderIfNeeds: true,
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
// 将渲染视图的 canvas 添加到 DOM 中
|
|
146
|
-
five.appendTo(document.getElementById("app"))
|
|
147
|
-
|
|
148
|
-
// 如果显示区域需要变动,在变动时请调用 refresh 重置显示参数
|
|
149
|
-
window.addEventListener("resize", function () {
|
|
150
|
-
five.refresh()
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
// 获取当前 VR 的房间数据,加载进来
|
|
154
|
-
ajax("./work.json?__random=" + Date.now(), function (error, json) {
|
|
155
|
-
if (error) throw error
|
|
156
|
-
// 房间数据在 work.json 中,具体数据定义请在文档中查询
|
|
157
|
-
five.load(JSON.parse(json))
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
// five 可以通过 on 方法来监听生命周期及交互事件
|
|
161
|
-
// 具体的事件类型和描述详见文档
|
|
162
|
-
// 这里肩痛 模型加载完成的事件
|
|
163
|
-
// 在这个事件之后,模型加载完成
|
|
164
|
-
five.on("modelLoaded", function() {
|
|
165
|
-
var buttons = document.getElementsByClassName("buttons")[0]
|
|
166
|
-
// 通过 five.model.hasFloors() 方法可以获取当前房间的模型有多少楼层
|
|
167
|
-
// 该方法请在 modelLoaded 之前之后执行
|
|
168
|
-
var floors = five.model.hasFloors()
|
|
169
|
-
function createButton (title, value) {
|
|
170
|
-
var button = document.createElement("button")
|
|
171
|
-
button.innerHTML = title
|
|
172
|
-
button.value = value
|
|
173
|
-
button.onclick = function buttonClick (event) {
|
|
174
|
-
var floor = JSON.parse(this.value)
|
|
175
|
-
// 通过 five.model.show 方法可以只显示某一层的模型
|
|
176
|
-
if (floor === null) five.model.show()
|
|
177
|
-
else five.model.show(floor)
|
|
178
|
-
}
|
|
179
|
-
return button
|
|
180
|
-
}
|
|
181
|
-
buttons.appendChild(createButton("全部楼层", "null"))
|
|
182
|
-
for (var index = 0; index < floors; index++) {
|
|
183
|
-
buttons.appendChild(createButton("第" + index + "层", String(index)))
|
|
184
|
-
}
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
// === 帮助函数 ===
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* 通过 xhr 异步获取数据
|
|
191
|
-
* @param {String} url 请求数据的地址
|
|
192
|
-
* @param {Function} callback 数据返回的回掉函数
|
|
193
|
-
*
|
|
194
|
-
* callback (error, responseText)
|
|
195
|
-
* @param {Error|Null} error 如果请求失败返回 error, 如果成功则为 null
|
|
196
|
-
* @param {String|Undefined} responseText 如果成功, 返回异步获取的数据的字符串
|
|
197
|
-
*/
|
|
198
|
-
function ajax (url, callback) {
|
|
199
|
-
var xhr = new XMLHttpRequest()
|
|
200
|
-
xhr.onreadystatechange = function () {
|
|
201
|
-
if (xhr.readyState !== 4) return
|
|
202
|
-
if (xhr.status === 200 || xhr.status === 0) {
|
|
203
|
-
if (callback) callback(null, xhr.response)
|
|
204
|
-
} else {
|
|
205
|
-
if (callback) callback(new Error("status:" + xhr.status))
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
xhr.open("GET", url, true)
|
|
209
|
-
xhr.send(null)
|
|
210
|
-
}
|
|
211
|
-
</script>
|
|
212
|
-
</body>
|
|
213
|
-
</html>
|
|
214
|
-
`;
|
|
215
|
-
|
|
216
|
-
const pyServer = `
|
|
217
|
-
import webbrowser
|
|
218
|
-
import posixpath
|
|
219
|
-
import urllib
|
|
220
|
-
import os
|
|
221
|
-
from datetime import datetime
|
|
222
|
-
from SimpleHTTPServer import SimpleHTTPRequestHandler
|
|
223
|
-
from BaseHTTPServer import HTTPServer
|
|
224
|
-
|
|
225
|
-
class RootedHTTPServer(HTTPServer):
|
|
226
|
-
def __init__(self, base_path, *args, **kwargs):
|
|
227
|
-
HTTPServer.__init__(self, *args, **kwargs)
|
|
228
|
-
self.RequestHandlerClass.base_path = base_path
|
|
229
|
-
|
|
230
|
-
class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
|
|
231
|
-
def translate_path(self, path):
|
|
232
|
-
path = posixpath.normpath(urllib.unquote(path)).split("?")[0]
|
|
233
|
-
words = path.split("/")
|
|
234
|
-
words = filter(None, words)
|
|
235
|
-
path = self.base_path
|
|
236
|
-
for word in words:
|
|
237
|
-
drive, word = os.path.splitdrive(word)
|
|
238
|
-
head, word = os.path.split(word)
|
|
239
|
-
if word in (os.curdir, os.pardir):
|
|
240
|
-
continue
|
|
241
|
-
path = os.path.join(path, word)
|
|
242
|
-
return path
|
|
243
|
-
|
|
244
|
-
def server(HandlerClass=RootedHTTPRequestHandler, ServerClass=RootedHTTPServer):
|
|
245
|
-
server_address = ("127.0.0.1", 8080)
|
|
246
|
-
print os.path.dirname(os.path.abspath(__file__))
|
|
247
|
-
httpd = ServerClass(os.path.dirname(os.path.abspath(__file__)), server_address, HandlerClass)
|
|
248
|
-
sa = httpd.socket.getsockname()
|
|
249
|
-
print "Serving HTTP on http://127.0.0.1:8080 ..."
|
|
250
|
-
webbrowser.open("http://127.0.0.1:8080/?__random=" + datetime.now().strftime("%s"), new=2)
|
|
251
|
-
httpd.serve_forever()
|
|
252
|
-
|
|
253
|
-
if __name__ == "__main__":
|
|
254
|
-
server()
|
|
255
|
-
`;
|
|
256
|
-
|
|
257
|
-
const readme = `
|
|
258
|
-
# How to run a project
|
|
259
|
-
|
|
260
|
-
Windows:
|
|
261
|
-
1. run chfs.exe
|
|
262
|
-
2. open \`http://127.0.0.1\`.
|
|
263
|
-
|
|
264
|
-
MacOS & Linux:
|
|
265
|
-
1. make sure you have *Python* on your computer already.
|
|
266
|
-
2. run \`python server.py\`.
|
|
267
|
-
3. if broswer is not open automatically, open \`http://127.0.0.1:8080\`.
|
|
268
|
-
|
|
269
|
-
# 如何使用
|
|
270
|
-
|
|
271
|
-
Windows:
|
|
272
|
-
1. 运行 chfs.exe
|
|
273
|
-
2. 打开浏览器访问 \`http://127.0.0.1\`.
|
|
274
|
-
|
|
275
|
-
MacOS & Linux:
|
|
276
|
-
1. 确保你已经安装了 *Python*;
|
|
277
|
-
2. 运行 \`python server.py\`;
|
|
278
|
-
3. 如果你的浏览器没有自动打开,那么请自行访问 \`http://127.0.0.1:8080\`。
|
|
279
|
-
`
|
|
280
|
-
|
|
281
|
-
let downloadQueue = Promise.resolve()
|
|
282
|
-
|
|
283
|
-
function main(work, exportPath) {
|
|
284
|
-
|
|
285
|
-
// 生成输出目录
|
|
286
|
-
mkdirp(path.resolve(exportPath));
|
|
287
|
-
|
|
288
|
-
// 修改work
|
|
289
|
-
traverse(work, (value, keyPath) => {
|
|
290
|
-
if (typeof value === "string" && urlRegExp.test(value) && fileRegExp.test(value)) {
|
|
291
|
-
const relativeValue = value.replace(urlRegExp, match => "downloads/" + md5(match) + "/");
|
|
292
|
-
const filename = shortPath(path.resolve(exportPath, relativeValue));
|
|
293
|
-
downloadQueue = downloadQueue.then(() => {
|
|
294
|
-
if (keyPath.indexOf("model.material_textures") >= 0) {
|
|
295
|
-
value = imageURL(value, { size: 512 });
|
|
296
|
-
}
|
|
297
|
-
return download(value, filename)
|
|
298
|
-
.then(() => console.log(`success ${value} => ${filename}`))
|
|
299
|
-
.catch(() => console.log(`error ${value} => ${filename}`));
|
|
300
|
-
})
|
|
301
|
-
return relativeValue;
|
|
302
|
-
}
|
|
303
|
-
return value;
|
|
304
|
-
})
|
|
305
|
-
|
|
306
|
-
work.base_url = "./";
|
|
307
|
-
|
|
308
|
-
// 输出 work.json
|
|
309
|
-
fs.writeFileSync(path.resolve(exportPath, "work.json"), JSON.stringify(work, "", " "), "utf-8");
|
|
310
|
-
|
|
311
|
-
// 输出 html
|
|
312
|
-
fs.writeFileSync(path.resolve(exportPath, "index.html"), htmlExample, "utf-8");
|
|
313
|
-
|
|
314
|
-
// 输出 readme
|
|
315
|
-
fs.writeFileSync(path.resolve(exportPath, "README.md"), readme, "utf-8");
|
|
316
|
-
|
|
317
|
-
// copy five.js
|
|
318
|
-
fs.copyFileSync(path.join(__dirname, "../bundles/five.js"), path.resolve(exportPath, "five.js"));
|
|
319
|
-
|
|
320
|
-
// copy five.js
|
|
321
|
-
fs.copyFileSync(path.join(__dirname, "chfs.exe"), path.resolve(exportPath, "chfs.exe"));
|
|
322
|
-
|
|
323
|
-
// 输出 server.py
|
|
324
|
-
fs.writeFileSync(path.resolve(exportPath, "server.py"), pyServer, "utf-8");
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
main(formatWork(work), exportPath);
|