ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

基于 React 360 构建媒体密集型 VR 应用:MediaAppTemplate 示例模板全解析

基于 React 360 构建媒体密集型 VR 应用:MediaAppTemplate 示例模板全解析 前端3D渲染【免费下载链接】react-360Create amazing 360 and VR content using React项目地址https://gitcode.com/gh_mirrors/re/react-360点击查看免费下载MediaAppTemplate 是 React 360 仓库中面向重度媒体应用的完整示例模板覆盖 360 照片、360 视频、矩形平面视频、环境音效、媒体预加载、环境过渡与多表面控制等核心能力。本文将结合 Samples/MediaAppTemplate 下的全部源码与 React360/js 底层模块实现逐层拆解该模板的架构设计与实战用法帮助读者掌握用 React 360 打造照片/视频浏览类 VR 应用的完整方案。模板概述与核心能力MediaAppTemplate是一个为希望使用 React 360 构建重度媒体型应用的开发者准备的示例代码模板代码中带有大量行内注释用于说明每个部分的工作原理。模板本身围绕一条场景数据定义 → 场景切换 → 媒体预加载 → 媒体展示的主线展开包含五大能力对应 README.md 的描述基础 UI 流程与音频主界面导航按钮、字幕文本、点击音效与环境背景音媒体预加载照片/视频提前把下一场景的 360 照片与视频加载进内存切换时零等待媒体展示与控制360 照片、360 视频、矩形平面视频的播放与停止环境过渡控制场景切换时带 2 秒淡入淡出过渡多表面控制主内容表面 跟随相机的字幕表面同时渲染。该示例还特意设计为可在 Facebook Instant Games即时游戏中运行入口页 index.html 加载了fbinstant.6.2.js脚本client.js中通过FBInstant.initializeAsync()/startGameAsync()完成初始化React360.init的调用方式也与普通项目一致因此可以平移到 Instant Games 的iframe环境中使用。环境准备与模板运行在运行模板前需要先搭建 React 360 开发环境。根据 docs/setup.md流程是安装 Node.js → 全局安装 React 360 CLI → 初始化项目 → 启动 Metro 开发服务器。npm install -g react-360-cli react-360 init MediaApp然后进入新项目目录将仓库 Samples/MediaAppTemplate 下的index.js、client.js、index.html、src/组件目录以及static_assets/静态资源chess-world.jpg、360_world.jpg、video360.mp4、video.mp4、cafe.wav、menu-click.wav、info_icon.png复制到项目对应位置最后启动开发服务器npm start在浏览器中打开http://localhost:8081/index.html首次加载因 Metro 需要爬取文件系统而较慢之后会明显加快即可看到欢迎场景点击按钮即可在各场景间切换。完整的示例说明也可参见 docs/example-mediaapptemplate.md。场景数据驱动SCENE_DEF 定义一切模板的精髓在于数据驱动场景所有场景内容都定义在 index.js 顶部的SCENE_DEF数组中每个条目描述一个场景的媒体类型、标题、资源、音频与下一场景指针const SCENE_DEF [ { type: photo, title: Welcome Scene, source: asset(chess-world.jpg), audio: asset(cafe.wav), next: 1, subtitle: This is the welcome scene, just look around!, }, { type: video, title: 360 Street View, source: {url: asset(video360.mp4).uri}, next: 2, subtitle: This is a 360 street view, you can see the traffic., }, { type: photo, title: 2D Street View, source: asset(360_world.jpg), screen: {url: asset(video.mp4).uri}, next: 0, subtitle: This is a 2d video of street view, you can see the traffic., }, ];各字段的作用如下字段类型含义typephoto \| video决定背景媒体是 360 照片还是 360 视频渲染分支据此选择Environment.setBackgroundImage或Environment.setBackgroundVideotitlestring场景标题显示在主表面场景页上sourcestring \| {url}背景媒体源。照片用asset()直接引用360 视频需要用asset(...).uri取得 URL 字符串Environment.setBackgroundVideo需要的是播放器 handle 而非 URLscreen{url}可选字段矩形平面视频如第三场景内嵌的 2D 视频audiostring环境背景音通过AudioModule.playEnvironmental循环播放nextnumber下一场景在数组中的索引构成一个场景跳转图此处形成 0→1→2→0 的循环subtitlestring字幕文本显示在独立的字幕表面上这种结构把界面与数据彻底解耦切换场景本质就是setState({index: nextID})随后所有渲染与媒体操作都由currentScene/nextScene派生。客户端初始化与多表面架构React 360 应用分客户端运行时与React 侧两部分。客户端侧 client.js 负责创建ReactInstance与Surfaceimport {ReactInstance, Surface} from react-360-web; function init(bundle, parent, options {}) { // initialise instant game if (FBInstant) { FBInstant.initializeAsync() .then(function() { FBInstant.setLoadingProgress(100); FBInstant.startGameAsync(); }); } const subtitleSurface new Surface(600, 800, Surface.SurfaceShape.Flat); subtitleSurface.setRadius(6); const r360 new ReactInstance(bundle, parent, { fullScreen: true, frame: () { // This will makes the subtitle surface always in front of user const cameraQuat r360.getCameraQuaternion(); subtitleSurface.recenter(cameraQuat, all); }, ...options, }); // Render your app content to the default cylinder surface r360.renderToSurface( r360.createRoot(MediaAppTemplate, { /* initial props */ }), r360.getDefaultSurface() ); // Render the subtitle content to a flat surface r360.renderToSurface( r360.createRoot(MediaAppTemplateSubtitle, { /* initial props */ }), subtitleSurface, ); } window.React360 {init};这里的多表面要点默认圆柱表面r360.getDefaultSurface()是 React 360 自动创建的环绕用户的圆柱形表面主场景页渲染其上自定义字幕表面new Surface(600, 800, Surface.SurfaceShape.Flat)创建 600×800 的平面表面setRadius(6)把它放置在以相机为球心、半径 6 米处HMD 式表面跟随相机frame回调每帧执行通过r360.getCameraQuaternion()获取相机朝向调用subtitleSurface.recenter(cameraQuat, all)让字幕表面始终正对用户。代码注释特别提醒这类头盔式表面在 VR 中如果放在角落位置将很难观看与交互设计时必须注意多根组件注册AppRegistry.registerComponent同时注册了MediaAppTemplate与MediaAppTemplateSubtitle两个根组件分别createRoot后渲染到两个表面。主界面 UI 流与交互动效主表面的场景页组件是 src/components/MediaAppTemplateScenePage.react.js其render()输出标题、内嵌视频屏幕与导航按钮View style{[styles.container, this.state.inTransition {opacity: 0}]} Text style{styles.title}{currentTitle}/Text MediaAppTemplateVideoScreen player{this._players.screen._player} style{styles.screen} visible{showScreen} / MediaAppTemplateInfoButton onClick{this._onClickNext} text{Go To: ${nextTitle}} width{300} / /View交互按钮组件 src/components/MediaAppTemplateInfoButton.react.js 同时示范了三件事输入处理、动效与音效通过VrButton的onEnter/onExit/onClick事件响应光标悬停与点击使用Animated.Value与Animated.timing300ms驱动scaleAnim再通过interpolate({inputRange: [0, 1], outputRange: [width, width * 1.3]})让按钮宽度随悬停放大到 1.3 倍配合hasFocus状态切换灰/白背景与边框色点击时调用AudioModule.playOneShot({source: asset(menu-click.wav)})播放一次性点击音效见 AudioModule.js其内部以autoPlay: true创建AudioInstance生命周期完全交给模块管理。媒体预加载机制这是模板最核心的工程实践用两组视频播放器轮换做到当前场景在播、下一场景在预载。componentWillMount中创建两组播放器this._players { scene: VideoModule.createPlayer(), screen: VideoModule.createPlayer(), }; this._nextPlayers { scene: VideoModule.createPlayer(), screen: VideoModule.createPlayer(), };照片预加载直接调用Environment.preloadBackgroundImage(data.source, {format: 2D})。代码注释说明即使照片仍在加载中就去调用setBackgroundImage也没问题加载完成后背景会自动显示。该调用最终落到 EnvironmentModule.js 的preloadScene内部按 URL 去重并释放上一张预载图片。视频预加载则是关键技巧——对一个未挂到环境或屏幕的播放器调用play()并配合muted: true、autoPlay: false即可实现后台预载_preloadVideo(player, source) { return new Promise((resolve, reject) { const onVideoLoadedSubscription player.addListener(onVideoStatusChanged, (event: VideoStatusEvent) { if (event.status ready) { player.removeSubscription(onVideoLoadedSubscription); resolve(); } }); player.play({ source: source, muted: true, autoPlay: false, }); }); }这里监听的是VideoModule的onVideoStatusChanged事件其实现见 VideoModule.js底层播放器状态变化时通过RCTDeviceEventEmitter把playerhandle 与状态一起 emit 到 React 侧状态为ready即代表缓冲完成。预加载以 Promise 串成流水线。_renderScene中的加载回调loadScene先停掉上一组播放器再交换两组播放器旧显示组变为下一轮预载组然后渲染当前场景并启动下一场景的预载const loadScene () { this._preloading false; this._players.scene.stop(); this._players.screen.stop(); // swap the players for next preload const temp this._players; this._players this._nextPlayers; this._nextPlayers temp; if (data.type photo) { Environment.setBackgroundImage(data.source, {format: 2D, transition: TRANSITION_TIME}); } else { this._players.scene.resume(); Environment.setBackgroundVideo(this._players.scene._player, {transition: TRANSITION_TIME}); } // ... // preload next scene const nextData nextProps.nextScene; this._preloadJob this._preloadScene(nextData); }; if (this._preloadJob ! null) { this._preloadJob.then(loadScene); } else { this._preloadScene(data).then(loadScene); }首次进入时先预载当前场景再渲染之后每次切换都等下一场景预载完成的 Promise 才执行渲染配合_preloading状态位防止切场景过快时闪现空画面。切换由_onClickNext触发更新index状态并dataStore.emit(dataChange, nextID)广播给字幕表面。媒体展示与环境切换环境Environment是 React 360 中承载 360 背景的抽象对应的 JS API 封装在 Libraries/VRModules/Environment.js底层由EnvironmentModule.loadScene执行EnvironmentModule.js。模板中的用法// 360 照片背景指定 2D 格式带 2000ms 淡入过渡 Environment.setBackgroundImage(data.source, {format: 2D, transition: TRANSITION_TIME}); // 360 视频背景把已预载的播放器挂到环境上 Environment.setBackgroundVideo(this._players.scene._player, {transition: TRANSITION_TIME});EnvironmentOptions支持的可选参数见 Environment.js参数说明format立体格式示例使用2D对应底层stereo字段作用于照片场景transition场景切换淡入淡出时长毫秒模板中TRANSITION_TIME 2000fadeLevel淡入时的初始透明度级别rotateTransform背景旋转变换数组经processTransform处理后传入底层环境过渡分为两层底层由transition控制背景自身的淡入UI 层在loadScene中同步setState({inTransition: true})并把场景页容器opacity置 02 秒后恢复——两层叠加构成完整的切换动画。此外EnvironmentModule还支持animateFade(fadeLevel, fadeTime)手动控制全局透明度以及type: black的黑屏场景clearBackground()。环境音频随场景联动有audio字段就AudioModule.playEnvironmental({source, volume: 0.5})循环播放咖啡馆背景音否则AudioModule.stopEnvironmental()停掉。从 AudioModule.js 的实现看playEnvironmental会自动给AudioInstance加上autoPlay: true, loop: true并记住唯一的环境实例以便切换/停止。平面视频屏幕与界面坐标对齐第三个场景演示了在 React 界面上内嵌矩形rectilinear2D 视频。关键组件 src/components/MediaAppTemplateVideoScreen.react.js 的思路是用UIManager.measureInWindow拿到占位 View 在表面内的窗口坐标再把视频纹理Environment.setScreen精确贴到同一位置const tag findNodeHandle(videoPlaceholder); setTimeout(() { UIManager.getViewRootID(tag).then(surface { this._surface surface; UIManager.measureInWindow(tag, (x, y, width, height) { this._videoBound {x, y, width, height}; }); }); });render()中根据visible决定挂载还是摘除if (this.props.visible) { Environment.setScreen( this.props.screenId, this.props.player, // 传入播放器 handle 即把视频纹理挂到屏幕 this._surface, x, y, width, height); } else { Environment.setScreen(this.props.screenId, null, this._surface, x, y, width, height); // playernull 摘除 }两个实现细节值得注意屏幕挂到表面后永远渲染在所有 React 组件之后注释明确说明因此占位 View 的坐标必须与视频内容重叠对齐视觉上才嵌在界面里showScreen的判定条件!_preloading !inTransition currentScene.screen保证预加载、环境过渡期间不显示屏幕避免纹理闪烁。Environment.setScreen在 Libraries/VRModules/Environment.js 中被封装为ScreenDef底层setScreen(id, handle, surface, x, y, width, height)指定屏幕 ID、播放器 handle、目标表面 ID 与相对坐标。跨根视图通信与字幕表面由于两个根组件渲染在两个不同表面共享状态不能直接靠 props 传递。模板采用极简事件总线方案index.js// To share data between different root views, the best way is to // use data frameworks such as flux or redux. // Here we just use a simple event emitter. const dataStore new EventEmitter();主场景页点击按钮时dataStore.emit(dataChange, nextID)字幕根组件MediaAppTemplateSubtitle在componentWillMount订阅、componentWillUnmount退订收到事件后setState({index})并渲染对应subtitle文本组件实现见 src/components/MediaAppTemplateSubtitleText.react.js。注释建议正式项目应改用 flux 或 redux 这类数据框架事件总线只是演示。底层模块 API 一览模板用到三个核心 NativeModule均为 React360/js/Modules 下的桥接模块VideoModuleVideoModule.js——管理视频播放器实例方法行为createPlayer()/destroyPlayer()创建 / 销毁播放器实例play(source, {autoPlay, muted, volume, stereo, layout, startPosition})设置源并加载source可传数组会按浏览器支持格式自动挑选getSupportedFormatspause()/resume()暂停 / 继续播放resume即player.play()stop()暂停并seekTo(0)复位seek(timeMs)/setParams(options)跳转 / 调整音量等参数EnvironmentModuleEnvironmentModule.js——loadSceneblack/photo/video 三类场景、preloadScene照片预载、setScreen表面内嵌屏幕、animateFade。AudioModuleAudioModule.js——playOneShot一次性音效、playEnvironmental/stopEnvironmental/setEnvironmentalParams循环背景音、createAudio/play/pause/stop/seek/destroy具名音频句柄并内置fetch → decodeAudioData的解码缓存管线_load。扩展方向模板是一个优秀的起点官方文档docs/example-mediaapptemplate.md给出了进一步扩展建议数据外置把硬编码在index.js中的SCENE_DEF迁移为独立 JSON 文件或由后端接口下发、前端异步查询即可支撑服务端运营的动态内容视频 UI 替代方案MediaAppTemplateVideoScreen之外可以选用仓库 addons/react-360-common-ui 中现成的VideoControl.react.js/VideoPlayer.react.js通用组件更多媒体形态参考 docs/photos-and-videos.md 与 docs/environment.md 扩展format立体视频与rotateTransform等环境能力多表面编排沿用client.js的framerecenter模式可进一步构建 HUD、菜单等更多 HMD 式表面但需始终注意 VR 观看舒适度。从场景数据模型、双播放器预载流水线、环境过渡到多表面事件通信MediaAppTemplate 用不到四百行代码演示了一条可复制的媒体密集型 VR 应用工程路径是学习 React 360 媒体能力的首选范例。赞分享前端3D渲染【免费下载链接】react-360Create amazing 360 and VR content using React项目地址https://gitcode.com/gh_mirrors/re/react-360点击查看免费下载相关推荐React 360基础应用模板解析与实战指南React 360基础应用模板解析与实战指南 什么是React 360基础应用模板 React 360基础应用模板 BasicAppTemplate 是为开发者前端3D渲染免费Switch模拟器yuzu在电脑上畅玩任天堂游戏的最简单方法免费Switch模拟器yuzu在电脑上畅玩任天堂游戏的最简单方法 想在电脑上体验《塞尔达传说旷野之息》、《超级马力欧奥德赛》这些经典Switch游戏吗y虚拟化桌面应用图形学【亲测免费】 基于粤嵌6818开发板的多媒体应用示例基于粤嵌6818开发板的多媒体应用示例 项目简介 本项目是专为粤嵌6818开发板设计的一款多媒体综合应用。它集成了电子相册、音乐播放器以及视频播放器三大功能旨上一篇Yuedu项目性能优化案例大赛社区参与活动下一篇RestKit文档生成使用Jazzy创建API参考文档的完整流程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表