@xrift/world-components 0.30.3 → 0.30.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,8 +4,16 @@ import { type Object3D } from 'three';
4
4
  * 対象の Object3D を毎フレームカメラに向けてY軸のみ回転させる
5
5
  * 親のワールド回転を考慮し、ローカル回転として正しい値を設定する
6
6
  *
7
- * sentinel Mesh の onBeforeRender を使用することで、
8
- * Mirror(Reflector)の virtualCamera でも正しい回転が適用される
7
+ * 2つの sentinel メッシュ(pre/post)により、Mirror(Reflector)の
8
+ * ネステッドレンダーと WebXR の両方に対応する。
9
+ * - pre-sentinel (renderOrder=-Infinity): 回転を保存 → カメラ用に設定
10
+ * - post-sentinel (renderOrder=+Infinity): 保存した回転を復元
11
+ * スタック構造で多重ネスト(Mirror + WebXR左右眼)にも対応。
12
+ *
13
+ * WebXR安全性:
14
+ * - setFromMatrixPosition(): matrixWorldを直接読み取り、updateWorldMatrixを呼ばない
15
+ * - decompose(): 同上
16
+ * - target.updateWorldMatrix(false, true): targetとその子のみ更新、カメラには触れない
9
17
  */
10
18
  export declare const useBillboardY: <T extends Object3D>() => import("react").RefObject<T>;
11
19
  //# sourceMappingURL=hooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/components/BillboardY/hooks.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,QAAQ,EAId,MAAM,OAAO,CAAA;AAed;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,QAAQ,mCA6C/C,CAAA"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/components/BillboardY/hooks.ts"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,QAAQ,EAGd,MAAM,OAAO,CAAA;AA4Bd;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,QAAQ,mCAkG/C,CAAA"}
@@ -4,20 +4,40 @@ import { getBillboardYRotation } from './utils';
4
4
  const _cameraWorldPos = new Vector3();
5
5
  const _targetWorldPos = new Vector3();
6
6
  const _parentQuat = new Quaternion();
7
+ const _parentPos = new Vector3();
8
+ const _parentScale = new Vector3();
7
9
  const _euler = new Euler();
8
10
  const SENTINEL_GEOMETRY = new BoxGeometry(0.001, 0.001, 0.001);
9
- const SENTINEL_MATERIAL = new MeshBasicMaterial({
11
+ // Three.js はレンダーリストを opaque → transparent の順で処理する。
12
+ // renderOrder はリスト内のソートにのみ影響するため、
13
+ // opaque/transparent 両方の子要素に対応するには両方のリストに sentinel が必要。
14
+ const OPAQUE_MATERIAL = new MeshBasicMaterial({
10
15
  colorWrite: false,
11
16
  depthWrite: false,
12
17
  depthTest: false,
13
18
  });
19
+ const TRANSPARENT_MATERIAL = new MeshBasicMaterial({
20
+ colorWrite: false,
21
+ depthWrite: false,
22
+ depthTest: false,
23
+ transparent: true,
24
+ opacity: 0,
25
+ });
14
26
  /**
15
27
  * Y軸ビルボードフック
16
28
  * 対象の Object3D を毎フレームカメラに向けてY軸のみ回転させる
17
29
  * 親のワールド回転を考慮し、ローカル回転として正しい値を設定する
18
30
  *
19
- * sentinel Mesh の onBeforeRender を使用することで、
20
- * Mirror(Reflector)の virtualCamera でも正しい回転が適用される
31
+ * 2つの sentinel メッシュ(pre/post)により、Mirror(Reflector)の
32
+ * ネステッドレンダーと WebXR の両方に対応する。
33
+ * - pre-sentinel (renderOrder=-Infinity): 回転を保存 → カメラ用に設定
34
+ * - post-sentinel (renderOrder=+Infinity): 保存した回転を復元
35
+ * スタック構造で多重ネスト(Mirror + WebXR左右眼)にも対応。
36
+ *
37
+ * WebXR安全性:
38
+ * - setFromMatrixPosition(): matrixWorldを直接読み取り、updateWorldMatrixを呼ばない
39
+ * - decompose(): 同上
40
+ * - target.updateWorldMatrix(false, true): targetとその子のみ更新、カメラには触れない
21
41
  */
22
42
  export const useBillboardY = () => {
23
43
  const ref = useRef(null);
@@ -25,15 +45,16 @@ export const useBillboardY = () => {
25
45
  if (!ref.current)
26
46
  return;
27
47
  const target = ref.current;
28
- const sentinel = new Mesh(SENTINEL_GEOMETRY, SENTINEL_MATERIAL);
29
- sentinel.frustumCulled = false;
30
- sentinel.renderOrder = -Infinity;
31
- sentinel.onBeforeRender = (_renderer, _scene, camera) => {
32
- camera.getWorldPosition(_cameraWorldPos);
33
- target.getWorldPosition(_targetWorldPos);
48
+ // 回転の save/restore 用スタック
49
+ const savedRotations = [];
50
+ const applyRotation = (camera) => {
51
+ savedRotations.push(target.rotation.y);
52
+ // WebXR安全: matrixWorldを直接読み取り、updateWorldMatrixを呼ばない
53
+ _cameraWorldPos.setFromMatrixPosition(camera.matrixWorld);
54
+ _targetWorldPos.setFromMatrixPosition(target.matrixWorld);
34
55
  const worldRotationY = getBillboardYRotation(_cameraWorldPos, _targetWorldPos);
35
56
  if (target.parent) {
36
- target.parent.getWorldQuaternion(_parentQuat);
57
+ target.parent.matrixWorld.decompose(_parentPos, _parentQuat, _parentScale);
37
58
  _euler.setFromQuaternion(_parentQuat, 'YXZ');
38
59
  target.rotation.y = worldRotationY - _euler.y;
39
60
  }
@@ -42,10 +63,44 @@ export const useBillboardY = () => {
42
63
  }
43
64
  target.updateWorldMatrix(false, true);
44
65
  };
45
- target.add(sentinel);
66
+ const restoreRotation = () => {
67
+ const saved = savedRotations.pop();
68
+ if (saved !== undefined) {
69
+ target.rotation.y = saved;
70
+ target.updateWorldMatrix(false, true);
71
+ }
72
+ };
73
+ // opaque リスト用 sentinel
74
+ const opaquePreSentinel = new Mesh(SENTINEL_GEOMETRY, OPAQUE_MATERIAL);
75
+ opaquePreSentinel.frustumCulled = false;
76
+ opaquePreSentinel.renderOrder = -Infinity;
77
+ opaquePreSentinel.onBeforeRender = (_r, _s, camera) => applyRotation(camera);
78
+ const opaquePostSentinel = new Mesh(SENTINEL_GEOMETRY, OPAQUE_MATERIAL);
79
+ opaquePostSentinel.frustumCulled = false;
80
+ opaquePostSentinel.renderOrder = Infinity;
81
+ opaquePostSentinel.onBeforeRender = restoreRotation;
82
+ // transparent リスト用 sentinel
83
+ const transparentPreSentinel = new Mesh(SENTINEL_GEOMETRY, TRANSPARENT_MATERIAL);
84
+ transparentPreSentinel.frustumCulled = false;
85
+ transparentPreSentinel.renderOrder = -Infinity;
86
+ transparentPreSentinel.onBeforeRender = (_r, _s, camera) => applyRotation(camera);
87
+ const transparentPostSentinel = new Mesh(SENTINEL_GEOMETRY, TRANSPARENT_MATERIAL);
88
+ transparentPostSentinel.frustumCulled = false;
89
+ transparentPostSentinel.renderOrder = Infinity;
90
+ transparentPostSentinel.onBeforeRender = restoreRotation;
91
+ const sentinels = [
92
+ opaquePreSentinel,
93
+ opaquePostSentinel,
94
+ transparentPreSentinel,
95
+ transparentPostSentinel,
96
+ ];
97
+ for (const s of sentinels)
98
+ target.add(s);
46
99
  return () => {
47
- sentinel.onBeforeRender = () => { };
48
- target.remove(sentinel);
100
+ for (const s of sentinels) {
101
+ s.onBeforeRender = () => { };
102
+ target.remove(s);
103
+ }
49
104
  };
50
105
  }, []);
51
106
  return ref;
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../src/components/BillboardY/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EACL,WAAW,EACX,KAAK,EACL,IAAI,EACJ,iBAAiB,EAEjB,UAAU,EAEV,OAAO,GACR,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAE/C,MAAM,eAAe,GAAG,IAAI,OAAO,EAAE,CAAA;AACrC,MAAM,eAAe,GAAG,IAAI,OAAO,EAAE,CAAA;AACrC,MAAM,WAAW,GAAG,IAAI,UAAU,EAAE,CAAA;AACpC,MAAM,MAAM,GAAG,IAAI,KAAK,EAAE,CAAA;AAE1B,MAAM,iBAAiB,GAAG,IAAI,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAA;AAC9D,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,CAAC;IAC9C,UAAU,EAAE,KAAK;IACjB,UAAU,EAAE,KAAK;IACjB,SAAS,EAAE,KAAK;CACjB,CAAC,CAAA;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,GAAuB,EAAE;IACpD,MAAM,GAAG,GAAG,MAAM,CAAI,IAAI,CAAC,CAAA;IAE3B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,GAAG,CAAC,OAAO;YAAE,OAAM;QAExB,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAA;QAE1B,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAAA;QAC/D,QAAQ,CAAC,aAAa,GAAG,KAAK,CAAA;QAC9B,QAAQ,CAAC,WAAW,GAAG,CAAC,QAAQ,CAAA;QAEhC,QAAQ,CAAC,cAAc,GAAG,CACxB,SAAkB,EAClB,MAAe,EACf,MAAc,EACd,EAAE;YACF,MAAM,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAA;YACxC,MAAM,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAA;YAExC,MAAM,cAAc,GAAG,qBAAqB,CAC1C,eAAe,EACf,eAAe,CAChB,CAAA;YAED,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAClB,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAA;gBAC7C,MAAM,CAAC,iBAAiB,CAAC,WAAW,EAAE,KAAK,CAAC,CAAA;gBAC5C,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,cAAc,GAAG,MAAM,CAAC,CAAC,CAAA;YAC/C,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,cAAc,CAAA;YACpC,CAAC;YAED,MAAM,CAAC,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QACvC,CAAC,CAAA;QAED,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAEpB,OAAO,GAAG,EAAE;YACV,QAAQ,CAAC,cAAc,GAAG,GAAG,EAAE,GAAE,CAAC,CAAA;YAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACzB,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA"}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../src/components/BillboardY/hooks.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xrift/world-components",
3
- "version": "0.30.3",
3
+ "version": "0.30.5",
4
4
  "description": "Shared components and utilities for Xrift worlds",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",