Browse Source

init微信小程序

胡佳骏 1 year ago
commit
f30686ea2d
100 changed files with 3604 additions and 0 deletions
  1. 31 0
      .eslintrc.js
  2. 13 0
      .gitignore
  3. 21 0
      LICENSE
  4. 186 0
      README.md
  5. 96 0
      miniprogram/app.json
  6. 25 0
      miniprogram/app.ts
  7. 3 0
      miniprogram/app.wxss
  8. 112 0
      miniprogram/assets/animation/basic-animation.json
  9. 57 0
      miniprogram/assets/animation/gltf-animation.json
  10. 51 0
      miniprogram/assets/animation/last-record-anchor-animation.json
  11. 35 0
      miniprogram/assets/animation/miku-kawaii-animation.json
  12. BIN
      miniprogram/assets/gltf/Fox.glb
  13. BIN
      miniprogram/assets/image/ar-box-border.png
  14. BIN
      miniprogram/assets/image/background.png
  15. BIN
      miniprogram/assets/image/handle.png
  16. BIN
      miniprogram/assets/waifu.png
  17. BIN
      miniprogram/assets/wx_logo.bmp.bin
  18. 48 0
      miniprogram/components/common/share-behavior.js
  19. 48 0
      miniprogram/components/pull-down-list/index.js
  20. 3 0
      miniprogram/components/pull-down-list/index.json
  21. 11 0
      miniprogram/components/pull-down-list/index.wxml
  22. 91 0
      miniprogram/components/pull-down-list/index.wxss
  23. 142 0
      miniprogram/components/template/xr-template-arLine/index.js
  24. 5 0
      miniprogram/components/template/xr-template-arLine/index.json
  25. 28 0
      miniprogram/components/template/xr-template-arLine/index.wxml
  26. 1 0
      miniprogram/components/template/xr-template-arLine/index.wxss
  27. 172 0
      miniprogram/components/template/xr-template-arPreview/index.js
  28. 5 0
      miniprogram/components/template/xr-template-arPreview/index.json
  29. 27 0
      miniprogram/components/template/xr-template-arPreview/index.wxml
  30. 1 0
      miniprogram/components/template/xr-template-arPreview/index.wxss
  31. 53 0
      miniprogram/components/template/xr-template-arui/index.js
  32. 5 0
      miniprogram/components/template/xr-template-arui/index.json
  33. 51 0
      miniprogram/components/template/xr-template-arui/index.wxml
  34. 1 0
      miniprogram/components/template/xr-template-arui/index.wxss
  35. 55 0
      miniprogram/components/template/xr-template-blendDouble/index.js
  36. 5 0
      miniprogram/components/template/xr-template-blendDouble/index.json
  37. 19 0
      miniprogram/components/template/xr-template-blendDouble/index.wxml
  38. 1 0
      miniprogram/components/template/xr-template-blendDouble/index.wxss
  39. 166 0
      miniprogram/components/template/xr-template-control/index.js
  40. 5 0
      miniprogram/components/template/xr-template-control/index.json
  41. 26 0
      miniprogram/components/template/xr-template-control/index.wxml
  42. 1 0
      miniprogram/components/template/xr-template-control/index.wxss
  43. 133 0
      miniprogram/components/template/xr-template-featherVideo/index.js
  44. 5 0
      miniprogram/components/template/xr-template-featherVideo/index.json
  45. 56 0
      miniprogram/components/template/xr-template-featherVideo/index.wxml
  46. 1 0
      miniprogram/components/template/xr-template-featherVideo/index.wxss
  47. 126 0
      miniprogram/components/template/xr-template-frameEffect/index.js
  48. 5 0
      miniprogram/components/template/xr-template-frameEffect/index.json
  49. 18 0
      miniprogram/components/template/xr-template-frameEffect/index.wxml
  50. 1 0
      miniprogram/components/template/xr-template-frameEffect/index.wxss
  51. 213 0
      miniprogram/components/template/xr-template-geometry/index.js
  52. 5 0
      miniprogram/components/template/xr-template-geometry/index.json
  53. 21 0
      miniprogram/components/template/xr-template-geometry/index.wxml
  54. 1 0
      miniprogram/components/template/xr-template-geometry/index.wxss
  55. 68 0
      miniprogram/components/template/xr-template-gltfAnimation/index.js
  56. 5 0
      miniprogram/components/template/xr-template-gltfAnimation/index.json
  57. 22 0
      miniprogram/components/template/xr-template-gltfAnimation/index.wxml
  58. 1 0
      miniprogram/components/template/xr-template-gltfAnimation/index.wxss
  59. 56 0
      miniprogram/components/template/xr-template-gltfEdit/index.js
  60. 5 0
      miniprogram/components/template/xr-template-gltfEdit/index.json
  61. 25 0
      miniprogram/components/template/xr-template-gltfEdit/index.wxml
  62. 1 0
      miniprogram/components/template/xr-template-gltfEdit/index.wxss
  63. 24 0
      miniprogram/components/template/xr-template-gltfOcclusion/index.js
  64. 5 0
      miniprogram/components/template/xr-template-gltfOcclusion/index.json
  65. 43 0
      miniprogram/components/template/xr-template-gltfOcclusion/index.wxml
  66. 1 0
      miniprogram/components/template/xr-template-gltfOcclusion/index.wxss
  67. 90 0
      miniprogram/components/template/xr-template-gltfUVAnimation/index.js
  68. 5 0
      miniprogram/components/template/xr-template-gltfUVAnimation/index.json
  69. 20 0
      miniprogram/components/template/xr-template-gltfUVAnimation/index.wxml
  70. 1 0
      miniprogram/components/template/xr-template-gltfUVAnimation/index.wxss
  71. 232 0
      miniprogram/components/template/xr-template-loading/index.js
  72. 5 0
      miniprogram/components/template/xr-template-loading/index.json
  73. 88 0
      miniprogram/components/template/xr-template-loading/index.wxml
  74. 1 0
      miniprogram/components/template/xr-template-loading/index.wxss
  75. 74 0
      miniprogram/components/template/xr-template-lookat/index.js
  76. 5 0
      miniprogram/components/template/xr-template-lookat/index.json
  77. 36 0
      miniprogram/components/template/xr-template-lookat/index.wxml
  78. 1 0
      miniprogram/components/template/xr-template-lookat/index.wxss
  79. 65 0
      miniprogram/components/template/xr-template-markerCenter/index.js
  80. 5 0
      miniprogram/components/template/xr-template-markerCenter/index.json
  81. 39 0
      miniprogram/components/template/xr-template-markerCenter/index.wxml
  82. 1 0
      miniprogram/components/template/xr-template-markerCenter/index.wxss
  83. 105 0
      miniprogram/components/template/xr-template-markerLock/index.js
  84. 5 0
      miniprogram/components/template/xr-template-markerLock/index.json
  85. 35 0
      miniprogram/components/template/xr-template-markerLock/index.wxml
  86. 1 0
      miniprogram/components/template/xr-template-markerLock/index.wxss
  87. 70 0
      miniprogram/components/template/xr-template-message/index.js
  88. 5 0
      miniprogram/components/template/xr-template-message/index.json
  89. 22 0
      miniprogram/components/template/xr-template-message/index.wxml
  90. 1 0
      miniprogram/components/template/xr-template-message/index.wxss
  91. 26 0
      miniprogram/components/template/xr-template-planeShadow/index.js
  92. 5 0
      miniprogram/components/template/xr-template-planeShadow/index.json
  93. 23 0
      miniprogram/components/template/xr-template-planeShadow/index.wxml
  94. 1 0
      miniprogram/components/template/xr-template-planeShadow/index.wxss
  95. 23 0
      miniprogram/components/template/xr-template-removeBlack/index.js
  96. 5 0
      miniprogram/components/template/xr-template-removeBlack/index.json
  97. 31 0
      miniprogram/components/template/xr-template-removeBlack/index.wxml
  98. 1 0
      miniprogram/components/template/xr-template-removeBlack/index.wxss
  99. 131 0
      miniprogram/components/template/xr-template-select/index.js
  100. 5 0
      miniprogram/components/template/xr-template-select/index.json

+ 31 - 0
.eslintrc.js

@@ -0,0 +1,31 @@
+/*
+ * Eslint config file
+ * Documentation: https://eslint.org/docs/user-guide/configuring/
+ * Install the Eslint extension before using this feature.
+ */
+module.exports = {
+  env: {
+    es6: true,
+    browser: true,
+    node: true,
+  },
+  ecmaFeatures: {
+    modules: true,
+  },
+  parserOptions: {
+    ecmaVersion: 2018,
+    sourceType: 'module',
+  },
+  globals: {
+    wx: true,
+    App: true,
+    Page: true,
+    getCurrentPages: true,
+    getApp: true,
+    Component: true,
+    requirePlugin: true,
+    requireMiniProgram: true,
+  },
+  // extends: 'eslint:recommended',
+  rules: {},
+}

+ 13 - 0
.gitignore

@@ -0,0 +1,13 @@
+.idea
+.DS_Store
+.vscode
+node_modules
+*.log
+lib
+**/lib/*
+**/components/fallBack/*
+.rpt2_cache
+package-lock.json
+miniprogram/components/template/xr-template-geometry/man-data/indexData.js
+miniprogram/components/template/xr-template-geometry/man-data/uvData.js
+miniprogram/components/template/xr-template-geometry/man-data/vertexData.js

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Tianyu Dai
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 186 - 0
README.md

@@ -0,0 +1,186 @@
+# xr-frame-demo
+
+微信小程序`xr-frame`系统的示例集。
+
+## 准备工作
+
+目前需要下载最新的[Nightly版本工具](https://developers.weixin.qq.com/miniprogram/dev/devtools/nightly.html),最新的客户端(安卓8.0.29,iOS8.0.29),以及基础库(2.27.1)。
+
+## 直接体验
+
+二维码以及部分样例的扫描图片详见:[官方文档-示例](https://developers.weixin.qq.com/miniprogram/dev/component/xr-frame/overview/index#示例)。
+
+https://user-images.githubusercontent.com/7337763/199401152-d3e14ca2-bcde-41aa-902c-dc0fbd6b6358.mp4
+
+
+## 快速索引
+
+#### [常见问题QA](/qa/README.md)
+
+#### [基础库版本分布](https://developers.weixin.qq.com/miniprogram/dev/framework/client-lib/version.html)
+
+
+<!-- ### [案例截图与描述](/screenshot/README.md) -->
+
+### 基础能力
+[基础案例](/miniprogram/components/xr-basic/) PBR材质下渲染的内置图形。
+
+[透明画布](/miniprogram/components/xr-basic-alpha/) 使用透明画布能力,透出背景。
+
+[灯光案例](/miniprogram/components/xr-basic-light/) 多种灯光作用下的四个白色图形。
+
+[动画案例](/miniprogram/components/xr-basic-animation/) `keyframe` 动画案例。
+
+[视频案例](/miniprogram/components/xr-basic-video/) 视频纹理,正式版本预计基础库 v2.32.0 及以上支持。
+
+[交互案例](/miniprogram/components/xr-basic-touch/) 简单的拖拽图形旋转移动案例。
+
+[显示与图层案例](/miniprogram/components/xr-basic-visible-layer/) 控制节点树的显示案例。
+
+[动态节点案例](/miniprogram/components/xr-basic-shadow/) 通过 `xr-shadow` 节点,来动态在其下添加节点,以及用代码加载资源。
+
+[渲染目标案例](/miniprogram/components/xr-basic-render-texture/) 使用 `xr-asset-render-texture` 生成渲染目标。
+
+[粒子系统](/miniprogram/components/xr-basic-particle/) 使用`xr-particle`,控制粒子系统的显示。
+
+[后处理系统](/miniprogram/components/xr-basic-postprocessing/) 展示了内置的几种后处理效果。
+
+[全局环境数据与局部环境数据](/miniprogram/components/xr-basic-envData/) 动态更改 `xr-mesh` 局部环境数据的案例。
+
+### AR 能力
+[相机渲染案例](/miniprogram/components/xr-ar-camera/) AR相机与glTF一同渲染的基础案例。
+
+[平面识别案例](/miniprogram/components/xr-ar-basic/) 基础的平面识别案例。
+
+[平面识别叠加Marker案例](/miniprogram/components/xr-vio-marker/) 平面识别叠加Marker案例
+
+[相机旋转案例](/miniprogram/components/xr-ar-threeDof/) threeDof,用于在不需要SLAM的场景,支持手持相机旋转,兼容性较好。
+
+[2DMarker案例](/miniprogram/components/xr-ar-2dmarker/) 2DMarker识别案例。
+
+[OSDMarker案例](/miniprogram/components/xr-ar-osdmarker/) OSDMarker识别案例。
+
+[人脸案例](/miniprogram/components/xr-ar-face/) 人脸识别案例。
+
+[人手案例](/miniprogram/components/xr-ar-hand/) 人手识别案例。
+
+[人体案例](/miniprogram/components/xr-ar-body/) 人体识别案例。
+
+### 物理 能力
+[射击积木案例](/miniprogram/components/xr-physics-shoot/) 射击积木案例
+
+[投球入筐案例](/miniprogram/components/xr-physics-throw/) 投球入筐案例
+
+
+### glTF 能力
+[金属头盔案例](/miniprogram/components/xr-gltf-damageHelmet/) 包含完整MetalRougnessMap、EmissiveMap、NormalMap、OcclusionTexture 以及各类因子的 glTF 模型案例。
+
+[动画案例](/miniprogram/components/xr-gltf-animation/) 包含 glTF 动画,以及 keyframe 动画协作的案例
+
+[加载与多光源案例](/miniprogram/components/xr-gltf-light-loading/) 组件和页面通信实现资源加载时覆盖加载界面,以及多个动画光源案例。
+
+[morph案例](/miniprogram/components/xr-gltf-morph/) morph targets的使用。
+
+[无光照案例](/miniprogram/components/xr-gltf-unlit/) 应用 KHR_materials_unlit 扩展的 glTF 案例。
+
+[扩展 - 压缩纹理](/miniprogram/components/xr-gltf-compressTextures/)
+
+[扩展 - KHR_texture_transform 贴图矩阵变换案例](/miniprogram/components/xr-gltf-textureTransform/) 应用 KHR_texture_transform 扩展的 glTF 案例,glTF 贴图矩阵变换支持(需基础库2.31.0)。
+
+[扩展 - KHR_materials_pbrSpecularGlossiness 高光光泽度案例](/miniprogram/components/xr-gltf-specularGlossiness/)
+
+[扩展 - KHR_materials_sheen 布料与织物材质的模拟案例](/miniprogram/components/xr-gltf-sheen/) glTF Sheen 扩展,主要用于布料与织物材质的模拟。基础库 2.32.1 支持。
+
+[扩展 - KHR_lights_punctual](/miniprogram/components/xr-gltf-lightsPunctual/)
+
+
+### 高级定制
+
+[定制组件和元素](/miniprogram/components/xr-custom-logic/) 定制组件和元素并使用。
+
+[定制渲染资源](/miniprogram/components/xr-custom-render/) 定制Effect和Geometry并使用。
+
+### 通用功能模版
+
+[ 小程序混合通信](/miniprogram/components/template/xr-template-message/) 通过小程序按钮事件,传递速度变量到 xr-frame 组件通信的案例。
+
+[Controller 第一人称漫游](/miniprogram/components/template/xr-template-control/) 第一人称相机控制器。
+
+[Loading 动态资源加载与使用](/miniprogram/components/template/xr-template-loading/) 点击按钮进行对应资源的加载与使用。
+
+[Tracker 动态多Tracker切换](/miniprogram/components/template/xr-template-tracker/) 点击按钮,对应不同识别效果 Marker 的添加与删除。
+
+[AR 模型摆放与手势控制](/miniprogram/components/template/xr-template-arPreview/) 点击屏幕摆放,然后单指拖动屏幕进行旋转,双指拖动进行放大缩小。
+
+[AR 面向屏幕的面片与模型](/miniprogram/components/template/xr-template-lookat/) 通过脚本控制的,四个方向各有一个面向屏幕的物体。
+
+[AR 平面模式下的 UI 面板](/miniprogram/components/template/xr-template-arui/) AR环境下,简单的UI面板
+
+[Effect 模型切换为Toon渲染(自定义多pass)](/miniprogram/components/template/xr-template-toon/)
+
+[Geometry 定制每帧变化的Geometry](/miniprogram/components/template/xr-template-geometry/)
+
+[glTF 模型更换贴图](/miniprogram/components/template/xr-template-gltfEdit/) 加载 glTF 模型,调整 glTF 的材质的贴图
+
+[glTF 模型动画(脚本、骨骼)](/miniprogram/components/template/xr-template-gltfAnimation/)
+
+[glTF 模型更改渲染状态,glTF设为遮挡模型](/miniprogram/components/template/xr-template-gltfOcclusion/) 使用模型做遮挡剔除,让该模型剔除其他物体
+
+[glTF 添加模型内UV动画](/miniprogram/components/template/xr-template-gltfUVAnimation/) 
+
+[Touch 点选物体与动画控制](/miniprogram/components/template/xr-template-select/)
+
+
+[序列帧动画(雪碧图、GIF)](/miniprogram/components/template/xr-template-frameEffect/) 使用自定义材质实现的序列帧动画案例。
+
+
+[截屏与分享](/miniprogram/components/template/xr-template-share/) 通过分享系统截屏分享
+
+[过滤黑色背景视频](/miniprogram/components/template/xr-template-removeBlack/) 通过自定义材质,过滤掉视频黑色部分的案例。
+
+### AR典型案例
+
+[扫描图片模型透视案例](/miniprogram/components/xr-classic-perspect/) 基于 Stencil裁剪 实现的基本模型透视效果案例。
+
+[传送门效果案例](/miniprogram/components/xr-classic-portal/) 基于平面识别与模版剔除实现的基本传送门效果案例。
+
+[平面视频案例](/miniprogram/components/xr-classic-video/) 基于 2DMarker 实现,扫描工卡照片显示对应的生活场景。
+
+[扫描物体查看信息](/miniprogram/components/xr-classic-osd/) 基于 OSD 实现的扫描 广州塔 或 虎年公仔,识别成功后会在物体右上角加上信息提示。
+
+[扫描人脸穿戴](/miniprogram/components/xr-classic-face/) 基于 人脸识别 的穿戴。
+
+[微信球案例](/miniprogram/components/xr-classic-wxball/) 扫描手握着的微信纪念球,会显示三维纪念球,点击三维纪念球会播放动画。
+
+### 扫描还原案例
+
+[扫描渲染案例](/miniprogram/components/xr-scan-render/) 根据三维重建模型与扫描全景图还原的案例,仅使用IBL作为光源,可切换天空盒。
+
+[卡 其 脱 离 太](/miniprogram/components/xr-scan-render/) xr-frame团队的办公区和成员三维重建,以及与小程序音频系统、2dview协作的例子。
+
+### 产品级案例
+
+[边缘迷走](/miniprogram/pages/scene-beside-edge/) AR文字互动游戏。
+
+[■■■■](/miniprogram/pages/scene-last-record/) ■■■■■■■■■■■■■■■■
+
+## 版权
+
+实例中用到的所有资源:
+
+https://sketchfab.com/3d-models/borboleta-azul-butterfly-ab9192b6bc8f49e3baed63e984c7073a  
+https://sketchfab.com/3d-models/just-a-girl-b2359160a4f54e76b5ae427a55d9594d  
+https://sketchfab.com/3d-models/metal-table-60f8c279c7b64fce8241220178e543ec  
+https://sketchfab.com/3d-models/fiesta-tea-8bde490c80444157b4545471d067423c  
+https://sketchfab.com/3d-models/ship-in-clouds-c475323dc7f24e26ba2009c08c8e1941  
+https://sketchfab.com/3d-models/cloud-station-26f81b24d83441ba88c7e80a52adbaaf  
+https://sketchfab.com/3d-models/shiteyanyo-hatsune-miku-0f4029ba805c4751933bba24dc72dd24  
+https://sketchfab.com/3d-models/miku-8b8028fa527549629b620752517812ac  
+https://sketchfab.com/3d-models/pokemon-frlg-loreleis-arena-ce7397e95ec9458b8df3c1453e4d0b82  
+https://sketchfab.com/3d-models/10th-attract-genderless-attraction-fc5548bb511e45748c393184ecbad26b  
+https://sketchfab.com/3d-models/camera-limits-demo-van-gogh-bedroom-in-arles-daefab319a584e559443e39ff05e84fa  
+https://sketchfab.com/3d-models/night-car-landscape-be4011aeb09740948bf30d33936c875b  
+https://sketchfab.com/models/b81008d513954189a063ff901f7abfe4  
+http://www.alexandre-pestana.com/pbr-textures-sponza/  
+https://sketchfab.com/3d-models/jokers-mask-persona-5-81669910c0b74f41a3a58febfd514794
+

+ 96 - 0
miniprogram/app.json

@@ -0,0 +1,96 @@
+{
+  "pages": [
+    "pages/ar-classic/scene-classic-video/index",
+    "pages/index/index",
+    "pages/basic/scene-basic/index",
+    "pages/basic/scene-basic-alpha/index",
+    "pages/basic/scene-basic-light/index",
+    "pages/basic/scene-basic-animation/index",
+    "pages/basic/scene-basic-touch/index",
+    "pages/basic/scene-basic-visible-layer/index",
+    "pages/basic/scene-basic-shadow/index",
+    "pages/basic/scene-basic-video/index",
+    "pages/basic/scene-basic-render-texture/index",
+    "pages/basic/scene-basic-postprocessing/index",
+    "pages/basic/scene-basic-envData/index",
+    "pages/basic/scene-basic-share/index",
+    "pages/gltf/scene-gltf-damageHelmet/index",
+    "pages/gltf/scene-gltf-unlit/index",
+    "pages/gltf/scene-gltf-animation/index",
+    "pages/gltf/scene-gltf-morph/index",
+    "pages/gltf/scene-gltf-light-loading/index",
+    "pages/gltf/scene-gltf-specularGlossiness/index",
+    "pages/gltf/scene-gltf-sheen/index",
+    "pages/gltf/scene-gltf-transmission/index",
+    "pages/gltf/scene-gltf-textureTransform/index",
+    "pages/gltf/scene-gltf-lightsPunctual/index",
+    "pages/gltf/scene-gltf-compressTextures/index",
+    "pages/ar/scene-ar-basic/index",
+    "pages/ar/scene-ar-2dmarker/index",
+    "pages/ar/scene-ar-osdmarker/index",
+    "pages/ar/scene-ar-face/index",
+    "pages/ar/scene-ar-hand/index",
+    "pages/ar/scene-ar-body/index",
+    "pages/ar/scene-ar-threeDof/index",
+    "pages/ar/scene-ar-camera/index",
+    "pages/ar/scene-ar-vio-marker/index",
+    "pages/ar/scene-ar-vio-depth/index",
+    "pages/custom/scene-custom-logic/index",
+    "pages/custom/scene-custom-render/index",
+    "pages/scan/scene-scan-render/index",
+    "pages/scan/scene-scan-team/index",
+    "pages/ar-classic/scene-classic-wxball/index",
+    "pages/ar-classic/scene-classic-perspect/index",
+    "pages/ar-classic/scene-classic-portal/index",
+    "pages/ar-classic/scene-classic-osd/index",
+    "pages/ar-classic/scene-classic-face/index",
+    "pages/template/xr-template-message/index",
+    "pages/template/xr-template-control/index",
+    "pages/template/xr-template-loading/index",
+    "pages/template/xr-template-toon/index",
+    "pages/template/xr-template-planeShadow/index",
+    "pages/template/xr-template-geometry/index",
+    "pages/template/xr-template-gltfEdit/index",
+    "pages/template/xr-template-gltfAnimation/index",
+    "pages/template/xr-template-gltfOcclusion/index",
+    "pages/template/xr-template-gltfUVAnimation/index",
+    "pages/template/xr-template-blendDouble/index",
+    "pages/template/xr-template-frameEffect/index",
+    "pages/template/xr-template-tracker/index",
+    "pages/template/xr-template-markerCenter/index",
+    "pages/template/xr-template-markerLock/index",
+    "pages/template/xr-template-arLine/index",
+    "pages/template/xr-template-select/index",
+    "pages/template/xr-template-share/index",
+    "pages/template/xr-template-removeBlack/index",
+    "pages/template/xr-template-featherVideo/index",
+    "pages/template/xr-template-arPreview/index",
+    "pages/template/xr-template-lookat/index",
+    "pages/template/xr-template-arui/index",
+    "pages/scene-last-record/index",
+    "pages/scene-beside-edge/index",
+    "pages/physics/scene-physics-shoot/index",
+    "pages/physics/scene-physics-throw/index",
+    "pages/particle/scene-particle-firework/index",
+    "pages/particle/scene-particle-portal/index",
+    "pages/particle/scene-particle-orb/index",
+    "pages/particle/scene-particle-shapeEmitter/index",
+    "pages/particle/scene-particle-custom/index",
+    "pages/particle/scene-particle-meshEmitter/index",
+    "pages/customParticle/scene-customParticle-firework/index",
+    "pages/customParticle/scene-customParticle-orb/index",
+    "pages/customParticle/scene-customParticle-portal/index",
+    "pages/customParticle/scene-customParticle-shapeEmitter/index",
+    "pages/customParticle/scene-customParticle-meshEmitter/index"
+  ],
+  "usingComponents": {},
+  "window": {
+    "backgroundTextStyle": "light",
+    "navigationBarBackgroundColor": "#f6f6f6",
+    "navigationBarTitleText": "",
+    "navigationBarTextStyle": "black"
+  },
+  "style": "v2",
+  "sitemapLocation": "sitemap.json",
+  "lazyCodeLoading": "requiredComponents"
+}

+ 25 - 0
miniprogram/app.ts

@@ -0,0 +1,25 @@
+// app.ts
+// import './xr-custom/components/AutoRotate';
+// import './xr-custom/elements/xr-auto-rotate-touchable-gltf';
+// import './xr-custom/assets/geometry-star';
+// import './xr-custom/assets/effect-shining';
+// import './xr-custom/elements/xr-shining-star';
+// import './xr-custom/assets/effect-last-record-final';
+
+App<IAppOption>({
+  globalData: {},
+  onLaunch() {
+    // 展示本地存储能力
+    // const logs = wx.getStorageSync('logs') || []
+    // logs.unshift(Date.now())
+    // wx.setStorageSync('logs', logs)
+
+    // 登录
+    wx.login({
+      success: res => {
+        console.log(res.code)
+        // 发送 res.code 到后台换取 openId, sessionKey, unionId
+      },
+    })
+  },
+})

+ 3 - 0
miniprogram/app.wxss

@@ -0,0 +1,3 @@
+page {
+  background: #f6f6f6;
+}

+ 112 - 0
miniprogram/assets/animation/basic-animation.json

@@ -0,0 +1,112 @@
+{
+  "keyframe": {
+    "cube": {
+      "0": {
+        "position": [-3, 0, 2]
+      },
+      "50": {
+        "rotation": [0, 0, 0],
+        "scale": [1, 1, 1]
+      },
+      "100": {
+        "position": [3, 0, 2],
+        "rotation": [0, 3.14, 0],
+        "scale": [1.4, 1.4, 1.4]
+      }
+    },
+    "sphere": {
+      "0": {
+        "position": [-3, 0, 0],
+        "scale": [0.8, 0.8, 0.8]
+      },
+      "50": {
+        "position": [0, 0.2, 0],
+        "scale": [1, 1, 1]
+      },
+      "100": {
+        "position": [3, 0, 0],
+        "scale": [0.8, 0.8, 0.8]
+      }
+    },
+    "cylinder": {
+      "0": {
+        "position": [-3, 0, -2],
+        "rotation": [0, 0, 0]
+      },
+      "50": {
+        "rotation": [0, 0, -3.14]
+      },
+      "100": {
+        "position": [3, 0, -2],
+        "rotation": [0, 0, 3.14]
+      }
+    },
+    "plane": {
+      "0": {
+        "material.u_baseColorFactor": [0.48, 0.78, 0.64, 1]
+      },
+      "50": {
+        "material.u_baseColorFactor": [0.368, 0.937, 0.176, 1]
+      },
+      "100": {
+        "material.u_baseColorFactor": [0.176, 0.368, 0.937, 1]
+      }
+    },
+    "spotLight": {
+      "0": {
+        "position": [-4, 1, -4]
+      },
+      "25": {
+        "position": [-4.3, 0.5, -2]
+      },
+      "75": {
+        "position": [-3, 1.5, 2]
+      },
+      "100": {
+        "position": [-4, 1, 4]
+      }
+    }
+  },
+  "animation": {
+    "default": {
+      "keyframe": "cube",
+      "duration": 1,
+      "ease": "ease-in-out",
+      "loop": 400000,
+      "delay": 1,
+      "direction": "both"
+    },
+    "sphere": {
+      "keyframe": "sphere",
+      "duration": 1,
+      "ease": "ease-out",
+      "loop": 400000,
+      "delay": 1,
+      "direction": "both"
+    },
+    "cylinder": {
+      "keyframe": "cylinder",
+      "duration": 1,
+      "ease": "ease-in",
+      "loop": 400000,
+      "delay": 1,
+      "direction": "both"
+    },
+    "plane": {
+      "keyframe": "plane",
+      "duration": 4,
+      "ease": "linear",
+      "loop": 400000,
+      "delay": 1,
+      "direction": "both"
+    },
+    "spotLight": {
+      "keyframe": "spotLight",
+      "duration": 2,
+      "ease": "ease-in-out",
+      "loop": 400000,
+      "delay": 1,
+      "direction": "both"
+    }
+  }
+}

+ 57 - 0
miniprogram/assets/animation/gltf-animation.json

@@ -0,0 +1,57 @@
+{
+  "keyframe": {
+    "directionalLight": {
+      "0": {
+        "rotation": [40, 170, 0]
+      },
+      "50": {
+        "rotation": [30, 140, 0]
+      },
+      "100": {
+        "rotation": [40, 170, 0]
+      }
+    },
+    "pointLight": {
+      "0": {
+        "position": [10, 0, 0]
+      },
+      "100": {
+        "position": [-10, 0, 0]
+      }
+    },
+    "spotLight": {
+      "0": {
+        "rotation": [0,90,0]
+      },
+      "100": {
+        "rotation": [0, 270, 4]
+      }
+    }
+  },
+  "animation": {
+    "default": {
+      "keyframe": "directionalLight",
+      "duration": 60,
+      "ease": "linear",
+      "loop": 400000,
+      "delay": 1,
+      "direction": "both"
+    },
+    "pointLight": {
+      "keyframe": "pointLight",
+      "duration": 6,
+      "ease": "linear",
+      "loop": 400000,
+      "delay": 1,
+      "direction": "both"
+    },
+    "spotLight": {
+      "keyframe": "spotLight",
+      "duration": 200,
+      "ease": "linear",
+      "loop": 400000,
+      "delay": 1,
+      "direction": "both"
+    }
+  }
+}

+ 51 - 0
miniprogram/assets/animation/last-record-anchor-animation.json

@@ -0,0 +1,51 @@
+{
+  "keyframe": {
+    "parent": {
+      "0": {
+        "rotation": [0, 0, 0]
+      },
+      "100": {
+        "rotation": [0, 6.28, 0]
+      }
+    },
+    "child": {
+      "0": {
+        "position.y": 0.8
+      },
+      "50": {
+        "position.y": 1
+      },
+      "100": {
+        "position.y": 0.8
+      }
+    },
+    "door": {
+      "0": {
+        "scale": [0, 1, 1]
+      },
+      "100": {
+        "scale": [1, 1, 1]
+      }
+    }
+  },
+  "animation": {
+    "parent": {
+      "keyframe": "parent",
+      "duration": 8,
+      "ease": "linear",
+      "loop": -1
+    },
+    "child": {
+      "keyframe": "child",
+      "duration": 4,
+      "ease": "linear",
+      "direction": "both",
+      "loop": -1
+    },
+    "door": {
+      "keyframe": "door",
+      "duration": 0.6,
+      "ease": "linear"
+    }
+  }
+}

+ 35 - 0
miniprogram/assets/animation/miku-kawaii-animation.json

@@ -0,0 +1,35 @@
+{
+  "keyframe": {
+    "parent": {
+      "0": {
+        "rotation": [0, 0, 0]
+      },
+      "100": {
+        "rotation": [0, 6.28, 0]
+      }
+    },
+    "child": {
+      "0": {
+        "position.y": -0.5
+      },
+      "100": {
+        "position.y": 1.5
+      }
+    }
+  },
+  "animation": {
+    "parent": {
+      "keyframe": "parent",
+      "duration": 8,
+      "ease": "linear",
+      "loop": -1
+    },
+    "child": {
+      "keyframe": "child",
+      "duration": 4,
+      "ease": "ease-in-out",
+      "direction": "both",
+      "loop": -1
+    }
+  }
+}

BIN
miniprogram/assets/gltf/Fox.glb


BIN
miniprogram/assets/image/ar-box-border.png


BIN
miniprogram/assets/image/background.png


BIN
miniprogram/assets/image/handle.png


BIN
miniprogram/assets/waifu.png


BIN
miniprogram/assets/wx_logo.bmp.bin


+ 48 - 0
miniprogram/components/common/share-behavior.js

@@ -0,0 +1,48 @@
+export default Behavior({
+  created: function () {
+    this.checkInitShare();
+  },
+  methods: {
+    checkInitShare() {
+      wx.xrScene = undefined;
+
+      if (!this.scene) {
+        setTimeout(() => {
+          this.checkInitShare()
+        }, 100);
+        return;
+      }
+
+      if (this.scene.ar) {
+        if (this.scene.ar.ready) {
+          this.initARTrackerState(this.scene);    
+        } else { 
+          this.scene.event.add('ar-ready', () => this.initARTrackerState(this.scene));
+        }
+      }
+
+      if (!this.scene.share.supported) {
+        console.warn('Not support xr-frame share system now!');
+        return;
+      }
+
+      this.sharing = false;
+      wx.xrScene = this.scene;
+    },
+    initARTrackerState(scene) {
+      const xrFrameSystem = wx.getXrFrameSystem();
+      scene.dfs(() => {}, undefined, true, el => {
+        const comp = el.getComponent(xrFrameSystem.ARTracker);
+        if (comp) {
+          if (typeof comp.state === 'number') {
+            this.triggerEvent('arTrackerState', {state: comp.state, error: comp.errorMessage});
+            el.event.add('ar-tracker-state', tracker => {
+              this.triggerEvent('arTrackerState', {state: tracker.state, error: tracker.errorMessage});
+            });
+          }
+          return true;
+        }
+      });
+    }
+  }
+})

+ 48 - 0
miniprogram/components/pull-down-list/index.js

@@ -0,0 +1,48 @@
+const itemHeight = 56 * 2;
+Component({
+    data: {
+        childBoxHeight: 0,
+    },
+    externalClasses: ['t-class'],
+    properties: {
+        defaultOpen: {
+            type: Boolean,
+            value: false,
+        },
+        name: {
+            type: String,
+            value: '',
+        },
+        tag: {
+            type: String,
+            value: '',
+        },
+        root: {
+            type: String,
+            value: '',
+        },
+        childArr: {
+            type: Array,
+            value: [],
+            observer(childArr) {
+                this.setData({
+                    childBoxHeight: this.data.defaultOpen ? itemHeight * childArr.length : 0,
+                });
+            },
+        },
+    },
+    methods: {
+        switchHandle() {
+            const { childArr, childBoxHeight } = this.data;
+            this.setData({
+                childBoxHeight: childBoxHeight > 0 ? 0 : childArr.length * itemHeight,
+            });
+        },
+        tapChild(e) {
+            this.triggerEvent('click', {
+                ...e.target.dataset,
+                root: this.data.root
+            });
+        },
+    },
+});

+ 3 - 0
miniprogram/components/pull-down-list/index.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 11 - 0
miniprogram/components/pull-down-list/index.wxml

@@ -0,0 +1,11 @@
+<view class="pullDownList t-class {{ childBoxHeight > 0 ? 'actived' : '' }}">
+  <view class="switchBox" catch:tap="switchHandle">
+    <view class="name">{{ name }}</view>
+    <view class="tag type-{{tag}}">{{ tag === 'func' ? '能力' : ''}}{{ tag === 'template' ? '模版' : ''}}{{ tag === 'case' ? '案例' : ''}}</view>
+  </view>
+  <view class="childBox" style="height: {{ childBoxHeight }}rpx">
+    <view class="child {{item.class}}" wx:for="{{childArr}}" wx:key="name" data-item="{{item}}" bindtap="tapChild">
+      {{ item.name }} {{ item.label }}
+    </view>
+  </view>
+</view>

+ 91 - 0
miniprogram/components/pull-down-list/index.wxss

@@ -0,0 +1,91 @@
+.pullDownList {
+  width: 100%;
+  box-sizing: border-box;
+  background-color: #fff;
+  border-radius: 8rpx;
+  margin-bottom: 24rpx;
+  overflow: hidden;
+}
+.pullDownList .switchBox {
+  height: 120rpx;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 0 32rpx;
+  font-size: 32rpx;
+  line-height: 48rpx;
+  color: #333;
+}
+.pullDownList .tag {
+  width: 100rpx;
+  text-align: center;
+  border-radius: 5rpx;
+  font-size: 26rpx;
+}
+
+.pullDownList .tag.type-func {
+  color: #fff;
+  background-color: #29bf12;
+}
+
+.pullDownList .tag.type-template {
+  color: #fff;
+  background-color: #ff9914;
+}
+
+.pullDownList .tag.type-case {
+  color: #fff;
+  background-color: #08bdbd;
+}
+.pullDownList .name,
+.pullDownList .icon {
+  transition: opacity 0.3s;
+}
+.pullDownList .name {
+  opacity: 0.9;
+}
+.pullDownList.actived .name {
+  opacity: 0.4;
+}
+.pullDownList.actived .icon {
+  opacity: 0.4;
+}
+.pullDownList .childBox {
+  transition: height 0.3s;
+}
+.pullDownList .childBox .child {
+  box-sizing: border-box;
+  border-bottom: 1rpx solid #e5e5e5;
+  border-top-width: 2rpx;
+  height: 112rpx;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding-left: 32rpx;
+  padding-right: 32rpx;
+  font-size: 28rpx;
+  opacity: 0.9;
+}
+.pullDownList .childBox .child:last-of-type {
+  border-bottom-color: transparent;
+}
+
+.message {
+  border: 20rpx solid #000;
+}
+
+.ar {
+  border: 20rpx solid #1D5B79;
+}
+
+.custom {
+  border: 20rpx solid #468B97;
+}
+
+.gltf {
+  border: 20rpx solid #EF6262;
+}
+
+.tool {
+  border: 20rpx solid #F3AA60;
+}

+ 142 - 0
miniprogram/components/template/xr-template-arLine/index.js

@@ -0,0 +1,142 @@
+const colorPattern1 = [
+  [0.129, 0.612, 0.565],
+  [0.914, 0.722, 0.141],
+  [0.933, 0.576, 0.133],
+  [0.847, 0.247, 0.192],
+]
+const colorPattern2 = [
+  [0.392, 0.6, 0.914],
+  [0.62, 0.867, 1],
+  [0.651, 0.965, 1],
+  [0.745, 1, 0.969],
+]
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false,
+    arReady: false,
+  },
+  lifetimes: {
+    async attached() {
+      console.log('data', this.data)
+    }
+  },
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+    },
+    handleARReady: function({detail}) {
+      console.log('arReady', this.scene.ar.arVersion);
+
+      const xr = wx.getXrFrameSystem();
+      const scene = this.scene;
+
+      const root = scene.getElementById('root');
+      const cursor = scene.getElementById('cursor');
+      const cursorTrs = cursor.getComponent(xr.Transform);
+
+      const geometryPoint = scene.assets.getAsset('geometry', 'sphere');
+      const geometryLine = scene.assets.getAsset('geometry', 'cube');
+      const effectStandard = scene.assets.getAsset('effect', 'standard');
+
+      let preCubeTrs = undefined;
+      let touchFlag = false;
+
+      // 缓存这些常量
+      const forward = xr.Vector3.createFromNumber(0,0,0);
+      const up =  xr.Vector3.createFromNumber(0, 1, 0);
+      const useQuaternion = xr.Quaternion.createFromNumber(0, 0, 0, 0);
+
+      scene.event.add('touchstart', (e) => {
+        // 点击开始后,放置
+
+        if (touchFlag) {
+          // 控制点击频率
+          return;
+        }
+        touchFlag = true;
+
+        // 新的cube
+        const cubeEle = scene.createElement(xr.XRNode, {
+        });
+        const cubeTrs = cubeEle.getComponent(xr.Transform);
+        const mat = scene.createMaterial(effectStandard);
+        const color1 = colorPattern1[Math.floor(Math.random() * colorPattern1.length)];
+        mat.setVector('u_baseColorFactor', xr.Vector4.createFromNumber(color1[0], color1[1], color1[2], 1.0));
+        mat.setRenderState('cullFace', xr.ECullMode.BACK);
+        const mesh = cubeEle.addComponent(xr.Mesh, {
+          geometry: geometryPoint,
+          material: mat,
+        });
+        // 加到场上
+        root.addChild(cubeEle);
+
+        // 获取相机 cursor 位置,并设置到新元素
+        cubeTrs.setLocalMatrix(cursorTrs.worldMatrix);
+
+        // 延时,控制点击频率,并保证矩阵信息完备
+        setTimeout(() => {
+          touchFlag = false;
+
+          if (preCubeTrs) {
+            // 存在上一个,进行连线
+            const preWorldPosition = preCubeTrs.worldPosition;
+            const worldPosition = cubeTrs.worldPosition;
+            // console.log(preWorldPosition.x, preWorldPosition.y, preWorldPosition.z, worldPosition.x, worldPosition.y, worldPosition.z)
+            
+            // 算中点
+            const posX = (preWorldPosition.x + worldPosition.x) / 2
+            const posY = (preWorldPosition.y + worldPosition.y) / 2
+            const posZ = (preWorldPosition.z + worldPosition.z) / 2
+
+            // forwad 向量
+            preWorldPosition.sub(worldPosition, forward);
+            console.log(forward.x, forward.y, forward.z);
+
+            // 向量的模
+            const module = preWorldPosition.distanceTo(worldPosition);
+
+            // 方向四元数
+            xr.Quaternion.lookRotation(forward, up, useQuaternion);
+            console.log(useQuaternion.x, useQuaternion.y, useQuaternion.z, useQuaternion.w)
+
+            const lineSize = 0.02;
+            // line
+            const lineEle = scene.createElement(xr.XRNode, {
+              position: `${posX} ${posY} ${posZ}`,
+              scale: `${lineSize} ${lineSize} ${module}`
+            });
+            // 加到场上
+            root.addChild(lineEle);
+            const lineTrs = lineEle.getComponent(xr.Transform);
+            lineTrs.quaternion.x = useQuaternion.x;
+            lineTrs.quaternion.y = useQuaternion.y;
+            lineTrs.quaternion.z = useQuaternion.z;
+            lineTrs.quaternion.w = useQuaternion.w;
+
+            const matLine = scene.createMaterial(effectStandard);
+            const color2 = colorPattern2[Math.floor(Math.random() * colorPattern2.length)];
+
+            matLine.setVector('u_baseColorFactor', xr.Vector4.createFromNumber(color2[0], color2[1], color2[2], 1.0));
+            matLine.setRenderState('cullFace', xr.ECullMode.FRONT);
+            const meshLine = lineEle.addComponent(xr.Mesh, {
+              geometry: geometryLine,
+              material: matLine,
+            });
+            
+            preCubeTrs = cubeTrs
+          }else {
+            preCubeTrs = cubeTrs
+          }
+        }, 100);
+
+
+      });
+
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-arLine/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 28 - 0
miniprogram/components/template/xr-template-arLine/index.wxml

@@ -0,0 +1,28 @@
+<xr-scene ar-system="modes:Plane" bind:ready="handleReady" bind:ar-ready="handleARReady">
+  <xr-assets>
+  </xr-assets>
+  <xr-env env-data="xr-frame-team-workspace-day" />
+
+  <xr-node>
+    <xr-node node-id="center" position="0 0 0"></xr-node>
+    <xr-ar-tracker mode="Plane">
+    </xr-ar-tracker>
+    
+    <!-- root 用于动态放置节点 -->
+    <xr-shadow id="root"></xr-shadow>
+
+    <xr-camera
+      id="camera" node-id="camera" clear-color="0.925 0.925 0.925 1"
+      background="ar" is-ar-camera
+    >
+      <xr-mesh id="cursor" position="0 0 0.3" rotation="0 0 0" scale="0.03 0.03 0.03" geometry="cube"
+        uniforms="u_baseColorFactor:0.298 0.764 0.85 0.8"
+        states="renderQueue: 3000, alphaMode: BLEND, cullFace: 2"
+      ></xr-mesh>
+    </xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="1" />
+    <xr-light type="directional" rotation="0 0 0" color="1 1 1" intensity="0.5" />
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-arLine/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 172 - 0
miniprogram/components/template/xr-template-arPreview/index.js

@@ -0,0 +1,172 @@
+const STATE = {
+  NONE: -1,
+  MOVE: 0,
+  ZOOM_OR_PAN: 1
+}
+
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false,
+    arReady: false,
+  },
+  lifetimes: {
+    async attached() {
+      console.log('data', this.data)
+    }
+  },
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      this.mat = new (wx.getXrFrameSystem().Matrix4)();
+      console.log('xr-scene', xrScene);
+      const { width, height } = this.scene
+      // 旋转缩放相关配置
+      this.radius = (width + height) / 4
+      this.rotateSpeed = 5
+
+      this.handleTouchStart = (event) => {
+        this.mouseInfo = { startX: 0, startY: 0, isDown: false, startPointerDistance: 0, state: STATE.NONE }
+        this.mouseInfo.isDown = true
+
+        const touch0 = event.touches[0]
+        const touch1 = event.touches[1]
+
+        if (event.touches.length === 1) {
+          this.mouseInfo.startX = touch0.pageX
+          this.mouseInfo.startY = touch0.pageY
+          this.mouseInfo.state = STATE.MOVE
+        } else if (event.touches.length === 2) {
+          const dx = (touch0.pageX - touch1.pageX)
+          const dy = (touch0.pageY - touch1.pageY)
+          this.mouseInfo.startPointerDistance = Math.sqrt(dx * dx + dy * dy)
+          this.mouseInfo.startX = (touch0.pageX + touch1.pageX) / 2
+          this.mouseInfo.startY = (touch0.pageY + touch1.pageY) / 2
+          this.mouseInfo.state = STATE.ZOOM_OR_PAN
+        }
+
+        this.scene.event.add('touchmove', this.handleTouchMove.bind(this))
+        this.scene.event.addOnce('touchend', this.handleTouchEnd.bind(this))
+
+      },
+      this.handleTouchMove = (event) => {
+        const mouseInfo = this.mouseInfo
+        if (!mouseInfo.isDown) {
+          return
+        }
+
+        switch (mouseInfo.state) {
+        case STATE.MOVE:
+          if (event.touches.length === 1) {
+            this.handleRotate(event)
+          } else if (event.touches.length === 2) {
+            // 支持单指变双指,兼容双指操作但是两根手指触屏时间不一致的情况
+            this.scene.event.remove('touchmove', this.handleTouchMove)
+            this.scene.event.remove('touchend', this.handleTouchEnd)
+            this.handleTouchStart(event)
+          }
+          break
+        case STATE.ZOOM_OR_PAN:
+          if (event.touches.length === 1) {
+            // 感觉双指松掉一指的行为还是不要自动切换成旋转了,实际操作有点奇怪
+          }
+          else if (event.touches.length === 2) {
+            this.handleZoomOrPan(event)
+          }
+          break
+        default:
+          break
+        }
+      }
+
+      this.handleTouchEnd = (event) => {
+        this.mouseInfo.isDown = false
+        this.mouseInfo.state = STATE.NONE
+
+        this.scene.event.remove('touchmove', this.handleTouchMove)
+        this.scene.event.addOnce('touchstart', this.handleTouchStart)
+      }
+
+      this.handleRotate = (event) => {
+        const x = event.touches[0].pageX
+        const y = event.touches[0].pageY
+
+        const { startX, startY } = this.mouseInfo
+
+        const theta = (x - startX) / this.radius * - this.rotateSpeed
+        const phi = (y - startY) / this.radius * - this.rotateSpeed
+        if (Math.abs(theta) < .01 && Math.abs(phi) < .01) {
+          return
+        }
+        this.gltfItemTRS.rotation.x -= phi
+        this.gltfItemSubTRS.rotation.y -= theta
+        this.mouseInfo.startX = x
+        this.mouseInfo.startY = y
+      }
+
+      this.handleZoomOrPan = (event) => {
+        const touch0 = event.touches[0]
+        const touch1 = event.touches[1]
+
+        const dx = (touch0.pageX - touch1.pageX)
+        const dy = (touch0.pageY - touch1.pageY)
+        const distance = Math.sqrt(dx * dx + dy * dy)
+
+        let deltaScale = distance - this.mouseInfo.startPointerDistance
+        this.mouseInfo.startPointerDistance = distance
+        this.mouseInfo.startX = (touch0.pageX + touch1.pageX) / 2
+        this.mouseInfo.startY = (touch0.pageY + touch1.pageY) / 2
+        if (deltaScale < -2) {
+          deltaScale = -2
+        } else if (deltaScale > 2) {
+          deltaScale = 2
+        }
+
+        const s = deltaScale * 0.02 + 1
+        // 缩小
+        this.gltfItemTRS.scale.x *= s
+        this.gltfItemTRS.scale.y *= s
+        this.gltfItemTRS.scale.z *= s
+      }
+    },
+    handleAssetsProgress: function({detail}) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function({detail}) {
+      console.log('assets loaded', detail.value);
+      // this.setData({loaded: true});
+      this.placedFlag = false;
+      this.scene.event.addOnce('touchstart', this.placeNode.bind(this));
+    },
+    handleARReady: function({detail}) {
+      console.log('arReady', this.scene.ar.arVersion);
+    },
+    placeNode(event) {
+      if (this.placedFlag) {
+        return;
+      }
+      const xrFrameSystem = wx.getXrFrameSystem()
+      this.placedFlag = true;
+      this.scene.ar.placeHere('setitem', true)
+      const anchorTRS = this.scene.getElementById('anchor').getComponent(xrFrameSystem.Transform)
+      anchorTRS.setData({ visible: false })
+      anchorTRS.scale.x = 0
+      anchorTRS.scale.y = 0
+      anchorTRS.scale.z = 0
+      wx.setKeepScreenOn({ keepScreenOn: true })
+
+
+      // 获取改动元素
+      this.gltfItemTRS = this.scene.getElementById('preview-model').getComponent(xrFrameSystem.Transform)
+      this.gltfItemSubTRS = this.scene.getElementById('preview-model-sub').getComponent(xrFrameSystem.Transform)
+
+
+
+      // 开启旋转缩放逻辑
+      this.scene.event.addOnce('touchstart', this.handleTouchStart)
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-arPreview/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 27 - 0
miniprogram/components/template/xr-template-arPreview/index.wxml

@@ -0,0 +1,27 @@
+<xr-scene ar-system="modes:Plane" bind:ready="handleReady" bind:ar-ready="handleARReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+    <xr-asset-load type="gltf" asset-id="gltf-item" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/just_a_girl/index.glb" />
+    <xr-asset-load type="gltf" asset-id="anchor" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/ar-plane-marker.glb" />
+    <xr-asset-material asset-id="standard-mat" effect="standard" />
+  </xr-assets>
+  <xr-node>
+    <xr-ar-tracker mode="Plane">
+      <xr-gltf id="anchor" model="anchor"></xr-gltf>
+    </xr-ar-tracker>
+    <xr-node node-id="setitem" visible="false">
+      <xr-node id="preview-model">
+        <xr-node id="preview-model-sub" scale="0.005 0.005 0.005">
+          <xr-gltf id="setitem-gltf" model="gltf-item" never-cull/>
+        </xr-node>
+      </xr-node>
+    </xr-node>
+    <xr-camera
+      id="camera" node-id="camera" clear-color="0.925 0.925 0.925 1"
+      background="ar" is-ar-camera
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="1" />
+    <xr-light type="directional" rotation="180 0 0" color="1 1 1" intensity="3" />
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-arPreview/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 53 - 0
miniprogram/components/template/xr-template-arui/index.js

@@ -0,0 +1,53 @@
+const STATE = {
+  NONE: -1,
+  MOVE: 0,
+  ZOOM_OR_PAN: 1
+}
+
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false,
+    arReady: false,
+  },
+  lifetimes: {
+    async attached() {
+      console.log('data', this.data)
+    }
+  },
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+    },
+    handleAssetsProgress: function({detail}) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function({detail}) {
+      console.log('assets loaded', detail.value);
+      // this.setData({loaded: true});
+      this.placedFlag = false;
+      this.scene.event.addOnce('touchstart', this.placeNode.bind(this));
+    },
+    handleARReady: function({detail}) {
+      console.log('arReady', this.scene.ar.arVersion);
+    },
+    placeNode(event) {
+      if (this.placedFlag) {
+        return;
+      }
+      const xrFrameSystem = wx.getXrFrameSystem()
+      this.placedFlag = true;
+      this.scene.ar.placeHere('setitem', true)
+      const anchorTRS = this.scene.getElementById('anchor').getComponent(xrFrameSystem.Transform)
+      anchorTRS.setData({ visible: false })
+      anchorTRS.scale.x = 0
+      anchorTRS.scale.y = 0
+      anchorTRS.scale.z = 0
+      wx.setKeepScreenOn({ keepScreenOn: true })
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-arui/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 51 - 0
miniprogram/components/template/xr-template-arui/index.wxml

@@ -0,0 +1,51 @@
+<xr-scene ar-system="modes:Plane" bind:ready="handleReady" bind:ar-ready="handleARReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+    <xr-asset-load type="gltf" asset-id="anchor" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/ar-plane-marker.glb" />
+    <xr-asset-load type="texture" asset-id="bg" src="https://holodata.s3.cn-northwest-1.amazonaws.com.cn/nameCardData/mingpiantu.png" />
+    <xr-asset-material asset-id="simple-mat" effect="simple" />
+    <xr-asset-material asset-id="text-mat" effect="simple" />
+  </xr-assets>
+  <xr-node>
+    <xr-node node-id="center" position="0 0 0"></xr-node>
+    <xr-ar-tracker mode="Plane">
+      <xr-gltf id="anchor" model="anchor"></xr-gltf>
+    </xr-ar-tracker>
+    
+    <xr-node node-id="setitem" visible="false">
+      <xr-node node-id="ui-block" scale="0.1 0.1 0.1">
+        <xr-mesh node-id="mesh-sphere" position="0 0 -2.1" scale="2 2 2" geometry="sphere" uniforms="u_baseColorFactor:0.937 0.176 0.368 1"></xr-mesh>
+        <xr-mesh
+          position="0 0 -0.01" scale="10 1 5" rotation="90 0 0" geometry="plane" material="simple-mat"
+          uniforms="u_baseColorMap: bg" states="cullOn: false, alphaMode: BLEND,renderQueue: 2500"
+        ></xr-mesh>
+        <xr-node node-id="text-wrap" position="-4 1.4 0">
+          <xr-text
+            material="text-mat" value="李逍遥"
+            position="0 0 0" never-cull
+            size="0.6" anchor="0 1" uniforms="u_baseColorFactor:1.0 1.0 1.0 1"
+          ></xr-text>
+          <xr-text
+            material="text-mat" value="原是一乡下客栈店小二,天资聪颖,因一壶酒被酒剑仙传授了蜀山仙剑派剑术,在仙灵岛与赵灵儿相遇,自此经历重重磨难成长为一代旷世奇侠"
+            position="0 -0.8 0" never-cull
+            width="8"
+            size="0.4" anchor="0 1" uniforms="u_baseColorFactor:1.0 1.0 1.0 1"
+          ></xr-text>
+          <xr-text
+            material="text-mat" value="仙剑奇侠传"
+            position="8 -2.7 0" never-cull
+            size="0.4" anchor="1 0" uniforms="u_baseColorFactor:1.0 1.0 1.0 1"
+          ></xr-text>
+        </xr-node>
+      </xr-node>
+    </xr-node>
+    
+    <xr-camera
+      id="camera" node-id="camera" clear-color="0.925 0.925 0.925 1"
+      background="ar" is-ar-camera
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="1" />
+    <xr-light type="directional" rotation="180 0 0" color="1 1 1" intensity="3" />
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-arui/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 55 - 0
miniprogram/components/template/xr-template-blendDouble/index.js

@@ -0,0 +1,55 @@
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false
+  },
+  lifetimes: {},
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+
+    },
+    handleAssetsProgress: function({detail}) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function({detail}) {
+      console.log('assets loaded', detail.value);
+      this.setBlend();
+    },
+    setBlend() {
+      const scene = this.scene;
+      const xrSystem = wx.getXrFrameSystem();
+
+      // 替换状态
+      const blendElm = this.scene.getElementById('blend');
+      const blendGLTF = blendElm.getComponent(xrSystem.GLTF);
+      // 延时保证glTF解析完毕
+      setTimeout(()=>{
+        const frontMesh = blendGLTF.getPrimitivesByMeshName('柱体')[0].primitives[0];
+        const frontMat = frontMesh.material;
+        // 正面
+        // 改变 RenderQueue 先绘制
+        frontMat.setRenderState('renderQueue', 2500);
+        // 开启剔除,去掉背面
+        frontMat.setRenderState('cullOn', true);
+        frontMat.setRenderState('cullFace', xrSystem.ECullMode.BACK);
+
+        const backMesh = blendGLTF.getPrimitivesByMeshName('柱体.001')[0].primitives[0];
+        const backMat = backMesh.material;
+        // 背面
+        // 改变 RenderQueue 后绘制
+        backMat.setRenderState('renderQueue', 2501);
+        // 开启剔除,去掉正面
+        backMat.setRenderState('cullOn', true);
+        backMat.setRenderState('cullFace', xrSystem.ECullMode.FRONT);
+
+
+      }, 200);
+
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-blendDouble/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 19 - 0
miniprogram/components/template/xr-template-blendDouble/index.wxml

@@ -0,0 +1,19 @@
+<xr-scene id="xr-scene" bind:ready="handleReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+    <xr-asset-load type="gltf" asset-id="gltf-blend" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/blend.glb" /> 
+  </xr-assets>
+  <xr-env env-data="xr-frame-team-workspace-day2" />
+  <xr-node>
+    <xr-node node-id="camera-target" position="0 0 0"></xr-node>
+    <xr-gltf id="blend" position="0 -0.6 0" rotation="0 0 0" scale="1.2 1.2 1.2" model="gltf-blend"></xr-gltf>
+    <xr-camera
+      id="camera" node-id="camera" position="2 2 4" clear-color="0.925 0.925 0.925 1"
+      target="camera-target" background="skybox"
+      camera-orbit-control=""
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="0.6" />
+    <xr-light type="directional" rotation="20 120 0" color="1 1 1" intensity="2"/>
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-blendDouble/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 166 - 0
miniprogram/components/template/xr-template-control/index.js

@@ -0,0 +1,166 @@
+let camera;
+let player;
+let xrFrameSystem;
+// 位移速度
+let speed = 5;
+// 视角旋转的速度
+let smoothSpeed = 8;
+
+// 世界坐标系下的标准方位
+let up;
+let left;
+
+// player相关
+let position;
+let quaternionP; //player的四元数
+let quaternionPIni; //player每次转动开始时的角度
+let quaternionPRes; //player每次需要转动到的角度
+let quaternionPTemp; //旋转四元数的临时变量
+
+// camera相关
+let quaternionC; //camera的四元数
+let quaternionCIni;  //camera每次转动开始时的角度
+let quaternionCRes;  //camera每次需要转动到的角度
+
+// 初始化是否完成的标记
+let initFinish = false;
+
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    width:Number,
+    height:Number,
+    transferData: {
+      type:Object,
+      observer(newVal, oldVal){
+        if(newVal.biasRotX != undefined){
+          this.biasRotX = newVal.biasRotX;
+          this.biasRotY = newVal.biasRotY;
+        }
+
+        if(newVal.initRotX != undefined){
+          this.initRotX = newVal.initRotX;
+          this.initRotY = newVal.initRotY;
+        }
+
+        if(newVal.biasX != undefined){
+          this.biasX = newVal.biasX;
+          this.biasY = newVal.biasY;
+        }
+      },
+    },
+    reset: {
+      type: Number,
+      observer(newVal, oldVal) {
+        //监听发生变化的reset后,执行重置逻辑
+        position.set(xrFrameSystem.Vector3.createFromNumber(0, 1.6, 1));
+        quaternionC.setFromYawRollPitch(0, 0, 0);
+        quaternionP.setFromYawRollPitch(Math.PI, 0, 0);
+      }
+    }
+  },
+  data: {
+    loaded: false
+  },
+  lifetimes: {},
+  methods: {
+    handleReady({
+      detail
+    }) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+
+      xrFrameSystem = wx.getXrFrameSystem();
+      camera = xrScene.getElementById("camera");
+      player = xrScene.getElementById("player");
+
+      up = xrFrameSystem.Vector3.createFromNumber(0, 1, 0);
+      left = xrFrameSystem.Vector3.createFromNumber(1, 0, 0);
+
+      quaternionC = camera.getComponent(xrFrameSystem.Transform).quaternion;
+      quaternionP = player.getComponent(xrFrameSystem.Transform).quaternion;
+      position = player.getComponent(xrFrameSystem.Transform).position;
+
+      quaternionPIni = new xrFrameSystem.Quaternion();
+      quaternionPIni.set(quaternionP);
+      quaternionPRes = new xrFrameSystem.Quaternion();
+      quaternionPRes.set(quaternionP);
+      quaternionPTemp = new xrFrameSystem.Quaternion();
+      quaternionPTemp.setFromYawRollPitch(0, 0, 0);
+
+      quaternionCIni = new xrFrameSystem.Quaternion();
+      quaternionCIni.set(quaternionC);
+      quaternionCRes = new xrFrameSystem.Quaternion();
+      quaternionCRes.set(quaternionC);
+
+      this.biasRotX = 0;
+      this.biasRotY = 0;
+      this.initRotX = 0;
+      this.initRotY = 0;
+      this.biasX = 0;
+      this.biasY = 0;
+
+      initFinish = true;
+    },
+    handleAssetsProgress: function ({
+      detail
+    }) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function ({
+      detail
+    }) {
+      console.log('assets loaded', detail.value);
+
+      this.setData({
+        loaded: true
+      });
+    },
+    handleTick: function (dt) {
+
+      //确保handleReady时期的初始化完成
+      if (!initFinish)
+        return;
+
+      var deltaTime = dt.detail.value / 1000;
+
+      //------摄像头旋转逻辑------//
+      let rotX = (this.biasRotX - this.initRotX) / this.data.width * Math.PI;
+      let rotY = (this.biasRotY - this.initRotY) / this.data.height * Math.PI;
+
+      //水平方向旋转player node
+      if (this.biasRotX == 0) {
+       quaternionPIni.set(quaternionPTemp);
+       quaternionPRes.set(quaternionPTemp);
+      } else {
+        quaternionPIni.multiply(xrFrameSystem.Quaternion.createFromAxisAngle(up, -rotX), quaternionPRes);
+      }
+
+      //垂直方向旋转camera node
+      if (this.biasRotY == 0) {
+        quaternionCIni.set(quaternionCRes);
+        quaternionCRes.set(quaternionCRes);
+      } else {
+        quaternionCIni.multiply(xrFrameSystem.Quaternion.createFromAxisAngle(left, rotY), quaternionCRes);   
+      }
+
+      quaternionPTemp.slerp(quaternionPRes, smoothSpeed * deltaTime, quaternionPTemp);
+      quaternionC.slerp(quaternionPTemp.multiply(quaternionCRes), smoothSpeed * deltaTime, quaternionC);
+
+       //------摄像头位移逻辑------//
+      var x = this.biasX;
+      var y = this.biasY;
+
+      if (x || y) {
+        var z = Math.sqrt(x * x + y * y);
+        var ratio = z / 50; //此处除以50,因为摇杆盘半径为50
+        ratio = ratio > 1 ? 1 : ratio < 0 ? 0 : ratio;
+        var temp = xrFrameSystem.Vector3.createFromNumber(-x / z, 0, -y / z);
+        temp = temp.scale(ratio * speed * deltaTime);
+        //位移需要根据旋转角度做转化, 这里需要取得camera的世界旋转矩阵
+        temp.applyQuaternion(camera.getComponent(xrFrameSystem.Transform).worldQuaternion);
+        position.set(position.add(temp));
+      }
+    },
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-control/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 26 - 0
miniprogram/components/template/xr-template-control/index.wxml

@@ -0,0 +1,26 @@
+<xr-scene id="xr-scene" bind:ready="handleReady" bind:tick="handleTick">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+    <xr-asset-material asset-id="standard-mat" effect="standard" />
+  </xr-assets>
+  <xr-env env-data="xr-frame-team-workspace-day"/>
+  
+  <xr-node>
+    <xr-mesh node-id="mesh-plane" position="0 -0.02 -4" rotation="0 0 0" scale="5 1 5" geometry="plane" material="standard-mat" uniforms="u_baseColorFactor:0.48 0.78 0.64 1" receive-shadow></xr-mesh>
+    <xr-mesh id="cube" node-id="mesh-cube" position="-1 0.5 -3.5" scale="1 1 1" rotation="0 45 0" geometry="cube" material="standard-mat" uniforms="u_baseColorFactor:0.298 0.764 0.85 1" cast-shadow></xr-mesh>
+    <xr-mesh node-id="mesh-cylinder" position="1 0.7 -3.5" scale="1 0.7 1" geometry="cylinder" material="standard-mat" uniforms="u_baseColorFactor:1 0.776 0.364 1" cast-shadow></xr-mesh>
+    <xr-mesh node-id="mesh-sphere" position="0 1.25 -5" scale="1.25 1.25 1.25" geometry="sphere" material="standard-mat" uniforms="u_baseColorFactor:0.937 0.176 0.368 1" cast-shadow></xr-mesh>
+
+    <xr-node id="player" node-id="player" position="0 1.6 1" rotation="0 180 0">
+      <xr-camera
+        id="camera" node-id="camera"
+        position="0 0 0" rotation="0 0 0"
+        clear-color="0.925 0.925 0.925 1"
+        background="skybox"
+      ></xr-camera>
+    </xr-node>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="1" />
+    <xr-light type="directional" rotation="40 170 0" color="1 1 1" intensity="3" cast-shadow />
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-control/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 133 - 0
miniprogram/components/template/xr-template-featherVideo/index.js

@@ -0,0 +1,133 @@
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false,
+    loading: false,
+    gltfLoaded: false,
+    videoLoaded: false,
+    gltfIdList: [],
+    videoIdList: [],
+  },
+  properties: {
+    gltfListRaw: {
+      type: Array,
+      value: [],
+    },
+    videoListRaw: {
+      type: Array,
+      value: [],
+    },
+  },
+  observers: {
+    gltfListRaw(newVal) {
+      this.releaseGLTF();
+      this.loadGLTF(newVal);
+    },
+    videoListRaw(newVal) {
+      this.releaseVideo();
+      this.loadVideo(newVal);
+    },
+  },
+  lifetimes: {},
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+      // 绑定tick事件
+      xrScene.event.add('tick', this.handleTick.bind(this));
+    },
+    handleAssetsProgress: function({detail}) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function({detail}) {
+      console.log('assets loaded', detail.value);
+      this.setData({loaded: true});
+    },
+    handleTick: function () {
+    },
+    releaseGLTF() {
+      if (this.data.gltfIdList && this.data.gltfIdList.length > 0) {
+        const scene = this.scene
+
+        this.data.gltfIdList.map((id) => {
+          // 释放加载过的资源
+          scene.assets.releaseAsset('gltf',`gltf-${id}`);
+        })
+      }
+    },
+    async loadGLTF(gltfList) {
+      const scene = this.scene
+
+      if (gltfList.length > 0) {
+        const gltfIdList = [];
+        const gltfModel = await Promise.all(gltfList.map( (gltfItem) => {
+          gltfIdList.push(gltfItem.id)
+          const gtltfPromise = scene.assets.loadAsset({
+            type: 'gltf',
+            assetId: `gltf-${gltfItem.id}`,
+            src: gltfItem.src,
+          })
+          return gtltfPromise;
+        }));
+        
+        console.log('glTF asset loaded')
+        this.setData({ 
+          gltfIdList: gltfIdList,
+          gltfLoaded: true
+        })
+      } else {
+        this.setData({ 
+          gltfIdList: [],
+          gltfLoaded: false,
+        });
+      }
+    },
+    releaseVideo() {
+      if (this.data.videoIdList && this.data.videoIdList.length > 0) {
+        const scene = this.scene
+
+        this.data.videoIdList.map((id) => {
+          // 释放加载过的资源
+          scene.assets.releaseAsset('video-texture', `video-${id}`);
+          scene.assets.releaseAsset('material', `video-mat-${id}`);
+        })
+      }
+    },
+    async loadVideo(videoList) {
+      const scene = this.scene
+      if (videoList.length > 0) {
+        const videoIdList = [];
+        const videos = await Promise.all(videoList.map((videoItem) =>{
+          videoIdList.push(videoItem.id);
+          return scene.assets.loadAsset({
+            type: 'video-texture',
+            assetId: `video-${videoItem.id}`,
+            src: videoItem.src,
+            options: { autoPlay: true, loop: true },
+          })
+        }))
+
+        videos.map((videoTexture, index) => {
+          const videoMat = scene.createMaterial(
+            scene.assets.getAsset('effect', 'standard'),
+            { u_baseColorMap: videoTexture.value.texture }
+          )
+          scene.assets.addAsset('material', `video-mat-${videoList[index].id}`, videoMat)
+        })
+        console.log('video asset loaded')
+        this.setData({
+          videoIdList: videoIdList,
+          videoLoaded: true
+        })
+      } else {
+        this.setData({
+          videoIdList: [],
+          videoLoaded: false
+        })
+      }
+    },
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-featherVideo/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 56 - 0
miniprogram/components/template/xr-template-featherVideo/index.wxml

@@ -0,0 +1,56 @@
+<xr-scene id="xr-scene" bind:ready="handleReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+    <xr-asset-material asset-id="standard-mat" effect="standard" />
+  </xr-assets>
+  <xr-node>
+    <xr-node node-id="camera-target" position="0 0 0"></xr-node>
+    <xr-mesh node-id="floor-plane" position="0 -1 0" rotation="0 0 0" scale="10 1 10" geometry="plane"
+      uniforms="u_baseColorFactor:1 1 1 1" receive-shadow
+    ></xr-mesh>
+    <!-- glTF -->
+    <xr-node wx:if="{{gltfLoaded}}">
+      <xr-node
+        wx:for="{{gltfIdList}}" wx:for-item="gltfId"
+        wx:key="gltfId"
+      >
+        <xr-gltf
+          wx:if="{{gltfId == 0}}"
+          position="-1 -0.46 -1" rotation="0 0 0"
+          scale="0.6 0.6 0.6"
+          model="gltf-{{gltfId}}"
+          cast-shadow
+        ></xr-gltf>
+        <xr-gltf
+          wx:if="{{gltfId == 1}}"
+          position="1 -0.98 -1" rotation="0 0 0"
+          scale="0.015 0.015 0.015"
+          model="gltf-{{gltfId}}"
+          cast-shadow
+        ></xr-gltf>
+      </xr-node>
+    </xr-node>
+    <!-- Video -->
+    <xr-node wx:if="{{videoLoaded}}">
+      <xr-node
+        wx:for="{{videoIdList}}" wx:for-item="videoId"
+        wx:key="videoId"
+      >
+      <xr-mesh
+        wx:if="{{videoId == 0}}"
+        node-id="mesh-cube" position="-1 -0.5 1" scale="0.8 1.4 0.8"
+        geometry="cube" material="video-mat-{{videoId}}"
+        cast-shadow
+      />
+      </xr-node>
+    </xr-node>
+    <xr-camera
+      id="camera" node-id="camera" position="0 2 4" clear-color="0.8 0.8 0.8 1"
+      target="camera-target"
+      camera-orbit-control=""
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="1" />
+    <xr-light type="directional" rotation="40 170 0" color="1 1 1" intensity="3" cast-shadow/>
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-featherVideo/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 126 - 0
miniprogram/components/template/xr-template-frameEffect/index.js

@@ -0,0 +1,126 @@
+Component({
+  properties: {
+  },
+  data: {
+  },
+  methods: {
+    handleReady({detail}) {
+      const xrFrameSystem  = wx.getXrFrameSystem()
+      const createFrameEffect = (scene) => {
+        const xrFrameSystem  = wx.getXrFrameSystem()
+        return scene.createEffect({
+          name: 'frame-effect',
+          properties: [
+            {
+              key: 'columCount',
+              type: xrFrameSystem.EUniformType.FLOAT,
+              default: 1
+            },
+            {
+                key: 'rowCount',
+                type: xrFrameSystem.EUniformType.FLOAT,
+                default: 1
+            },
+            {
+                key: 'during',
+                type: xrFrameSystem.EUniformType.FLOAT,
+                default: 1
+            }
+          ],
+          images: [
+            {
+              key: 'u_baseColorMap',
+              default: 'white',
+              macro: 'WX_USE_BASECOLORMAP'
+            }
+          ],
+          // 透明物体需要大于`2500`!
+          defaultRenderQueue: 2501,
+          passes: [
+            {
+              renderStates: {
+                blendOn: false,
+                depthWrite: true,
+                cullOn: false,
+                // 基础库 v3.0.1 开始 默认的 plane 切为适配 cw 的顶点绕序
+              },
+              lightMode: 'ForwardBase',
+              useMaterialRenderStates: true,
+              shaders: [0, 1]
+            }
+          ],
+          shaders: [`#version 100
+
+          precision highp float;
+          precision highp int;
+    
+          attribute vec3 a_position;
+          attribute highp vec2 a_texCoord;
+      
+          uniform mat4 u_view;
+          uniform mat4 u_projection;
+          uniform mat4 u_world;
+          varying highp vec2 v_uv;
+          void main()
+          {
+            v_uv = a_texCoord;
+            gl_Position = u_projection * u_view * u_world * vec4(a_position, 1.0);
+          }`,
+          // float 使用 highp 保证精度
+          `#version 100
+            precision highp float;
+            precision highp int;
+
+            uniform sampler2D u_baseColorMap;
+            uniform highp float u_gameTime;
+            uniform highp float rowCount;
+            uniform highp float columCount;
+            uniform highp float during;
+            varying highp vec2 v_uv;
+            void main()
+            {
+              float loopTime = mod(u_gameTime, during);
+
+              float tickPerFrame = during / (columCount * rowCount);
+              
+              float columTick = mod(floor(loopTime / tickPerFrame), columCount);
+              float rowTick = floor(loopTime / tickPerFrame / columCount);
+
+              vec2 texCoord = vec2(v_uv.x / columCount + (1.0 / columCount) * columTick , v_uv.y / rowCount + (1.0 / rowCount) * rowTick);
+              vec4 color = texture2D(u_baseColorMap, texCoord);
+              gl_FragColor = color;
+            }`
+            ],
+        });
+      }
+      console.log('序列帧特效加载')
+      xrFrameSystem.registerEffect('frame-effect', createFrameEffect)
+      const xrScene = this.scene = detail.value;
+      this.loadAsset()
+    },
+    async loadAsset(){
+        const xrFrameSystem = wx.getXrFrameSystem();
+        const xrScene = this.scene;
+        const shadowRoot = xrScene.getElementById("shadow-root");
+
+        await xrScene.assets.loadAsset({type: 'texture', assetId: 'frame', src: 'https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/sprite-frames.png'})
+
+        // 第一个参数是效果实例的引用,第二个参数是默认`uniforms`
+        const frameMaterial = xrScene.createMaterial(
+            // 使用定制的效果
+            xrScene.assets.getAsset('effect', 'frame-effect'),
+            {u_baseColorMap: xrScene.assets.getAsset('texture', 'frame')}
+        );
+        
+        // 可以将其添加到资源系统中备用
+        xrScene.assets.addAsset('material', 'frame-effect', frameMaterial);
+
+        const meshElement = xrScene.getElementById("animation-mesh").getComponent(xrFrameSystem.Mesh);
+        frameMaterial.setFloat('columCount', 4);
+        frameMaterial.setFloat('rowCount', 32);
+        frameMaterial.setFloat('during', 2);
+        frameMaterial.alphaMode = "BLEND";
+        meshElement.material = frameMaterial
+    },
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-frameEffect/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 18 - 0
miniprogram/components/template/xr-template-frameEffect/index.wxml

@@ -0,0 +1,18 @@
+<xr-scene id="xr-scene" bind:ready="handleReady">
+  <xr-assets>
+  </xr-assets>
+  <xr-node>
+    <xr-shadow id="shadow-root"></xr-shadow>
+    <!-- <xr-mesh position="0 -0.06 0" scale="1.4 0.1 1.4" uniforms="u_baseColorFactor:0.3 0.4 0.6 1" geometry="cube"></xr-mesh> -->
+    <xr-mesh id="animation-mesh" node-id="animation-mesh" position="0 0 0" scale="1 1 1" geometry="plane"></xr-mesh>
+    <xr-camera
+      id="camera" node-id="camera" position="0 3 0" clear-color="0.925 0.925 0.925 1"
+      target="animation-mesh"
+      camera-orbit-control="true"
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="1" />
+    <xr-light type="directional" rotation="40 170 0" color="1 1 1" intensity="3"/>
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-frameEffect/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 213 - 0
miniprogram/components/template/xr-template-geometry/index.js

@@ -0,0 +1,213 @@
+
+
+function getVertexBuffer(vertexData) {
+  const vertexCount = vertexData.length / 12;
+  const noise = 0.03;
+  for (let i = 0; i < vertexCount; i++) {
+    const vertexIndex = i * 12;
+    // x
+    vertexData[vertexIndex] = vertexData[vertexIndex] + Math.random() * noise - noise / 2;
+    // y
+    vertexData[vertexIndex + 1] = vertexData[vertexIndex + 1]+ Math.random() * noise - noise / 2;
+    // z
+    vertexData[vertexIndex + 2] = vertexData[vertexIndex + 2] + Math.random() * noise - noise / 2;
+    // normal x
+    // vertexData[vertexIndex + 3]
+    // normal y
+    // vertexData[vertexIndex + 4]
+    // normal z
+    // vertexData[vertexIndex + 5]
+    // u
+    // vertexData[vertexIndex + 6]
+    // v
+    // vertexData[vertexIndex + 7]
+    // r
+    vertexData[vertexIndex + 8] = i / vertexCount;
+    // g
+    vertexData[vertexIndex + 9] = i / vertexCount;
+    // b
+    vertexData[vertexIndex + 10] = i / vertexCount;
+    // a
+    // vertexData[vertexIndex + 11]
+  }
+  return new Float32Array(vertexData);
+}
+
+
+function buildSphere(
+  vertexs,
+  indices,
+  radius = 1,
+  widthSegments = 32,
+  heightSegments = 16,
+  phiStart = Math.PI /2,
+  phiLength = Math.PI * 2,
+  thetaStart = Math.PI,
+  thetaLength = Math.PI
+) {
+  
+  widthSegments = Math.max( 3, Math.floor( widthSegments ) );
+  heightSegments = Math.max( 2, Math.floor( heightSegments ) );
+
+  const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );
+
+  let index = 0;
+  const grid = [];
+
+  // generate vertices, normals and uvs
+  for ( let iy = 0; iy <= heightSegments; iy ++ ) {
+    const verticesRow = [];
+    const v = iy / heightSegments;
+    // special case for the poles
+    let uOffset = 0;
+    if ( iy == 0 && thetaStart == 0 ) {
+      uOffset = 0.5 / widthSegments;
+    } else if ( iy == heightSegments && thetaEnd == Math.PI ) {
+      uOffset = - 0.5 / widthSegments;
+    }
+    for ( let ix = 0; ix <= widthSegments; ix ++ ) {
+      const u = ix / widthSegments;
+      // vertex
+      const vertexX = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
+      const vertexY = radius * Math.cos( thetaStart + v * thetaLength );
+      const vertexZ = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
+      vertexs.push(vertexX, vertexY, vertexZ);
+      // normal
+      vertexs.push(vertexX / 3, vertexY / 3, vertexZ / 3);
+      // uv
+      vertexs.push(u + uOffset, 1 - v );
+      // color
+      vertexs.push(0, 0, 0, 1);
+
+
+      verticesRow.push( index ++ );
+    }
+    grid.push( verticesRow );
+  }
+  // indices
+  for ( let iy = 0; iy < heightSegments; iy ++ ) {
+    for ( let ix = 0; ix < widthSegments; ix ++ ) {
+      const a = grid[ iy ][ ix + 1 ];
+      const b = grid[ iy ][ ix ];
+      const c = grid[ iy + 1 ][ ix ];
+      const d = grid[ iy + 1 ][ ix + 1 ];
+
+      if ( iy !== 0 || thetaStart > 0 ) indices.push( a, d, b );
+      if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, d, c );
+    }
+  }
+}
+
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false
+  },
+  lifetimes: {},
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+      const xrFrameSystem  = wx.getXrFrameSystem()
+
+      this.geometryRoot = this.scene.getElementById('geometryRoot');
+
+      const geoRadius = 1;
+
+      this.vertexData = [];
+      this.indexData = [];
+      // 构造圆形的 顶点信息,可以通过增加切分区域增加顶点数量
+      // 一般复杂人物 vertex 长度 77030 index 88266
+      buildSphere(this.vertexData, this.indexData, geoRadius, 64, 64);
+      
+      console.log('vertexDataCount', this.vertexData.length);
+      console.log('indexDataCount', this.indexData.length);
+
+
+      // 注册 Geometry 信息
+      xrFrameSystem.registerGeometry('man', scene => {
+        const vl = scene.createVertexLayout({
+          attributes: [
+            {
+              name: "a_position",
+              format: xrFrameSystem.EVertexFormat.FLOAT3,
+              offset: 0,
+              usage: xrFrameSystem.EVertexLayoutUsage.POSITION
+            },
+            {
+              name: "a_normal",
+              format: xrFrameSystem.EVertexFormat.FLOAT3,
+              offset: 12,
+              usage: xrFrameSystem.EVertexLayoutUsage.NORMAL,
+            },
+            {
+              name: "a_texCoord",
+              format: xrFrameSystem.EVertexFormat.FLOAT2,
+              offset: 24,
+              usage: xrFrameSystem.EVertexLayoutUsage.UV0
+            },
+            {
+              name: "a_color",
+              format: xrFrameSystem.EVertexFormat.FLOAT4,
+              offset: 32,
+              usage: xrFrameSystem.EVertexLayoutUsage.COLOR
+            }
+          ],
+          stride: 48
+        });
+      
+        // VertexBuffer IndexBuffer 不能动态更改长度,需要一开始设定较大的长度。
+        const vb = new Float32Array(this.vertexData.length);
+        const ib = new Uint16Array(this.indexData);
+      
+        const geo = scene.createGeometry(vl, vb, ib);
+      
+        geo.setBoundBall(new xrFrameSystem.Vector3(), 1);
+        geo.addSubMesh(ib.length, 0, 0);
+      
+        return geo;
+      });
+
+      this.geoElem = xrScene.createElement(xrFrameSystem.XRMesh, {
+        geometry: "man",
+        material: 'simple-mat',
+        position: "0 0 0"
+      });
+      this.geometryRoot.addChild(this.geoElem);
+
+      // 延时保证挂载与初始化完毕
+      setTimeout(()=>{
+        this.meshGeo = this.geoElem.getComponent(xrFrameSystem.Mesh);
+        this.geometryGeo = this.meshGeo.geometry;
+
+        this.matGeo = this.meshGeo.material;
+        // 使用顶点色
+        this.matGeo.setMacro("WX_USE_COLOR_0", true);
+        // 设定 绘制双面
+        this.matGeo.setRenderState("cullOn", false);
+
+        xrScene.event.add('tick', this.handleTick.bind(this));
+      },100);
+
+    },
+    
+    handleAssetsProgress: function({detail}) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function({detail}) {
+      console.log('assets loaded', detail.value);
+    },
+    handleTick(delta) {
+
+      const vb = getVertexBuffer(this.vertexData);
+      const ib = new Uint16Array(this.indexData);
+    
+      this.geometryGeo.uploadVertexBuffer(0, vb);
+      this.geometryGeo.uploadIndexBuffer(0, ib);
+    },
+
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-geometry/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 21 - 0
miniprogram/components/template/xr-template-geometry/index.wxml

@@ -0,0 +1,21 @@
+<xr-scene id="xr-scene" bind:ready="handleReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+      <xr-asset-material asset-id="simple-mat" effect="simple" />
+  </xr-assets>
+  <xr-node>
+    <xr-node node-id="camera-target" position="0 0 0"></xr-node>
+
+    <xr-shadow id="geometryRoot" node-id="geometryRoot"></xr-shadow>
+
+
+    <xr-camera
+      id="camera" node-id="camera" position="2 2 4" clear-color="0.4 0.4 0.4 1"
+      target="camera-target" near="0.1" far="2000"
+      camera-orbit-control=""
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="1.2" />
+    <xr-light type="directional" rotation="120 20 0" color="1 1 1" intensity="2" />
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-geometry/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 68 - 0
miniprogram/components/template/xr-template-gltfAnimation/index.js

@@ -0,0 +1,68 @@
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false
+  },
+  lifetimes: {},
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+
+    },
+    handleAssetsProgress: function({detail}) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function({detail}) {
+      console.log('assets loaded', detail.value);
+      this.setData({loaded: true});
+    },
+
+    handleGLTFLoaded({ detail }) {
+      const xrFrameSystem = wx.getXrFrameSystem();
+
+      const wrapElement = this.scene.getElementById("wrap");
+      this.wrapTRS = wrapElement.getComponent(xrFrameSystem.Transform);
+      const gltfElement = this.scene.getElementById("gltf");
+      this.gltfTRS = gltfElement.getComponent(xrFrameSystem.Transform);
+      this.editGLTF = gltfElement.getComponent(xrFrameSystem.GLTF);
+
+      console.log(this.wrapTRS, this.gltfTRS)
+
+      // Birds
+      const brid = this.editGLTF.getInternalNodeByName("Birds");
+      this.bridTRS = brid.getComponent(xrFrameSystem.Transform);
+
+      // TurtleAndCastle
+      const turtle = this.editGLTF.getInternalNodeByName("TurtleAndCastle");
+      this.turtleTRS = turtle.getComponent(xrFrameSystem.Transform);
+
+      // 都用四元数
+      this.rotation = this.turtleTRS.quaternion.toEulerAngles();
+
+      this.scene.event.add('tick', this.handleTick.bind(this));
+    },
+
+    handleTick: function (time) {
+      const xrSystem = wx.getXrFrameSystem();
+
+      this.wrapTRS.position.x -= 0.002;
+      // this.wrapTRS.rotation.y += Math.PI * 0.0001;
+
+      // 比例尺不一样,需要放大改变数值
+      this.bridTRS.position.x += 1;
+      this.bridTRS.position.y += Math.random() * 4 - 2;
+
+      // 欧拉角直接设置有误 v2.31.0
+      // this.turtleTRS.rotation.y += Math.PI * 0.0004;
+
+      // 目前使用四元数兼容
+      this.rotation.y += Math.PI * 0.0004;
+      xrSystem.Quaternion.fromEulerAngles(this.rotation, this.turtleTRS.quaternion);
+
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-gltfAnimation/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 22 - 0
miniprogram/components/template/xr-template-gltfAnimation/index.wxml

@@ -0,0 +1,22 @@
+<xr-scene id="xr-scene" bind:ready="handleReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+    <xr-asset-load type="gltf" asset-id="gltf-floating_castle" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/floating_castle.glb" /> 
+  </xr-assets>
+  <xr-env env-data="xr-frame-team-workspace-day2" />
+  <xr-node>
+    <xr-node node-id="camera-target" position="0 0 0"></xr-node>
+
+    <xr-node id="wrap">
+      <xr-gltf id="gltf" position="0 0 0" rotation="0 0 0" scale="6 6 6" model="gltf-floating_castle" bind:gltf-loaded="handleGLTFLoaded"></xr-gltf>
+    </xr-node>
+    <xr-camera
+      id="camera" node-id="camera" position="2 3 -5" clear-color="0.2 0.2 0.2 1"
+      target="camera-target"
+      camera-orbit-control=""
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="0.6" />
+    <xr-light type="directional" rotation="20 120 0" color="1 1 1" intensity="2"/>
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-gltfAnimation/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 56 - 0
miniprogram/components/template/xr-template-gltfEdit/index.js

@@ -0,0 +1,56 @@
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false
+  },
+  lifetimes: {},
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+
+    },
+    handleAssetsProgress: function({detail}) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function({detail}) {
+      console.log('assets loaded', detail.value);
+      this.setData({loaded: true});
+      this.setBallon();
+    },
+    async setBallon() {
+      const scene = this.scene;
+      const xrSystem = wx.getXrFrameSystem();
+
+      // 替换贴图
+      const ballonElm = this.scene.getElementById('ballon');
+      const ballonGLTF = ballonElm.getComponent(xrSystem.GLTF);
+      const textureAsset = await scene.assets.loadAsset({
+        type: 'texture',
+        assetId: `texture-1`,
+        src: 'https://webar.hereto.cn/asset/fe/ast-show/BalloonTEXc1.png',
+      });
+      for(const mesh of ballonGLTF.meshes) {
+        console.log('textureAsset', textureAsset.value);
+        mesh.material.setVector('u_specularFactor', xrSystem.Vector3.createFromNumber(0, 0, 0));
+        mesh.material.setTexture('u_baseColorMap', textureAsset.value);
+      }
+
+      // 替换状态
+      const ballonBlendElm = this.scene.getElementById('ballonBlend');
+      const ballonBlendGLTF = ballonBlendElm.getComponent(xrSystem.GLTF);
+      for(const mesh of ballonBlendGLTF.meshes) {
+        // 清理模型金属度
+        mesh.material.setVector('u_specularFactor', xrSystem.Vector3.createFromNumber(0, 0, 0));
+
+        // 通过alphaMode 的 Setter 设置,或者写入renderState,但需要手动控制宏
+        mesh.material.alphaMode = "BLEND";
+        mesh.material.setVector('u_baseColorFactor', xrSystem.Vector4.createFromNumber(0, 0.5, 0, 0.5));
+      }
+
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-gltfEdit/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 25 - 0
miniprogram/components/template/xr-template-gltfEdit/index.wxml

@@ -0,0 +1,25 @@
+<xr-scene id="xr-scene" bind:ready="handleReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+    <xr-asset-load type="gltf" asset-id="gltf-ballon-origin" src="https://webar.hereto.cn/asset/fe/ast-show/ballon-anim.glb" />
+    <xr-asset-load type="gltf" asset-id="gltf-ballon" src="https://webar.hereto.cn/asset/fe/ast-show/ballon-anim.glb" /> 
+    <xr-asset-load type="gltf" asset-id="gltf-ballon-blend" src="https://webar.hereto.cn/asset/fe/ast-show/ballon-anim.glb" /> 
+  </xr-assets>
+  <xr-env env-data="xr-frame-team-workspace-day2" />
+  <xr-node>
+    <xr-node node-id="camera-target" position="0 0 0"></xr-node>
+
+    <xr-gltf position="-0.8 0 0" rotation="0 0 0" scale="1.2 1.2 1.2" model="gltf-ballon-origin"></xr-gltf>
+    <xr-gltf id="ballon" node-id="gltf-ballon" position="0.8 0 0" rotation="0 0 0" scale="1.2 1.2 1.2" model="gltf-ballon"></xr-gltf>
+    <xr-gltf id="ballonBlend" node-id="gltf-ballon-blend" position="0 0 -0.8" rotation="0 0 0" scale="1.2 1.2 1.2" model="gltf-ballon-blend"></xr-gltf>
+
+    <xr-camera
+      id="camera" node-id="camera" position="2 2 4" clear-color="0.925 0.925 0.925 1"
+      target="camera-target" background="skybox"
+      camera-orbit-control=""
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="0.6" />
+    <xr-light type="directional" rotation="20 120 0" color="1 1 1" intensity="2"/>
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-gltfEdit/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 24 - 0
miniprogram/components/template/xr-template-gltfOcclusion/index.js

@@ -0,0 +1,24 @@
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false
+  },
+  lifetimes: {},
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+    },
+    handleAssetsProgress: function({detail}) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function({detail}) {
+      console.log('assets loaded', detail.value);
+      this.setData({loaded: true});
+    },
+
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-gltfOcclusion/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 43 - 0
miniprogram/components/template/xr-template-gltfOcclusion/index.wxml

@@ -0,0 +1,43 @@
+<xr-scene id="xr-scene" bind:ready="handleReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+    <xr-asset-load type="gltf" asset-id="gltf-door" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/door.glb" /> 
+    <xr-asset-load type="gltf" asset-id="gltf-twa" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/twa.glb" /> 
+
+  </xr-assets>
+  <xr-env env-data="xr-frame-team-workspace-day2" />
+  <xr-node>
+    <xr-node node-id="camera-target" position="0 0 0"></xr-node>
+
+    <!-- 设置为遮挡的模型,需设置模版剔除状态 -->
+    <!-- 参数逻辑:
+      1. 该实现流程核心为 模版测试,首先 stencilTestOn 开启模版测试
+      2. stencilComp 设为 7(NEVER),相当于永远不通过模板测试,会丢弃这个模型的渲染片段。
+      3. stencilPass 设为 1(KEEP),stencilFail 设为 2(REPLACE),由于 stencilComp 为 NEVER,一定会走到失败,执行 stencilFail 的行为,将 stencilRef (案例设定为 1) 写入深度缓冲。
+      4. 设置 renderQueue 为 1,保证遮挡物体优先渲染,保证遮挡所需 ref ,在后续模型渲染前,已经写入模版缓存。
+    -->
+    <xr-gltf id="occlusion" node-id="occlusion" position="0 0 0" rotation="0 0 0" scale="0.01 0.01 0.01" model="gltf-door"
+      states="renderQueue: 1, stencilTestOn: true, stencilComp: 7, stencilRef: 1, stencilReadMask: 1, stencilWriteMask: 1, stencilPass: 1, stencilFail: 2"
+    ></xr-gltf>
+
+    <!-- 需要被遮挡显示的模型,需保证渲染状态设置为合理,进行模版测试被剔除 -->
+    <!-- 参数逻辑:
+      1. 该实现流程核心为 模版测试,首先 stencilTestOn 开启模版测试
+      2. stencilComp 设为 6(NOTEQUAL),相当于只有模版缓冲的 Ref 匹配时,才保留实际的渲染片段。
+      3. stencilRef 设为 1,保证与遮挡物体写入的 ref 值一致;stencilReadMask 为读取 ref 值的数字掩码,一般存在多个 ref 的情况会使用这个掩码。
+      4. 设置 renderQueue 为 10 (相同数字会通过远近确定顺序),保证被遮挡物体后于遮挡物体渲染,保证已有模版缓存值。
+    -->
+    <xr-gltf node-id="renderItem" position="0 0 0" rotation="0 0 0" scale="1.6 1.6 1.6" model="gltf-twa"
+      states="renderQueue: 10, stencilTestOn: true, stencilComp: 6, stencilRef: 1, stencilReadMask: 1"
+    ></xr-gltf>
+
+    <xr-camera
+      id="camera" node-id="camera" position="6 0 0" clear-color="0.925 0.925 0.925 1"
+      target="camera-target" background="skybox"
+      camera-orbit-control=""
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="0.6" />
+    <xr-light type="directional" rotation="20 120 0" color="1 1 1" intensity="2"/>
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-gltfOcclusion/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 90 - 0
miniprogram/components/template/xr-template-gltfUVAnimation/index.js

@@ -0,0 +1,90 @@
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false
+  },
+  lifetimes: {},
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+    },
+    handleAssetsProgress: function({detail}) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function({detail}) {
+      console.log('assets loaded', detail.value);
+      this.setData({loaded: true});
+      // 做个简单的延时,保证glTF构建完成
+      setTimeout(()=>{
+        this.setUVAnimation();
+      },200);
+    },
+    setUVAnimation() {
+      const scene = this.scene;
+      const xrSystem = wx.getXrFrameSystem();
+
+      // 获取元素
+      const twaElm = this.scene.getElementById('twa');
+      const twaGLTF = twaElm.getComponent(xrSystem.GLTF);
+
+      // console.log(twaGLTF);
+
+      const changeMesh = twaGLTF.getPrimitivesByNodeName('Cube_0')[0];
+      const changeMaterial = changeMesh.material;
+
+      let offsetX = 0;
+      let offsetY = 0;
+      let scaleX = 1;
+      let scaleY = 1;
+      let rotation = 0;
+
+      // 这里采用一个固定计时器方便编写,建议使用tick
+      setInterval(()=>{
+        // 这里做一个 1% 每帧的偏移。
+        offsetX = offsetX > 1 ? 0 : offsetX + 0.01;
+        offsetY = offsetY > 1 ? 0 : offsetY + 0.01;
+        // 这里做一个每帧的缩放
+        // scaleX = scaleX > 2 ? 1 : scaleX + 0.01;
+        // scaleY = scaleY > 2 ? 1 : scaleY + 0.01;
+        // 这里做一个每帧的旋转。
+        // rotation = rotation > Math.PI ? 0 : rotation + Math.PI / 360;
+        const uvMatrix = xrSystem.Matrix4.createFromArray(this.getUvTransform(offsetX, offsetY, scaleX, scaleY, rotation))
+        // 设置uv矩阵
+        changeMaterial.setMatrix('u_uvTransform', uvMatrix);
+      }, 40);
+
+      const uvMatrix = xrSystem.Matrix4.createFromArray(this.getUvTransform(offsetX, offsetY, scaleX, scaleY, rotation))
+      // 设置uv矩阵
+      changeMaterial.setMatrix('u_uvTransform', uvMatrix);
+      // 开启使用uv矩阵的宏
+      changeMaterial.setMacro('WX_USE_UVTRANSFORM', true );
+      changeMaterial.setMacro('WX_USE_UVTRANSFORM_BASECOLOR', true );
+    }
+    ,
+    /**
+     * 获取UV变化矩阵,列主序
+     * 
+     * @param {number} tx x轴偏移
+     * @param {number} ty y轴偏移
+     * @param {number} sx x轴缩放
+     * @param {number} sy y轴缩放
+     * @param {number} rotation 旋转
+     * @return {Array} uvMatrixArray
+     */
+    getUvTransform(tx, ty, sx, sy, rotation) {
+      const c = Math.cos( rotation );
+      const s = Math.sin( rotation );
+
+      return [
+        sx * c, -sx * s, 0, 0,
+        sy * s, sy * c, 0, 0,
+        0, 0, 1, 0,
+        tx, ty, 0, 1,
+      ];
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-gltfUVAnimation/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 20 - 0
miniprogram/components/template/xr-template-gltfUVAnimation/index.wxml

@@ -0,0 +1,20 @@
+<xr-scene id="xr-scene" bind:ready="handleReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+    <xr-asset-load type="gltf" asset-id="gltf-twa" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/twa.glb" /> 
+  </xr-assets>
+  <xr-env env-data="xr-frame-team-workspace-day2" />
+  <xr-node>
+    <xr-node node-id="camera-target" position="0 0 0"></xr-node>
+
+    <xr-gltf id="twa" node-id="renderItem" position="0 0 0" rotation="0 0 0" scale="1.6 1.6 1.6" model="gltf-twa"></xr-gltf>
+    <xr-camera
+      id="camera" node-id="camera" position="6 0 0" clear-color="0.925 0.925 0.925 1"
+      target="camera-target" background="skybox"
+      camera-orbit-control=""
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="0.6" />
+    <xr-light type="directional" rotation="20 120 0" color="1 1 1" intensity="2"/>
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-gltfUVAnimation/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 232 - 0
miniprogram/components/template/xr-template-loading/index.js

@@ -0,0 +1,232 @@
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false,
+    loading: false,
+    gltfLoaded: false,
+    videoLoaded: false,
+    imageLoaded: false,
+    gltfIdList: [],
+    videoIdList: [],
+    imageIdList: [],
+  },
+  properties: {
+    gltfListRaw: {
+      type: Array,
+      value: [],
+    },
+    videoListRaw: {
+      type: Array,
+      value: [],
+    },
+    imageListRaw: {
+      type: Array,
+      value: [],
+    },
+  },
+  observers: {
+    gltfListRaw(newVal) {
+      this.releaseGLTF();
+      this.loadGLTF(newVal);
+    },
+    videoListRaw(newVal) {
+      this.releaseVideo();
+      this.loadVideo(newVal);
+    },
+    imageListRaw(newVal) {
+      this.releaseImage();
+      this.loadImage(newVal);
+    },
+  },
+  lifetimes: {},
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+      // 绑定tick事件
+      xrScene.event.add('tick', this.handleTick.bind(this));
+    },
+    handleAssetsProgress: function({detail}) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function({detail}) {
+      console.log('assets loaded', detail.value);
+      this.setData({loaded: true});
+    },
+    handleTick: function () {
+    },
+    releaseGLTF() {
+      if (this.data.gltfIdList && this.data.gltfIdList.length > 0) {
+        const scene = this.scene
+
+        // 声明使 gltf Mesh 移除
+        this.setData({
+          gltfLoaded: false
+        });
+
+        this.data.gltfIdList.map((id) => {
+          // 释放加载过的资源
+          scene.assets.releaseAsset('gltf',`gltf-${id}`);
+        })
+      }
+    },
+    async loadGLTF(gltfList) {
+      const scene = this.scene
+
+      if (gltfList.length > 0) {
+        const gltfIdList = [];
+        const gltfModel = await Promise.all(gltfList.map( (gltfItem) => {
+          gltfIdList.push(gltfItem.id)
+          const gtltfPromise = scene.assets.loadAsset({
+            type: 'gltf',
+            assetId: `gltf-${gltfItem.id}`,
+            src: gltfItem.src,
+          })
+          return gtltfPromise;
+        }));
+        
+        console.log('glTF asset loaded')
+        this.setData({ 
+          gltfIdList: gltfIdList,
+          gltfLoaded: true
+        })
+      } else {
+        this.setData({ 
+          gltfIdList: [],
+          gltfLoaded: false,
+        });
+      }
+    },
+    releaseVideo() {
+      if (this.data.videoIdList && this.data.videoIdList.length > 0) {
+        const scene = this.scene
+
+        // 声明使视频 Mesh 移除
+        this.setData({
+          videoLoaded: false
+        });
+
+        this.data.videoIdList.map((id) => {
+          // 释放加载过的资源
+          scene.assets.releaseAsset('video-texture', `video-${id}`);
+          scene.assets.releaseAsset('material', `video-mat-${id}`);
+        })
+      }
+    },
+    async loadVideo(videoList) {
+      const scene = this.scene
+      if (videoList.length > 0) {
+        const videoIdList = [];
+        const videos = await Promise.all(videoList.map((videoItem) =>{
+          videoIdList.push(videoItem.id);
+          return scene.assets.loadAsset({
+            type: 'video-texture',
+            assetId: `video-${videoItem.id}`,
+            src: videoItem.src,
+            options: { autoPlay: true, loop: true, abortAudio: false },
+          })
+        }))
+        videos.map((videoTexture, index) => {
+          const videoMat = scene.createMaterial(
+            scene.assets.getAsset('effect', 'simple'),
+            { u_baseColorMap: videoTexture.value.texture }
+          )
+          scene.assets.addAsset('material', `video-mat-${videoList[index].id}`, videoMat)
+        })
+        console.log('video asset loaded')
+        this.setData({
+          videoIdList: videoIdList,
+          videoLoaded: true
+        })
+      } else {
+        this.setData({
+          videoIdList: [],
+          videoLoaded: false
+        })
+      }
+    },
+    releaseImage() {
+      if (this.data.imageIdList && this.data.imageIdList.length > 0) {
+        const scene = this.scene
+
+        // 声明使视频 Mesh 移除
+        this.setData({
+          imageLoaded: false
+        });
+
+        this.data.imageIdList.map((id) => {
+          // 释放加载过的资源
+          scene.assets.releaseAsset('texture', `texture-${id}`);
+          scene.assets.releaseAsset('material', `texture-mat-${id}`);
+        })
+      }
+    },
+    async loadImage(imageList) {
+      const scene = this.scene
+      if (imageList.length > 0) {
+        const xrFrameSystem = wx.getXrFrameSystem();
+
+        const imageIdList = [];
+        const images = await Promise.all(imageList.map((imageItem) =>{
+          const id = imageItem.id;
+          console.log(imageItem, id);
+          imageIdList.push(id);
+          if (id === 2) {
+            // 走 asset 直接加载方式
+            return scene.assets.loadAsset({
+              type: 'texture',
+              assetId: `texture-${imageItem.id}`,
+              src: imageItem.src,
+            })
+
+          } else if (id === 3) {
+            // 走 createImage 方式
+            return new Promise(resolve => {
+              const image = scene.createImage();
+              image.src = imageItem.src;
+              image.onload = () => {
+                resolve({
+                  value: scene.createTexture({
+                    source: [image],
+                    width: image.width,
+                    height: image.height,
+                    // 按需加后面的
+                    magFilter: xrFrameSystem.EFilterMode.LINEAR_MIPMAP_LINEAR,
+                    minFilter: xrFrameSystem.EFilterMode.LINEAR_MIPMAP_LINEAR,
+                    wrapU: xrFrameSystem.EWrapMode.CLAMP_TO_EDGE,
+                    wrapV: xrFrameSystem.EWrapMode.CLAMP_TO_EDGE,
+                    anisoLevel:1
+                  })
+                });
+              };
+              image.onerror = error => {};
+            });
+          }
+        }));
+
+        console.log(images);
+        
+        images.map((texture, index) => {
+          const textureMat = scene.createMaterial(
+            scene.assets.getAsset('effect', 'simple'),
+            { u_baseColorMap: texture.value }
+          )
+          scene.assets.addAsset('material', `texture-mat-${imageList[index].id}`, textureMat)
+        })
+
+        this.setData({
+          imageIdList: imageIdList,
+          imageLoaded: true
+        })
+      } else {
+        this.setData({
+          imageIdList: [],
+          imageLoaded: false
+        })
+      }
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-loading/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 88 - 0
miniprogram/components/template/xr-template-loading/index.wxml

@@ -0,0 +1,88 @@
+<xr-scene id="xr-scene" bind:ready="handleReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+    <xr-asset-material asset-id="standard-mat" effect="standard" />
+  </xr-assets>
+  <xr-node>
+    <xr-node node-id="camera-target" position="0 0 0"></xr-node>
+    <xr-mesh node-id="floor-plane" position="0 -1 0" rotation="0 0 0" scale="10 1 10" geometry="plane"
+      uniforms="u_baseColorFactor:1 1 1 1" receive-shadow
+    ></xr-mesh>
+    <!-- glTF -->
+    <xr-node wx:if="{{gltfLoaded}}">
+      <xr-node
+        wx:for="{{gltfIdList}}" wx:for-item="gltfId"
+        wx:key="gltfId"
+      >
+        <xr-gltf
+          wx:if="{{gltfId == 0}}"
+          position="-1 -0.46 -1" rotation="0 0 0"
+          scale="0.6 0.6 0.6"
+          model="gltf-{{gltfId}}"
+          cast-shadow
+        ></xr-gltf>
+        <xr-gltf
+          wx:if="{{gltfId == 1}}"
+          position="1 -0.98 -1" rotation="0 0 0"
+          scale="0.015 0.015 0.015"
+          model="gltf-{{gltfId}}"
+          cast-shadow
+        ></xr-gltf>
+      </xr-node>
+    </xr-node>
+    <!-- Image -->
+    <xr-node wx:if="{{imageLoaded}}">
+      <xr-node
+        wx:for="{{imageIdList}}" wx:for-item="imageId"
+        wx:key="imageId"
+      >
+        <xr-mesh
+          wx:if="{{imageId === 2}}"
+          position="1 1 0" scale="1 1 0.2"
+          geometry="cube"  material="texture-mat-{{imageId}}"
+          cast-shadow
+        />
+        <xr-mesh
+          wx:if="{{imageId === 3}}"
+          position="-1 1 0" scale="1 1 0.2"
+          geometry="cube" material="texture-mat-{{imageId}}"
+          cast-shadow
+        />
+      </xr-node>
+    </xr-node>
+    <!-- Video -->
+    <xr-node wx:if="{{videoLoaded}}">
+      <xr-node
+        wx:for="{{videoIdList}}" wx:for-item="videoId"
+        wx:key="videoId"
+      >
+      <xr-mesh
+        wx:if="{{videoId === 4}}"
+        node-id="mesh-cube" position="0 -0.5 1" scale="0.8 1.4 0.8"
+        geometry="cube" material="video-mat-{{videoId}}"
+        cast-shadow
+      />
+      <xr-mesh
+        wx:if="{{videoId === 5}}"
+        node-id="mesh-cube" position="-1.5 -0.6 1" scale="1.2 0.8 0.8"
+        geometry="cube" material="video-mat-{{videoId}}"
+        cast-shadow
+      />
+      <xr-mesh
+        wx:if="{{videoId === 6}}"
+        node-id="mesh-cube" position="1.5 -0.6 1" scale="1.2 0.8 0.8"
+        geometry="cube" material="video-mat-{{videoId}}"
+        cast-shadow
+      />
+      </xr-node>
+    </xr-node>
+    <xr-camera
+      id="camera" node-id="camera" position="0 3 5" clear-color="0.8 0.8 0.8 1"
+      target="camera-target"
+      camera-orbit-control=""
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="1" />
+    <xr-light type="directional" rotation="40 170 0" color="1 1 1" intensity="3" cast-shadow/>
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-loading/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 74 - 0
miniprogram/components/template/xr-template-lookat/index.js

@@ -0,0 +1,74 @@
+const STATE = {
+  NONE: -1,
+  MOVE: 0,
+  ZOOM_OR_PAN: 1
+}
+
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false,
+    arReady: false,
+  },
+  lifetimes: {
+    async attached() {
+      console.log('data', this.data)
+    }
+  },
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      const xrSystem = wx.getXrFrameSystem();
+
+      this.mat = new (xrSystem.Matrix4)();
+      console.log('xr-scene', xrScene);
+      const { width, height } = this.scene
+
+
+      this.cameraTrs = this.scene.getElementById('camera').getComponent(xrSystem.Transform);
+      
+      this.leftTRS = this.scene.getElementById('l').getComponent(xrSystem.Transform);
+      this.rightTRS = this.scene.getElementById('r').getComponent(xrSystem.Transform);
+      this.frontTRS = this.scene.getElementById('f').getComponent(xrSystem.Transform);
+      this.backTRS = this.scene.getElementById('b').getComponent(xrSystem.Transform);
+
+      this.FACING = xrSystem.Vector3.createFromNumber(0, 0, 0);
+      this.UP = xrSystem.Vector3.createFromNumber(0, 1, 0);
+
+
+      xrScene.event.add('tick', this.handleTick.bind(this));
+    },
+    handleTick: function () {
+      const xrSystem = wx.getXrFrameSystem();
+
+      if (this.leftTRS) {
+        console.log()
+        const quaternion = this.leftTRS.quaternion;
+        // 算出从物体到相机的向量
+        this.FACING.set(this.cameraTrs.position).sub(this.leftTRS.position, this.FACING);
+        xrSystem.Quaternion.lookRotation(this.FACING, this.UP, quaternion);
+      }
+      if (this.rightTRS) {
+        const quaternion = this.rightTRS.quaternion;
+        // 算出从物体到相机的向量
+        this.FACING.set(this.cameraTrs.position).sub(this.rightTRS.position, this.FACING);
+        xrSystem.Quaternion.lookRotation(this.FACING, this.UP, quaternion);
+      }
+      if (this.frontTRS) {
+        const quaternion = this.frontTRS.quaternion;
+        // // 算出从物体到相机的向量
+        this.FACING.set(this.cameraTrs.position).sub(this.frontTRS.position, this.FACING);
+        xrSystem.Quaternion.lookRotation(this.FACING, this.UP, quaternion);
+      }
+      if (this.backTRS) {
+        const quaternion = this.backTRS.quaternion;
+        // 算出从物体到相机的向量
+        this.FACING.set(this.cameraTrs.position).sub(this.backTRS.position, this.FACING);
+        xrSystem.Quaternion.lookRotation(this.FACING, this.UP, quaternion);
+      }
+    },
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-lookat/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 36 - 0
miniprogram/components/template/xr-template-lookat/index.wxml

@@ -0,0 +1,36 @@
+<xr-scene ar-system="modes:Plane" bind:ready="handleReady" bind:ar-ready="handleARReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+    <xr-asset-load type="gltf" asset-id="anchor" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/ar-plane-marker.glb" />
+    <xr-asset-load type="gltf" asset-id="door" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/door.glb" /> 
+    <xr-asset-material asset-id="standard-mat" effect="standard" />
+  </xr-assets>
+  <xr-node>
+    <xr-ar-tracker mode="Plane">
+      <xr-gltf id="anchor" model="anchor"></xr-gltf>
+    </xr-ar-tracker>
+    <xr-node id="f" position="0 0 3.0">
+      <xr-mesh rotation="90 0 0" geometry="plane" uniforms="u_baseColorFactor:0.4 0.2 0.2 1, u_metallicRoughnessValues: 0 0.6" states="cullOn: false"></xr-mesh>
+    </xr-node>
+    <!-- <xr-node id="b" position="0 0 -3.0">
+      <xr-mesh rotation="90 0 0" geometry="plane" uniforms="u_baseColorFactor:0.2 0.4 0.2 1, u_metallicRoughnessValues: 0 0.6" states="cullOn: false"></xr-mesh>
+    </xr-node> -->
+    <xr-node id="b" position="0 0 -3.0">
+      <xr-gltf rotation="0 -90 0" scale="0.01 0.01 0.01" model="door"></xr-gltf>
+    </xr-node>
+    <xr-node id="l" position="-3.0 0 0.0">
+      <xr-mesh rotation="90 0 0" geometry="plane" uniforms="u_baseColorFactor:0.2 0.2 0.4 1, u_metallicRoughnessValues: 0 0.6" states="cullOn: false"></xr-mesh>
+    </xr-node>
+    <xr-node id="r" position="3.0 0 0.0">
+      <xr-mesh rotation="90 0 0" geometry="plane" uniforms="u_baseColorFactor:0.4 0.2 0.6 1, u_metallicRoughnessValues: 0 0.6" states="cullOn: false"></xr-mesh>
+    </xr-node>
+
+    <xr-camera
+      id="camera" node-id="camera" clear-color="0.925 0.925 0.925 1"
+      background="ar" is-ar-camera
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="1" />
+    <xr-light type="directional" rotation="180 0 0" color="1 1 1" intensity="3" />
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-lookat/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 65 - 0
miniprogram/components/template/xr-template-markerCenter/index.js

@@ -0,0 +1,65 @@
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false,
+    arReady: false,
+    markerMatch: false
+  },
+  lifetimes: {
+    async attached() {
+      console.log('data', this.data)
+    }
+  },
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      this.mat = new (wx.getXrFrameSystem().Matrix4)();
+      console.log('xr-scene', xrScene);
+    },
+
+    handleARReady: async function({detail}) {
+      console.log('arReady', this.scene.ar.arVersion);
+      const xr = wx.getXrFrameSystem();
+
+      // shadow root
+      this.root = this.scene.getElementById('root');
+
+      // 动态创建添加tracker
+      const lockTrackerEl = this.scene.createElement(xr.XRNode);
+      const lockTracker = lockTrackerEl.addComponent(xr.ARTracker, {
+        mode: 'Marker',
+        src: 'https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/marker/2dmarker-test.jpg',
+      });
+      
+      this.root.addChild(lockTrackerEl);
+
+      let waiting = false;
+      
+      lockTrackerEl.event.add('ar-tracker-state', tracker => {
+        // 获取当前状态和错误信息
+        const {state, errorMessage} = tracker;
+
+        if (state === 2 && !waiting) {
+          console.log('match')
+          waiting = true;
+          // 识别成功后切换到世界坐标
+          
+          // 延时保证坐标已经设置
+          setTimeout(() => {
+            
+            this.setData({
+              markerMatch: true
+            });
+
+            // 去除tracker监听
+            this.root.removeChild(lockTrackerEl);
+          }, 30);
+
+        }
+      })
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-markerCenter/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 39 - 0
miniprogram/components/template/xr-template-markerCenter/index.wxml

@@ -0,0 +1,39 @@
+<xr-scene ar-system="modes:Marker;" bind:ready="handleReady" bind:ar-ready="handleARReady">
+  <xr-assets>
+      <xr-asset-load
+        type="env-data" asset-id="env1" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/env-test.bin"
+      />
+      <xr-asset-load type="gltf" asset-id="gltf-damageHelmet" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/damage-helmet/index.gltf" />
+  </xr-assets>
+  <xr-node>
+  <xr-env env-data="env1" />
+
+    <!-- marker -->
+    <!-- <xr-ar-tracker id="lockTracker" mode="Marker" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/marker/2dmarker-test.jpg">
+      <xr-node id="lockItem">
+        <xr-gltf model="butterfly" anim-autoplay position="0.2 0 -0.2" scale="0.6 0.6 0.6" rotation="0 -50 0" />
+        <xr-gltf model="butterfly" anim-autoplay position="0.4 0 0.3" scale="0.5 0.5 0.5" rotation="0 -50 0" />
+        <xr-gltf model="butterfly" anim-autoplay position="-0.3 0 0.3" scale="0.4 0.4 0.4" rotation="0 -50 0" />
+      </xr-node>
+    </xr-ar-tracker> -->
+
+    <!-- marker 会动态创建并放在root下 -->
+    <xr-shadow id="root"></xr-shadow>
+
+    <xr-camera
+      id="camera" node-id="camera" clear-color="0.925 0.925 0.925 1"
+      background="ar" is-ar-camera
+    >
+      <!-- 将模型放在相机内部,相当于是放在视图空间里面,只需要z轴正方向移动,就是远离相机 -->
+      <!-- 放ar相机内部,这个流程有bug,感觉是vk返回的矩阵里面有负数,准备排查 -->
+      <xr-gltf
+        wx:if="{{markerMatch}}"
+        node-id="gltf-damageHelmet" position="0 0 6" rotation="0 0 0" scale="1 1 -1" model="gltf-damageHelmet"
+      ></xr-gltf>
+    </xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="0.5" />
+    <xr-light type="directional" rotation="20 120 0" color="1 1 1" intensity="2" />
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-markerCenter/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 105 - 0
miniprogram/components/template/xr-template-markerLock/index.js

@@ -0,0 +1,105 @@
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false,
+    arReady: false,
+  },
+  lifetimes: {
+    async attached() {
+      console.log('data', this.data)
+    }
+  },
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      this.mat = new (wx.getXrFrameSystem().Matrix4)();
+      console.log('xr-scene', xrScene);
+    },
+
+    handleARReady: async function({detail}) {
+      console.log('arReady', this.scene.ar.arVersion);
+      const xr = wx.getXrFrameSystem();
+
+      // shadow root
+      this.root = this.scene.getElementById('root');
+
+      // 动态创建添加tracker
+      const lockTrackerEl = this.scene.createElement(xr.XRNode);
+      const lockTracker = lockTrackerEl.addComponent(xr.ARTracker, {
+        mode: 'Marker',
+        src: 'https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/marker/2dmarker-test.jpg',
+      });
+      
+      this.root.addChild(lockTrackerEl);
+
+      // 动态改动模型根节点
+      const lockItemEle = this.scene.createElement(xr.XRNode, {
+        position: '10000 0 0',
+      });
+
+      const {value: model} = await this.scene.assets.loadAsset({type: 'gltf', assetId: 'butterfly', src: 'https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/butterfly/index.glb'});
+
+      // 添加蝴蝶
+      const gltf1 = this.scene.createElement(xr.XRGLTF, {
+        position: '0.2 0 -0.2',
+        scale: '0.6 0.6 0.6',
+        rotation: '0 -50 0',
+        'anim-autoplay': '',
+      });
+      lockItemEle.addChild(gltf1);
+      gltf1.getComponent(xr.GLTF).setData({
+        model: model,
+      });
+      const gltf2 = this.scene.createElement(xr.XRGLTF, {
+        position: '0.4 0 0.3',
+        scale: '0.5 0.5 0.5',
+        rotation: '0 -50 0',
+        'anim-autoplay': '',
+      });
+      lockItemEle.addChild(gltf2);
+      gltf2.getComponent(xr.GLTF).setData({
+        model: model,
+      });
+      const gltf3 = this.scene.createElement(xr.XRGLTF, {
+        position: '-0.3 0 0.3',
+        scale: '0.4 0.4 0.4',
+        rotation: '0 -50 0',
+        'anim-autoplay': '',
+      });
+      lockItemEle.addChild(gltf3);
+      gltf3.getComponent(xr.GLTF).setData({
+        model: model,
+      });
+      // 先挂到场上,但是可以放在离屏
+      this.root.addChild(lockItemEle);
+
+      let waiting = false;
+      
+      lockTrackerEl.event.add('ar-tracker-state', tracker => {
+        // 获取当前状态和错误信息
+        const {state, errorMessage} = tracker;
+
+        if (state === 2 && !waiting) {
+          console.log('match')
+          waiting = true;
+          // 识别成功后切换到世界坐标
+          
+          // 延时保证坐标已经设置
+          setTimeout(() => {
+            // 将 lockTrackerEl 的世界矩阵信息同步到 lockItemEle
+            const lockTrackerTrs = lockTrackerEl.getComponent(xr.Transform)
+            const lockItemTrs = lockItemEle.getComponent(xr.Transform)
+            lockItemTrs.setLocalMatrix(lockTrackerTrs.worldMatrix);
+            
+            // 去除tracker监听
+            this.root.removeChild(lockTrackerEl);
+          }, 30);
+
+        }
+      })
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-markerLock/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 35 - 0
miniprogram/components/template/xr-template-markerLock/index.wxml

@@ -0,0 +1,35 @@
+<xr-scene ar-system="modes:Plane Marker; planeMode: 1" bind:ready="handleReady" bind:ar-ready="handleARReady">
+  <!-- vio + marker 模式下 planeMode 需设置为 1 (只允许水平面识别) -->
+  <xr-assets>
+    <xr-asset-load type="gltf" asset-id="anchor" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/ar-plane-marker.glb" />
+  </xr-assets>
+  <xr-node>
+
+    <!-- plane -->
+    <xr-ar-tracker mode="Plane">
+      <xr-gltf model="anchor"></xr-gltf>
+    </xr-ar-tracker>
+
+    <!-- marker -->
+    <!-- <xr-ar-tracker id="lockTracker" mode="Marker" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/marker/2dmarker-test.jpg">
+      <xr-node id="lockItem">
+        <xr-gltf model="butterfly" anim-autoplay position="0.2 0 -0.2" scale="0.6 0.6 0.6" rotation="0 -50 0" />
+        <xr-gltf model="butterfly" anim-autoplay position="0.4 0 0.3" scale="0.5 0.5 0.5" rotation="0 -50 0" />
+        <xr-gltf model="butterfly" anim-autoplay position="-0.3 0 0.3" scale="0.4 0.4 0.4" rotation="0 -50 0" />
+      </xr-node>
+    </xr-ar-tracker> -->
+
+    <!-- 识别成功后放置的世界位置 -->
+    <!-- marker 会动态创建并放在root下 -->
+    <xr-shadow id="root"></xr-shadow>
+
+    <xr-camera
+      id="camera" node-id="camera" clear-color="0.925 0.925 0.925 1"
+      background="ar" is-ar-camera
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="1" />
+    <xr-light type="directional" rotation="180 0 0" color="1 1 1" intensity="3" />
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-markerLock/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 70 - 0
miniprogram/components/template/xr-template-message/index.js

@@ -0,0 +1,70 @@
+
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+    messageData: {
+      type: Object,
+      value: {
+        moveX: 0,
+        moveZ: 0,
+      },
+      observer(newVal, oldVal) {
+        this.speedX = Math.sign(this.speedX) !== 0 ? Math.sign(this.speedX) * Math.abs(newVal.moveX) * 0.01 : newVal.moveX * 0.01;
+        this.speedZ = Math.sign(this.speedZ) !== 0 ? Math.sign(this.speedZ) * Math.abs(newVal.moveZ) * 0.01 : newVal.moveZ * 0.01;
+      }
+    }
+  },
+  data: {
+    loaded: false,
+  },
+  lifetimes: {},
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+      const xrSystem = wx.getXrFrameSystem();
+
+      // 绑定运动目标
+      this.moveSphereTRS = this.scene.getElementById('move-sphere').getComponent(xrSystem.Transform);
+      // 绑定内置变量
+      this.speedX = 0;
+      this.speedZ = 0;
+      this.planeWidth = 5;
+      // 绑定tick事件
+      xrScene.event.add('tick', this.handleTick.bind(this));
+    },
+    handleAssetsProgress: function({detail}) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function({detail}) {
+      console.log('assets loaded', detail.value);
+      this.setData({loaded: true});
+    },
+    handleTick: function () {
+      if (this.moveSphereTRS) {
+        const nowPos = this.moveSphereTRS.position;
+        if(nowPos.x > this.planeWidth) {
+          this.speedX = -this.speedX;
+        } else if (nowPos.x < -this.planeWidth){
+          this.speedX = -this.speedX;
+        }
+        if(nowPos.z > this.planeWidth) {
+          this.speedZ = -this.speedZ;
+        } else if (nowPos.z < -this.planeWidth){
+          this.speedZ = -this.speedZ;
+        }
+        nowPos.x += this.speedX;
+        nowPos.z += this.speedZ;
+
+        this.triggerEvent('infoListener', { 
+          speedX: this.speedX,
+          speedZ: this.speedZ,
+          posX: nowPos.x.toFixed(2),
+          posZ: nowPos.z.toFixed(2),
+         });
+      }
+
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-message/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 22 - 0
miniprogram/components/template/xr-template-message/index.wxml

@@ -0,0 +1,22 @@
+<xr-scene id="xr-scene" bind:ready="handleReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+  </xr-assets>
+  <xr-node>
+    <xr-mesh node-id="floor-plane" position="0 -1 0" rotation="0 0 0" scale="10 1 10" geometry="plane"
+      uniforms="u_baseColorFactor:1 1 1 1" receive-shadow
+    ></xr-mesh>
+    <xr-mesh id="move-sphere" node-id="move-sphere"
+      position="0 0 0" scale="1 1 1" geometry="sphere"
+      uniforms="u_metallicRoughnessValues: 0 1"
+      cast-shadow
+    ></xr-mesh>
+    <xr-camera
+      id="camera" node-id="camera" position="0 5 10" clear-color="0.8 0.8 0.8 1"
+      target="move-sphere"
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="1" />
+    <xr-light type="directional" rotation="40 170 0" color="1 1 1" intensity="3" cast-shadow/>
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-message/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 26 - 0
miniprogram/components/template/xr-template-planeShadow/index.js

@@ -0,0 +1,26 @@
+
+
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false
+  },
+  lifetimes: {},
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+
+    },
+    handleAssetsProgress: function({detail}) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function({detail}) {
+      console.log('assets loaded', detail.value);
+
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-planeShadow/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 23 - 0
miniprogram/components/template/xr-template-planeShadow/index.wxml

@@ -0,0 +1,23 @@
+<xr-scene id="xr-scene" bind:ready="handleReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+    <xr-asset-load type="gltf" asset-id="gltf-mech_drone" src="https://mmbizwxaminiprogram-1258344707.cos.ap-guangzhou.myqcloud.com/xr-frame/demo/mech_drone/scene.gltf" />
+    <xr-asset-material asset-id="plane-shadow-mat" effect="plane-shadow" />
+  </xr-assets>
+  <xr-env env-data="xr-frame-team-workspace-day2" />
+  <xr-node>
+    <xr-node node-id="camera-target" position="0 0 0"></xr-node>
+
+    <xr-gltf node-id="gltf-mech_drone" position="0 -2 0" rotation="0 0 0" scale="7 7 7" model="gltf-mech_drone" anim-autoplay cast-shadow></xr-gltf>
+    <xr-mesh position="0 -2 0" scale="10 1 10" geometry="plane"  material="plane-shadow-mat" receive-shadow></xr-mesh>
+
+    <xr-camera
+      id="camera" node-id="camera" position="2 3 -5" clear-color="0.96 0.96 0.96 1"
+      target="camera-target" near="0.1" far="2000"
+      camera-orbit-control="" background="skybox"
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="1.2" />
+    <xr-light type="directional" rotation="40 0 0" color="1 1 1" intensity="3" cast-shadow />
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-planeShadow/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 23 - 0
miniprogram/components/template/xr-template-removeBlack/index.js

@@ -0,0 +1,23 @@
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    a: Number,
+  },
+  data: {
+    loaded: false
+  },
+  lifetimes: {},
+  methods: {
+    handleReady({detail}) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+    },
+    handleAssetsProgress: function({detail}) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function({detail}) {
+      console.log('assets loaded', detail.value);
+      this.setData({loaded: true});
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-removeBlack/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

+ 31 - 0
miniprogram/components/template/xr-template-removeBlack/index.wxml

@@ -0,0 +1,31 @@
+<xr-scene id="xr-scene" bind:ready="handleReady">
+  <xr-assets bind:progress="handleAssetsProgress" bind:loaded="handleAssetsLoaded">
+    <xr-asset-load
+      type="video-texture" asset-id="test2"
+      src="https://h5-project.oss-cn-shenzhen.aliyuncs.com/XR/test2.mp4" options="autoPlay:true,loop:true"
+    />
+    <xr-asset-material asset-id="removeBlack-mat" effect="removeBlack" />
+  </xr-assets>
+  <xr-node>
+    <xr-node node-id="camera-target" position="0 0 0"></xr-node>
+    <xr-node wx:if="{{loaded}}">
+      <xr-mesh node-id="floor-plane" position="0 -1 0" rotation="0 0 0" scale="10 1 10" geometry="plane"
+        uniforms="u_baseColorFactor:1 1 1 1"
+      ></xr-mesh>
+      <xr-mesh node-id="video-item" position="0 0 0" rotation="90 0 0" scale="2 2 2" geometry="plane"
+        material="removeBlack-mat"
+        uniforms="u_videoMap: video-test2"
+        states="renderQueue:2500"
+      ></xr-mesh>
+    </xr-node>
+    <xr-camera
+      id="camera" node-id="camera" position="2 2 4" clear-color="0.925 0.925 0.925 1"
+      target="camera-target"
+      camera-orbit-control=""
+    ></xr-camera>
+  </xr-node>
+  <xr-node node-id="lights">
+    <xr-light type="ambient" color="1 1 1" intensity="1" />
+    <xr-light type="directional" rotation="40 170 0" color="1 1 1" intensity="3" cast-shadow/>
+  </xr-node>
+</xr-scene>

+ 1 - 0
miniprogram/components/template/xr-template-removeBlack/index.wxss

@@ -0,0 +1 @@
+/* xr/index.wxss */

+ 131 - 0
miniprogram/components/template/xr-template-select/index.js

@@ -0,0 +1,131 @@
+var touch = false;
+Component({
+  behaviors: [require('../../common/share-behavior').default],
+  properties: {
+    itemIndex: {
+      type: Number,
+      observer(newVal, oldVal) {
+        if (newVal != undefined) {
+          switch (newVal) {
+            case 0:
+              this.pause()
+              break;
+            case 1:
+              this.resume()
+              break;
+            default:
+              //前两位给了暂停、继续状态, 这里需要-2
+              this.play(newVal - 2)
+              this.itemIndex = newVal - 2;
+              break;
+          }
+        }
+      },
+    },
+  },
+  data: {
+    loaded: false,
+  },
+  lifetimes: {},
+  methods: {
+    handleReady({
+      detail
+    }) {
+      const xrScene = this.scene = detail.value;
+      console.log('xr-scene', xrScene);
+    },
+    handleAssetsProgress: function ({
+      detail
+    }) {
+      console.log('assets progress', detail.value);
+    },
+    handleAssetsLoaded: function ({
+      detail
+    }) {
+      console.log('assets loaded', detail.value);
+      this.setData({
+        loaded: true
+      });
+    },
+    handleTouchModel(e) {
+      touch = true
+      const xrScene = this.scene;
+      const xrFrameSystem = wx.getXrFrameSystem();
+      const myModel = xrScene.getElementById('myModel');
+      this.myModelAnimator = myModel.getComponent(xrFrameSystem.Animator);
+      const clips = this.myModelAnimator._clips;
+      this.clipName = []
+
+      clips.forEach((v, key) => {
+        if (key.indexOf('pose') == -1) {
+          this.clipName.push(key)
+        }
+      })
+
+      this.triggerEvent('infoListener', {
+        clipName: this.clipName,
+      });
+    },
+
+    handleTick: function (dt) {
+      if (touch) {
+        const xrFrameSystem = wx.getXrFrameSystem();
+        const camera = this.scene.getElementById('camera').getComponent(xrFrameSystem.Camera)
+        const myModel = this.scene.getElementById('myModel');
+        const modelTRS = myModel.getComponent(xrFrameSystem.Transform)
+        const trackerPos = camera.convertWorldPositionToClip(modelTRS.worldPosition.add(xrFrameSystem.Vector3.createFromNumber(0, 2, 0)))
+
+
+        const dirX = camera.convertWorldPositionToClip(xrFrameSystem.Vector3.createFromNumber(1, 0, 0))
+        const dirO = camera.convertWorldPositionToClip(xrFrameSystem.Vector3.createFromNumber(0, 0, 0))
+        const dirZ = camera.convertWorldPositionToClip(xrFrameSystem.Vector3.createFromNumber(0, 0, 1))
+        var len1 = dirX.sub(dirO).length()
+        var len2 = dirZ.sub(dirO).length()
+        var lenRes = len1 > len2 ? len1 : len2
+        lenRes = lenRes < 0 ? 0 : lenRes > 1 ? 1 : lenRes
+
+        this.triggerEvent('infoListener', {
+          position: {
+            'x': trackerPos.x,
+            'y': trackerPos.y,
+          },
+          len: 0.5 + lenRes
+        });
+      }
+    },
+
+    handleGltfLoaded: async function () {
+      const xrScene = this.scene;
+      const xrFrameSystem = wx.getXrFrameSystem();
+      const myModel = xrScene.getElementById('myModel');
+      const shadowNode = myModel.getComponent("gltf").getInternalNodeByName("mixamorig:RightHandIndex1")
+      const el = this.scene.createElement(xrFrameSystem.XRMesh, {
+        geometry: "cube",
+        scale: "20 20 20",
+        uniforms: "u_baseColorFactor:1 0 0 1",
+        position: "0 0 0",
+        rotation: "0 0 0"
+      });
+
+      shadowNode.addChild(el);
+    },
+    play(index) {
+      console.log("play:", this.clipName[index])
+      if (this.clipName.length != 0) {
+        this.myModelAnimator.play(this.clipName[index], {
+          loop: 10,
+        });
+      }
+    },
+    pause() {
+      console.log("pause:", this.clipName[this.itemIndex])
+      //   this.myModelAnimator.pause(this.clipName[this.itemIndex])
+      this.myModelAnimator.pause()
+    },
+    resume() {
+      console.log("resume:", this.clipName[this.itemIndex])
+      //   this.myModelAnimator.resume(this.clipName[this.itemIndex])
+      this.myModelAnimator.resume()
+    }
+  }
+})

+ 5 - 0
miniprogram/components/template/xr-template-select/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "renderer": "xr-frame"
+}

Some files were not shown because too many files changed in this diff