跳转至

VR 带看3 快速接入指南

本文档是最简化的带看3接入指南,帮助你用最少的代码在项目中跑通「双端 VR 同步带看」。

如需了解完整的架构设计、UI 同步、画笔标注等高级功能,请阅读 带看3集成指南(完整版)。 SDK 全量 API 参考请阅读 带看3 SDK 对接指导文档


前置条件

  1. VR 场景已初始化完成,housePlay 实例可用(参见 VR 初始化展示指南)。
  2. 已获取众趣开放平台的服务 Token(serviceId)。
  3. 已引入带看3 SDK:
import { NestTakelook3 } from 'nest-takelook3-plugin'

最简流程(5 步跑通)

第一步:设置服务参数

await NestTakelook3.setSDKParams('your-service-token', 'https://opendev.3dnest.cn')
await NestTakelook3.getConfig()

第二步:注册核心事件

// 连接成功 → 开启 VR 同步 + 通知 housePlay 进入带看连接状态
NestTakelook3.onUserConnected(() => {
  NestTakelook3.enableSyncLocalActionToRemote(true)
  // 必须:通知 housePlay 已进入带看连接状态,SDK 才会开始收发同步消息
  housePlay.setConnectionStatus(true)
})

// 收到远端 VR 操作 → 同步到本地
NestTakelook3.onRemoteControllingNotify((action) => {
  if (!action?.payload) return

  // 首次视角同步(接听方加入后,发起方会广播当前完整视角快照)
  if (action.payload.isFirstSyncAction && housePlay.firstSyncRemoteActions) {
    housePlay.firstSyncRemoteActions(action.payload.state)
    return
  }

  // 常规增量同步(持续跟随对方视角)
  housePlay.syncRemoteActions(action.payload)
})

// 成员加入 → 发起方广播当前视角给新成员
NestTakelook3.onMemberJoin((member) => {
  console.log('成员加入:', member.userId)
  // 发起方:将当前 VR 视角快照发给新加入的成员
  if (isCaller && housePlay.getCurrentState) {
    const state = housePlay.getCurrentState()
    if (state) {
      NestTakelook3.syncLocalActionToRemote({
        state,
        isFirstSyncAction: true,
      })
    }
  }
})

// 带看结束 → 重置连接状态
NestTakelook3.onEndTour((isMe, reason) => {
  console.log('带看结束', isMe ? '主动' : '被动', reason)
  housePlay.setConnectionStatus(false)
})

setConnectionStatus(true) 说明:必须在连接成功后调用,通知 housePlay 当前处于带看连接状态。housePlay 内部依赖此状态来决定是否启用操作同步(如 uploadLocalActions 事件的触发、syncRemoteActions 的接收等)。带看结束时需调用 setConnectionStatus(false) 重置。

首次视角同步说明:接听方加入带看后,需要立即同步到发起方当前的 VR 视角位置。发起方在 onMemberJoin 中调用 housePlay.getCurrentState() 获取完整视角快照,通过 syncLocalActionToRemote 发送给接听方。接听方在 onRemoteControllingNotify 中检测到 isFirstSyncAction 标记后,调用 housePlay.firstSyncRemoteActions(state) 执行一次性完整同步,而非增量同步。

第三步:启动带看

带看会话由发起方创建,接听方通过 URL 参数获取会议信息后加入。

发起方(经纪人) — 创建会议室并启动:

// 1. 创建会议室createMeetingRoom或发起呼叫callout(仅发起方调用)
const result = await NestTakelook3.createMeetingRoom('your-package-id')
const meetingId = result.meetingId   // 后端分配的会议 ID
const roomId = result.roomId         // TIM 群组 ID

// 2. 打开消息同步
NestTakelook3.enableSyncLocalActionToRemote(true)

// 3. 启动带看
await NestTakelook3.startTour({
  userId: 'agent_01',
  callerUserId: 'agent_01',   // 发起者 userId == callerUserId
  meetingId,
  roomId,
  imPlatform: 'web',
  packageId: 'your-package-id',
})

// 4. 将 meetingId 和 roomId 拼入 URL 传给接听方
const customerUrl = `https://your-domain.com/vr?m=模型ID`
  + `&useVrTakeSee=1&startTour=1`
  + `&meetingId=${meetingId}&roomId=${roomId}`
  + `&userId=customer_01&callerUserId=agent_01`
console.log('接听方链接:', customerUrl)

接听方(客户) — 从 URL 获取参数后加入:

// 从 URL 中解析参数(接听方不创建会议室,直接加入)
const params = new URLSearchParams(window.location.search)

await NestTakelook3.startTour({
  userId: params.get('userId'),            // 接听方自己的 ID
  callerUserId: params.get('callerUserId'), // 发起者的 ID
  meetingId: params.get('meetingId'),       // 从 URL 获取
  roomId: params.get('roomId'),            // 从 URL 获取
  imPlatform: 'web',
  packageId: 'your-package-id',
})

注意createMeetingRoom 只能由发起方调用。接听方的 meetingIdroomId 必须从 URL 参数(或业务接口推送)中获取,不能自行创建。

第四步:同步本地 VR 操作到远端

// 监听 housePlay 的视角变化事件,将操作发送给对方
housePlay.on('uploadLocalActions', (vrState) => {
  NestTakelook3.syncLocalActionToRemote(vrState)
})

第五步:结束带看

await NestTakelook3.endTour('用户主动结束')

完整最小示例

以下是一个可直接运行的最小完整示例,展示从初始化到结束带看的全过程:

import { NestTakelook3 } from 'nest-takelook3-plugin'

/**
 * 判断当前用户是否为发起者。
 * 约定:userId === callerUserId 即为发起者。
 */
function getIsCaller(): boolean {
  const params = new URLSearchParams(window.location.search)
  const userId = params.get('userId') ?? ''
  const callerUserId = params.get('callerUserId') ?? ''
  return userId !== '' && userId === callerUserId
}

// ============================================================
// 初始化(VR 场景 init_UI 完成后调用)
// ============================================================
async function initTakeLook(housePlay) {
  const isCaller = getIsCaller()

  // 1. 设置服务参数 + 拉取配置
  await NestTakelook3.setSDKParams('your-service-token', 'https://opendev.3dnest.cn')
  await NestTakelook3.getConfig()

  // 2. 注册事件
  NestTakelook3.onUserConnected(() => {
    console.log('连接成功')
    NestTakelook3.enableSyncLocalActionToRemote(true)
    housePlay.setConnectionStatus(true)
  })

  NestTakelook3.onRemoteControllingNotify((action) => {
    if (!action?.payload) return

    // 首次视角同步:接听方收到发起方的完整视角快照
    if (action.payload.isFirstSyncAction && housePlay.firstSyncRemoteActions) {
      housePlay.firstSyncRemoteActions(action.payload.state)
      return
    }

    // 常规增量同步
    housePlay.syncRemoteActions(action.payload)
  })

  // 成员加入:发起方广播当前视角给新成员
  NestTakelook3.onMemberJoin((member) => {
    console.log('成员加入:', member.userId)
    if (isCaller && housePlay.getCurrentState) {
      const state = housePlay.getCurrentState()
      if (state) {
        NestTakelook3.syncLocalActionToRemote({
          state,
          isFirstSyncAction: true,
        })
      }
    }
  })

  NestTakelook3.onMemberExit((member) => {
    console.log('成员退出:', member.userId)
  })

  NestTakelook3.onEndTour((isMe, reason) => {
    console.log('带看结束', isMe ? '主动' : '被动', reason)
    housePlay.setConnectionStatus(false)
  })

  // 3. 同步本地 VR 操作到远端
  housePlay.on('uploadLocalActions', (vrState) => {
    NestTakelook3.syncLocalActionToRemote(vrState)
  })
}

// ============================================================
// 发起带看(经纪人端调用)
// ============================================================
async function startAsAgent(housePlay) {
  await initTakeLook(housePlay)

  // 创建会议室(仅发起方创建)
  const result = await NestTakelook3.createMeetingRoom('pkg_001')

  NestTakelook3.enableSyncLocalActionToRemote(false)

  await NestTakelook3.startTour({
    userId: 'agent_01',
    callerUserId: 'agent_01',
    meetingId: result.meetingId,
    roomId: result.roomId,
    imPlatform: 'web',
    packageId: 'pkg_001',
  })

  // 将 meetingId / roomId 拼入 URL 传给客户端
  const customerUrl = window.location.origin + window.location.pathname
    + '?m=' + new URLSearchParams(window.location.search).get('m')
    + '&useVrTakeSee=1&startTour=1'
    + '&meetingId=' + result.meetingId
    + '&roomId=' + result.roomId
    + '&userId=customer_01&callerUserId=agent_01'
    + '&packageId=pkg_001'
  console.log('接听方链接:', customerUrl)
}

// ============================================================
// 加入带看(客户端调用,参数从 URL 获取)
// ============================================================
async function joinAsCustomer(housePlay) {
  await initTakeLook(housePlay)

  const params = new URLSearchParams(window.location.search)

  await NestTakelook3.startTour({
    userId: params.get('userId'),
    callerUserId: params.get('callerUserId'),
    meetingId: params.get('meetingId'),       // 从 URL 获取,不自行创建
    roomId: params.get('roomId'),            // 从 URL 获取,不自行创建
    imPlatform: 'web',
    packageId: params.get('packageId') || 'pkg_001',
  })
}

// ============================================================
// 结束带看(任意一方调用)
// ============================================================
async function stopTour() {
  await NestTakelook3.endTour('用户主动结束')
}

发送 → 监听 速查

你想做什么 本端调用 对端收到
同步 VR 视角 syncLocalActionToRemote(state) onRemoteControllingNotify(cb)
发送业务动作 syncLocalCustomActionToRemote(action) onSyncRemoteCustomActionToLocal(cb)
静音某人 voiceForbidden(userId, true) onVoiceForbidden(cb)
踢出某人 kickOutById(userId) onKickOut(cb)
结束带看 endTour(reason) onEndTour(cb)

进阶功能

跑通基础流程后,可按需接入以下能力:

功能 说明 参考文档
UI 状态同步 楼层切换、详情面板等双端联动 带看3集成指南 - 第十一章
画笔标注 双方在画面上实时绘制标注 带看3集成指南 - 第十二章
操作权限管理 「谁在操作」状态机,防冲突 带看3集成指南 - 第十章
呼叫模式 callOut 推送通知到对方 SDK 文档 - 4.2 会议管理
App WebView 适配 Android/iOS JSBridge 音频桥接 SDK 文档 - 第8章 多平台对接
自定义动作扩展 同步任意业务逻辑到远端 带看3集成指南 - 第九章