跳到主要内容

展示三维空间

上一章回顾: 起步

  • 你学会了如何初始化环境。
  • 并且你书写了一段代码,虽然不知道这段代码干了什么,不过也顺利得完成了载入并展示一个 VR 的工作。
本章你可以学习到
  • 了解什么是 Work
  • 了解 FiveProvider / FiveCanvas 组件是如何工作的

准备工作

和上一章节一样,我们新建一个目录(src/1.displaying-work)以及对应的 html 文件 以及 jsxtsx 文件。

jsxtsx 文件可以先拷贝上一章节的内容。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link rel="icon" href="data:;base64,iVBORw0KGgo=">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>展示空间 | Display a work</title>
  <style>
    * { margin: 0; padding: 0; }
    html, body #app { width: 100%; height: 100%; overflow: hidden; }
  </style>
</head>
<body>
  <div id="app"></div>
  <script type="module" src="./index"></script>
</body>
</html>

src/1.displaying-work/withFetchWork.jsx

import React, { Component } from "react";
import { parseWork } from "@realsee/five";

/**
 * React HOC 获取 work
 * @param url work.json 的地址
 */
function withFetchWork(url) {
  return function(Compnent) {
    return class extends Component {
      state = { work: null };
      componentDidMount() {
        fetch(url).then(res => res.json()).then(json => {
          this.setState({ work: parseWork(json) });
        });
      }
      render() {
        if (this.state.work === null) return null;
        return <Compnent work={this.state.work} {...this.props}/>;
      }
    }
  }
}

export { withFetchWork };

src/1.displaying-work/withWindowDimensions.jsx

import React, { Component } from "react";

/**
* React HOC: 获取当前窗口的尺寸
*/
function withWindowDimensions() {
return function(Compnent) {
return class extends Component {
state = this.getWindowDimensions();
resizeListener = () => {
this.setState(this.getWindowDimensions());
};
getWindowDimensions() {
return { width: window.innerWidth, height: window.innerHeight };
}
componentDidMount() {
window.addEventListener("resize", this.resizeListener, false);
}
componentWillUnmount() {
window.removeEventListener("resize", this.resizeListener, false);
}
render() {
const dimensions = { width: this.state.width, height: this.state.height };
return <Compnent windowDimensions={dimensions} {...this.props}/>;
}
}
}
}

export { withWindowDimensions };

src/1.displaying-work/App.jsx

import React, { Component } from "react";
import { compose } from "@wordpress/compose";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
import { withFetchWork } from "./withFetchWork";
import { withWindowDimensions } from "./withWindowDimensions";

/** work.json 的数据 URL */
const workURL = "https://vrlab-public.ljcdn.com/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";

const FiveProvider = createFiveProvider();

const App = compose(
withFetchWork(workURL),
withWindowDimensions()
)(class extends Component {
render() {
const { work, windowDimensions } = this.props;
return <FiveProvider initialWork={work}>
<FiveCanvas width={windowDimensions.width} height={windowDimensions.height}/>
</FiveProvider>;
}
});

export { App };

src/1.displaying-work/index.jsx

import React from "react";
import ReactDOM from "react-dom";
import { App } from "./App";

ReactDOM.render(<App/>, document.querySelector("#app"));

export {};

启动服务 npm run dev。 并跳转到当前页面 "http://localhost:3000/src/1.displaying-work/index.html"。

信息

请查看你的控制台,端口号会因为你的配置以及当前端口占用情况变更,请已控制台输出的为准。 如果你使用其他开发构建工具,请按照自己的开发构建工具的要求启动服务。

什么是 Work

接下来停下写代码的双手,我们来理解一些概念,放心很简单。

Work 简介

我们将一个三维空间叫做一个 Work。 那么一个 Work 是通过 json 的结构体描述的,称之为 work.jsonWork 你可以通过如视开放平台接口获取。 也可以像本次示例一样将之静态化使用。

Five 提供了 parseWork 的方法,用于解析 work.json,然后便可以得到 work 对象。 将 work 对象传入 FiveProviderinitialWork 属性中就可以初始化场景。你在上一章也是这么做的。

work 的使用限制

你需要在如视开发者中心配置你的 安全域名 以及 work数据的 可用时间。 在生成环境中使用 Five SDK 对对此做校验来保护开发者以及如视的数据安全。

在以下情况不会校验上述限制,便于开发和测试:

  • 域名为 localhost
  • 域名为 ip 地址,如 127.0.0.1, 192.168.0.5, 172.30.2.0, 10.33.10.2 等
  • 在非 http 情况下访问,比如 file:// 协议下

work.json的数据样例及数据说明

你并不需要了解 work.json 的内容也可能很好的使用 Five SDK. 虽然多了解一些,也不是坏事。

点击查看work.json
{
  "_signature": "LLzk2WHDbRfzQ5R+v82uVQqAGWMPfvgQ05hTwxgWKGeXbTPKtoQ8eI6FmCxJjtVjQW+wuZmZfxpzXePv4MGrWidG/05i5RRSELlPLEFZN3qYPykJLEIYhg3Wtvr8XkOI8wdeMgV82CP4Hyi84k/W2g+S+HcFs5oXfbfbFXPL/Gs=",
  "allow_hosts": [
    "*"
  ],
  "base_url": "https://vrlab-public.ljcdn.com/release/auto3dhd/9380ce27b46cbc5ba8d47fcf0e4c9e4f/",
  "certificate": "-----BEGIN CERTIFICATE-----\nMIIEMzCCAhsCCQDYAS/7ATZRmTANBgkqhkiG9w0BAQsFADCBkzELMAkGA1UEBhMC\nQ04xEDAOBgNVBAgMB0JlaWppbmcxEDAOBgNVBAcMB0JlaWppbmcxFDASBgNVBAoM\nC2xpYW5qaWEuY29tMRAwDgYDVQQLDAdSZWFsc2VlMREwDwYDVQQDDAhIYXJkd2Fy\nZTElMCMGCSqGSIb3DQEJARYWbml1aGFpcWluZ0BsaWFuamlhLmNvbTAeFw0yMTA5\nMTAwNTIwMDBaFw0zMTA5MDgwNTIwMDBaMIGmMQswCQYDVQQGEwJDTjEQMA4GA1UE\nCAwHQmVpSmluZzEQMA4GA1UEBwwHQmVpSmluZzEQMA4GA1UECgwHUmVhbHNlZTEZ\nMBcGA1UECwwQUmVhbHNlZUFwcEdldHdheTEgMB4GA1UEAwwXYXBwLWdhdGV3YXku\ncmVhbHNlZS5jb20xJDAiBgkqhkiG9w0BCQEWFWRldmVsb3BlckByZWFsc2VlLmNv\nbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuv/y3Ezsy/wh3LCA8vomPbgI\nSO9iO5kyR+oAetklD+epMU6J/ZbvTDEomZxuS5iyyKGBupzAh2ZFLIy7tsE71Vx1\nIIvT7Kdyq66lMU4YzdrpKUcxv7oOQnO8DA1orKluNa4jkyXBywHKs/Q+20LVc+RD\ngKXqFGJUdo8mAxEScs0CAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAkMxsU4VLPd4J\n0rElBNBIyqPtvnlTs6VkhIK0l4oM58wtDKc1uG9UPSX5j29NguZM6LOe0jCsU2Vg\nEpUseMWQjx4o2yBg7MokQyjWc1zu6PppKhQ+RqHQy/biJ2zsIMpX3oMASXffvnW5\nn4Bjyo1JdDJiLm1fLvLlVVxQoraJD+rtpqWDEYixGVREUo5OIL5Y5dVjkHG2r9RQ\nQuu3yEiyr9gAW8yhz3YR6/sJ6boyGK8NC0v8Jih7NnCdT+9ML+3jn3P5F3TeXdSf\nVeYIm5oWAOTe3AjjKP8ARMb2RYACjg80/AcowD/dvRRjbwQmyucUNug2pXJynXpD\nNfx1IBmUmzSAT1Z5yNuY/f3VRBJvmIQ6Jpmef+g0/wUJpyS4SObguItyYlFPLqRH\nK1oKqNX/uV0GWWEQl6Lml986TzlHxc4ljtHBhjzlKYIYYZLWWipk4JiB8hxJcTK+\ncrgvclEQSxFlmAyoqxYFClrOOsPqZJdBhDTvoUWnnWuJLQt7DLHpyInp+S75Gg3o\n0zgHpt9m26B3YbjQGYMQlYmhl2VLQa+Ey0W8UZQXLcTvoRT4p+8crqr6cNNsxCyZ\nm08vBbEMIMvhBeLQvpM75oaMBmelegipFl2eelxVIHdGJWoyJSZQUdXN0uSidhZp\nI7AIgzhqK1Ku/IXK0OSXJonn+/9X/VI=\n-----END CERTIFICATE-----",
  "create_time": "2020-07-29T15:18:06+08:00",
  "expire_at": "2132653492169",
  "initial": {
    "flag_position": [
      -1.8683282713225706,
      -1.1184803014502747,
      -2.536637882840082
    ],
    "fov": 95,
    "heading": 0,
    "latitude": 0,
    "longitude": 5.58602282229265,
    "pano": 4,
    "pano_index": 4
  },
  "model": {
    "file_url": "model/auto3d-syVb5hzy8ZL1gZut_VvGDo.at3d",
    "material_base_url": "materials/",
    "material_textures": [
      "texture_0.jpg",
      "texture_1.jpg",
      "texture_2.jpg",
      "texture_3.jpg",
      "texture_4.jpg",
      "texture_5.jpg",
      "texture_6.jpg",
      "texture_7.jpg",
      "texture_8.jpg"
    ],
    "modify_time": "2020-07-29T15:37:17+08:00",
    "type": 0
  },
  "observers": [
    {
      "accessible_nodes": [
        1,
        2,
        3,
        4,
        6,
        7,
        8
      ],
      "floor_index": 0,
      "index": 0,
      "offset_point_count": 551,
      "position": [
        -2.9148900508880615,
        0,
        1.392490029335022
      ],
      "quaternion": {
        "w": 0.44238951628615497,
        "x": -0.0011834399273419546,
        "y": -0.8968221073969266,
        "z": -0.00045692663054024737
      },
      "standing_position": [
        -2.9148900508880615,
        -1.1193245547539874,
        1.392490029335022
      ],
      "visible_nodes": [
        1,
        2,
        3,
        4,
        6,
        7,
        8
      ]
    },
    {
      "accessible_nodes": [
        0,
        2,
        3,
        4
      ],
      "floor_index": 0,
      "index": 1,
      "offset_point_count": 1382,
      "position": [
        -1.780460000038147,
        -0.00217098998837173,
        4.450079917907715
      ],
      "quaternion": {
        "w": 0.46776604948048534,
        "x": -0.0011699393533674196,
        "y": -0.883851410579187,
        "z": -0.000490464139922521
      },
      "standing_position": [
        -1.780460000038147,
        -1.1214462854241507,
        4.450079917907715
      ],
      "visible_nodes": [
        0,
        2,
        3,
        4
      ]
    },
    {
      "accessible_nodes": [
        0,
        1,
        3,
        4
      ],
      "floor_index": 0,
      "index": 2,
      "offset_point_count": 378,
      "position": [
        -1.3428200483322144,
        -0.0028426700737327337,
        6.358610153198242
      ],
      "quaternion": {
        "w": 0.6069850728938949,
        "x": -0.001073151580086956,
        "y": -0.7947122170838032,
        "z": -0.0006765059598702671
      },
      "standing_position": [
        -1.3428200483322144,
        -1.1225737228916606,
        6.358610153198242
      ],
      "visible_nodes": [
        0,
        1,
        3,
        4
      ]
    },
    {
      "accessible_nodes": [
        0,
        1,
        2,
        4,
        6,
        7,
        8
      ],
      "floor_index": 0,
      "index": 3,
      "offset_point_count": 0,
      "position": [
        -2.554189920425415,
        -0.005082080140709877,
        6.343259811401367
      ],
      "quaternion": {
        "w": -0.030997155509175898,
        "x": -0.0033666821765646494,
        "y": -0.9994984128781037,
        "z": -0.005546881036692224
      },
      "standing_position": [
        -2.554189920425415,
        -1.1224907918710612,
        6.343259811401367
      ],
      "visible_nodes": [
        0,
        1,
        2,
        4,
        6,
        7,
        8
      ]
    },
    {
      "accessible_nodes": [
        0,
        1,
        2,
        3,
        5,
        6,
        7,
        8,
        9,
        10,
        11
      ],
      "floor_index": 0,
      "index": 4,
      "offset_point_count": 941,
      "position": [
        -2.91471004486084,
        -0.0003035110130440444,
        0.06049229949712753
      ],
      "quaternion": {
        "w": 0.0513025987418296,
        "x": -0.0012676475973127641,
        "y": -0.9986823460816978,
        "z": 0.00004879134915086605
      },
      "standing_position": [
        -2.91471004486084,
        -1.1184803014502747,
        0.06049229949712753
      ],
      "visible_nodes": [
        0,
        1,
        2,
        3,
        5,
        6,
        7,
        8,
        9,
        10,
        11
      ]
    },
    {
      "accessible_nodes": [
        4,
        6,
        9,
        10
      ],
      "floor_index": 0,
      "index": 5,
      "offset_point_count": 863,
      "position": [
        -1.0017000436782837,
        -0.005517140030860901,
        -1.6075899600982666
      ],
      "quaternion": {
        "w": -0.0344319061946854,
        "x": -0.001258810265919515,
        "y": -0.9994062434209862,
        "z": 0.0001571970577815824
      },
      "standing_position": [
        -1.0017000436782837,
        -1.1178040247150276,
        -1.6075899600982666
      ],
      "visible_nodes": [
        4,
        6,
        9,
        10
      ]
    },
    {
      "accessible_nodes": [
        0,
        3,
        4,
        5,
        7,
        8
      ],
      "floor_index": 0,
      "index": 6,
      "offset_point_count": 1322,
      "position": [
        -2.846139907836914,
        -0.001211759983561933,
        -3.169840097427368
      ],
      "quaternion": {
        "w": 0.32066123052403445,
        "x": -0.0012332355032137405,
        "y": -0.9471930957831524,
        "z": -0.00029739399948980815
      },
      "standing_position": [
        -2.846139907836914,
        -1.1164889512469,
        -3.169840097427368
      ],
      "visible_nodes": [
        0,
        3,
        4,
        5,
        7,
        8
      ]
    },
    {
      "accessible_nodes": [
        0,
        3,
        4,
        6,
        8
      ],
      "floor_index": 0,
      "index": 7,
      "offset_point_count": 2356,
      "position": [
        -3.0448501110076904,
        -0.0010134399635717273,
        -4.505109786987305
      ],
      "quaternion": {
        "w": 0.49087982982843503,
        "x": -0.001156616652291604,
        "y": -0.8712263733357108,
        "z": -0.0005211039435373182
      },
      "standing_position": [
        -3.0448501110076904,
        -1.11562920091362,
        -4.505109786987305
      ],
      "visible_nodes": [
        0,
        3,
        4,
        6,
        8
      ]
    },
    {
      "accessible_nodes": [
        0,
        3,
        4,
        6,
        7
      ],
      "floor_index": 0,
      "index": 8,
      "offset_point_count": 234,
      "position": [
        -2.9152801036834717,
        -0.01438829954713583,
        -6.370659828186035
      ],
      "quaternion": {
        "w": -0.30469427695314993,
        "x": 0.0033588028429806095,
        "y": -0.952412964681632,
        "z": -0.007724194714338225
      },
      "standing_position": [
        -2.9152801036834717,
        -1.1144715989725875,
        -6.370659828186035
      ],
      "visible_nodes": [
        0,
        3,
        4,
        6,
        7
      ]
    },
    {
      "accessible_nodes": [
        4,
        5,
        10,
        11,
        12,
        13
      ],
      "floor_index": 0,
      "index": 9,
      "offset_point_count": 4886,
      "position": [
        -4.0423102378845215,
        0.003333129920065403,
        -0.03953389823436737
      ],
      "quaternion": {
        "w": -0.18957592794754674,
        "x": 0.010895134657991246,
        "y": -0.9818002618819436,
        "z": -0.0032427031038127978
      },
      "standing_position": [
        -4.0423102378845215,
        -1.118231507556375,
        -0.03953389823436737
      ],
      "visible_nodes": [
        4,
        5,
        10,
        11,
        12,
        13
      ]
    },
    {
      "accessible_nodes": [
        4,
        5,
        9,
        11
      ],
      "floor_index": 0,
      "index": 10,
      "offset_point_count": 1773,
      "position": [
        -4.850550174713135,
        0.004613489843904972,
        0.1713390052318573
      ],
      "quaternion": {
        "w": 0.12768161943121548,
        "x": -0.0012676586552423492,
        "y": -0.9918143930048722,
        "z": -0.00004849317962342722
      },
      "standing_position": [
        -4.850550174713135,
        -1.1182253683511887,
        0.1713390052318573
      ],
      "visible_nodes": [
        4,
        5,
        9,
        11
      ]
    },
    {
      "accessible_nodes": [
        4,
        9,
        10
      ],
      "floor_index": 0,
      "index": 11,
      "offset_point_count": 654,
      "position": [
        -5.53085994720459,
        -0.013371099717915058,
        -0.143778994679451
      ],
      "quaternion": {
        "w": -0.0030183054753861976,
        "x": -0.00047414000140664293,
        "y": -0.9999897553992034,
        "z": -0.0033406236879980804
      },
      "standing_position": [
        -5.53085994720459,
        -1.1179010210789888,
        -0.143778994679451
      ],
      "visible_nodes": [
        4,
        9,
        10
      ]
    },
    {
      "accessible_nodes": [
        9,
        13
      ],
      "floor_index": 0,
      "index": 12,
      "offset_point_count": 1237,
      "position": [
        -4.178860187530518,
        -0.013643399812281132,
        1.3469799757003784
      ],
      "quaternion": {
        "w": 0.06683888675991313,
        "x": -0.0047767000805582485,
        "y": -0.9977055393311836,
        "z": -0.00966420424898995
      },
      "standing_position": [
        -4.178860187530518,
        -1.1190794461899993,
        1.3469799757003784
      ],
      "visible_nodes": [
        9,
        13
      ]
    },
    {
      "accessible_nodes": [
        9,
        12
      ],
      "floor_index": 0,
      "index": 13,
      "offset_point_count": 466,
      "position": [
        -4.963950157165527,
        -0.005961719900369644,
        3.710700035095215
      ],
      "quaternion": {
        "w": -0.19462188396064967,
        "x": 0.004454742146828046,
        "y": -0.9807853643462634,
        "z": -0.012749200565824454
      },
      "standing_position": [
        -4.963950157165527,
        -1.12043610464341,
        3.710700035095215
      ],
      "visible_nodes": [
        9,
        12
      ]
    }
  ],
  "panorama": {
    "count": 14,
    "list": [
      {
        "back": "images/cube_2048/0/9bf403506f2bc22eea0a81cdb09a8e22/0_b.jpg",
        "down": "images/cube_2048/0/9bf403506f2bc22eea0a81cdb09a8e22/0_d.jpg",
        "front": "images/cube_2048/0/9bf403506f2bc22eea0a81cdb09a8e22/0_f.jpg",
        "index": 0,
        "left": "images/cube_2048/0/9bf403506f2bc22eea0a81cdb09a8e22/0_l.jpg",
        "right": "images/cube_2048/0/9bf403506f2bc22eea0a81cdb09a8e22/0_r.jpg",
        "up": "images/cube_2048/0/9bf403506f2bc22eea0a81cdb09a8e22/0_u.jpg"
      },
      {
        "back": "images/cube_2048/1/cb8db51bc30afdd40cf6e4f3f7341c40/1_b.jpg",
        "down": "images/cube_2048/1/cb8db51bc30afdd40cf6e4f3f7341c40/1_d.jpg",
        "front": "images/cube_2048/1/cb8db51bc30afdd40cf6e4f3f7341c40/1_f.jpg",
        "index": 1,
        "left": "images/cube_2048/1/cb8db51bc30afdd40cf6e4f3f7341c40/1_l.jpg",
        "right": "images/cube_2048/1/cb8db51bc30afdd40cf6e4f3f7341c40/1_r.jpg",
        "up": "images/cube_2048/1/cb8db51bc30afdd40cf6e4f3f7341c40/1_u.jpg"
      },
      {
        "back": "images/cube_2048/2/67cdadb9caa0f844f56fee0aac7bb56d/2_b.jpg",
        "down": "images/cube_2048/2/67cdadb9caa0f844f56fee0aac7bb56d/2_d.jpg",
        "front": "images/cube_2048/2/67cdadb9caa0f844f56fee0aac7bb56d/2_f.jpg",
        "index": 2,
        "left": "images/cube_2048/2/67cdadb9caa0f844f56fee0aac7bb56d/2_l.jpg",
        "right": "images/cube_2048/2/67cdadb9caa0f844f56fee0aac7bb56d/2_r.jpg",
        "up": "images/cube_2048/2/67cdadb9caa0f844f56fee0aac7bb56d/2_u.jpg"
      },
      {
        "back": "images/cube_2048/3/791c38edaf6bbcc16e19682543745e9b/3_b.jpg",
        "down": "images/cube_2048/3/791c38edaf6bbcc16e19682543745e9b/3_d.jpg",
        "front": "images/cube_2048/3/791c38edaf6bbcc16e19682543745e9b/3_f.jpg",
        "index": 3,
        "left": "images/cube_2048/3/791c38edaf6bbcc16e19682543745e9b/3_l.jpg",
        "right": "images/cube_2048/3/791c38edaf6bbcc16e19682543745e9b/3_r.jpg",
        "up": "images/cube_2048/3/791c38edaf6bbcc16e19682543745e9b/3_u.jpg"
      },
      {
        "back": "images/cube_2048/4/ee318d536c51ef3de38c4aa059d65ef0/4_b.jpg",
        "down": "images/cube_2048/4/ee318d536c51ef3de38c4aa059d65ef0/4_d.jpg",
        "front": "images/cube_2048/4/ee318d536c51ef3de38c4aa059d65ef0/4_f.jpg",
        "index": 4,
        "left": "images/cube_2048/4/ee318d536c51ef3de38c4aa059d65ef0/4_l.jpg",
        "right": "images/cube_2048/4/ee318d536c51ef3de38c4aa059d65ef0/4_r.jpg",
        "up": "images/cube_2048/4/ee318d536c51ef3de38c4aa059d65ef0/4_u.jpg"
      },
      {
        "back": "images/cube_2048/5/b19d98dc23ec04d86df755dd1a15fdb3/5_b.jpg",
        "down": "images/cube_2048/5/b19d98dc23ec04d86df755dd1a15fdb3/5_d.jpg",
        "front": "images/cube_2048/5/b19d98dc23ec04d86df755dd1a15fdb3/5_f.jpg",
        "index": 5,
        "left": "images/cube_2048/5/b19d98dc23ec04d86df755dd1a15fdb3/5_l.jpg",
        "right": "images/cube_2048/5/b19d98dc23ec04d86df755dd1a15fdb3/5_r.jpg",
        "up": "images/cube_2048/5/b19d98dc23ec04d86df755dd1a15fdb3/5_u.jpg"
      },
      {
        "back": "images/cube_2048/6/b8f425e5f8943c38ad1386ab391b54bc/6_b.jpg",
        "down": "images/cube_2048/6/b8f425e5f8943c38ad1386ab391b54bc/6_d.jpg",
        "front": "images/cube_2048/6/b8f425e5f8943c38ad1386ab391b54bc/6_f.jpg",
        "index": 6,
        "left": "images/cube_2048/6/b8f425e5f8943c38ad1386ab391b54bc/6_l.jpg",
        "right": "images/cube_2048/6/b8f425e5f8943c38ad1386ab391b54bc/6_r.jpg",
        "up": "images/cube_2048/6/b8f425e5f8943c38ad1386ab391b54bc/6_u.jpg"
      },
      {
        "back": "images/cube_2048/7/a05b06a01171babb1aceb5aad8406ab8/7_b.jpg",
        "down": "images/cube_2048/7/a05b06a01171babb1aceb5aad8406ab8/7_d.jpg",
        "front": "images/cube_2048/7/a05b06a01171babb1aceb5aad8406ab8/7_f.jpg",
        "index": 7,
        "left": "images/cube_2048/7/a05b06a01171babb1aceb5aad8406ab8/7_l.jpg",
        "right": "images/cube_2048/7/a05b06a01171babb1aceb5aad8406ab8/7_r.jpg",
        "up": "images/cube_2048/7/a05b06a01171babb1aceb5aad8406ab8/7_u.jpg"
      },
      {
        "back": "images/cube_2048/8/2cd717b9c97f48ae79511855cc7e5138/8_b.jpg",
        "down": "images/cube_2048/8/2cd717b9c97f48ae79511855cc7e5138/8_d.jpg",
        "front": "images/cube_2048/8/2cd717b9c97f48ae79511855cc7e5138/8_f.jpg",
        "index": 8,
        "left": "images/cube_2048/8/2cd717b9c97f48ae79511855cc7e5138/8_l.jpg",
        "right": "images/cube_2048/8/2cd717b9c97f48ae79511855cc7e5138/8_r.jpg",
        "up": "images/cube_2048/8/2cd717b9c97f48ae79511855cc7e5138/8_u.jpg"
      },
      {
        "back": "images/cube_2048/9/0b634fe985df7011472b81c75babfd95/9_b.jpg",
        "down": "images/cube_2048/9/0b634fe985df7011472b81c75babfd95/9_d.jpg",
        "front": "images/cube_2048/9/0b634fe985df7011472b81c75babfd95/9_f.jpg",
        "index": 9,
        "left": "images/cube_2048/9/0b634fe985df7011472b81c75babfd95/9_l.jpg",
        "right": "images/cube_2048/9/0b634fe985df7011472b81c75babfd95/9_r.jpg",
        "up": "images/cube_2048/9/0b634fe985df7011472b81c75babfd95/9_u.jpg"
      },
      {
        "back": "images/cube_2048/10/40c1a6463b8c7462aadfca2a5f80f685/10_b.jpg",
        "down": "images/cube_2048/10/40c1a6463b8c7462aadfca2a5f80f685/10_d.jpg",
        "front": "images/cube_2048/10/40c1a6463b8c7462aadfca2a5f80f685/10_f.jpg",
        "index": 10,
        "left": "images/cube_2048/10/40c1a6463b8c7462aadfca2a5f80f685/10_l.jpg",
        "right": "images/cube_2048/10/40c1a6463b8c7462aadfca2a5f80f685/10_r.jpg",
        "up": "images/cube_2048/10/40c1a6463b8c7462aadfca2a5f80f685/10_u.jpg"
      },
      {
        "back": "images/cube_2048/11/9663b7885a119f2f06da06212986bc9b/11_b.jpg",
        "down": "images/cube_2048/11/9663b7885a119f2f06da06212986bc9b/11_d.jpg",
        "front": "images/cube_2048/11/9663b7885a119f2f06da06212986bc9b/11_f.jpg",
        "index": 11,
        "left": "images/cube_2048/11/9663b7885a119f2f06da06212986bc9b/11_l.jpg",
        "right": "images/cube_2048/11/9663b7885a119f2f06da06212986bc9b/11_r.jpg",
        "up": "images/cube_2048/11/9663b7885a119f2f06da06212986bc9b/11_u.jpg"
      },
      {
        "back": "images/cube_2048/12/01f84f2edd8642d0bf5e4874d01a28ac/12_b.jpg",
        "down": "images/cube_2048/12/01f84f2edd8642d0bf5e4874d01a28ac/12_d.jpg",
        "front": "images/cube_2048/12/01f84f2edd8642d0bf5e4874d01a28ac/12_f.jpg",
        "index": 12,
        "left": "images/cube_2048/12/01f84f2edd8642d0bf5e4874d01a28ac/12_l.jpg",
        "right": "images/cube_2048/12/01f84f2edd8642d0bf5e4874d01a28ac/12_r.jpg",
        "up": "images/cube_2048/12/01f84f2edd8642d0bf5e4874d01a28ac/12_u.jpg"
      },
      {
        "back": "images/cube_2048/13/e9ce1249af9000a33d566c653560c3d6/13_b.jpg",
        "down": "images/cube_2048/13/e9ce1249af9000a33d566c653560c3d6/13_d.jpg",
        "front": "images/cube_2048/13/e9ce1249af9000a33d566c653560c3d6/13_f.jpg",
        "index": 13,
        "left": "images/cube_2048/13/e9ce1249af9000a33d566c653560c3d6/13_l.jpg",
        "right": "images/cube_2048/13/e9ce1249af9000a33d566c653560c3d6/13_r.jpg",
        "up": "images/cube_2048/13/e9ce1249af9000a33d566c653560c3d6/13_u.jpg"
      }
    ]
  },
  "picture_url": "https://vrlab-public.ljcdn.com/release/auto3dhd/9380ce27b46cbc5ba8d47fcf0e4c9e4f/screenshot/1596005211_4/pc0_3aoiit6zp.jpg",
  "title_picture_url": "https://vrlab-public.ljcdn.com/release/auto3dhd/9380ce27b46cbc5ba8d47fcf0e4c9e4f/screenshot/1596005211_4/pc1_iQLf2N6a6_1.jpg",
  "vr_code": "8054djM0oR6ky3Ey8e"
}
  • _signature / certificate: work 内容的数字签名

  • expire_at: work 的过期时间

  • allow_hosts: work 的安全域名

  • initial: 初始化数据,是一个 State 数据。描述 Work 被加载初始状态的位姿,也叫做VR的初始视角

    • mode: 模态
    • pano_index: 初始化点位
    • longitude: 相机的水平角
    • latitude: 相机的偏航角
    • fov: 相机垂直方向的可视角度
  • model: 三维模型

    • file_url: 三维模型的资源地址,文件为 .at3d 为如视定制的模型格式
    • material_textures: 三维模型的贴图资源地址
  • panorama: 全景彩色信息

    • list:
      • up / down / left / right / front / back: 全景彩色信息以 cubemap 方式存储和使用。
  • observers: 采集点信息

    • visible_nodes: 采集点之间的可见性列表
    • accessible_nodes: 采集点之间的连通性列表
    • quaternion: 采集点与模型坐标的旋转偏移量
    • standing_position: 采集点地面坐标
    • position: 采集点坐标
    • floor_index: 采集点楼层

Work 对象

相比上面的 work.json, 你可能更常用到的是 Work 对象,他是 parseWork 函数的产物。 Work 对象 相比 work.json 会做很好的序列化,你可以在 Five API 文档 中查看详细说明。

了解 FiveProvider 及 FiveCanvas

FiveProvider 及 FiveCanvas 的由来

FiveProvider / FiveCanvas 是通过 React Context API 的思路开发的。 我们可以认为 FiveProvider 创建了一个三维空间实例。而 FiveCanvas 是对应显示到 DOM 结构中的画布(cnavas)。在 FiveProvider 内的子组件均可以通过 context 获取到 FiveProvider 上提供的方法来获取三维空间的信息或者控制三维空间,我们还开发了一系列的 hooks, 便于你更方便的完成上述事情。

这样的文字描述可能不好理解,那么我们动手做一些看看。

添加模态控制按钮

我们这次完成的工作是添加模态控制按钮,Five 内置了多种模态,默认状态展示的是 全景态,就和上一章最终得到的结果一样,我们还可以展示 模型态 来查看三维空间的宏观状态。切换我们会用到 Five SDK 提供的 useCurrentState 的 React hooks。关于 模态State, useCurrentState 等会在下一章详细学习到,而本章我们要做的事情是:

  • 编写一个 React 组件
  • 将组件安插为 FiveProvider 的子组件
  • 通过 Five 提供的 api 控制三维空间

安装 ui 组件

为了减少示例代码复杂度,这边使用 material-UI 作为 UI 组件库, 你也可以使用 Ant Design Fluent UI 等。

npm install @mui/material @mui/icons-material @emotion/react @emotion/styled

了解 withFive

import { withFive } from "@realsee/react" 是 Five SDK 提供的 React HOC。 可以通过 withFive 注入三维空间相关的属性/特征和方法。 他通过 import { createFiveFeature } from "@realsee/react"createFiveFeature 方法创建需要的依赖注入后,通过 this.props.$five 即可使用。 本次我们需要注入 currentStatesetState 来切换模态。

接下来开始编写代码

  1. 添加一个 ModeController 文件,用于编写组件。
  2. 首先在头部从 @realsee/five 引用 Five Mode
  3. Mode 是模态的类型声明。
  4. Five.Mode[string] 是模态的枚举。
  5. 首先在头部从 @realsee/five/react 引用 withFive createFiveFeature
  6. 书写 ModeController 组件。
  7. 通过 material-UI 组件,添加界面。
  8. 通过 this.props.$five.currentState this.props.$five.setState() 可以获取/设置 三维空间的模态(mode)。
import React, { Component } from "react";
import { Five } from "@realsee/five";
import { withFive, createFiveFeature } from "@realsee/five/react";
import { compose } from "@wordpress/compose";
import BottomNavigation from "@mui/material/BottomNavigation";
import BottomNavigationAction from "@mui/material/BottomNavigationAction";
import Paper from "@mui/material/Paper";
import DirectionsWalkIcon from "@mui/icons-material/DirectionsWalk";
import ViewInArIcon from "@mui/icons-material/ViewInAr";

const FEATURES = createFiveFeature("currentState", "setState");

/**
 * React Component: 模态控制
 */
const ModeController = compose(
  withFive(FEATURES)
)(class extends Component {
  render() {
    return <Paper sx={{ position: "fixed", bottom: 0, left: 0, right: 0 }}>
      <BottomNavigation
        showLabels
        value={this.props.$five.currentState.mode}
        onChange={(_, newValue) => {
          this.props.$five.setState({ mode: newValue });
        }}
      >
        <BottomNavigationAction label="全景漫游" icon={<DirectionsWalkIcon/>} value={Five.Mode.Panorama}/>
        <BottomNavigationAction label="空间总览" icon={<ViewInArIcon/>} value={Five.Mode.Floorplan}/>
      </BottomNavigation>
    </Paper>;
  }
})

export { ModeController };

使用模态控制按钮组件

接下来将 ModeController 组件插入到 App 文件的 FiveProvider 中。

import React, { Component } from "react";
import { compose } from "@wordpress/compose";
import { createFiveProvider, FiveCanvas } from "@realsee/five/react";
import { withFetchWork } from "./withFetchWork";
import { withWindowDimensions } from "./withWindowDimensions";
//highlight-start
import { ModeController } from "./ModeController";
//highlight-end

/** work.json 的数据 URL */
const workURL = "https://vrlab-public.ljcdn.com/release/static/image/release/five/work-sample/07bdc58f413bc5494f05c7cbb5cbdce4/work.json";

const FiveProvider = createFiveProvider();

const App = compose(
  withFetchWork(workURL),
  withWindowDimensions()
)(class extends Component {
  render() {
    const { work, windowDimensions } = this.props;
    return <FiveProvider initialWork={work}>
      <FiveCanvas width={windowDimensions.width} height={windowDimensions.height}/>
      //highlight-start
      <ModeController/>;
      //highlight-end
    </FiveProvider>;
  }
});

export { App };

回到你的浏览器查看,会发现你的页面底部出现了控制条,点击不同的按钮 全景漫游 空间总览 可以让三维空间改变状态。

真不错 🥳 !

下一章节你会学到

下一章节你会学到
  • 了解什么是 State
  • 如何改变三维空间观察的方向 / 位置
  • 了解刚才的代码,比如 currentState setState 及其他响应的是如何工作的
  • 通过 State 完成了自动环视的功能