评论

Visionkit v1官方示例改写:渲染视频素材

此文记录探索实现three.js渲染视频素材的主要思路。自行将此文喂给GPT5-HIGH等高性能AI即可实现功能。

视频在 Three.js 场景中的渲染与播放实现说明

本文档详细记录“视频纹理如何被渲染到 Three.js 场景并实现自动/循环播放”的整体方案、关键代码、资源清理与常见问题。

概述

  • 技术路线:wx.createVideoDecoder 解码 → 将帧数据绘制到隐藏的 2D Canvas → 使用 THREE.CanvasTexture 绑定该 Canvas → 在定时循环中推进帧并标记纹理更新。
  • 优先使用 CanvasTexture 持续刷新,避免每帧经由 Base64 重新创建纹理的性能瓶颈。
  • 自动播放:在素材加载完成后进行首帧预热,并通过视频纹理更新器以约 30fps 驱动播放。
  • 循环播放:检测无帧时通过 seek(0) 重置到开头,持续循环。

目录与关键文件

  • index.wxml:定义 WebGL Canvas 与隐藏的 2D Canvas
  • behavior.js:加载素材、创建视频平面、绑定纹理、启动更新循环
  • video-player.js:封装视频下载压缩、解码、帧绘制到 Canvas
  • video-texture-updater.js:以 setInterval 驱动逐帧播放并刷新纹理

示例(index.wxml)

<view class="container page" data-weui-theme="{{theme}}">
  <canvas type="webgl" id="webgl" style="width: {{width}}px; height: {{height}}px" bindtouchend="onTouchEnd"></canvas>
  <!-- 用于视频渲染的2D Canvas,隐藏显示 -->
  <canvas 
    type="2d" 
    id="videoCanvas" 
    style="position: absolute; left: -9999px; top: -9999px; width: 320px; height: 240px;"
  ></canvas>
</view>

渲染管线(逐步说明)

  1. 组件初始化
  • onReady 中通过 this.createSelectorQuery().select('#webgl').node() 获取 WebGL Canvas 并初始化 Three.js 与 VKSession。
  • 设置画布尺寸,监听窗口尺寸变化。
  1. 素材批量加载
  • loadAllModels() 遍历 data.modelConfigs,对 type: 'video' 调用 loadVideoAsset(...)
  1. 视频平面与材质
  • 使用 new THREE.PlaneGeometry(16/9, 1) 创建 16:9 的几何体(长方形)。
  • 使用 new THREE.MeshBasicMaterial({ side: THREE.DoubleSide, transparent: true }) 创建材质并构建平面 Mesh
  1. 视频解码与 CanvasTexture
  • video-player.js 中:
    • 下载视频:wx.downloadFile → 可选压缩:wx.compressVideo({ quality: 'low' })
    • 创建解码器:const decoder = wx.createVideoDecoder()await decoder.start({ abortAudio: true, source: path })
    • 每次播放推进:decoder.getFrameData() 获取当前帧的 RGBA 数据并绘制到 2D Canvas:
      • context.createImageData(width, height) 创建 ImageData
      • imageData.data.set(Uint8ClampedArray) 填充像素
      • context.putImageData(imageData, 0, 0) 绘制
  • behavior.js 中:
    • playVideo('videoCanvas', url, cb).then(videoController => { ... })
    • 创建 new THREE.CanvasTexture(videoController.canvas) 并赋给 material.map,保存到 assetData.canvasTexture
    • 首帧预热:videoController.play()
  1. 纹理更新循环
  • video-texture-updater.js 启动 setInterval(updateLoop, 33)(约 30fps):
    • 每次调用 videoController.play() 推进到下一帧(并绘制到 2D Canvas)。
    • play() 返回 false(无帧),调用 videoController.restart()(内部使用 decoder.seek(0))实现循环播放。
    • CanvasTexturematerial.map.needsUpdate = true,确保纹理每帧刷新。
  1. 放置到场景
  • 加载完成后,可在素材组合/克隆流程中将视频平面设置位置、旋转、缩放并添加到场景或组合中;播放与纹理更新独立运行,无需额外触发。
  1. 资源清理
  • onUnload 中:
    • 停止所有视频纹理更新循环:this.videoTextureUpdater.stopAllVideoTextureUpdates()
    • 销毁视频播放器与解码器:this.videoPlayer.destroy()
    • 清理材质与几何体、渲染器、场景、时钟等,避免内存泄漏。

循环播放与自动播放

  • 自动播放:在绑定纹理后立即执行一次 videoController.play(),确保首帧显示。
  • 循环播放:
    • play() 返回布尔值,表示是否成功渲染一帧。
    • 当返回 false 时,调用 restart()seek(0) 回到起点并继续播放。

配置与尺寸

  • 几何体比例:当前使用 PlaneGeometry(16/9, 1)
  • 尺寸控制:通过配置中的 scale 同步缩放(对长宽等比缩放)。
  • 如果希望以“宽度为 1,高度为 9/16”的方式保持宽度不变,可改为 PlaneGeometry(1, 9/16)

性能与兼容建议

  • 基础库要求:wx.createVideoDecoder 从基础库 2.11.0 开始支持(需保证真机/开发者工具环境满足要求)。
  • 更新频率:默认 30fps(33ms),如遇性能瓶颈可调大间隔降低帧率(如 24fps、20fps)。
  • 纹理更新:CanvasTexture 每帧仅标记 needsUpdate,比每帧 TextureLoader.load(dataURL) 更高效。
  • 音频:当前使用 abortAudio: true,不解码音频流以降低开销,如需音频可调整解码参数并自己处理播放。

新增视频素材的步骤

  1. behavior.jsdata.modelConfigs 中添加条目:
{
  id: 1533,
  path: "https://example.com/video.mp4",
  positionX: "1.5",
  positionY: "1.71",
  positionZ: "-3",
  rotationX: "0",
  rotationY: "0",
  rotationZ: "0",
  scale: "3",
  type: "video"
}
  1. 进入页面后会自动加载、绑定纹理并开始播放;若视频结束会自动循环。

常见问题排查

  • 视频不播放/黑屏:
    • 确认 index.wxml 中存在 id="videoCanvas" 的 2D Canvas。
    • 检查视频 URL 是否可访问且不跨域受限;当前通过 wx.downloadFile 获取本地路径以规避跨域。
    • 确认基础库版本 ≥ 2.11.0,真机也需满足。
  • 画面拉伸:
    • 几何体为 16:9,如源视频不是 16:9,建议在几何体或缩放上调整比例,或在 2D Canvas 绘制前做裁剪/留边。
  • 卡顿/高耗:
    • 将更新频率从 33ms 调大(降低到 24fps/20fps)。
    • 避免每帧使用 Base64 新建纹理(已切换为 CanvasTexture)。

参考

最后一次编辑于  10-15  
点赞 1
收藏
评论
登录 后发表内容