webgpu-computed 0.0.6 → 0.0.8

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.
package/package.json CHANGED
@@ -1,17 +1,23 @@
1
1
  {
2
2
  "name": "webgpu-computed",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "对webgpu的封装,处理了繁琐的前置工作,只关注wgsl本身逻辑",
5
5
  "main": "./src/index.js",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1"
8
8
  },
9
- "keywords": [
10
- "webgpu", "computed", "web", "js"
11
- ],
9
+ "keywords": ["webgpu", "gpu", "compute", "wgsl", "typescript", "javascript"],
12
10
  "dependencies": {
13
11
  "webgpu": "^0.3.8"
14
12
  },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/xiaguochuqiu/webgpu-computed.git"
16
+ },
17
+ "bugs": {
18
+ "url": "https://github.com/xiaguochuqiu/webgpu-computed/issues"
19
+ },
20
+ "homepage": "https://github.com/xiaguochuqiu/webgpu-computed#readme",
15
21
  "author": "夏过初秋",
16
22
  "license": "ISC"
17
23
  }
@@ -0,0 +1,2 @@
1
+ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
2
+ export default _default;
package/src/build.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { GpuComputed } from './utils/GpuComputed';
2
+ import * as WGSL_Fun from "./utils/WGSL_Fun";
3
+ export { GpuComputed, WGSL_Fun };
package/src/index.js CHANGED
@@ -1,237 +1,371 @@
1
- async function P(v, r = !0) {
1
+ async function q(f, e = !0) {
2
2
  if (typeof global < "u" && typeof require < "u")
3
- return require(v);
3
+ return require(f);
4
4
  {
5
- let e = await import(
5
+ let t = await import(
6
6
  /* @vite-ignore */
7
- v
7
+ f
8
8
  );
9
- return r && (e = e.default), e;
9
+ return e && (t = t.default), t;
10
10
  }
11
11
  }
12
- const w = {
12
+ function S(f) {
13
+ return f && f[0].toUpperCase() + f.slice(1);
14
+ }
15
+ function x(f) {
16
+ return O.includes(f);
17
+ }
18
+ function w(f) {
19
+ return f && Array.isArray(f) && f.length ? f.every((e) => e && typeof e == "object" && "name" in e && "type" in e && x(e.type)) : !1;
20
+ }
21
+ function $(f) {
22
+ return f && "layout" in f && w(f.layout);
23
+ }
24
+ function _(f, e) {
25
+ const t = B[e];
26
+ return (t - f % t) % t;
27
+ }
28
+ function P(f, e) {
29
+ return f + (e - f % e) % e;
30
+ }
31
+ function T(f) {
32
+ const e = Object.keys(f), t = e.map((c) => {
33
+ const n = f[c];
34
+ if (Array.isArray(n)) {
35
+ for (const i of ["vec2", "vec3", "vec4", "mat3x3", "mat4x4"])
36
+ if (E[i] === n.length) return i;
37
+ throw new Error(`${c} 不支持的数组长度 ${n.length}`);
38
+ }
39
+ if (typeof n == "number") return "f32";
40
+ throw new Error(`${c} 不支持的类型`);
41
+ });
42
+ if (e.length !== t.length) throw new Error("keys 与 types 长度不一致");
43
+ let a = 0;
44
+ const s = e.map((c, n) => {
45
+ const i = t[n];
46
+ a += _(a, i);
47
+ const u = {
48
+ name: c,
49
+ type: i,
50
+ offset: a,
51
+ size: E[i]
52
+ };
53
+ return a += E[i], u;
54
+ }), r = Math.max(...t.map((c) => B[c]));
55
+ return {
56
+ stride: a + (r - a % r) % r,
57
+ layout: s
58
+ };
59
+ }
60
+ const E = {
13
61
  f32: 1,
14
62
  vec2: 2,
15
63
  vec3: 3,
16
64
  vec4: 4,
17
65
  mat3x3: 12,
18
66
  mat4x4: 16
19
- }, h = {
67
+ // array: Infinity
68
+ }, B = {
20
69
  f32: 1,
21
70
  vec2: 2,
22
71
  vec3: 4,
23
72
  vec4: 4,
24
73
  mat3x3: 4,
25
74
  mat4x4: 4
26
- };
27
- function B(v, r) {
28
- const e = h[r];
29
- return (e - v % e) % e;
30
- }
31
- let y = null, m = null;
32
- class A {
33
- constructor() {
75
+ // array: 1
76
+ }, O = ["f32", "vec2", "vec3", "vec4", "mat3x3", "mat4x4"];
77
+ let g = null, b = null;
78
+ class z {
79
+ template;
80
+ option;
81
+ pipeline;
82
+ device;
83
+ groupLayout;
84
+ code;
85
+ constructor(e, t) {
86
+ this.template = e, this.option = t, this.improveTemplateOption(this.template);
34
87
  }
35
- static async init() {
36
- if (!(y && m)) {
37
- if (typeof globalThis < "u" && typeof window > "u") {
38
- const { create: r, globals: e } = await P("webgpu", !1);
39
- Object.assign(globalThis, e), globalThis.navigator || (globalThis.navigator = {}), Object.assign(globalThis.navigator, { gpu: r([]) });
40
- }
41
- if (!navigator.gpu) throw new Error("该环境不支持webgpu");
42
- if (y || (y = await navigator.gpu.requestAdapter({})), !y) throw new Error("获取适配器失败");
43
- if (m = await y.requestDevice(), !y) throw new Error("获取设备失败");
44
- }
45
- }
46
- static destroy() {
47
- m && m.destroy(), m = null;
88
+ /** 完善模版数据
89
+ * @param template
90
+ */
91
+ improveTemplateOption(e) {
92
+ const t = (r) => {
93
+ let o = 0;
94
+ r.forEach((c) => {
95
+ o += _(o, c.type), c.offset = o, c.size = E[c.type], o += c.size;
96
+ });
97
+ }, a = (r) => {
98
+ t(r.layout);
99
+ const o = r.layout[r.layout.length - 1], c = o.offset + o.size;
100
+ let n = 1;
101
+ for (const i of r.layout) n = Math.max(n, B[i.type]);
102
+ r.stride = P(c, n);
103
+ };
104
+ Object.keys(e).forEach((r) => {
105
+ const o = e[r];
106
+ w(o) ? t(o) : $(o) && a(o);
107
+ });
48
108
  }
109
+ /** 获取Gpu设备
110
+ * @returns
111
+ */
49
112
  async getDevice() {
50
- if (!y || !m) throw new Error("webgpu未初始化或不可用");
51
- return { adapter: y, device: m };
113
+ if (!g || !b) throw new Error("webgpu未初始化或不可用");
114
+ return { adapter: g, device: b };
52
115
  }
53
- async createPipeline(r, e) {
54
- const { device: o } = await this.getDevice(), a = Object.keys(e).map((f, s) => {
55
- const i = e[f], u = new Float32Array(Array.isArray(i) ? i : i.buffer), t = o.createBuffer({
56
- size: u.byteLength,
57
- usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE
58
- });
59
- return o.queue.writeBuffer(t, 0, u), {
60
- name: f,
61
- buffer: t,
62
- float32Array: u,
63
- groupLayoutItem: {
64
- binding: s,
65
- // 绑定到组里的0号位插槽
66
- visibility: GPUShaderStage.COMPUTE,
67
- // 数据在哪些阶段可以使用, 计算着色器、片元着色器、顶点着色器
68
- buffer: {
69
- type: "storage"
70
- }
71
- },
72
- groupItem: {
73
- binding: s,
74
- resource: { buffer: t }
116
+ /**
117
+ * 初始化计算管线
118
+ */
119
+ async initPipeline() {
120
+ if (!this.template) throw new Error("初始化计算管线错误,未找到可用数据模版");
121
+ await z.init();
122
+ const e = this.template, { device: t } = await this.getDevice(), a = [], s = [], r = [];
123
+ this.device = t, Object.keys(e).forEach((p, d) => {
124
+ if (r.push({
125
+ binding: d,
126
+ // 绑定到组里的0号位插槽
127
+ visibility: GPUShaderStage.COMPUTE,
128
+ // 数据在哪些阶段可以使用, 计算着色器、片元着色器、顶点着色器
129
+ buffer: {
130
+ type: "storage"
75
131
  }
76
- };
77
- }), l = o.createBindGroupLayout({
78
- entries: a.map((f) => f.groupLayoutItem)
79
- }), g = o.createBindGroup({
80
- layout: l,
81
- entries: a.map((f) => f.groupItem)
132
+ }), w(e[p])) {
133
+ const v = e[p], A = v.map((h) => `${h.name}:${h.type === "f32" ? "f32" : h.type + "<f32>"}`).join(","), m = `${S(p)}Struct`;
134
+ a.push(`struct ${S(p)}Struct {${A}};`), s.push(`@group(0) @binding(${d}) var<storage, read_write> ${p}: ${m};`);
135
+ } else if ($(e[p])) {
136
+ const v = e[p], A = v.layout.map((h) => `${h.name}:${h.type === "f32" ? "f32" : h.type + "<f32>"}`).join(","), m = `${S(p)}Struct`;
137
+ a.push(`struct ${m} {${A}};`), s.push(`@group(0) @binding(${d}) var<storage, read_write> ${p}: array<${m}>;`);
138
+ } else
139
+ s.push(`@group(0) @binding(${d}) var<storage, read_write> ${p}: array<f32>;`);
82
140
  });
83
- return { pipeline: o.createComputePipeline({
84
- layout: o.createPipelineLayout({
85
- bindGroupLayouts: [l]
86
- }),
87
- compute: {
88
- module: o.createShaderModule({ code: r, label: "" }),
89
- entryPoint: "main"
90
- }
91
- }), group: g, device: o, bufferInfoList: a };
92
- }
93
- buildCode(r, e, o) {
94
141
  const {
95
- workgroupSize: a = [32, 1, 1],
96
- globalInvocationIdName: l = "grid",
97
- workgroupIndexName: g = "index"
98
- } = o ?? {}, d = (t) => t && t[0].toUpperCase() + t.slice(1), f = Object.keys(r).map((t) => {
99
- const p = r[t];
100
- return Array.isArray(p) ? void 0 : `struct ${d(t)}Struct { ${p.layout.map((n) => `${n.name}: ${n.type === "f32" ? "f32" : `${n.type}<f32>`}`).join(",")} };`;
101
- }).filter((t) => !!t).join(`
102
- `), s = Object.keys(r).map((t, p) => {
103
- const c = r[t], n = "read_write";
104
- return Array.isArray(c) ? `@group(0) @binding(${p}) var<storage, ${n}> ${t}: array<f32>;` : `@group(0) @binding(${p}) var<storage, ${n}> ${t}: array<${d(t)}Struct>;`;
105
- }).join(`
106
- `), i = l;
107
- return (
142
+ beforeCodes: o = [],
143
+ workgroupSize: c = [32, 1, 1],
144
+ globalInvocationIdName: n = "grid",
145
+ workgroupIndexName: i = "index",
146
+ code: u = ""
147
+ } = this.option ?? {}, l = (
108
148
  /*wgsl*/
109
149
  `
110
- ${f}
111
- ${s}
112
-
113
- ${o?.beforeCodes?.join(" ") ?? ""}
150
+ ${a.join("")}
151
+ ${s.join("")}
152
+ ${o.join(" ") ?? ""}
114
153
 
115
- @compute @workgroup_size(${a.join(",")})
116
- fn main(@builtin(global_invocation_id) ${i}: vec3<u32>) {
117
- var ${g} = ${i}.x;
118
- ${e}
154
+ @compute @workgroup_size(${c.join(",")})
155
+ fn main(@builtin(global_invocation_id) ${n}: vec3<u32>) {
156
+ var ${i} = ${n}.x;
157
+ ${u}
119
158
  }
120
159
  `
121
160
  );
161
+ this.code = l;
162
+ const y = t.createBindGroupLayout({
163
+ entries: r
164
+ });
165
+ this.groupLayout = y, this.pipeline = t.createComputePipeline({
166
+ layout: t.createPipelineLayout({
167
+ bindGroupLayouts: [y]
168
+ }),
169
+ compute: {
170
+ module: t.createShaderModule({ code: l, label: "" }),
171
+ entryPoint: "main"
172
+ }
173
+ });
122
174
  }
123
- buildBuffer(r, e, o) {
124
- if (!Array.isArray(r) || r.length === 0)
125
- throw new Error("数据必须是非空数组");
126
- if (e || (e = Object.keys(r[0])), o || (o = e.map((s) => {
127
- const i = r[0][s];
128
- if (Array.isArray(i)) {
129
- for (const u of ["vec2", "vec3", "vec4", "mat3x3", "mat4x4"])
130
- if (w[u] === i.length) return u;
131
- throw new Error(`${s} 不支持的数组长度 ${i.length}`);
175
+ /** 根据数据创建buffer组
176
+ * @param data
177
+ */
178
+ createBindGroup(e) {
179
+ if (!this.template) throw new Error("创建buffer组错误,未找到可用数据模版");
180
+ if (!this.device) throw new Error("创建buffer组错误,未找到可用的gpu设备,请确保初始化完计算管线");
181
+ const t = this.device, a = this.template, s = [];
182
+ function r(n, i, u = 0, l) {
183
+ if (!l) {
184
+ const y = i[i.length - 1], p = y.offset + y.size;
185
+ let d = 1;
186
+ for (const v of i) d = Math.max(d, B[v.type]);
187
+ l = l ?? new Array(P(p, d)).fill(0);
132
188
  }
133
- if (typeof i == "number") return "f32";
134
- throw new Error(`${s} 不支持的类型`);
135
- })), e.length !== o.length) throw new Error("keys types 长度不一致");
136
- let a = 0;
137
- const l = e.map((s, i) => {
138
- const u = o[i];
139
- a += B(a, u);
140
- const t = {
141
- name: s,
142
- type: u,
143
- offset: a,
144
- size: w[u]
145
- };
146
- return a += w[u], t;
147
- }), g = Math.max(...o.map((s) => h[s])), d = a + (g - a % g) % g, f = new Array(d * r.length).fill(0);
148
- return r.forEach((s, i) => {
149
- const u = i * d;
150
- l.forEach(({ name: t, offset: p, size: c }) => {
151
- let n = s[t];
152
- Array.isArray(n) || (n = [n]);
153
- for (let b = 0; b < c; b++)
154
- f[u + p + b] = Number(n[b] ?? 0);
189
+ return i.forEach((y) => {
190
+ let p = n[y.name];
191
+ Array.isArray(p) || (p = [p]);
192
+ for (let d = 0; d < y.size; d++)
193
+ l[u + y.offset + d] = Number(p[d] ?? 0);
194
+ }), l;
195
+ }
196
+ function o(n, i) {
197
+ const u = new Array(i.stride * n.length).fill(0);
198
+ return n.forEach((l, y) => {
199
+ const p = y * i.stride;
200
+ r(l, i.layout, p, u);
201
+ }), u;
202
+ }
203
+ return Object.keys(a).forEach((n) => {
204
+ if (!(n in e)) throw new Error(`传入的数据中,不存在${n}字段`);
205
+ const i = a[n], u = e[n];
206
+ let l = [];
207
+ w(i) ? l = r(u, i) : $(i) ? l = o(u, i) : Array.isArray(u) && l.push(...u);
208
+ const y = new Float32Array(l), p = t.createBuffer({
209
+ size: y.byteLength,
210
+ usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE
155
211
  });
212
+ t.queue.writeBuffer(p, 0, y), s.push({ name: n, buffer: p });
156
213
  }), {
157
- buffer: f,
158
- stride: d,
159
- layout: l,
160
- count: r.length
214
+ group: t.createBindGroup({
215
+ layout: this.groupLayout,
216
+ entries: s.map((n, i) => ({
217
+ binding: i,
218
+ resource: { buffer: n.buffer }
219
+ }))
220
+ }),
221
+ buffers: s
161
222
  };
162
223
  }
163
- async computed(r) {
164
- let { code: e, data: o, ...a } = r;
165
- const l = Object.keys(o).reduce((c, n) => {
166
- const b = o[n];
167
- if (typeof b[0] == "number") c[n] = b;
168
- else {
169
- const $ = this.buildBuffer(b);
170
- c[n] = $;
224
+ /** 数据映射回模版数据
225
+ * @param array
226
+ * @param key
227
+ */
228
+ dataMap(e, t) {
229
+ if (!(t in this.template)) throw new Error("未找到数据字段:" + t);
230
+ if ($(this.template[t])) {
231
+ const a = this.template[t], s = e.length / a.stride, r = [];
232
+ for (let o = 0; o < s; o++) {
233
+ const c = o * a.stride, n = {};
234
+ a.layout.forEach((i) => {
235
+ const u = e.slice(c + i.offset, c + i.offset + i.size);
236
+ n[i.name] = u.length === 1 ? u[0] : u;
237
+ }), r.push(n);
171
238
  }
172
- return c;
173
- }, {});
174
- e = this.buildCode(l, e, a);
175
- const { pipeline: g, group: d, device: f, bufferInfoList: s } = await this.createPipeline(e, l), i = f.createCommandEncoder(), u = i.beginComputePass();
176
- u.setPipeline(g), u.setBindGroup(0, d), u.dispatchWorkgroups(a.workgroupCount[0], a.workgroupCount[1], a.workgroupCount[2]), u.end();
177
- const t = s?.map((c) => {
178
- if (a.synchronize?.includes(c.name)) {
179
- const n = f.createBuffer({
180
- size: c.float32Array.byteLength,
239
+ return r;
240
+ }
241
+ if (w(this.template[t])) {
242
+ const a = this.template[t], s = {};
243
+ return a.forEach((r) => {
244
+ const o = e.slice(r.offset, r.offset + r.size);
245
+ s[r.name] = o.length === 1 ? o[0] : o;
246
+ }), s;
247
+ }
248
+ return e;
249
+ }
250
+ /** 开始计算
251
+ * @param group 数据组
252
+ * @param workgroupCount 工作组大小
253
+ * @param synchronize 需要同步的数据字段
254
+ * @returns
255
+ */
256
+ async computed(e, t, a) {
257
+ if (!this.pipeline) throw new Error("未找到可用计算管线,请确保计算管线已经创建成功");
258
+ const s = this.device, r = this.pipeline, o = s.createCommandEncoder(), c = o.beginComputePass();
259
+ c.setPipeline(r), c.setBindGroup(0, e.group), c.dispatchWorkgroups(t[0], t[1], t[2]), c.end();
260
+ const n = e.buffers?.map((u) => {
261
+ if (a?.includes(u.name)) {
262
+ const l = s.createBuffer({
263
+ size: u.buffer.size,
181
264
  usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST
182
265
  });
183
- return i.copyBufferToBuffer(c.buffer, 0, n, 0, n.size), { buffer: n, name: c.name };
266
+ return o.copyBufferToBuffer(u.buffer, 0, l, 0, l.size), { buffer: l, name: u.name };
184
267
  }
185
- }).filter((c) => !!c);
186
- f.queue.submit([i.finish()]), await f.queue.onSubmittedWorkDone();
187
- const p = await Promise.all(
188
- t.map(async (c) => {
189
- await c.buffer.mapAsync(GPUMapMode.READ);
190
- const n = c.buffer.getMappedRange();
191
- return [...new Float32Array(n)];
268
+ }).filter((u) => !!u);
269
+ return s.queue.submit([o.finish()]), await s.queue.onSubmittedWorkDone(), await Promise.all(
270
+ n.map(async (u) => {
271
+ await u.buffer.mapAsync(GPUMapMode.READ);
272
+ const l = u.buffer.getMappedRange();
273
+ return [...new Float32Array(l)];
192
274
  })
193
275
  );
194
- return a?.onSuccess && a.onSuccess({ code: e, bufferInfoList: s, results: p }), p;
195
276
  }
196
- static instance;
197
- static get computed() {
198
- return this.instance || (this.instance = new A()), this.instance.computed.bind(this.instance);
277
+ /** 初始化gpu设备
278
+ * @returns
279
+ */
280
+ static async init() {
281
+ if (!(g && b)) {
282
+ if (typeof globalThis < "u" && typeof window > "u") {
283
+ const { create: e, globals: t } = await q("webgpu", !1);
284
+ Object.assign(globalThis, t), globalThis.navigator || (globalThis.navigator = {}), Object.assign(globalThis.navigator, { gpu: e([]) });
285
+ }
286
+ if (!navigator.gpu) throw new Error("该环境不支持webgpu");
287
+ if (g || (g = await navigator.gpu.requestAdapter({})), !g) throw new Error("获取适配器失败");
288
+ if (b = await g.requestDevice(), !g) throw new Error("获取设备失败");
289
+ }
290
+ }
291
+ /** 注销gpu设备
292
+ */
293
+ static destroy() {
294
+ b && b.destroy(), b = null;
295
+ }
296
+ /**
297
+ * @param data
298
+ */
299
+ static buildBufferTypeByData(e) {
300
+ return Object.keys(e).reduce((a, s) => {
301
+ const r = e[s];
302
+ if (Array.isArray(r))
303
+ if (typeof r[0] == "number") a[s] = [];
304
+ else if (typeof r[0] == "object" || r.length) {
305
+ const o = T(r[0]);
306
+ a[s] = o;
307
+ } else console.log(`字段:${s}, 不支持该值对应数据类型或数组为空`);
308
+ else if (typeof r == "object") {
309
+ const o = T(r);
310
+ a[s] = o.layout;
311
+ } else console.log(`字段:${s}, 不支持的数据类型`);
312
+ return a;
313
+ }, {});
314
+ }
315
+ /** 通过数据创建
316
+ * @param opt
317
+ * @returns
318
+ */
319
+ static async fromByData(e) {
320
+ let { data: t, ...a } = e;
321
+ const s = this.buildBufferTypeByData(t), r = new z(s, a);
322
+ return await r.initPipeline(), r;
323
+ }
324
+ /** 快捷计算方法
325
+ * @param opt
326
+ * @returns
327
+ */
328
+ static async computed(e) {
329
+ let { data: t, map: a = !1, workgroupCount: s, synchronize: r, onSuccess: o, ...c } = e;
330
+ const n = await this.fromByData({ data: t, ...c }), i = n.createBindGroup(t), u = await n.computed(i, s, r);
331
+ return o && o({ gpuComputed: n, group: i, results: u }), a ? u.map((l, y) => n.dataMap(l, r[y])) : u;
199
332
  }
200
333
  }
201
- const q = Object.freeze({
202
- quat_rotate: (
203
- /* wgsl */
204
- `
205
- fn quat_rotate(q: vec4<f32>, v: vec3<f32>) -> vec3<f32> {
206
- // q.xyz = vector part, q.w = scalar part
207
- let t = 2.0 * cross(q.xyz, v);
208
- return v + q.w * t + cross(q.xyz, t);
209
- }
210
- `
211
- ),
212
- point_in_obb: (
213
- /* wgsl */
214
- `
215
- fn point_in_obb(
216
- point: vec3<f32>,
217
- center: vec3<f32>,
218
- halfSize: vec3<f32>,
219
- quat: vec4<f32>
220
- ) -> bool {
221
- // 世界空间 → OBB 局部空间
222
- let local = point - center;
334
+ const j = (
335
+ /* wgsl */
336
+ `
337
+ fn quat_rotate(q: vec4<f32>, v: vec3<f32>) -> vec3<f32> {
338
+ // q.xyz = vector part, q.w = scalar part
339
+ let t = 2.0 * cross(q.xyz, v);
340
+ return v + q.w * t + cross(q.xyz, t);
341
+ }
342
+ `
343
+ ), D = (
344
+ /* wgsl */
345
+ `
346
+ fn point_in_obb(
347
+ point: vec3<f32>,
348
+ center: vec3<f32>,
349
+ halfSize: vec3<f32>,
350
+ quat: vec4<f32>
351
+ ) -> bool {
352
+ // 世界空间 → OBB 局部空间
353
+ let local = point - center;
223
354
 
224
- // 逆旋转(共轭四元数)
225
- let invQuat = vec4<f32>(-quat.xyz, quat.w);
226
- let pLocal = quat_rotate(invQuat, local);
355
+ // 逆旋转(共轭四元数)
356
+ let invQuat = vec4<f32>(-quat.xyz, quat.w);
357
+ let pLocal = quat_rotate(invQuat, local);
227
358
 
228
- // AABB 判断
229
- return all(abs(pLocal) <= halfSize);
230
- }
231
- `
232
- )
233
- });
359
+ // AABB 判断
360
+ return all(abs(pLocal) <= halfSize);
361
+ }
362
+ `
363
+ ), G = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
364
+ __proto__: null,
365
+ point_in_obb: D,
366
+ quat_rotate: j
367
+ }, Symbol.toStringTag, { value: "Module" }));
234
368
  export {
235
- A as GpuComputed,
236
- q as WGSL_Fun
369
+ z as GpuComputed,
370
+ G as WGSL_Fun
237
371
  };
package/src/main.d.ts ADDED
File without changes
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ import { App } from 'vue';
2
+ export declare function useRouter(app: App): void;