@holoscript/core 7.0.0 → 8.0.0
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/README.md +2 -2
- package/bin/holoscript.cjs +3 -0
- package/dist/GLTFPipeline-276GE64O.js +16 -0
- package/dist/GLTFPipeline-M7WSSJED.cjs +37 -0
- package/dist/HoloScriptPlusParser-7FBIFUFC.js +693 -0
- package/dist/HoloScriptPlusParser-A2W7OCN2.cjs +698 -0
- package/dist/HoloScriptPlusParser-F2Z56FJR.js +10 -0
- package/dist/HoloScriptPlusParser-WKHRIH6T.cjs +27 -0
- package/dist/HoloScriptRuntime-3URVTKPJ.js +10 -0
- package/dist/HoloScriptRuntime-SXEAEU2N.cjs +19 -0
- package/dist/USDZExporter-3FWJ25JI.cjs +1037 -0
- package/dist/USDZExporter-D2HQLQYK.js +1035 -0
- package/dist/agents/index.cjs +19 -0
- package/dist/agents/index.d.ts +100 -0
- package/dist/agents/index.js +17 -0
- package/dist/chunk-23J755AR.js +1046 -0
- package/dist/chunk-253GBQZY.cjs +627 -0
- package/dist/chunk-25IQCHTO.cjs +781 -0
- package/dist/chunk-2BSMSUCE.js +1941 -0
- package/dist/chunk-2M2DPHKB.js +762 -0
- package/dist/chunk-2YSNA2F2.cjs +1274 -0
- package/dist/chunk-3AO425MZ.cjs +886 -0
- package/dist/chunk-3FOKASKO.cjs +348 -0
- package/dist/chunk-3HYYMEXI.cjs +56578 -0
- package/dist/chunk-3NFFOWGG.js +4287 -0
- package/dist/chunk-3WZEJHUQ.cjs +116 -0
- package/dist/chunk-4C57PR42.js +468 -0
- package/dist/chunk-4N4SXXWF.js +769 -0
- package/dist/chunk-4PDEPEQW.cjs +41 -0
- package/dist/chunk-4R6SBXDB.js +45 -0
- package/dist/chunk-4V2E7U7Q.cjs +2015 -0
- package/dist/chunk-5FSKKMR7.cjs +2092 -0
- package/dist/chunk-5GLCTO44.js +161 -0
- package/dist/chunk-5JEU52DW.js +382 -0
- package/dist/chunk-5S7RKFGR.cjs +446 -0
- package/dist/chunk-5WUNN6ZN.cjs +428 -0
- package/dist/chunk-62FBK3B7.js +70 -0
- package/dist/chunk-6CTRH7HT.cjs +1985 -0
- package/dist/chunk-6DPSFNJB.cjs +847 -0
- package/dist/chunk-6EX3I5P4.cjs +130 -0
- package/dist/chunk-73FELZVJ.cjs +611 -0
- package/dist/chunk-7CUEMLDZ.cjs +6445 -0
- package/dist/chunk-7HIASF7S.cjs +814 -0
- package/dist/chunk-A6KINLZJ.js +236 -0
- package/dist/chunk-AIA52I7T.cjs +543 -0
- package/dist/chunk-ANXZFVY2.js +113 -0
- package/dist/chunk-AYBXB26F.js +2176 -0
- package/dist/chunk-B4TFTDG4.js +449 -0
- package/dist/chunk-BE4UJCQT.js +623 -0
- package/dist/chunk-BRQJKJGT.cjs +20 -0
- package/dist/chunk-C2A5DUMF.cjs +689 -0
- package/dist/chunk-C37BHB7N.cjs +636 -0
- package/dist/chunk-CBJY23VL.js +126 -0
- package/dist/chunk-CIWWXYHZ.cjs +50 -0
- package/dist/chunk-CXFDRBQU.cjs +672 -0
- package/dist/chunk-D54CNIAJ.cjs +413 -0
- package/dist/chunk-DAJXW4KX.js +725 -0
- package/dist/chunk-DTGBOSEM.cjs +319 -0
- package/dist/chunk-E7JP3BS3.cjs +61 -0
- package/dist/chunk-EKBKLK7P.js +1169 -0
- package/dist/chunk-EKYL4PE3.cjs +404 -0
- package/dist/chunk-EUDQTK7N.cjs +4310 -0
- package/dist/chunk-EXKSFGSX.cjs +274 -0
- package/dist/chunk-EXUP2BUM.cjs +1173 -0
- package/dist/chunk-F43YAA34.js +623 -0
- package/dist/chunk-FDSGHPAK.js +130 -0
- package/dist/chunk-FEWUHQNM.cjs +144 -0
- package/dist/chunk-FGGJQRLZ.js +270 -0
- package/dist/chunk-FHP6LXJS.js +415 -0
- package/dist/chunk-FJPADH77.cjs +666 -0
- package/dist/chunk-FYSPZT4V.cjs +169 -0
- package/dist/chunk-GIOYPNTH.js +5575 -0
- package/dist/chunk-GJNCFRJU.cjs +125 -0
- package/dist/chunk-GMP623FG.cjs +1508 -0
- package/dist/chunk-GQHQOPXZ.cjs +5580 -0
- package/dist/chunk-GQT4TYKY.cjs +4381 -0
- package/dist/chunk-GTU2Z2WW.cjs +262 -0
- package/dist/chunk-GYZE55MO.js +2007 -0
- package/dist/chunk-GZG4KA4E.js +529 -0
- package/dist/chunk-H652NHX5.js +600 -0
- package/dist/chunk-HCCQLAA4.cjs +74 -0
- package/dist/chunk-HINXWAOD.cjs +1049 -0
- package/dist/chunk-HYNTS5CP.js +422 -0
- package/dist/chunk-HZSPDCXV.cjs +457 -0
- package/dist/chunk-HZTDET3N.js +1399 -0
- package/dist/chunk-I6XZ5DZF.cjs +488 -0
- package/dist/chunk-ILRBGFVD.cjs +72 -0
- package/dist/chunk-IPWSXCCN.js +1183 -0
- package/dist/chunk-IUTY5WQ2.cjs +424 -0
- package/dist/chunk-IVSZDECV.js +882 -0
- package/dist/chunk-IVY74O6C.js +247 -0
- package/dist/chunk-IZM5VQZD.js +714 -0
- package/dist/chunk-J32ZJZJH.js +554 -0
- package/dist/chunk-J6M4FPK5.js +421 -0
- package/dist/chunk-JC5YBPSF.cjs +984 -0
- package/dist/chunk-JCLBKPMX.js +3813 -0
- package/dist/chunk-JD7CIZ33.js +1949 -0
- package/dist/chunk-JIYN45TV.cjs +2525 -0
- package/dist/chunk-JJBE3TIH.cjs +1189 -0
- package/dist/chunk-JX7YL6ZE.js +2252 -0
- package/dist/chunk-K4VVR7CN.cjs +2433 -0
- package/dist/chunk-KEFNV2WM.cjs +2257 -0
- package/dist/chunk-KH4CNH66.cjs +424 -0
- package/dist/chunk-KJLB4OPV.js +5731 -0
- package/dist/chunk-KKFZ3B6J.cjs +557 -0
- package/dist/chunk-KKP7JKN4.cjs +6002 -0
- package/dist/chunk-KPJL34Y7.cjs +186 -0
- package/dist/chunk-KQCN6AKJ.cjs +3042 -0
- package/dist/chunk-KVRSTFNH.cjs +72 -0
- package/dist/chunk-LICPB5HZ.cjs +1409 -0
- package/dist/chunk-LM2VU56C.cjs +37 -0
- package/dist/chunk-M56JSP4A.js +400 -0
- package/dist/chunk-MBOOR7X4.js +18 -0
- package/dist/chunk-MGE5Z4GS.js +608 -0
- package/dist/chunk-MXFUTKCO.js +56 -0
- package/dist/chunk-MYY4PMWX.cjs +264 -0
- package/dist/chunk-N75IH2HY.js +258 -0
- package/dist/chunk-NBMHU6SW.js +669 -0
- package/dist/chunk-NG77ATEW.cjs +778 -0
- package/dist/chunk-NGKREZ36.js +6384 -0
- package/dist/chunk-NHWSN2SD.cjs +718 -0
- package/dist/chunk-NV4VMVXU.js +421 -0
- package/dist/chunk-NW5G5FBQ.js +215 -0
- package/dist/chunk-NXZFOPVD.cjs +5737 -0
- package/dist/chunk-OBIYPYYS.cjs +1993 -0
- package/dist/chunk-OIQYIIO3.cjs +473 -0
- package/dist/chunk-OL46QLBJ.js +61 -0
- package/dist/chunk-OMXII44L.js +5386 -0
- package/dist/chunk-OR4Q2BGL.cjs +759 -0
- package/dist/chunk-OSYNRVOV.cjs +243 -0
- package/dist/chunk-PGANYCAG.cjs +220 -0
- package/dist/chunk-PHENW4MQ.js +65 -0
- package/dist/chunk-PHVRG4I2.js +844 -0
- package/dist/chunk-Q56TT7IL.js +483 -0
- package/dist/chunk-QPOQ7VPI.js +1491 -0
- package/dist/chunk-QPSKHBJP.js +5963 -0
- package/dist/chunk-QXH7QDSZ.js +1989 -0
- package/dist/chunk-R75BSDH7.cjs +50 -0
- package/dist/chunk-RARB3MBR.js +207 -0
- package/dist/chunk-RVBHAXFG.js +56160 -0
- package/dist/chunk-S3MDHNKB.cjs +490 -0
- package/dist/chunk-S4W6Z2MN.js +2426 -0
- package/dist/chunk-S6YWHCKV.cjs +410 -0
- package/dist/chunk-SIEXCILW.js +229 -0
- package/dist/chunk-SJBGLS25.cjs +2196 -0
- package/dist/chunk-SLU6UPJI.cjs +410 -0
- package/dist/chunk-SMIWS6DE.cjs +212 -0
- package/dist/chunk-T2QCTZMO.js +811 -0
- package/dist/chunk-T5J7ZKP3.cjs +4885 -0
- package/dist/chunk-TDCNJHWO.js +341 -0
- package/dist/chunk-TG7O4WBC.js +406 -0
- package/dist/chunk-THCK6ECW.js +2085 -0
- package/dist/chunk-TJHVSBP2.js +439 -0
- package/dist/chunk-TVHSPJ4N.cjs +606 -0
- package/dist/chunk-U44IKGG7.cjs +5390 -0
- package/dist/chunk-UJXISJBN.js +487 -0
- package/dist/chunk-UM6C3CGK.js +4375 -0
- package/dist/chunk-UMABK6SI.js +686 -0
- package/dist/chunk-UOIGFQXC.cjs +9750 -0
- package/dist/chunk-URG2SJLK.js +2521 -0
- package/dist/chunk-V6MKC2FZ.js +979 -0
- package/dist/chunk-VECQYRXL.js +474 -0
- package/dist/chunk-VJ3L7CHT.cjs +169 -0
- package/dist/chunk-VMLKSV26.js +1216 -0
- package/dist/chunk-VVKVQZI6.js +55 -0
- package/dist/chunk-W6RW64BB.cjs +1219 -0
- package/dist/chunk-W7VDOASB.cjs +639 -0
- package/dist/chunk-WDT3JTGM.cjs +483 -0
- package/dist/chunk-WJIHFLMJ.js +404 -0
- package/dist/chunk-WKX5AMOY.js +309 -0
- package/dist/chunk-WNNE3PO3.js +34 -0
- package/dist/chunk-WRKUDAZJ.js +3038 -0
- package/dist/chunk-WRLUBRKS.cjs +1943 -0
- package/dist/chunk-WRNEH5MO.js +3169 -0
- package/dist/chunk-WRWEX5ZF.js +658 -0
- package/dist/chunk-X3GJPRVK.cjs +3246 -0
- package/dist/chunk-XHIV6326.cjs +793 -0
- package/dist/chunk-XIVIE43A.cjs +729 -0
- package/dist/chunk-XJAN7CZG.cjs +432 -0
- package/dist/chunk-XKTPFXGA.js +164 -0
- package/dist/chunk-XL6INWKT.js +121 -0
- package/dist/chunk-XSFNHP2E.js +632 -0
- package/dist/chunk-XT6JY5W5.js +9684 -0
- package/dist/chunk-XUILI4KB.cjs +430 -0
- package/dist/chunk-XUUVDHIF.cjs +3962 -0
- package/dist/chunk-YF2I3MV3.js +46 -0
- package/dist/chunk-YIMN575O.js +4847 -0
- package/dist/chunk-YIVFJNYV.js +176 -0
- package/dist/chunk-YKGPCZEE.cjs +237 -0
- package/dist/chunk-YN6V7R3L.cjs +327 -0
- package/dist/chunk-YQELFNJV.js +39 -0
- package/dist/chunk-YYXH45E2.js +426 -0
- package/dist/chunk-ZBQXLH2L.js +756 -0
- package/dist/chunk-ZDSYWBIE.cjs +69 -0
- package/dist/chunk-ZU7NIRT6.js +325 -0
- package/dist/chunk-ZZ7RO2UQ.js +1243 -0
- package/dist/chunk-ZZEI7MV4.js +778 -0
- package/dist/cli/holoscript-runner.cjs +2255 -0
- package/dist/cli/holoscript-runner.js +2230 -0
- package/dist/codebase/index.cjs +336 -0
- package/dist/codebase/index.js +331 -0
- package/dist/compiler/agent-inference.cjs +31 -0
- package/dist/compiler/agent-inference.js +8 -0
- package/dist/compiler/android-xr.cjs +24 -0
- package/dist/compiler/android-xr.js +14 -0
- package/dist/compiler/android.cjs +24 -0
- package/dist/compiler/android.js +14 -0
- package/dist/compiler/ar.cjs +23 -0
- package/dist/compiler/ar.js +11 -0
- package/dist/compiler/babylon.cjs +21 -0
- package/dist/compiler/babylon.js +15 -0
- package/dist/compiler/business-quest.cjs +43 -0
- package/dist/compiler/business-quest.js +4 -0
- package/dist/compiler/coco.cjs +27 -0
- package/dist/compiler/coco.js +4 -0
- package/dist/compiler/context.cjs +25 -0
- package/dist/compiler/context.d.ts +28 -0
- package/dist/compiler/context.js +8 -0
- package/dist/compiler/domain-block-utils.cjs +605 -0
- package/dist/compiler/domain-block-utils.js +11 -0
- package/dist/compiler/dtdl.cjs +27 -0
- package/dist/compiler/dtdl.js +11 -0
- package/dist/compiler/gltf-pipeline.cjs +39 -0
- package/dist/compiler/gltf-pipeline.js +4 -0
- package/dist/compiler/godot.cjs +18 -0
- package/dist/compiler/godot.js +12 -0
- package/dist/compiler/incremental.cjs +34 -0
- package/dist/compiler/incremental.js +9 -0
- package/dist/compiler/index.cjs +5860 -0
- package/dist/compiler/index.d.ts +322 -21
- package/dist/compiler/index.js +5525 -0
- package/dist/compiler/ios.cjs +23 -0
- package/dist/compiler/ios.js +13 -0
- package/dist/compiler/llm-provider-capabilities.cjs +25 -0
- package/dist/compiler/llm-provider-capabilities.d.ts +43 -0
- package/dist/compiler/llm-provider-capabilities.js +8 -0
- package/dist/compiler/multi-layer.cjs +24 -0
- package/dist/compiler/multi-layer.js +15 -0
- package/dist/compiler/nodetoy.cjs +23 -0
- package/dist/compiler/nodetoy.js +4 -0
- package/dist/compiler/openxr.cjs +19 -0
- package/dist/compiler/openxr.js +13 -0
- package/dist/compiler/playcanvas.cjs +19 -0
- package/dist/compiler/playcanvas.js +13 -0
- package/dist/compiler/r3f.cjs +38 -0
- package/dist/compiler/r3f.d.ts +22 -0
- package/dist/compiler/r3f.js +16 -0
- package/dist/compiler/remotion.cjs +23 -0
- package/dist/compiler/remotion.js +4 -0
- package/dist/compiler/reproducibility.cjs +39 -0
- package/dist/compiler/reproducibility.js +4 -0
- package/dist/compiler/sdf.cjs +24 -0
- package/dist/compiler/sdf.js +12 -0
- package/dist/compiler/semantic-scene.cjs +31 -0
- package/dist/compiler/semantic-scene.js +4 -0
- package/dist/compiler/state.cjs +21 -0
- package/dist/compiler/state.js +11 -0
- package/dist/compiler/trait-composition.cjs +30 -0
- package/dist/compiler/trait-composition.js +9 -0
- package/dist/compiler/unity.cjs +19 -0
- package/dist/compiler/unity.js +13 -0
- package/dist/compiler/unreal.cjs +23 -0
- package/dist/compiler/unreal.js +13 -0
- package/dist/compiler/urdf.cjs +52 -0
- package/dist/compiler/urdf.js +12 -0
- package/dist/compiler/usd-physics.cjs +26 -0
- package/dist/compiler/usd-physics.js +9 -0
- package/dist/compiler/visionos.cjs +19 -0
- package/dist/compiler/visionos.js +13 -0
- package/dist/compiler/vrchat.cjs +22 -0
- package/dist/compiler/vrchat.js +12 -0
- package/dist/compiler/vrr.cjs +24 -0
- package/dist/compiler/vrr.js +12 -0
- package/dist/compiler/wasm.cjs +36 -0
- package/dist/compiler/wasm.js +12 -0
- package/dist/compiler/webgpu.cjs +18 -0
- package/dist/compiler/webgpu.js +12 -0
- package/dist/coordinators/index.cjs +1266 -0
- package/dist/coordinators/index.d.ts +72 -1
- package/dist/coordinators/index.js +1259 -0
- package/dist/debugger.cjs +24 -0
- package/dist/debugger.js +11 -0
- package/dist/entries/interop.cjs +64 -0
- package/dist/entries/interop.js +7 -0
- package/dist/entries/scripting.cjs +55 -0
- package/dist/entries/scripting.js +10 -0
- package/dist/hololand/index.cjs +146 -0
- package/dist/hololand/index.d.ts +70 -0
- package/dist/hololand/index.js +5 -0
- package/dist/index.cjs +43233 -0
- package/dist/index.d.ts +976 -21
- package/dist/index.js +39995 -0
- package/dist/math/tropical-spmv.cjs +45 -0
- package/dist/math/tropical-spmv.js +4 -0
- package/dist/math/vec3.cjs +57 -0
- package/dist/math/vec3.js +4 -0
- package/dist/ml-dsa-FSKBTE3W.cjs +1265 -0
- package/dist/ml-dsa-Z7JDKW4L.js +1265 -0
- package/dist/paper-0c-spike/index.cjs +150 -0
- package/dist/paper-0c-spike/index.js +141 -0
- package/dist/parser.cjs +61 -0
- package/dist/parser.d.ts +11 -0
- package/dist/parser.js +12 -0
- package/dist/playwright-3AT3AKTV.cjs +98673 -0
- package/dist/playwright-VZPDVUEQ.js +98660 -0
- package/dist/reconstruction/index.cjs +153 -0
- package/dist/reconstruction/index.d.ts +29 -2
- package/dist/reconstruction/index.js +8 -0
- package/dist/runtime.cjs +316 -0
- package/dist/runtime.d.ts +61 -0
- package/dist/runtime.js +31 -0
- package/dist/self-improvement/index.cjs +563 -0
- package/dist/self-improvement/index.js +545 -0
- package/dist/storage/index.cjs +38 -0
- package/dist/storage/index.js +5 -0
- package/dist/testing.cjs +25 -0
- package/dist/testing.d.ts +70 -0
- package/dist/testing.js +4 -0
- package/dist/traitDocs/traitDocs.cjs +33 -0
- package/dist/traitDocs/traitDocs.js +7 -0
- package/dist/traits/botanical-lotus.cjs +41 -0
- package/dist/traits/botanical-lotus.d.ts +172 -0
- package/dist/traits/botanical-lotus.js +4 -0
- package/dist/traits/engines/index.cjs +520 -0
- package/dist/traits/engines/index.js +380 -0
- package/dist/traits/index.cjs +24409 -0
- package/dist/traits/index.d.ts +171 -35
- package/dist/traits/index.js +21634 -0
- package/dist/traits/simulation-solver-factory.cjs +13 -0
- package/dist/traits/simulation-solver-factory.d.ts +23 -0
- package/dist/traits/simulation-solver-factory.js +4 -0
- package/dist/traits/webcam-gaze.cjs +35 -0
- package/dist/traits/webcam-gaze.d.ts +17 -0
- package/dist/traits/webcam-gaze.js +4 -0
- package/dist/type-checker.cjs +19 -0
- package/dist/type-checker.js +6 -0
- package/dist/world/index.cjs +947 -0
- package/dist/world/index.d.ts +147 -0
- package/dist/world/index.js +939 -0
- package/dist/world-model/index.cjs +1446 -0
- package/dist/world-model/index.d.ts +119 -0
- package/dist/world-model/index.js +1414 -0
- package/dist/wot/index.cjs +29 -0
- package/dist/wot/index.js +4 -0
- package/package.json +93 -49
|
@@ -0,0 +1,1491 @@
|
|
|
1
|
+
import { init_safeJsonParse, jsonClone } from './chunk-VVKVQZI6.js';
|
|
2
|
+
|
|
3
|
+
// src/traits/LightingTrait.ts
|
|
4
|
+
var LightingTrait = class {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.lights = /* @__PURE__ */ new Map();
|
|
7
|
+
this.lightIdCounter = 0;
|
|
8
|
+
this.globalIllumination = {
|
|
9
|
+
enabled: true,
|
|
10
|
+
intensity: 1,
|
|
11
|
+
skyColor: { r: 0.5, g: 0.7, b: 1 },
|
|
12
|
+
skyIntensity: 1,
|
|
13
|
+
groundColor: { r: 0.4, g: 0.4, b: 0.4 },
|
|
14
|
+
groundIntensity: 0.5,
|
|
15
|
+
probes: true,
|
|
16
|
+
indirectDiffuse: 1,
|
|
17
|
+
indirectSpecular: 1,
|
|
18
|
+
aoIntensity: 1,
|
|
19
|
+
screenSpaceAO: true,
|
|
20
|
+
...config
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Add a light to the scene
|
|
25
|
+
*/
|
|
26
|
+
addLight(light) {
|
|
27
|
+
const id = light.name || `light_${this.lightIdCounter++}`;
|
|
28
|
+
this.lights.set(id, light);
|
|
29
|
+
return id;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get light by ID
|
|
33
|
+
*/
|
|
34
|
+
getLight(id) {
|
|
35
|
+
return this.lights.get(id);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get all lights
|
|
39
|
+
*/
|
|
40
|
+
getLights() {
|
|
41
|
+
return Array.from(this.lights.values());
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get lights by type
|
|
45
|
+
*/
|
|
46
|
+
getLightsByType(type) {
|
|
47
|
+
return Array.from(this.lights.values()).filter((l) => l.type === type);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Update light properties
|
|
51
|
+
*/
|
|
52
|
+
updateLight(id, updates) {
|
|
53
|
+
const light = this.lights.get(id);
|
|
54
|
+
if (!light) return false;
|
|
55
|
+
this.lights.set(id, { ...light, ...updates });
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Remove light
|
|
60
|
+
*/
|
|
61
|
+
removeLight(id) {
|
|
62
|
+
return this.lights.delete(id);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Clear all lights
|
|
66
|
+
*/
|
|
67
|
+
clearLights() {
|
|
68
|
+
this.lights.clear();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get global illumination config
|
|
72
|
+
*/
|
|
73
|
+
getGlobalIllumination() {
|
|
74
|
+
return { ...this.globalIllumination };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Update global illumination
|
|
78
|
+
*/
|
|
79
|
+
updateGlobalIllumination(updates) {
|
|
80
|
+
this.globalIllumination = {
|
|
81
|
+
...this.globalIllumination,
|
|
82
|
+
...updates
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Enable/disable GI
|
|
87
|
+
*/
|
|
88
|
+
setGIEnabled(enabled) {
|
|
89
|
+
this.globalIllumination.enabled = enabled;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Set ambient light colors (skybox mode)
|
|
93
|
+
*/
|
|
94
|
+
setAmbientLight(skyColor, groundColor, intensity = 1) {
|
|
95
|
+
this.globalIllumination.skyColor = skyColor;
|
|
96
|
+
this.globalIllumination.groundColor = groundColor;
|
|
97
|
+
this.globalIllumination.skyIntensity = intensity;
|
|
98
|
+
this.globalIllumination.groundIntensity = intensity * 0.5;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Enable/disable screen-space ambient occlusion
|
|
102
|
+
*/
|
|
103
|
+
setScreenSpaceAO(enabled, intensity = 1) {
|
|
104
|
+
this.globalIllumination.screenSpaceAO = enabled;
|
|
105
|
+
this.globalIllumination.aoIntensity = intensity;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Create directional light (sun)
|
|
109
|
+
*/
|
|
110
|
+
createDirectionalLight(direction, color, intensity = 1, castShadows = true) {
|
|
111
|
+
const light = {
|
|
112
|
+
type: "directional",
|
|
113
|
+
name: `sun_${this.lightIdCounter}`,
|
|
114
|
+
direction,
|
|
115
|
+
color,
|
|
116
|
+
intensity,
|
|
117
|
+
shadow: castShadows ? {
|
|
118
|
+
type: "soft",
|
|
119
|
+
resolution: 2048,
|
|
120
|
+
cascades: 4,
|
|
121
|
+
softness: 1
|
|
122
|
+
} : void 0,
|
|
123
|
+
volumetric: true,
|
|
124
|
+
priority: 100
|
|
125
|
+
};
|
|
126
|
+
return this.addLight(light);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Create point light
|
|
130
|
+
*/
|
|
131
|
+
createPointLight(position, color, intensity, range, castShadows = false) {
|
|
132
|
+
const light = {
|
|
133
|
+
type: "point",
|
|
134
|
+
name: `point_${this.lightIdCounter}`,
|
|
135
|
+
position,
|
|
136
|
+
color,
|
|
137
|
+
intensity,
|
|
138
|
+
range,
|
|
139
|
+
shadow: castShadows ? {
|
|
140
|
+
type: "soft",
|
|
141
|
+
resolution: 512,
|
|
142
|
+
softness: 0.5
|
|
143
|
+
} : void 0,
|
|
144
|
+
priority: 50
|
|
145
|
+
};
|
|
146
|
+
return this.addLight(light);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Create spot light
|
|
150
|
+
*/
|
|
151
|
+
createSpotLight(position, direction, color, intensity, range, spotAngle = 45, castShadows = true) {
|
|
152
|
+
const light = {
|
|
153
|
+
type: "spot",
|
|
154
|
+
name: `spot_${this.lightIdCounter}`,
|
|
155
|
+
position,
|
|
156
|
+
direction,
|
|
157
|
+
color,
|
|
158
|
+
intensity,
|
|
159
|
+
range,
|
|
160
|
+
spotAngle,
|
|
161
|
+
innerSpotAngle: spotAngle * 0.5,
|
|
162
|
+
shadow: castShadows ? {
|
|
163
|
+
type: "soft",
|
|
164
|
+
resolution: 1024,
|
|
165
|
+
softness: 0.8
|
|
166
|
+
} : void 0,
|
|
167
|
+
priority: 75
|
|
168
|
+
};
|
|
169
|
+
return this.addLight(light);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Create area light for soft lighting
|
|
173
|
+
*/
|
|
174
|
+
createAreaLight(position, color, intensity, width, height) {
|
|
175
|
+
const light = {
|
|
176
|
+
type: "area",
|
|
177
|
+
name: `area_${this.lightIdCounter}`,
|
|
178
|
+
position,
|
|
179
|
+
color,
|
|
180
|
+
intensity,
|
|
181
|
+
range: Math.max(width, height) * 2,
|
|
182
|
+
priority: 25
|
|
183
|
+
};
|
|
184
|
+
return this.addLight(light);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get shadow-casting lights
|
|
188
|
+
*/
|
|
189
|
+
getShadowCastingLights() {
|
|
190
|
+
return Array.from(this.lights.values()).filter((l) => l.shadow && l.shadow.type !== "none");
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Get light count by type
|
|
194
|
+
*/
|
|
195
|
+
getLightCount() {
|
|
196
|
+
const counts = {
|
|
197
|
+
directional: 0,
|
|
198
|
+
point: 0,
|
|
199
|
+
spot: 0,
|
|
200
|
+
area: 0,
|
|
201
|
+
probe: 0
|
|
202
|
+
};
|
|
203
|
+
for (const light of Array.from(this.lights.values())) {
|
|
204
|
+
counts[light.type]++;
|
|
205
|
+
}
|
|
206
|
+
return counts;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Estimate light impact for performance optimization
|
|
210
|
+
*/
|
|
211
|
+
getPerformanceImpact() {
|
|
212
|
+
const totalLights = this.lights.size;
|
|
213
|
+
const shadowCasters = this.getShadowCastingLights().length;
|
|
214
|
+
let estimatedGPUCost = "low";
|
|
215
|
+
if (totalLights > 16 || shadowCasters > 4) {
|
|
216
|
+
estimatedGPUCost = "high";
|
|
217
|
+
} else if (totalLights > 8 || shadowCasters > 2) {
|
|
218
|
+
estimatedGPUCost = "medium";
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
totalLights,
|
|
222
|
+
shadowCasters,
|
|
223
|
+
estimatedGPUCost
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Get scene complexity info
|
|
228
|
+
*/
|
|
229
|
+
getSceneInfo() {
|
|
230
|
+
const counts = this.getLightCount();
|
|
231
|
+
const impact = this.getPerformanceImpact();
|
|
232
|
+
return `Lighting: ${counts.directional} dir, ${counts.point} point, ${counts.spot} spot | Shadows: ${impact.shadowCasters} | GPU: ${impact.estimatedGPUCost}`;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Dispose and cleanup
|
|
236
|
+
*/
|
|
237
|
+
dispose() {
|
|
238
|
+
this.lights.clear();
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
function createLightingTrait(config) {
|
|
242
|
+
return new LightingTrait(config);
|
|
243
|
+
}
|
|
244
|
+
var LIGHTING_PRESETS = {
|
|
245
|
+
/** Neutral studio lighting */
|
|
246
|
+
studio: () => ({
|
|
247
|
+
enabled: true,
|
|
248
|
+
intensity: 1,
|
|
249
|
+
skyColor: { r: 0.5, g: 0.5, b: 0.5 },
|
|
250
|
+
skyIntensity: 0.5,
|
|
251
|
+
groundColor: { r: 0.3, g: 0.3, b: 0.3 },
|
|
252
|
+
groundIntensity: 0.3
|
|
253
|
+
}),
|
|
254
|
+
/** Bright outdoor lighting */
|
|
255
|
+
outdoor: () => ({
|
|
256
|
+
enabled: true,
|
|
257
|
+
intensity: 1.2,
|
|
258
|
+
skyColor: { r: 0.7, g: 0.85, b: 1 },
|
|
259
|
+
skyIntensity: 1,
|
|
260
|
+
groundColor: { r: 0.4, g: 0.4, b: 0.35 },
|
|
261
|
+
groundIntensity: 0.6,
|
|
262
|
+
indirectDiffuse: 1.2
|
|
263
|
+
}),
|
|
264
|
+
/** Dim interior lighting */
|
|
265
|
+
interior: () => ({
|
|
266
|
+
enabled: true,
|
|
267
|
+
intensity: 0.6,
|
|
268
|
+
skyColor: { r: 0.3, g: 0.3, b: 0.35 },
|
|
269
|
+
skyIntensity: 0.4,
|
|
270
|
+
groundColor: { r: 0.2, g: 0.2, b: 0.2 },
|
|
271
|
+
groundIntensity: 0.2
|
|
272
|
+
}),
|
|
273
|
+
/** Night scene */
|
|
274
|
+
night: () => ({
|
|
275
|
+
enabled: true,
|
|
276
|
+
intensity: 0.3,
|
|
277
|
+
skyColor: { r: 0.01, g: 0.01, b: 0.02 },
|
|
278
|
+
skyIntensity: 0.1,
|
|
279
|
+
groundColor: { r: 0.02, g: 0.02, b: 0.02 },
|
|
280
|
+
groundIntensity: 0.05,
|
|
281
|
+
screenSpaceAO: false
|
|
282
|
+
}),
|
|
283
|
+
/** Sunset/golden hour */
|
|
284
|
+
sunset: () => ({
|
|
285
|
+
enabled: true,
|
|
286
|
+
intensity: 1.1,
|
|
287
|
+
skyColor: { r: 1, g: 0.7, b: 0.3 },
|
|
288
|
+
skyIntensity: 1,
|
|
289
|
+
groundColor: { r: 0.6, g: 0.4, b: 0.2 },
|
|
290
|
+
groundIntensity: 0.8
|
|
291
|
+
})
|
|
292
|
+
};
|
|
293
|
+
var lightingHandler = {
|
|
294
|
+
name: "lighting",
|
|
295
|
+
defaultConfig: {},
|
|
296
|
+
onAttach(node, config, ctx) {
|
|
297
|
+
const instance = new LightingTrait(config);
|
|
298
|
+
node.__lighting_instance = instance;
|
|
299
|
+
ctx.emit("lighting_attached", { node, config });
|
|
300
|
+
},
|
|
301
|
+
onDetach(node, _config, ctx) {
|
|
302
|
+
const instance = node.__lighting_instance;
|
|
303
|
+
if (instance) {
|
|
304
|
+
if (typeof instance.onDetach === "function") instance.onDetach(node, ctx);
|
|
305
|
+
else if (typeof instance.dispose === "function") instance.dispose();
|
|
306
|
+
else if (typeof instance.cleanup === "function") instance.cleanup();
|
|
307
|
+
}
|
|
308
|
+
ctx.emit("lighting_detached", { node });
|
|
309
|
+
delete node.__lighting_instance;
|
|
310
|
+
},
|
|
311
|
+
onEvent(node, _config, ctx, event) {
|
|
312
|
+
const instance = node.__lighting_instance;
|
|
313
|
+
if (!instance) return;
|
|
314
|
+
if (typeof instance.onEvent === "function") instance.onEvent(event);
|
|
315
|
+
else if (typeof instance.emit === "function" && event.type) instance.emit(event);
|
|
316
|
+
if (event.type === "lighting_configure" && event.payload) {
|
|
317
|
+
Object.assign(instance, event.payload);
|
|
318
|
+
ctx.emit("lighting_configured", { node });
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
onUpdate(node, _config, ctx, dt) {
|
|
322
|
+
const instance = node.__lighting_instance;
|
|
323
|
+
if (!instance) return;
|
|
324
|
+
if (typeof instance.onUpdate === "function") instance.onUpdate(node, ctx, dt);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
// src/traits/MaterialTrait.ts
|
|
329
|
+
var MaterialTrait = class {
|
|
330
|
+
constructor(config) {
|
|
331
|
+
this.textureCache = /* @__PURE__ */ new Map();
|
|
332
|
+
this.material = {
|
|
333
|
+
...{ type: "pbr" },
|
|
334
|
+
...config
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Get material properties
|
|
339
|
+
*/
|
|
340
|
+
getMaterial() {
|
|
341
|
+
return { ...this.material };
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Update material property
|
|
345
|
+
*/
|
|
346
|
+
setProperty(key, value) {
|
|
347
|
+
this.material[key] = value;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Get PBR properties
|
|
351
|
+
*/
|
|
352
|
+
getPBRProperties() {
|
|
353
|
+
return this.material.pbr;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Update PBR material
|
|
357
|
+
*/
|
|
358
|
+
updatePBR(pbr) {
|
|
359
|
+
if (!this.material.pbr) {
|
|
360
|
+
this.material.pbr = {
|
|
361
|
+
baseColor: { r: 1, g: 1, b: 1 },
|
|
362
|
+
metallic: 0,
|
|
363
|
+
roughness: 0.5
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
this.material.pbr = { ...this.material.pbr, ...pbr };
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Add texture map
|
|
370
|
+
*/
|
|
371
|
+
addTexture(texture) {
|
|
372
|
+
if (!this.material.textures) {
|
|
373
|
+
this.material.textures = [];
|
|
374
|
+
}
|
|
375
|
+
this.material.textures.push(texture);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Get all textures
|
|
379
|
+
*/
|
|
380
|
+
getTextures() {
|
|
381
|
+
return [...this.material.textures || []];
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Clear texture cache (for memory optimization)
|
|
385
|
+
*/
|
|
386
|
+
clearTextureCache() {
|
|
387
|
+
this.textureCache.clear();
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Get shader code if custom
|
|
391
|
+
*/
|
|
392
|
+
getCustomShader() {
|
|
393
|
+
return this.material.customShader;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Set custom shader
|
|
397
|
+
*/
|
|
398
|
+
setCustomShader(shader) {
|
|
399
|
+
this.material.customShader = shader;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Get optimization hints
|
|
403
|
+
*/
|
|
404
|
+
getOptimization() {
|
|
405
|
+
return this.material.optimization;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Enable/disable texture streaming
|
|
409
|
+
*/
|
|
410
|
+
setTextureStreaming(enabled) {
|
|
411
|
+
if (!this.material.optimization) {
|
|
412
|
+
this.material.optimization = {};
|
|
413
|
+
}
|
|
414
|
+
this.material.optimization.streamTextures = enabled;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Set texture compression
|
|
418
|
+
*/
|
|
419
|
+
setCompression(compression) {
|
|
420
|
+
if (!this.material.optimization) {
|
|
421
|
+
this.material.optimization = {};
|
|
422
|
+
}
|
|
423
|
+
this.material.optimization.compression = compression;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Enable material instancing for performance
|
|
427
|
+
*/
|
|
428
|
+
setInstanced(instanced) {
|
|
429
|
+
if (!this.material.optimization) {
|
|
430
|
+
this.material.optimization = {};
|
|
431
|
+
}
|
|
432
|
+
this.material.optimization.instanced = instanced;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Dispose and cleanup
|
|
436
|
+
*/
|
|
437
|
+
dispose() {
|
|
438
|
+
this.textureCache.clear();
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
function createMaterialTrait(config) {
|
|
442
|
+
return new MaterialTrait(config);
|
|
443
|
+
}
|
|
444
|
+
var MATERIAL_PRESETS = {
|
|
445
|
+
/** Shiny metal */
|
|
446
|
+
chrome: () => ({
|
|
447
|
+
type: "pbr",
|
|
448
|
+
pbr: {
|
|
449
|
+
baseColor: { r: 0.77, g: 0.77, b: 0.77 },
|
|
450
|
+
metallic: 1,
|
|
451
|
+
roughness: 0.1
|
|
452
|
+
}
|
|
453
|
+
}),
|
|
454
|
+
/** Rough plastic */
|
|
455
|
+
plastic: () => ({
|
|
456
|
+
type: "pbr",
|
|
457
|
+
pbr: {
|
|
458
|
+
baseColor: { r: 1, g: 1, b: 1 },
|
|
459
|
+
metallic: 0,
|
|
460
|
+
roughness: 0.8
|
|
461
|
+
}
|
|
462
|
+
}),
|
|
463
|
+
/** Wood texture */
|
|
464
|
+
wood: () => ({
|
|
465
|
+
type: "pbr",
|
|
466
|
+
pbr: {
|
|
467
|
+
baseColor: { r: 0.6, g: 0.4, b: 0.2 },
|
|
468
|
+
metallic: 0,
|
|
469
|
+
roughness: 0.4
|
|
470
|
+
}
|
|
471
|
+
}),
|
|
472
|
+
/** Glass */
|
|
473
|
+
glass: () => ({
|
|
474
|
+
type: "transparent",
|
|
475
|
+
blendMode: "blend",
|
|
476
|
+
pbr: {
|
|
477
|
+
baseColor: { r: 1, g: 1, b: 1, a: 0.3 },
|
|
478
|
+
metallic: 0,
|
|
479
|
+
roughness: 0,
|
|
480
|
+
ior: 1.5,
|
|
481
|
+
transmission: 0.9
|
|
482
|
+
}
|
|
483
|
+
}),
|
|
484
|
+
/** Emissive (glowing) */
|
|
485
|
+
emissive: () => ({
|
|
486
|
+
type: "pbr",
|
|
487
|
+
pbr: {
|
|
488
|
+
baseColor: { r: 0, g: 1, b: 0 },
|
|
489
|
+
metallic: 0,
|
|
490
|
+
roughness: 1,
|
|
491
|
+
emission: {
|
|
492
|
+
color: { r: 0, g: 1, b: 0 },
|
|
493
|
+
intensity: 2
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}),
|
|
497
|
+
/** Skin material */
|
|
498
|
+
skin: () => ({
|
|
499
|
+
type: "pbr",
|
|
500
|
+
pbr: {
|
|
501
|
+
baseColor: { r: 1, g: 0.8, b: 0.7 },
|
|
502
|
+
metallic: 0,
|
|
503
|
+
roughness: 0.5,
|
|
504
|
+
ambientOcclusion: 0.8
|
|
505
|
+
}
|
|
506
|
+
})
|
|
507
|
+
};
|
|
508
|
+
var materialHandler = {
|
|
509
|
+
name: "material",
|
|
510
|
+
defaultConfig: {},
|
|
511
|
+
onAttach(node, config, ctx) {
|
|
512
|
+
const instance = new MaterialTrait(config);
|
|
513
|
+
node.__material_instance = instance;
|
|
514
|
+
ctx.emit("material_attached", { node, config });
|
|
515
|
+
},
|
|
516
|
+
onDetach(node, _config, ctx) {
|
|
517
|
+
const instance = node.__material_instance;
|
|
518
|
+
if (instance) {
|
|
519
|
+
if (typeof instance.onDetach === "function") instance.onDetach(node, ctx);
|
|
520
|
+
else if (typeof instance.dispose === "function") instance.dispose();
|
|
521
|
+
else if (typeof instance.cleanup === "function") instance.cleanup();
|
|
522
|
+
}
|
|
523
|
+
ctx.emit("material_detached", { node });
|
|
524
|
+
delete node.__material_instance;
|
|
525
|
+
},
|
|
526
|
+
onEvent(node, _config, ctx, event) {
|
|
527
|
+
const instance = node.__material_instance;
|
|
528
|
+
if (!instance) return;
|
|
529
|
+
if (typeof instance.onEvent === "function") instance.onEvent(event);
|
|
530
|
+
else if (typeof instance.emit === "function" && event.type) instance.emit(event);
|
|
531
|
+
if (event.type === "material_configure" && event.payload) {
|
|
532
|
+
Object.assign(instance, event.payload);
|
|
533
|
+
ctx.emit("material_configured", { node });
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
onUpdate(node, _config, ctx, dt) {
|
|
537
|
+
const instance = node.__material_instance;
|
|
538
|
+
if (!instance) return;
|
|
539
|
+
if (typeof instance.onUpdate === "function") instance.onUpdate(node, ctx, dt);
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
// src/traits/RenderingTrait.ts
|
|
544
|
+
init_safeJsonParse();
|
|
545
|
+
var RenderingTrait = class {
|
|
546
|
+
constructor(config) {
|
|
547
|
+
this.optimization = {
|
|
548
|
+
lodStrategy: "automatic",
|
|
549
|
+
culling: {
|
|
550
|
+
mode: "back",
|
|
551
|
+
frustum: true,
|
|
552
|
+
occlusion: true
|
|
553
|
+
},
|
|
554
|
+
batching: {
|
|
555
|
+
static: true,
|
|
556
|
+
dynamic: true,
|
|
557
|
+
instancing: true,
|
|
558
|
+
maxInstanceCount: 1e3
|
|
559
|
+
},
|
|
560
|
+
textures: {
|
|
561
|
+
streaming: true,
|
|
562
|
+
compression: "auto",
|
|
563
|
+
mipmaps: true,
|
|
564
|
+
maxResolution: 2048
|
|
565
|
+
},
|
|
566
|
+
shaders: {
|
|
567
|
+
simplifiedShaders: true,
|
|
568
|
+
lodBias: 0
|
|
569
|
+
},
|
|
570
|
+
targetGPUTier: "high",
|
|
571
|
+
adaptiveQuality: true,
|
|
572
|
+
targetFrameRate: 60,
|
|
573
|
+
...config
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Get rendering optimization config
|
|
578
|
+
*/
|
|
579
|
+
getOptimization() {
|
|
580
|
+
return jsonClone(this.optimization);
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Update rendering configuration
|
|
584
|
+
*/
|
|
585
|
+
updateOptimization(updates) {
|
|
586
|
+
this.optimization = { ...this.optimization, ...updates };
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Setup LOD levels (3 levels is typical)
|
|
590
|
+
*/
|
|
591
|
+
setupLODLevels(strategy = "automatic") {
|
|
592
|
+
const levels = [
|
|
593
|
+
{
|
|
594
|
+
level: 0,
|
|
595
|
+
screenRelativeSize: 0.5,
|
|
596
|
+
polygonReduction: 1,
|
|
597
|
+
textureScale: 1
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
level: 1,
|
|
601
|
+
screenRelativeSize: 0.25,
|
|
602
|
+
polygonReduction: 0.6,
|
|
603
|
+
disabledFeatures: ["specular"],
|
|
604
|
+
textureScale: 0.5
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
level: 2,
|
|
608
|
+
screenRelativeSize: 0.1,
|
|
609
|
+
polygonReduction: 0.3,
|
|
610
|
+
disabledFeatures: ["specular", "normals"],
|
|
611
|
+
textureScale: 0.25
|
|
612
|
+
}
|
|
613
|
+
];
|
|
614
|
+
this.optimization.lodStrategy = strategy;
|
|
615
|
+
this.optimization.lodLevels = levels;
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Get LOD levels
|
|
619
|
+
*/
|
|
620
|
+
getLODLevels() {
|
|
621
|
+
return [...this.optimization.lodLevels || []];
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Configure culling
|
|
625
|
+
*/
|
|
626
|
+
setCulling(config) {
|
|
627
|
+
const defaultCulling = { mode: "back" };
|
|
628
|
+
this.optimization.culling = {
|
|
629
|
+
...defaultCulling,
|
|
630
|
+
...this.optimization.culling,
|
|
631
|
+
...config
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Enable frustum culling
|
|
636
|
+
*/
|
|
637
|
+
setFrustumCulling(enabled) {
|
|
638
|
+
if (!this.optimization.culling) {
|
|
639
|
+
this.optimization.culling = { mode: "back" };
|
|
640
|
+
}
|
|
641
|
+
this.optimization.culling.frustum = enabled;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Enable occlusion culling
|
|
645
|
+
*/
|
|
646
|
+
setOcclusionCulling(enabled, distance) {
|
|
647
|
+
if (!this.optimization.culling) {
|
|
648
|
+
this.optimization.culling = { mode: "back" };
|
|
649
|
+
}
|
|
650
|
+
this.optimization.culling.occlusion = enabled;
|
|
651
|
+
if (distance) {
|
|
652
|
+
this.optimization.culling.occlusionDistance = distance;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Configure batching
|
|
657
|
+
*/
|
|
658
|
+
setBatching(config) {
|
|
659
|
+
this.optimization.batching = {
|
|
660
|
+
...this.optimization.batching,
|
|
661
|
+
...config
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Enable GPU instancing
|
|
666
|
+
*/
|
|
667
|
+
setInstancing(enabled, maxInstances) {
|
|
668
|
+
if (!this.optimization.batching) {
|
|
669
|
+
this.optimization.batching = {};
|
|
670
|
+
}
|
|
671
|
+
this.optimization.batching.instancing = enabled;
|
|
672
|
+
if (maxInstances) {
|
|
673
|
+
this.optimization.batching.maxInstanceCount = maxInstances;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Configure texture optimization
|
|
678
|
+
*/
|
|
679
|
+
setTextureOptimization(config) {
|
|
680
|
+
this.optimization.textures = {
|
|
681
|
+
...this.optimization.textures,
|
|
682
|
+
...config
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Enable texture streaming
|
|
687
|
+
*/
|
|
688
|
+
setTextureStreaming(enabled, budgetMB) {
|
|
689
|
+
if (!this.optimization.textures) {
|
|
690
|
+
this.optimization.textures = {};
|
|
691
|
+
}
|
|
692
|
+
this.optimization.textures.streaming = enabled;
|
|
693
|
+
if (budgetMB) {
|
|
694
|
+
this.optimization.textures.streamingBudget = budgetMB;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Set texture compression
|
|
699
|
+
*/
|
|
700
|
+
setTextureCompression(compression) {
|
|
701
|
+
if (!this.optimization.textures) {
|
|
702
|
+
this.optimization.textures = {};
|
|
703
|
+
}
|
|
704
|
+
this.optimization.textures.compression = compression;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Set max texture resolution
|
|
708
|
+
*/
|
|
709
|
+
setMaxTextureResolution(resolution) {
|
|
710
|
+
if (!this.optimization.textures) {
|
|
711
|
+
this.optimization.textures = {};
|
|
712
|
+
}
|
|
713
|
+
this.optimization.textures.maxResolution = resolution;
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Configure shader optimization
|
|
717
|
+
*/
|
|
718
|
+
setShaderOptimization(config) {
|
|
719
|
+
this.optimization.shaders = {
|
|
720
|
+
...this.optimization.shaders,
|
|
721
|
+
...config
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Set target GPU tier
|
|
726
|
+
*/
|
|
727
|
+
setTargetGPUTier(tier) {
|
|
728
|
+
this.optimization.targetGPUTier = tier;
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Enable adaptive quality (adjust based on frame rate)
|
|
732
|
+
*/
|
|
733
|
+
setAdaptiveQuality(enabled, targetFrameRate) {
|
|
734
|
+
this.optimization.adaptiveQuality = enabled;
|
|
735
|
+
if (targetFrameRate) {
|
|
736
|
+
this.optimization.targetFrameRate = targetFrameRate;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* Set fixed timestep for VR/AR
|
|
741
|
+
*/
|
|
742
|
+
setFixedTimestep(timestep) {
|
|
743
|
+
this.optimization.fixedTimestep = timestep;
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* Get rendering preset for quality level
|
|
747
|
+
*/
|
|
748
|
+
getPresetForQuality(quality) {
|
|
749
|
+
const presets = {
|
|
750
|
+
low: {
|
|
751
|
+
targetGPUTier: "low",
|
|
752
|
+
lodStrategy: "automatic",
|
|
753
|
+
culling: { mode: "back", frustum: true, occlusion: false },
|
|
754
|
+
batching: { instancing: true, maxInstanceCount: 500 },
|
|
755
|
+
textures: {
|
|
756
|
+
compression: "astc",
|
|
757
|
+
maxResolution: 512,
|
|
758
|
+
streaming: true,
|
|
759
|
+
streamingBudget: 128
|
|
760
|
+
},
|
|
761
|
+
adaptiveQuality: true,
|
|
762
|
+
targetFrameRate: 30
|
|
763
|
+
},
|
|
764
|
+
medium: {
|
|
765
|
+
targetGPUTier: "medium",
|
|
766
|
+
lodStrategy: "automatic",
|
|
767
|
+
culling: { mode: "back", frustum: true, occlusion: true },
|
|
768
|
+
batching: { instancing: true, maxInstanceCount: 1e3 },
|
|
769
|
+
textures: {
|
|
770
|
+
compression: "basis",
|
|
771
|
+
maxResolution: 1024,
|
|
772
|
+
streaming: true,
|
|
773
|
+
streamingBudget: 256
|
|
774
|
+
},
|
|
775
|
+
adaptiveQuality: true,
|
|
776
|
+
targetFrameRate: 60
|
|
777
|
+
},
|
|
778
|
+
high: {
|
|
779
|
+
targetGPUTier: "high",
|
|
780
|
+
lodStrategy: "automatic",
|
|
781
|
+
culling: { mode: "back", frustum: true, occlusion: true },
|
|
782
|
+
batching: { instancing: true, maxInstanceCount: 2e3 },
|
|
783
|
+
textures: {
|
|
784
|
+
compression: "dxt",
|
|
785
|
+
maxResolution: 2048,
|
|
786
|
+
streaming: true,
|
|
787
|
+
streamingBudget: 512
|
|
788
|
+
},
|
|
789
|
+
adaptiveQuality: false,
|
|
790
|
+
targetFrameRate: 60
|
|
791
|
+
},
|
|
792
|
+
ultra: {
|
|
793
|
+
targetGPUTier: "ultra",
|
|
794
|
+
lodStrategy: "manual",
|
|
795
|
+
culling: {
|
|
796
|
+
mode: "back",
|
|
797
|
+
frustum: true,
|
|
798
|
+
occlusion: true,
|
|
799
|
+
hierarchicalZ: true
|
|
800
|
+
},
|
|
801
|
+
batching: { instancing: true, maxInstanceCount: 5e3 },
|
|
802
|
+
textures: {
|
|
803
|
+
compression: "none",
|
|
804
|
+
maxResolution: 4096,
|
|
805
|
+
virtualTexturing: true,
|
|
806
|
+
streaming: true,
|
|
807
|
+
streamingBudget: 1024
|
|
808
|
+
},
|
|
809
|
+
adaptiveQuality: false,
|
|
810
|
+
targetFrameRate: 120
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
return { ...this.optimization, ...presets[quality] };
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Apply quality preset
|
|
817
|
+
*/
|
|
818
|
+
applyQualityPreset(quality) {
|
|
819
|
+
const preset = this.getPresetForQuality(quality);
|
|
820
|
+
this.optimization = preset;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Estimate GPU memory usage
|
|
824
|
+
*/
|
|
825
|
+
estimateGPUMemory() {
|
|
826
|
+
let textureMemory = 0;
|
|
827
|
+
let vertexBuffers = 0;
|
|
828
|
+
const maxRes = this.optimization.textures?.maxResolution || 2048;
|
|
829
|
+
textureMemory = maxRes * maxRes * 4 / (1024 * 1024);
|
|
830
|
+
const instanceCount = this.optimization.batching?.maxInstanceCount || 1e3;
|
|
831
|
+
const verticesPerMesh = 1e4;
|
|
832
|
+
vertexBuffers = verticesPerMesh * 36 * instanceCount / (1024 * 1024) * 0.1;
|
|
833
|
+
return {
|
|
834
|
+
textureMemory: Math.round(textureMemory),
|
|
835
|
+
vertexBuffers: Math.max(1, Math.round(vertexBuffers)),
|
|
836
|
+
// At least 1MB
|
|
837
|
+
estimatedTotal: Math.round(textureMemory + Math.max(1, vertexBuffers))
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Get rendering statistics/info
|
|
842
|
+
*/
|
|
843
|
+
getInfo() {
|
|
844
|
+
const tier = this.optimization.targetGPUTier;
|
|
845
|
+
const lod = this.optimization.lodStrategy;
|
|
846
|
+
const culling = this.optimization.culling?.mode;
|
|
847
|
+
const instancing = this.optimization.batching?.instancing ? "yes" : "no";
|
|
848
|
+
const memory = this.estimateGPUMemory();
|
|
849
|
+
return `Rendering: tier=${tier} | LOD=${lod} | culling=${culling} | instancing=${instancing} | memory=${memory.estimatedTotal}MB`;
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Optimize for VR/AR (fixed timestep, fast culling)
|
|
853
|
+
*/
|
|
854
|
+
optimizeForVRAR(targetFPS = 90) {
|
|
855
|
+
this.optimization.fixedTimestep = 1 / targetFPS;
|
|
856
|
+
this.optimization.targetFrameRate = targetFPS;
|
|
857
|
+
this.setOcclusionCulling(true, 50);
|
|
858
|
+
this.setInstancing(true, 5e3);
|
|
859
|
+
this.setAdaptiveQuality(true, targetFPS);
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Optimize for mobile (lower resources)
|
|
863
|
+
*/
|
|
864
|
+
optimizeForMobile() {
|
|
865
|
+
this.applyQualityPreset("low");
|
|
866
|
+
this.setTextureCompression("astc");
|
|
867
|
+
this.setInstancing(true, 256);
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Optimize for desktop (higher resources)
|
|
871
|
+
*/
|
|
872
|
+
optimizeForDesktop() {
|
|
873
|
+
this.applyQualityPreset("ultra");
|
|
874
|
+
this.setTextureCompression("none");
|
|
875
|
+
this.setInstancing(true, 5e3);
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Dispose and cleanup
|
|
879
|
+
*/
|
|
880
|
+
dispose() {
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
function createRenderingTrait(config) {
|
|
884
|
+
return new RenderingTrait(config);
|
|
885
|
+
}
|
|
886
|
+
var renderingHandler = {
|
|
887
|
+
name: "rendering",
|
|
888
|
+
defaultConfig: {},
|
|
889
|
+
onAttach(node, config, ctx) {
|
|
890
|
+
const instance = new RenderingTrait(config);
|
|
891
|
+
node.__rendering_instance = instance;
|
|
892
|
+
ctx.emit("rendering_attached", { node, config });
|
|
893
|
+
},
|
|
894
|
+
onDetach(node, _config, ctx) {
|
|
895
|
+
const instance = node.__rendering_instance;
|
|
896
|
+
if (instance) {
|
|
897
|
+
if (typeof instance.onDetach === "function") instance.onDetach(node, ctx);
|
|
898
|
+
else if (typeof instance.dispose === "function") instance.dispose();
|
|
899
|
+
else if (typeof instance.cleanup === "function") instance.cleanup();
|
|
900
|
+
}
|
|
901
|
+
ctx.emit("rendering_detached", { node });
|
|
902
|
+
delete node.__rendering_instance;
|
|
903
|
+
},
|
|
904
|
+
onEvent(node, _config, ctx, event) {
|
|
905
|
+
const instance = node.__rendering_instance;
|
|
906
|
+
if (!instance) return;
|
|
907
|
+
if (typeof instance.onEvent === "function") instance.onEvent(event);
|
|
908
|
+
else if (typeof instance.emit === "function" && event.type) instance.emit(event);
|
|
909
|
+
if (event.type === "rendering_configure" && event.payload) {
|
|
910
|
+
Object.assign(instance, event.payload);
|
|
911
|
+
ctx.emit("rendering_configured", { node });
|
|
912
|
+
}
|
|
913
|
+
},
|
|
914
|
+
onUpdate(node, _config, ctx, dt) {
|
|
915
|
+
const instance = node.__rendering_instance;
|
|
916
|
+
if (!instance) return;
|
|
917
|
+
if (typeof instance.onUpdate === "function") instance.onUpdate(node, ctx, dt);
|
|
918
|
+
}
|
|
919
|
+
};
|
|
920
|
+
|
|
921
|
+
// src/traits/ShaderTrait.ts
|
|
922
|
+
var SHADER_CHUNKS = {
|
|
923
|
+
/** Common noise functions */
|
|
924
|
+
noise: `
|
|
925
|
+
// Simplex 2D noise
|
|
926
|
+
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
|
|
927
|
+
vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
|
|
928
|
+
vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); }
|
|
929
|
+
|
|
930
|
+
float snoise(vec2 v) {
|
|
931
|
+
const vec4 C = vec4(0.211324865405187, 0.366025403784439,
|
|
932
|
+
-0.577350269189626, 0.024390243902439);
|
|
933
|
+
vec2 i = floor(v + dot(v, C.yy));
|
|
934
|
+
vec2 x0 = v - i + dot(i, C.xx);
|
|
935
|
+
vec2 i1 = (x0[0] > x0[1]) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
|
|
936
|
+
vec4 x12 = x0.xyxy + C.xxzz;
|
|
937
|
+
x12.xy -= i1;
|
|
938
|
+
i = mod289(i);
|
|
939
|
+
vec3 p = permute(permute(i[1] + vec3(0.0, i1[1], 1.0)) + i[0] + vec3(0.0, i1[0], 1.0));
|
|
940
|
+
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);
|
|
941
|
+
m = m*m;
|
|
942
|
+
m = m*m;
|
|
943
|
+
vec3 x = 2.0 * fract(p * C.www) - 1.0;
|
|
944
|
+
vec3 h = abs(x) - 0.5;
|
|
945
|
+
vec3 ox = floor(x + 0.5);
|
|
946
|
+
vec3 a0 = x - ox;
|
|
947
|
+
m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h);
|
|
948
|
+
vec3 g;
|
|
949
|
+
g[0] = a0[0] * x0[0] + h[0] * x0[1];
|
|
950
|
+
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
|
|
951
|
+
return 130.0 * dot(m, g);
|
|
952
|
+
}
|
|
953
|
+
`,
|
|
954
|
+
/** Hologram effect */
|
|
955
|
+
hologram: `
|
|
956
|
+
// Hologram scanline effect
|
|
957
|
+
float hologramScanline(vec2 uv, float time, float density) {
|
|
958
|
+
return sin(uv[1] * density + time * 2.0) * 0.5 + 0.5;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// Hologram flicker
|
|
962
|
+
float hologramFlicker(float time) {
|
|
963
|
+
return 0.9 + 0.1 * sin(time * 20.0) * sin(time * 13.0);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// Hologram edge glow
|
|
967
|
+
float hologramEdge(vec3 normal, vec3 viewDir) {
|
|
968
|
+
return pow(1.0 - abs(dot(normal, viewDir)), 2.0);
|
|
969
|
+
}
|
|
970
|
+
`,
|
|
971
|
+
/** Fresnel effect */
|
|
972
|
+
fresnel: `
|
|
973
|
+
// Basic Fresnel
|
|
974
|
+
float fresnel(vec3 normal, vec3 viewDir, float power) {
|
|
975
|
+
return pow(1.0 - abs(dot(normal, viewDir)), power);
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
// Schlick's approximation
|
|
979
|
+
float fresnelSchlick(float cosTheta, float F0) {
|
|
980
|
+
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
|
981
|
+
}
|
|
982
|
+
`,
|
|
983
|
+
/** PBR lighting */
|
|
984
|
+
pbr: `
|
|
985
|
+
// Distribution function (GGX/Trowbridge-Reitz)
|
|
986
|
+
float distributionGGX(vec3 N, vec3 H, float roughness) {
|
|
987
|
+
float a = roughness * roughness;
|
|
988
|
+
float a2 = a * a;
|
|
989
|
+
float NdotH = max(dot(N, H), 0.0);
|
|
990
|
+
float NdotH2 = NdotH * NdotH;
|
|
991
|
+
float num = a2;
|
|
992
|
+
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
|
993
|
+
denom = 3.14159265 * denom * denom;
|
|
994
|
+
return num / denom;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// Geometry function (Schlick-GGX)
|
|
998
|
+
float geometrySchlickGGX(float NdotV, float roughness) {
|
|
999
|
+
float r = (roughness + 1.0);
|
|
1000
|
+
float k = (r * r) / 8.0;
|
|
1001
|
+
float num = NdotV;
|
|
1002
|
+
float denom = NdotV * (1.0 - k) + k;
|
|
1003
|
+
return num / denom;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
// Smith's geometry function
|
|
1007
|
+
float geometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
|
|
1008
|
+
float NdotV = max(dot(N, V), 0.0);
|
|
1009
|
+
float NdotL = max(dot(N, L), 0.0);
|
|
1010
|
+
float ggx2 = geometrySchlickGGX(NdotV, roughness);
|
|
1011
|
+
float ggx1 = geometrySchlickGGX(NdotL, roughness);
|
|
1012
|
+
return ggx1 * ggx2;
|
|
1013
|
+
}
|
|
1014
|
+
`,
|
|
1015
|
+
/** UV utilities */
|
|
1016
|
+
uv: `
|
|
1017
|
+
// Rotate UV
|
|
1018
|
+
vec2 rotateUV(vec2 uv, float angle) {
|
|
1019
|
+
float c = cos(angle);
|
|
1020
|
+
float s = sin(angle);
|
|
1021
|
+
return vec2(c * uv[0] - s * uv[1], s * uv[0] + c * uv[1]);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// Tile UV
|
|
1025
|
+
vec2 tileUV(vec2 uv, vec2 scale) {
|
|
1026
|
+
return fract(uv * scale);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// Parallax mapping
|
|
1030
|
+
vec2 parallaxUV(vec2 uv, vec3 viewDir, sampler2D heightMap, float scale) {
|
|
1031
|
+
float height = texture2D(heightMap, uv).r;
|
|
1032
|
+
vec2 p = viewDir.xy / viewDir[2] * (height * scale);
|
|
1033
|
+
return uv - p;
|
|
1034
|
+
}
|
|
1035
|
+
`
|
|
1036
|
+
};
|
|
1037
|
+
var ShaderTrait = class {
|
|
1038
|
+
constructor(config) {
|
|
1039
|
+
this.uniformValues = /* @__PURE__ */ new Map();
|
|
1040
|
+
this.config = {
|
|
1041
|
+
...config,
|
|
1042
|
+
source: {
|
|
1043
|
+
language: config.source?.language || "glsl",
|
|
1044
|
+
vertex: config.source?.vertex || "",
|
|
1045
|
+
fragment: config.source?.fragment || "",
|
|
1046
|
+
geometry: config.source?.geometry,
|
|
1047
|
+
tessellationControl: config.source?.tessellationControl,
|
|
1048
|
+
tessellationEvaluation: config.source?.tessellationEvaluation,
|
|
1049
|
+
compute: config.source?.compute
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
if (config.uniforms) {
|
|
1053
|
+
for (const [name, uniform] of Object.entries(config.uniforms)) {
|
|
1054
|
+
this.uniformValues.set(name, uniform.value);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Get shader configuration
|
|
1060
|
+
*/
|
|
1061
|
+
getConfig() {
|
|
1062
|
+
return { ...this.config };
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* Get vertex shader source with includes
|
|
1066
|
+
*/
|
|
1067
|
+
getVertexSource() {
|
|
1068
|
+
return this.assembleShaderSource("vertex");
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* Get fragment shader source with includes
|
|
1072
|
+
*/
|
|
1073
|
+
getFragmentSource() {
|
|
1074
|
+
return this.assembleShaderSource("fragment");
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Assemble shader source with includes and uniforms
|
|
1078
|
+
*/
|
|
1079
|
+
assembleShaderSource(stage) {
|
|
1080
|
+
const source = this.config.source ? this.config.source[stage] : void 0;
|
|
1081
|
+
if (!source) return "";
|
|
1082
|
+
let assembled = "";
|
|
1083
|
+
if (this.config.source?.language === "glsl") {
|
|
1084
|
+
assembled += "precision highp float;\n\n";
|
|
1085
|
+
}
|
|
1086
|
+
if (this.config.uniforms) {
|
|
1087
|
+
for (const [name, uniform] of Object.entries(this.config.uniforms)) {
|
|
1088
|
+
assembled += `uniform ${this.getGLSLType(uniform.type)} ${name};
|
|
1089
|
+
`;
|
|
1090
|
+
}
|
|
1091
|
+
assembled += "\n";
|
|
1092
|
+
}
|
|
1093
|
+
if (this.config.includes) {
|
|
1094
|
+
for (const include of this.config.includes) {
|
|
1095
|
+
const chunk = SHADER_CHUNKS[include.path];
|
|
1096
|
+
if (chunk) {
|
|
1097
|
+
assembled += `// Include: ${include.path}
|
|
1098
|
+
${chunk}
|
|
1099
|
+
`;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
assembled += source;
|
|
1104
|
+
return assembled;
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Convert uniform type to GLSL type
|
|
1108
|
+
*/
|
|
1109
|
+
getGLSLType(type) {
|
|
1110
|
+
const typeMap = {
|
|
1111
|
+
float: "float",
|
|
1112
|
+
int: "int",
|
|
1113
|
+
bool: "bool",
|
|
1114
|
+
vec2: "vec2",
|
|
1115
|
+
vec3: "vec3",
|
|
1116
|
+
vec4: "vec4",
|
|
1117
|
+
mat2: "mat2",
|
|
1118
|
+
mat3: "mat3",
|
|
1119
|
+
mat4: "mat4",
|
|
1120
|
+
sampler2D: "sampler2D",
|
|
1121
|
+
samplerCube: "samplerCube"
|
|
1122
|
+
};
|
|
1123
|
+
return typeMap[type] || "float";
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Set uniform value
|
|
1127
|
+
*/
|
|
1128
|
+
setUniform(name, value) {
|
|
1129
|
+
this.uniformValues.set(name, value);
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1132
|
+
* Get uniform value
|
|
1133
|
+
*/
|
|
1134
|
+
getUniform(name) {
|
|
1135
|
+
return this.uniformValues.get(name);
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Get all uniform values
|
|
1139
|
+
*/
|
|
1140
|
+
getUniforms() {
|
|
1141
|
+
return new Map(this.uniformValues);
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
* Validate shader syntax
|
|
1145
|
+
*/
|
|
1146
|
+
validate() {
|
|
1147
|
+
const errors = [];
|
|
1148
|
+
const warnings = [];
|
|
1149
|
+
if (this.config.source?.vertex) {
|
|
1150
|
+
const vertexErrors = this.validateShaderSyntax(this.config.source.vertex, "vertex");
|
|
1151
|
+
errors.push(...vertexErrors);
|
|
1152
|
+
}
|
|
1153
|
+
if (this.config.source?.fragment) {
|
|
1154
|
+
const fragmentErrors = this.validateShaderSyntax(this.config.source.fragment, "fragment");
|
|
1155
|
+
errors.push(...fragmentErrors);
|
|
1156
|
+
}
|
|
1157
|
+
if (this.config.source?.vertex && !this.config.source.vertex.includes("void main")) {
|
|
1158
|
+
errors.push({
|
|
1159
|
+
stage: "vertex",
|
|
1160
|
+
line: 1,
|
|
1161
|
+
message: "Vertex shader must contain a main() function",
|
|
1162
|
+
code: "E001"
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
if (this.config.source?.fragment && !this.config.source.fragment.includes("void main")) {
|
|
1166
|
+
errors.push({
|
|
1167
|
+
stage: "fragment",
|
|
1168
|
+
line: 1,
|
|
1169
|
+
message: "Fragment shader must contain a main() function",
|
|
1170
|
+
code: "E002"
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
this.compilationResult = {
|
|
1174
|
+
success: errors.length === 0,
|
|
1175
|
+
errors,
|
|
1176
|
+
warnings
|
|
1177
|
+
};
|
|
1178
|
+
return this.compilationResult;
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Basic shader syntax validation
|
|
1182
|
+
*/
|
|
1183
|
+
validateShaderSyntax(source, stage) {
|
|
1184
|
+
const errors = [];
|
|
1185
|
+
const lines = source.split("\n");
|
|
1186
|
+
let braceCount = 0;
|
|
1187
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1188
|
+
const line = lines[i];
|
|
1189
|
+
braceCount += (line.match(/{/g) || []).length;
|
|
1190
|
+
braceCount -= (line.match(/}/g) || []).length;
|
|
1191
|
+
}
|
|
1192
|
+
if (braceCount !== 0) {
|
|
1193
|
+
errors.push({
|
|
1194
|
+
stage,
|
|
1195
|
+
line: lines.length,
|
|
1196
|
+
message: `Unbalanced braces in ${stage} shader`,
|
|
1197
|
+
code: "E003"
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
let parenCount = 0;
|
|
1201
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1202
|
+
const line = lines[i];
|
|
1203
|
+
parenCount += (line.match(/\(/g) || []).length;
|
|
1204
|
+
parenCount -= (line.match(/\)/g) || []).length;
|
|
1205
|
+
}
|
|
1206
|
+
if (parenCount !== 0) {
|
|
1207
|
+
errors.push({
|
|
1208
|
+
stage,
|
|
1209
|
+
line: lines.length,
|
|
1210
|
+
message: `Unbalanced parentheses in ${stage} shader`,
|
|
1211
|
+
code: "E004"
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
return errors;
|
|
1215
|
+
}
|
|
1216
|
+
/**
|
|
1217
|
+
* Compile shader to target platform
|
|
1218
|
+
*/
|
|
1219
|
+
compile(options) {
|
|
1220
|
+
const validation = this.validate();
|
|
1221
|
+
if (!validation.success) {
|
|
1222
|
+
return validation;
|
|
1223
|
+
}
|
|
1224
|
+
let vertexSource = this.getVertexSource();
|
|
1225
|
+
let fragmentSource = this.getFragmentSource();
|
|
1226
|
+
if (options?.defines) {
|
|
1227
|
+
for (const [key, value] of Object.entries(options.defines)) {
|
|
1228
|
+
const define = `#define ${key} ${value}
|
|
1229
|
+
`;
|
|
1230
|
+
vertexSource = define + vertexSource;
|
|
1231
|
+
fragmentSource = define + fragmentSource;
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
return {
|
|
1235
|
+
success: true,
|
|
1236
|
+
errors: [],
|
|
1237
|
+
warnings: [],
|
|
1238
|
+
compiledCode: {
|
|
1239
|
+
vertex: vertexSource,
|
|
1240
|
+
fragment: fragmentSource
|
|
1241
|
+
}
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* Create Three.js ShaderMaterial config
|
|
1246
|
+
*/
|
|
1247
|
+
toThreeJSConfig() {
|
|
1248
|
+
const uniformsObj = {};
|
|
1249
|
+
for (const [name, value] of this.uniformValues) {
|
|
1250
|
+
uniformsObj[name] = { value };
|
|
1251
|
+
}
|
|
1252
|
+
return {
|
|
1253
|
+
vertexShader: this.getVertexSource(),
|
|
1254
|
+
fragmentShader: this.getFragmentSource(),
|
|
1255
|
+
uniforms: uniformsObj,
|
|
1256
|
+
transparent: this.config.blendMode !== "opaque",
|
|
1257
|
+
depthTest: this.config.depthTest ?? true,
|
|
1258
|
+
depthWrite: this.config.depthWrite ?? true,
|
|
1259
|
+
side: this.getCullSide()
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
getCullSide() {
|
|
1263
|
+
const THREE_FrontSide = 0;
|
|
1264
|
+
const THREE_BackSide = 1;
|
|
1265
|
+
const THREE_DoubleSide = 2;
|
|
1266
|
+
switch (this.config.cullFace) {
|
|
1267
|
+
case "front":
|
|
1268
|
+
return THREE_BackSide;
|
|
1269
|
+
case "back":
|
|
1270
|
+
return THREE_FrontSide;
|
|
1271
|
+
case "none":
|
|
1272
|
+
return THREE_DoubleSide;
|
|
1273
|
+
default:
|
|
1274
|
+
return THREE_FrontSide;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
};
|
|
1278
|
+
var SHADER_PRESETS = {
|
|
1279
|
+
/** Hologram effect shader */
|
|
1280
|
+
hologram: {
|
|
1281
|
+
name: "hologram",
|
|
1282
|
+
source: {
|
|
1283
|
+
language: "glsl",
|
|
1284
|
+
vertex: `
|
|
1285
|
+
varying vec2 vUv;
|
|
1286
|
+
varying vec3 vNormal;
|
|
1287
|
+
varying vec3 vViewPosition;
|
|
1288
|
+
|
|
1289
|
+
void main() {
|
|
1290
|
+
vUv = uv;
|
|
1291
|
+
vNormal = normalize(normalMatrix * normal);
|
|
1292
|
+
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
|
|
1293
|
+
vViewPosition = -mvPosition.xyz;
|
|
1294
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
1295
|
+
}
|
|
1296
|
+
`,
|
|
1297
|
+
fragment: `
|
|
1298
|
+
uniform float time;
|
|
1299
|
+
uniform vec3 color;
|
|
1300
|
+
uniform float opacity;
|
|
1301
|
+
uniform float scanlineIntensity;
|
|
1302
|
+
uniform float flickerIntensity;
|
|
1303
|
+
|
|
1304
|
+
varying vec2 vUv;
|
|
1305
|
+
varying vec3 vNormal;
|
|
1306
|
+
varying vec3 vViewPosition;
|
|
1307
|
+
|
|
1308
|
+
void main() {
|
|
1309
|
+
// Fresnel edge glow
|
|
1310
|
+
vec3 viewDir = normalize(vViewPosition);
|
|
1311
|
+
float fresnel = pow(1.0 - abs(dot(vNormal, viewDir)), 2.0);
|
|
1312
|
+
|
|
1313
|
+
// Scanlines
|
|
1314
|
+
float scanline = sin(vUv[1] * 100.0 + time * 2.0) * scanlineIntensity;
|
|
1315
|
+
|
|
1316
|
+
// Flicker
|
|
1317
|
+
float flicker = 0.9 + flickerIntensity * sin(time * 20.0) * sin(time * 13.0);
|
|
1318
|
+
|
|
1319
|
+
// Combine
|
|
1320
|
+
float alpha = (opacity + fresnel * 0.3 + scanline) * flicker;
|
|
1321
|
+
vec3 finalColor = color + fresnel * 0.5;
|
|
1322
|
+
|
|
1323
|
+
gl_FragColor = vec4(finalColor, alpha);
|
|
1324
|
+
}
|
|
1325
|
+
`
|
|
1326
|
+
},
|
|
1327
|
+
uniforms: {
|
|
1328
|
+
time: { type: "float", value: 0 },
|
|
1329
|
+
color: { type: "vec3", value: [0, 1, 1] },
|
|
1330
|
+
opacity: { type: "float", value: 0.5, min: 0, max: 1 },
|
|
1331
|
+
scanlineIntensity: { type: "float", value: 0.1, min: 0, max: 0.5 },
|
|
1332
|
+
flickerIntensity: { type: "float", value: 0.1, min: 0, max: 0.3 }
|
|
1333
|
+
},
|
|
1334
|
+
blendMode: "blend",
|
|
1335
|
+
depthWrite: false,
|
|
1336
|
+
cullFace: "none"
|
|
1337
|
+
},
|
|
1338
|
+
/** Force field shader */
|
|
1339
|
+
forceField: {
|
|
1340
|
+
name: "forceField",
|
|
1341
|
+
source: {
|
|
1342
|
+
language: "glsl",
|
|
1343
|
+
vertex: `
|
|
1344
|
+
varying vec2 vUv;
|
|
1345
|
+
varying vec3 vNormal;
|
|
1346
|
+
varying vec3 vWorldPosition;
|
|
1347
|
+
|
|
1348
|
+
void main() {
|
|
1349
|
+
vUv = uv;
|
|
1350
|
+
vNormal = normalize(normalMatrix * normal);
|
|
1351
|
+
vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
|
|
1352
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
1353
|
+
}
|
|
1354
|
+
`,
|
|
1355
|
+
fragment: `
|
|
1356
|
+
uniform float time;
|
|
1357
|
+
uniform vec3 color;
|
|
1358
|
+
uniform float pulseSpeed;
|
|
1359
|
+
uniform float hexScale;
|
|
1360
|
+
|
|
1361
|
+
varying vec2 vUv;
|
|
1362
|
+
varying vec3 vNormal;
|
|
1363
|
+
varying vec3 vWorldPosition;
|
|
1364
|
+
|
|
1365
|
+
float hexPattern(vec2 p) {
|
|
1366
|
+
vec2 q = vec2(p[0] * 2.0 * 0.5773503, p[1] + p[0] * 0.5773503);
|
|
1367
|
+
vec2 pi = floor(q);
|
|
1368
|
+
vec2 pf = fract(q);
|
|
1369
|
+
float v = mod(pi[0] + pi[1], 3.0);
|
|
1370
|
+
float ca = step(1.0, v);
|
|
1371
|
+
float cb = step(2.0, v);
|
|
1372
|
+
vec2 ma = step(pf.xy, pf.yx);
|
|
1373
|
+
float e = dot(ma, 1.0 - pf.yx + ca * (pf[0] + pf[1] - 1.0) + cb * (pf.yx - 2.0 * pf.xy));
|
|
1374
|
+
return e;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
void main() {
|
|
1378
|
+
float hex = hexPattern(vUv * hexScale);
|
|
1379
|
+
float pulse = sin(time * pulseSpeed) * 0.5 + 0.5;
|
|
1380
|
+
float alpha = hex * (0.3 + pulse * 0.2);
|
|
1381
|
+
gl_FragColor = vec4(color, alpha);
|
|
1382
|
+
}
|
|
1383
|
+
`
|
|
1384
|
+
},
|
|
1385
|
+
uniforms: {
|
|
1386
|
+
time: { type: "float", value: 0 },
|
|
1387
|
+
color: { type: "vec3", value: [0.2, 0.5, 1] },
|
|
1388
|
+
pulseSpeed: { type: "float", value: 2, min: 0.5, max: 5 },
|
|
1389
|
+
hexScale: { type: "float", value: 10, min: 5, max: 50 }
|
|
1390
|
+
},
|
|
1391
|
+
blendMode: "additive",
|
|
1392
|
+
depthWrite: false,
|
|
1393
|
+
cullFace: "none"
|
|
1394
|
+
},
|
|
1395
|
+
/** Dissolve effect shader */
|
|
1396
|
+
dissolve: {
|
|
1397
|
+
name: "dissolve",
|
|
1398
|
+
source: {
|
|
1399
|
+
language: "glsl",
|
|
1400
|
+
vertex: `
|
|
1401
|
+
varying vec2 vUv;
|
|
1402
|
+
varying vec3 vPosition;
|
|
1403
|
+
|
|
1404
|
+
void main() {
|
|
1405
|
+
vUv = uv;
|
|
1406
|
+
vPosition = position;
|
|
1407
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
1408
|
+
}
|
|
1409
|
+
`,
|
|
1410
|
+
fragment: `
|
|
1411
|
+
uniform float progress;
|
|
1412
|
+
uniform vec3 edgeColor;
|
|
1413
|
+
uniform float edgeWidth;
|
|
1414
|
+
uniform sampler2D noiseTexture;
|
|
1415
|
+
|
|
1416
|
+
varying vec2 vUv;
|
|
1417
|
+
varying vec3 vPosition;
|
|
1418
|
+
|
|
1419
|
+
void main() {
|
|
1420
|
+
float noise = texture2D(noiseTexture, vUv).r;
|
|
1421
|
+
float diff = noise - progress;
|
|
1422
|
+
|
|
1423
|
+
if (diff < 0.0) discard;
|
|
1424
|
+
|
|
1425
|
+
float edge = smoothstep(0.0, edgeWidth, diff);
|
|
1426
|
+
vec3 color = mix(edgeColor, vec3(1.0), edge);
|
|
1427
|
+
|
|
1428
|
+
gl_FragColor = vec4(color, 1.0);
|
|
1429
|
+
}
|
|
1430
|
+
`
|
|
1431
|
+
},
|
|
1432
|
+
uniforms: {
|
|
1433
|
+
progress: { type: "float", value: 0, min: 0, max: 1 },
|
|
1434
|
+
edgeColor: { type: "vec3", value: [1, 0.5, 0] },
|
|
1435
|
+
edgeWidth: { type: "float", value: 0.1, min: 0.01, max: 0.5 },
|
|
1436
|
+
noiseTexture: { type: "sampler2D", value: "" }
|
|
1437
|
+
},
|
|
1438
|
+
blendMode: "opaque"
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
function createShaderTrait(config) {
|
|
1442
|
+
return new ShaderTrait({
|
|
1443
|
+
name: "custom",
|
|
1444
|
+
source: {
|
|
1445
|
+
language: "glsl",
|
|
1446
|
+
vertex: "",
|
|
1447
|
+
fragment: ""
|
|
1448
|
+
},
|
|
1449
|
+
uniforms: {},
|
|
1450
|
+
blendMode: "opaque",
|
|
1451
|
+
...config
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
var shaderHandler = {
|
|
1455
|
+
name: "shader",
|
|
1456
|
+
defaultConfig: {},
|
|
1457
|
+
onAttach(node, config, ctx) {
|
|
1458
|
+
const instance = new ShaderTrait(config);
|
|
1459
|
+
node.__shader_instance = instance;
|
|
1460
|
+
ctx.emit("shader_attached", { node, config });
|
|
1461
|
+
},
|
|
1462
|
+
onDetach(node, _config, ctx) {
|
|
1463
|
+
const instance = node.__shader_instance;
|
|
1464
|
+
if (instance) {
|
|
1465
|
+
if (typeof instance.onDetach === "function") instance.onDetach(node, ctx);
|
|
1466
|
+
else if (typeof instance.dispose === "function") instance.dispose();
|
|
1467
|
+
else if (typeof instance.cleanup === "function") instance.cleanup();
|
|
1468
|
+
}
|
|
1469
|
+
ctx.emit("shader_detached", { node });
|
|
1470
|
+
delete node.__shader_instance;
|
|
1471
|
+
},
|
|
1472
|
+
onEvent(node, _config, ctx, event) {
|
|
1473
|
+
const instance = node.__shader_instance;
|
|
1474
|
+
if (!instance) return;
|
|
1475
|
+
if (typeof instance.onEvent === "function") instance.onEvent(event);
|
|
1476
|
+
else if (typeof instance.emit === "function" && event.type) instance.emit(event);
|
|
1477
|
+
if (event.type === "shader_configure" && event.payload) {
|
|
1478
|
+
Object.assign(instance, event.payload);
|
|
1479
|
+
ctx.emit("shader_configured", { node });
|
|
1480
|
+
}
|
|
1481
|
+
},
|
|
1482
|
+
onUpdate(node, _config, ctx, dt) {
|
|
1483
|
+
const instance = node.__shader_instance;
|
|
1484
|
+
if (!instance) return;
|
|
1485
|
+
if (typeof instance.onUpdate === "function") instance.onUpdate(node, ctx, dt);
|
|
1486
|
+
}
|
|
1487
|
+
};
|
|
1488
|
+
|
|
1489
|
+
export { LIGHTING_PRESETS, LightingTrait, MATERIAL_PRESETS, MaterialTrait, RenderingTrait, SHADER_CHUNKS, SHADER_PRESETS, ShaderTrait, createLightingTrait, createMaterialTrait, createRenderingTrait, createShaderTrait, lightingHandler, materialHandler, renderingHandler, shaderHandler };
|
|
1490
|
+
//# sourceMappingURL=chunk-QPOQ7VPI.js.map
|
|
1491
|
+
//# sourceMappingURL=chunk-QPOQ7VPI.js.map
|