1.2.4 • Published 3 years ago

alibabacloud-tdsr-js-sdk v1.2.4

Weekly downloads
-
License
MIT
Repository
-
Last release
3 years ago

三维重建(临云镜)SDK 使用文档

1. 背景介绍

三维重建(TDSR)SDK 主要为三维重建(TDSR)提供了平台生成的三维模型的:模型播放能力、 与模型进行互动的能力、以及标签标注能力。整个 SDK 分为 PanoramaScenePlayer 和 PanoramaSceneEdtior 两部分:

  • PanoramaScenePlayer 提供了基本模型加载,模型交互(如场景漫游,飞入标签,多视图 切换,事件监听等能力)
  • PanoramaSceneEditor 继承了 PanoramaScenePlayer 对象,该对象除了提供模型加载, 模型交互,还提供了标签编辑的能力,可以跟进 API 进行标签创建、标签删除、标签修 改等操作。

该 SDK 与框架无关,您可在 React 框架中使用,也可嵌入到 Angular\Vue 等任何框架中 使用。本文档将以嵌入 React 的方式演示如何利用该 SDK 加载三维模型以及如何与三维模 型进行交互。

2. 关键术语

  • 模型: 用户将全景照片上传到三维重建(TDSR)平台,利用平台的模型重建能力创造出来的 模型;用户可以通过 3D 交互的方式查看该模型的结构。也可以飞入到模型中以全景视角 产看场景。
  • 场景: 场景跟模型是一一对应的
  • 子场景: 与平台子场景含义相同,一张全景图即一个子场景,用户可以在不同子场景进行 漫游。
  • 三维模式:传说中的“上帝视角“,在该模式下,用户可以较清晰看到模型结构,以及各个 子场景之间的关联关系
  • 全景模式: 子场景模型,可通过鼠标点击/SDK 提供的 API 的操作实现场景间切换从而实 现场景漫游
  • 标签:SDK 允许在编辑模式下进行图像的标注,标注后会一标签的形势存在,目前支持标 注模式有图片,图像,文本,链接。

3. 快速上手

3.1 PanoramaScenePlayer 快速上手

PanoramaScenePlayer 相关,详见第 5 章

  1. 初始化 PlayerService 对象, 该对象封装了前后端通信的能力,提供与后端接口交互 API,详见章节 4。

    const service = new PanoramaScenePlayerService();
    // service.registerFetch(utils.mock)  // NOTICE: 本地mock测试,线上不要使用
    service.registerHook({
      // 详见章节4
      async request(method, url, data, header) {
        const prefix = '//localhost/aoding/demo';
        return [`${prefix}${url}`, data, header];
      },
      async response(result, context) {
        return {
          code: result.code,
          message: result.message,
          data: result.data,
        };
      },
    });
  2. 初始化播放器对象

    const player = new PanoramaScenePlayer(document, {
      service: service, // PlayerService对象
      mode: '1', // mode: 1 | 2,  参数详见5.1
    });
  3. 模型加载

    await player.load(token); // TODO: 请求获取模型数据接口,并加载模型
  4. 设置监听事件,详见 5.3 节

    player.registerSceneHook({
      onOrbitRotate: (quaternion) => {
        console.log('Current Quaternion', quaternion);
      },
      onChangePanorama: (panoId) => {
        console.log('Current Panorama', panoId);
      },
    });
  5. 基于 React 的完整代码如下:

    import React, { Component } from 'react';
    import ReactDOM from 'react-dom';
    import {
      PanoramaScenePlayer,
      PanoramaScenePlayerService,
      utils,
      DefaultSceneData,
    } from 'alibabacloud-tdsr-js-sdk';
    import axios from 'axios';
    
    /**
     * 加载模型
     * @param {string} token
     * @param {HTMLDivElement} target
     */
    function usePlayer(token, target) {
      const [myPlayer, setMyPlayer] = React.useState(null);
      const init = async () => {
        const service = new PanoramaScenePlayerService();
        service.registerHook({
          // 详见章节4
          async request(method, url, data, header) {
            const prefix = '//localhost/aoding/demo';
            return [`${prefix}${url}`, data, header];
          },
          async response(result, context) {
            return {
              code: result.code,
              message: result.message,
              data: result.data,
            };
          },
        });
    
        const player = new PanoramaScenePlayer(target.current, {
          service: service,
          mode: '1', // 如果想预览未发布的Tag, mode设置为2,mode参数详见5.1
        });
    
        await player.load(token); // 请求接口&加载模型
    
        // 设置监听事件,详见5.3节
        player.registerSceneHook({
          onOrbitRotate: (quaternion) => {
            console.log('Current Quaternion', quaternion);
          },
          onChangePanorama: (panoId) => {
            console.log('Current Panorama', panoId);
          },
        });
        return player;
      };
    
      React.useEffect(() => {
        init().then((p) => setMyPlayer(p));
      }, [token]);
    
      return myPlayer;
    }
    
    function Player(props) {
      // token 即 listMainScenes 接口中获取的 previewToken
      const token = '58b51071d0a446318607443bd2135d74';
      const target = React.useRef();
      const player = usePlayer(token, target);
      const style = {
        width: '100%',
        height: 450,
        position: 'relative',
      };
      return <div ref={target} style={style} />;
    }
    
    ReactDOM.render(<Player />, mountNode);

3.2 PanoramaSceneEditor 快速上手

PanoramaSceneEditor 相关,详见第 6 章

  1. 初始化 PanoramaSceneEditorService 对象, 该对象封装了前后端通信的能力,提供与 后端接口交互 API,详见下一章节。

    const service = new PanoramaSceneEditorService();
    service.registerFetch(utils.mock); // NOTICE: 本地mock测试,线上不要使用
  2. 初始化播放器对象

    const editor = new PanoramaSceneEditor(document, {
      service,
      autoSave: false,
    });
  3. 模型加载

    await editor.load(token);
  4. 设置监听事件,详见 5.3 节

    editor.registerTagHook({
      onSelected: (tag) => {
        console.log('tag', tag);
      },
    });
  5. 基于 React 的完整代码如下:

    import React, { useCallback, useState, useEffect } from 'react';
    import {
      PanoramaSceneEditor,
      PanoramaSceneEditorService,
    } from 'alibabacloud-tdsr-js-sdk';
    /**
     * 加载模型
     * @param {string} token
     * @param {HTMLDivElement} target
     */
    function useEditor(token, target) {
      const [editor, setEditor] = useState(null);
      const init = async () => {
        const service = new PanoramaSceneEditorService();
        // service.registerFetch(utils.mock) // NOTICE: 本地mock测试,线上不要使用
    
        service.registerHook({
          async request(method, url, data, header) {
            const prefix = '//localhost/aoding/demo'; // 域名需更换为业务方自己服务器域名
            return [`${prefix}${url}`, data, header];
          },
          async response(result, context) {
            return {
              code: result.code,
              message: result.message,
              data: result.data,
            };
          },
        });
    
        const editor = new PanoramaSceneEditor(target.current, {
          service,
          autoSave: false, // 是否开启标签自动保存
        });
    
        await editor.load(token); // 请求接口&加载模型
    
        editor.registerTagHook({
          // 标签创建必要
          onCreating: () => {
            // tag参数,详见6.4.1
            const tag = {
              type: 'TEXT',
              config: {
                backgroundColor: '#000',
                content: '444',
                title: '1231',
              },
            };
            return tag;
          },
          // 标签创建完成
          onCreated: (tag) => {
            console.log(tag);
            // editor.updateTag(tag.id, tag)
          },
        });
        return editor;
      };
    
      useEffect(() => {
        init().then((editor) => {
          setEditor(editor);
        });
      }, [token]);
      return editor;
    }
    
    function Editor(props) {
      // token 即 listMainScenes 接口中获取的 previewToken
      const token = 'f9d19ae0541f4131bb787d8a4521d46d';
      const target = React.useRef();
      const editor = useEditor(token, target);
    
      // 添加标签
      const addTag = useCallback(() => {
        if (!editor) return;
        // tips: 添加标签,需配合onCreating事件使用
        editor.setState(2); // tips: 改为2 即 EDIT态,可鼠标右键创建标签
        // editor.createTagInView({ x: 1, y: 1 }) // 在指定位置添加标签
      }, [editor]);
    
      // 切换至3D模型,DollHouse: 3D模型,Panorama: 全景模式
      const go3D = useCallback(() => {
        if (!editor) return;
        editor.changeView('DollHouse');
      }, [editor]);
    
      // 保存标签
      const save = useCallback(() => {
        if (!editor) return;
        // save后的标签,可在mode为Preview时展示
        editor.save();
      }, [editor]);
    
      // 发布标签
      const publish = useCallback(() => {
        if (!editor) return;
        // save后的标签,可在mode为Online时展示
        editor.publish();
      }, [editor]);
    
      return (
        <div>
          <div
            ref={target}
            style={{
              width: '100%',
              height: 450,
              position: 'relative',
            }}
          />
          <button onClick={() => addTag()}>ADD Tag</button>
          <button onClick={() => go3D()}>go 3D</button>
          <button onClick={() => save()}>save</button>
          <button onClick={() => publish()}>publish</button>
        </div>
      );
    }
    export default Editor;

4. 通信

SDK 需要依赖后端接口进行模型的加载以及标签的增删改查,考虑到安全性,需要业务 方对依赖接口进行转发,其架构如下图。三维重建服务端把依赖的后端接口通过 Open API 的方式开放给业务方,业务方可以通过 Open API SDK 方式与这些接口进行交互,并通 过 WEB API 方式转发给 WEB 端的播放器。播放器通过转发后的 API 实现三维重建服务端 通信, 又能保证其安全性,以及各平台兼容性 。image.pngPanoramaScenePlayerService、PanoramaSceneEditorService 对象封装了通信能力,开发者可以通过 const service = new PanoramaSceneEditorService();  和 const service = new PanoramaSceneEditorService();的方式创建该对象。

  • Mock:为了方便开发者进行本地调试 ,PanoramaScenePlayerService、PanoramaSceneEditorService 提供了 Mock 数据的能 力,开发者在开发前期可以通过如下的方式加载 Mock 数据进行本地开发

    • service.registerFetch: (replacedFetch: fetch) => viod; 替换底层 fetch 库, 用于 mock 数据

      service.registerFetch(utils.mock); // NOTICE: 本地mock测试,线上不要使用
  • 协议适配: 考虑到不同业务方前后端通信协议会有较大差异 ,PanoramaScenePlayerService、PanoramaSceneEditorService 开发了协议转换的能力 ,用户可以通过 registerHook 接口进行协议转换。比如以下 Code 给 URL 增加前缀, 同时对返回结果进行适配

    • service.registerHook: ({request, response}) => viod;

    • 参数说明:

      • request 请求拦截器

        • method: GET | POST 请求方式

        • url: string 临云镜后端 SDK 接口地址,接口在前端 SDK 内部调用,详见下 文服务端接口对应交互API

        • data: object 请求参数

        • header: object 请求头

      • response 响应拦截器

        • code: number 状态码 code:0 为成功,否则抛出异常

        • message: string 错误信息

        • data: object 临云镜后端 SDK 返回的 data 数据,具体参数详见临云镜服务端 SDK 接口文档

    • 示例

      service.registerHook({
        // 请求拦截器
        async request(method, url, data, header) {
          const prefix = '//localhost/biz'
          return [`${prefix}${url}`, data, header];
        },
        // 响应拦截器
        async response(result, context) {
          return {
            code: result.errorCode,
            message: result.errorMessage,
            data: result.data
        }
      });
  • API: 以下 API 均为 SDK 内部已封装集成,无需手动调用(域名需业务方自己通过 registerHook 配置),API 内会自动调用服务端接口。接口参数可参考临云镜服务端 SDK 接口文档。

    - PanoramaScenePlayerService
    
        > player.load()时,SDK内部调用
    
        - service.getPanoramaConfigData: `(token: string) => response;` 获得全局配置信息,调用接口:`/getWindowConfig`
    
        - service.getSceneData: `(token: string) => response;` 获取场景渲染数据,调用接口:`/getSceneData`
    
        - service.getTags: `(subSceneUuid: number, previewToken: string, type: number) => response;` 获取所有热点标注数据,调用接口:`/getHotspotTag`
    
    - PanoramaSceneEditorService
    
        > tips: 继承 PanoramaScenePlayerService 所有 API,无需手动调用,save()&publish()时自动调用
    
        - service.saveTags: `(subSceneUuid: number, tags: ICombinedTag[]) => response;` 保存标签。tips: ICombinedTag为标签数据,调用接口:`/saveHotspotTag`
    
        - service.publish: `(subSceneUuid: number) => response;` 发布标签,调用接口:`/publishHotspot`

5. Panorama Scene Player

PanoramaScenePlayer 对象提供了基本模型加载,模型交互(如场景漫游,飞入标签,多视 图切换,事件监听等能力)

5.1 Constructor

constructor(target: HTMLDivElement, protected config: IPanoramaScenePlayerConfig)
  • target: Player 的 DOM 容器
  • config
    • service: 前后端通信对象,见 4. 通信 章节内容
    • mode:
      • Player 的模式,支持 Preview = '2', Online = '1',
      • 其中 Preview 加载已经创建,但是还没有发布的标签和已经发布的标签;Online 只 会加载已经发布的标签
    • view: DollHouse(3D 模式)\Panorama(全景模式), 默认为 DollHouse 模式

5.2 Load/Unload

  • 加载模型,previewToken 为模型的唯一标示,可以通过 OPEN API 提供的接口获得,详 见后端 SDK

      async player.load(previewToken: string)
  • 卸载模型

      async player.unload()

5.3 注册监听事件

registerSceneHook(hooks); // hooks: {} 一个事件对象
  • hooks.onLoad: () => void;  加载完成事件
  • hooks.onChangeView: (type: EnumPanoramaSceneView) => void;  切换全景/3D 模式 事件
  • hooks.onChangePanorama: (panoId: string) => void;  切换子场景事件
  • hooks.onOrbitRotate: (quanertion: TypeQuaternion) => void; 场景旋转, 目前暂 不支持三维空间旋转

5.4 API

  1. player.getTagList()  获得所有标签
  2. player.getTagListByPanoramaId(panoId)  获得当前子场景下标签
  3. player.getPanoramaList()  获得所有子场景
  4. player.changeView(view)  切换视图,支持 DollHouse(3D 模式)\Panorama(全景模 式),
  5. player.flyToPanoramaById(panoId)  跳转到指定子场景
  6. player.hideTag()  隐藏标签
  7. player.showTag()  显示标签
  8. player.flyToTag(tagId)  跳转到指定标签位置
  9. player.getTagClientPosition(tagId)  获得 Tag 的屏幕坐标
  10. player.getCurrentPanorama()  获得当前子场景,若在 Dollhouse(3D)模式下,返 回为 undefined
  11. player.isTagInViewScene(tagId)  判断标签是否当前视口可见
  12. player.getRotateQuaternion() 获得当前场景旋转四元组
  13. player.setRotateQuaternion(quaternion) 设置当前场景的旋转四元组

6. Panorama Scene Editor

PanoramaSceneEditor 继承了 PanoramaScenePlayer 对象,该对象除了提供模型加载,模 型交互,还提供了标签编辑的能力,可以跟进 API 进行标签创建、标签删除、标签修改等 操作。

6.1 Constructor

constructor(target: HTMLDivElement, protected config: IPanoramaSceneEditorConfig)
  • target: Player 的 DOM 容器
  • config
    • service: 前后端通信对象,见 4. 通信 章节内容
    • autoSave: 是否自动保存 TAG, 若 autoSave 为 true, 模型创建、模型取消选中、模 型更新、模型拖拽、
    • view: DollHouse(3D 模式)\Panorama(全景模式), 默认为 DollHouse 模式

6.2 Load/UnLoad

  • 加载模型,previewToken 为模型的唯一标示,可以通过 OPEN API 提供的接口获得,详 见后端 SDK

      async editor.load(previewToken: string)
  • 卸载模型

      async editor.unload()

6.3 注册监听事件

registerTagHook(hooks); // hooks: {} 一个事件对象
  • hooks.onClick: (tag: ICombinedTag) => void;  点击标签事件
  • hooks.onSelected: (tag: ICombinedTag) => boolean;  标签选中事件
  • hooks.onWillUnselected: (tag: ICombinedTag) => boolean;  标签取消选中事件
  • hooks.onCreating: () => ICombinedTag;  创建标签事件
  • hooks.onCreated: (tag: ICombinedTag) => void;  标签创建完成事件
  • hooks.onUpdatePositions: (tag: ICombinedTagWithScenePosition[]) => void;  标 签位置更新事件
  • hooks.onDragStart: (tag: ICombinedTag) => void;  标签拖拽事件
  • hooks.onDragStop: (tag: ICombinedTag) => void; 标签拖拽事件
  • hooks.onDragging: (tag: ICombinedTag) => void; 标签拖拽事件

6.4 API

PanoramaSceneEditor 继承了 PanoramaScenePlayer 所有 API 除此之外 ,PanoramaSceneEditor 还提供了跟标签编辑有关的 API

  • 6.4.1 创建标签

创建标签目前只能在全景模型下创建,标签创建必须通过 onCreating 事件。

自定义创建 tips(参考 3.2 示例): 1.通过 onCreating 创建默认标签。2.通过 onCreated 拿到标签 Id。3. 通过editor.updateTag(tagId, tag)方法自定义标签内容

  1. 通过注册 onCreating 事件回填标签内容

    • tag 参数说明:

      • type: tag 类型支持 IMAGE | TEXT | VIDEO

        tips: VIDEO 类型的暂时无法播放!如果有播放需求,需业务方前端额外添加弹 出层,视频在弹出框中播放

      • config: tag 配置

      • formSelectImgType: 'default'(默认) | 'point'(小标) | 'mural'(壁纸); 图片 类型,仅 IMAGE 支持

      • title: string 标题
      • content: string 内容
      • backgroundColor: string 背景色
      • images: string[] 图片 CDN 地址
      • video: string 视频 CDN 地址
    • tag 示例:

      • 图片:

        {
              type: 'IMAGE',
              config: {
                backgroundColor: '#000', // 背景色
                images: [    // 图片cdn地址
                  'http://s.alicdn.com/@lyj/pano_src/100070-82766/hotspot/image/4bbc-06439_LD.png',
                ],
                title: '22222',
                formSelectImgType: 'mural',
              },
        }
      • 文本:

        {
              type: 'TEXT',
              config: {
                backgroundColor: '#000',
                title: '22222',
                content: '11111'
              },
        }
      • 视频:

        {
              type: 'VIEDO',
              config: {
                backgroundColor: '#000',
                title: '22222',
                content: '11111',
                video: '' // 视频cdn地址
              },
        }
    • onCreating 示例:

      editor.registerTagHook({
        onCreating: () => {
          const tag = {
            type: 'IMAGE',
            config: {
              backgroundColor: '#000',
              images: [
                'http://s.alicdn.com/@lyj/pano_src/100070-82766/hotspot/image/4bbc-06439_LD.png',
              ],
              title: '60152892558',
              formSelectImgType: 'mural',
            },
          };
          return tag;
        },
      });
  2. 通过 createTagInView(position?: { x: number, y: number })  接口创建标签,默 认在视口中心创建

    editor.createTagInView();
  3. 另外也支持通过鼠标点击方式在指定位置创建标签,开启鼠标点击交互能力

    /*
      播放器状态, state: 1 | 2   默认为: 1
      1: ROMA, 默认允许进行场景漫游,场景旋转等操作
      2: EDIT, 编辑态,允许用户右键创建标签
    */
    editor.setState(1)
    editor.setState(2)
    const state = editor.getState() // 获得当前播放器状态
  • 6.4.2 更新标签

    editor.updateTag(tagId, tag);
  • 6.4.3 选中标签

    editor.selectTag(tagId);
  • 6.4.4 删除标签

    editor.deleteTag(tagId);
  • 6.4.5 保存标签

    • 当开启了 autoSave 模式,模型创建、模型取消选中、模型更新、模型拖拽都会触发保 存,否则就需要调用 save()  手动触发保存。

    • 保存后的标签可以在 PanoramaScenePlayer 的 Preiview 模式查看,但是不能 Online 模式查看

      editor.save();
  • 6.4.6 发布标签

    • 发布后的标签既可以在 PanoramaScenePlayer 的 Preiview 模式查看,又可以在 Online 模式查看

      editor.publish();

已知问题

  • 暂时无法支持天花板打标
  • flyToTag 接口会触发页面闪动问题
1.2.4

3 years ago

1.2.3

3 years ago

1.2.2

4 years ago

1.2.1

4 years ago

1.2.0

4 years ago

1.1.0-beta.6

4 years ago

1.1.0-beta.5

4 years ago

1.1.0-beta.4

4 years ago

1.1.0-beta.2

4 years ago

1.1.0-beta.3

4 years ago

1.1.0-beta.1

4 years ago

1.0.2

4 years ago

1.0.2-beta.1

4 years ago

1.0.1-beta.3

4 years ago

1.0.1-beta.2

4 years ago

1.0.1-beta.1

4 years ago

1.0.0-beta.12

4 years ago

1.0.0-beta.11

4 years ago

1.0.0-beta.10

4 years ago

1.0.0-beta.8

4 years ago

1.0.0-beta.9

4 years ago

1.0.0-beta.7

4 years ago

1.0.0-beta.6

4 years ago

1.0.0-beta.5

4 years ago

1.0.0-beta.4

4 years ago

1.0.0-beta.3

4 years ago

1.0.0-beta.2

4 years ago

1.0.0-beta.0

4 years ago