lythreeframe 1.3.1 → 1.3.2

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.
@@ -5,12 +5,12 @@ var Addons_js = require('three/examples/jsm/Addons.js');
5
5
  var tsl = require('three/tsl');
6
6
  var DepthOfFieldNode_js = require('three/examples/jsm/tsl/display/DepthOfFieldNode.js');
7
7
  var BloomNode_js = require('three/examples/jsm/tsl/display/BloomNode.js');
8
- var DenoiseNode_js = require('three/examples/jsm/tsl/display/DenoiseNode.js');
9
8
  var FXAANode_js = require('three/examples/jsm/tsl/display/FXAANode.js');
10
9
  var GTAONode_js = require('three/examples/jsm/tsl/display/GTAONode.js');
11
10
  var OutlineNode_js = require('three/examples/jsm/tsl/display/OutlineNode.js');
12
11
  var SMAANode_js = require('three/examples/jsm/tsl/display/SMAANode.js');
13
- var SSRNode_js = require('three/examples/jsm/tsl/display/SSRNode.js');
12
+ var TRAANode_js = require('three/examples/jsm/tsl/display/TRAANode.js');
13
+ var LensflareNode_js = require('three/examples/jsm/tsl/display/LensflareNode.js');
14
14
  var gsap = require('gsap');
15
15
  var three = require('three');
16
16
  var SkyMesh_js = require('three/examples/jsm/objects/SkyMesh.js');
@@ -1364,6 +1364,7 @@ exports.PostProcessStepType = void 0;
1364
1364
  PostProcessStepType[PostProcessStepType["GroundTruthAmbientOcclusion"] = 3] = "GroundTruthAmbientOcclusion";
1365
1365
  PostProcessStepType[PostProcessStepType["Outline"] = 4] = "Outline";
1366
1366
  PostProcessStepType[PostProcessStepType["Antialiasing"] = 5] = "Antialiasing";
1367
+ PostProcessStepType[PostProcessStepType["LensFlare"] = 6] = "LensFlare";
1367
1368
  })(exports.PostProcessStepType || (exports.PostProcessStepType = {}));
1368
1369
 
1369
1370
  class World {
@@ -1450,168 +1451,63 @@ class World {
1450
1451
  }
1451
1452
  }
1452
1453
 
1453
- class WebGPUPostProcessFactory {
1454
- // scene pass
1455
- static constructScenePass(scene, camera) {
1456
- const scenePass = tsl.pass(scene, camera, { minFilter: webgpu.NearestFilter, magFilter: webgpu.NearestFilter });
1457
- // scenePass.setMRT(mrt({
1458
- // output: output,
1459
- // }));
1460
- scenePass.setMRT(tsl.mrt({
1461
- output: tsl.output,
1462
- }));
1463
- return scenePass;
1464
- }
1465
- static updateScenePass(scenePass, outputNodes) {
1466
- let oldMRT = scenePass.getMRT();
1467
- let newMRT = tsl.mrt(outputNodes);
1468
- if (oldMRT) {
1469
- let merge = oldMRT.merge(newMRT);
1470
- scenePass.setMRT(merge);
1471
- }
1472
- else {
1473
- scenePass.setMRT(newMRT);
1474
- }
1475
- }
1476
- // bloom pass
1477
- static constructBloomPass(scenePass, params) {
1478
- const scenePassColor = scenePass.getTextureNode('output');
1479
- const bloomPass = BloomNode_js.bloom(scenePassColor);
1480
- WebGPUPostProcessFactory.updateBloomPass(bloomPass, params);
1481
- return bloomPass;
1482
- }
1483
- static updateBloomPass(bloomPass, params) {
1484
- bloomPass.threshold.value = params.threshold;
1485
- bloomPass.strength.value = params.strength;
1486
- bloomPass.radius.value = params.radius;
1487
- }
1488
- // DOF pass
1489
- static constructDOFPass(scenePass, params) {
1490
- const scenePassColor = scenePass.getTextureNode('output');
1491
- const scenePassViewZ = scenePass.getViewZNode();
1492
- const dofPass = DepthOfFieldNode_js.dof(scenePassColor, scenePassViewZ, tsl.uniform(1), tsl.uniform(0.01), tsl.uniform(0.01));
1493
- WebGPUPostProcessFactory.updateDOFPass(dofPass, params);
1494
- return dofPass;
1495
- }
1496
- static updateDOFPass(dofPass, params) {
1497
- dofPass.focusDistanceNode.value = params.focus;
1498
- dofPass.focalLengthNode.value = params.aperture;
1499
- dofPass.bokehScaleNode.value = params.maxblur;
1500
- }
1501
- // motion blur
1502
- // static constructMotionBlurPass(lastNode:NodeRepresentation, scenePass: ShaderNodeObject<PassNode>, param:MotionBlurParam): ShaderNodeObject<Node>
1503
- // {
1504
- // WebGPUPostProcessFactory.updateScenePass(scenePass, {velocity})
1505
- // const scenePassVelocity = scenePass.getTextureNode( 'velocity' ).mul( param.blurAmount );
1506
- // const scenePassColor = scenePass.getTextureNode('output');
1507
- // const motionBlurPass = motionBlur( scenePassColor, scenePassVelocity );
1508
- // return motionBlurPass
1509
- // }
1510
- // ssr
1511
- static constructSSRPass(scenePass, params) {
1512
- WebGPUPostProcessFactory.updateScenePass(scenePass, {
1513
- output: tsl.output,
1514
- normal: tsl.transformedNormalView,
1515
- metalness: tsl.metalness
1516
- });
1517
- const scenePassColor = scenePass.getTextureNode('output');
1518
- const scenePassDepth = scenePass.getTextureNode('depth');
1519
- const scenePassNormal = scenePass.getTextureNode('normal');
1520
- const scenePassMetalness = scenePass.getTextureNode('metalness');
1521
- const ssrPass = SSRNode_js.ssr(scenePassColor, scenePassDepth, scenePassNormal, scenePassMetalness, scenePass.camera);
1522
- ssrPass.resolutionScale = 1.0;
1523
- WebGPUPostProcessFactory.updateSSRPass(ssrPass, params);
1524
- return ssrPass;
1525
- }
1526
- static updateSSRPass(ssrPass, params) {
1527
- ssrPass.maxDistance.value = params.maxDistance;
1528
- ssrPass.opacity.value = params.opacity;
1529
- ssrPass.thickness.value = params.thickness;
1530
- }
1531
- // GTAO
1532
- static constructGTAOPass(scenePass, params) {
1533
- WebGPUPostProcessFactory.updateScenePass(scenePass, {
1534
- normal: tsl.transformedNormalView,
1535
- });
1536
- const scenePassNormal = scenePass.getTextureNode('normal');
1537
- const scenePassDepth = scenePass.getTextureNode('depth');
1538
- const aoPass = GTAONode_js.ao(scenePassDepth, scenePassNormal, scenePass.camera);
1539
- aoPass.resolutionScale = 0.5;
1540
- WebGPUPostProcessFactory.updateGTAOPass(aoPass, params);
1541
- return aoPass;
1542
- }
1543
- static updateGTAOPass(gtaoPass, params) {
1544
- gtaoPass.distanceExponent.value = params.distanceExponent;
1545
- gtaoPass.distanceFallOff.value = params.distanceFallOff;
1546
- gtaoPass.radius.value = params.radius;
1547
- gtaoPass.scale.value = params.scale;
1548
- gtaoPass.thickness.value = params.thickness;
1549
- }
1550
- static constructDenoisePass(scenePass, inputNode, params) {
1551
- WebGPUPostProcessFactory.updateScenePass(scenePass, {
1552
- normal: tsl.transformedNormalView,
1553
- });
1554
- const scenePassNormal = scenePass.getTextureNode('normal');
1555
- const scenePassDepth = scenePass.getTextureNode('depth');
1556
- const denoisePass = DenoiseNode_js.denoise(inputNode, scenePassDepth, scenePassNormal, scenePass.camera);
1557
- WebGPUPostProcessFactory.updateDenoisePass(denoisePass, params);
1558
- return denoisePass;
1559
- }
1560
- static updateDenoisePass(denoisePass, params) {
1561
- denoisePass.radius.value = params.denoiseRadius;
1562
- denoisePass.lumaPhi.value = params.lumaPhi;
1563
- denoisePass.depthPhi.value = params.depthPhi;
1564
- denoisePass.normalPhi.value = params.normalPhi;
1565
- }
1566
- static constructGTAODenoisePass(scenePass, gtaoPass, params) {
1567
- return WebGPUPostProcessFactory.constructDenoisePass(scenePass, gtaoPass.getTextureNode(), params.denoiseParam);
1568
- }
1569
- static updateGTAODenoisePass(denoisePass, params) {
1570
- WebGPUPostProcessFactory.updateDenoisePass(denoisePass, params.denoiseParam);
1571
- }
1572
- // static constructLensFlarePass(inputNode: NodeRepresentation, params: LensFlareParam): ShaderNodeObject<LensflareNode>
1573
- // {
1574
- // const lensflarePass = lensflare(inputNode, {
1575
- // threshold : uniform(params.threshold),
1576
- // ghostAttenuationFactor: uniform(params.ghostAttenuationFactor),
1577
- // ghostSpacing : uniform(params.ghostSpacing),
1578
- // });
1579
- // return lensflarePass;
1580
- // }
1581
- // static updateLensFlarPass(lensflarePass: ShaderNodeObject<LensflareNode>, params: LensFlareParam)
1582
- // {
1583
- // lensflarePass.thresholdNode.value = params.threshold
1584
- // lensflarePass.ghostSpacingNode.value = params.ghostSpacing
1585
- // lensflarePass.ghostAttenuationFactorNode.value = params.ghostAttenuationFactor
1586
- // }
1587
- static constructOutlinePass(scene, camera, outlineObjects, param) {
1588
- const outlinePass = OutlineNode_js.outline(scene, camera, {
1589
- selectedObjects: outlineObjects,
1590
- edgeGlow: tsl.uniform(1),
1591
- edgeThickness: tsl.uniform(1)
1592
- });
1593
- WebGPUPostProcessFactory.updateOutlinePass(outlinePass, outlineObjects, param);
1594
- return outlinePass;
1595
- }
1596
- static updateOutlinePass(outlinePass, outlineObjects, params) {
1597
- outlinePass.edgeGlowNode.value = params.edgeGlow;
1598
- outlinePass.edgeThicknessNode.value = params.edgeThickness;
1599
- outlinePass.selectedObjects = outlineObjects;
1600
- }
1601
- // fxaa
1602
- static constructFXAAPass(inputNode) {
1603
- return FXAANode_js.fxaa(inputNode);
1604
- }
1605
- // smaa
1606
- static constructSMAAPass(inputNode) {
1607
- return SMAANode_js.smaa(inputNode);
1608
- }
1609
- }
1454
+ const DefaultBloomParam = {
1455
+ type: exports.PostProcessStepType.Bloom,
1456
+ threshold: 0,
1457
+ strength: 1,
1458
+ radius: 0,
1459
+ };
1460
+
1461
+ const DefaultDOFParam = {
1462
+ type: exports.PostProcessStepType.DepthOfField,
1463
+ focus: 500.0,
1464
+ aperture: 5,
1465
+ maxblur: 0.01
1466
+ };
1467
+
1468
+ const DefaultGTAOParam = {
1469
+ type: exports.PostProcessStepType.GroundTruthAmbientOcclusion,
1470
+ distanceExponent: 1,
1471
+ distanceFallOff: 1,
1472
+ radius: 0.25,
1473
+ scale: 1,
1474
+ thickness: 1,
1475
+ samples: 16,
1476
+ useTemporalFiltering: false
1477
+ };
1478
+
1479
+ const DefaultOutlineParams = {
1480
+ type: exports.PostProcessStepType.Outline,
1481
+ edgeStrength: 3.0,
1482
+ edgeGlow: 1.0,
1483
+ edgeThickness: 1.0,
1484
+ pulsePeriod: 0.0,
1485
+ visibleEdgeColor: 0xffffff,
1486
+ hiddenEdgeColor: 0xffffff,
1487
+ };
1488
+
1489
+ const DefaultLensFlareParam = {
1490
+ type: exports.PostProcessStepType.LensFlare,
1491
+ threshold: 0.5,
1492
+ ghostSamples: 4,
1493
+ ghostSpacing: 0.25,
1494
+ ghostAttenuationFactor: 25,
1495
+ ghostTint: [1, 1, 1],
1496
+ downSampleRatio: 4,
1497
+ };
1610
1498
 
1611
1499
  class PostProcessManager {
1612
1500
  constructor(renderer, scene, camera, postProcessParam, onDirtyCallback) {
1613
1501
  this.postProcessing = null;
1614
1502
  this.outlineObjects = [];
1503
+ this.effectUniforms = null;
1504
+ this.outlinePass = null;
1505
+ this.bloomPass = null;
1506
+ this.dofPass = null;
1507
+ this.gtaoPass = null;
1508
+ this.traaPass = null;
1509
+ this.lensflarePass = null;
1510
+ this.lut3dTexture = null;
1615
1511
  this.onDirtyCallback = null;
1616
1512
  this.renderer = renderer;
1617
1513
  this.scene = scene;
@@ -1624,116 +1520,301 @@ class PostProcessManager {
1624
1520
  }
1625
1521
  updateCamera(camera) {
1626
1522
  this.camera = camera;
1627
- if (this.postProcessing) {
1628
- this.setup();
1523
+ if (!this.postProcessing || !this.effectUniforms) {
1524
+ this.buildPipeline();
1525
+ this.updateAllUniforms();
1526
+ this.markDirty();
1629
1527
  }
1630
1528
  }
1631
1529
  setup() {
1632
- if (this.postProcessParam.steps.length === 0) {
1633
- this.destroy();
1634
- this.markDirty();
1635
- return;
1530
+ if (!this.postProcessing || !this.effectUniforms) {
1531
+ this.buildPipeline();
1636
1532
  }
1533
+ this.updateAllUniforms();
1534
+ this.markDirty();
1535
+ }
1536
+ buildPipeline() {
1537
+ var _a, _b, _c, _d, _e;
1637
1538
  if (this.postProcessing) {
1638
1539
  this.postProcessing.dispose();
1639
1540
  }
1640
1541
  this.postProcessing = new webgpu.PostProcessing(this.renderer);
1641
- const scenePass = WebGPUPostProcessFactory.constructScenePass(this.scene, this.camera);
1642
- let finalNode = scenePass.getTextureNode('output');
1643
- this.postProcessParam.steps.forEach((step) => {
1644
- switch (step.type) {
1645
- case exports.PostProcessStepType.Bloom:
1646
- {
1647
- const bloomPass = WebGPUPostProcessFactory.constructBloomPass(scenePass, step);
1648
- finalNode = finalNode.add(bloomPass);
1649
- break;
1650
- }
1651
- case exports.PostProcessStepType.DepthOfField:
1652
- {
1653
- finalNode = WebGPUPostProcessFactory.constructDOFPass(scenePass, step);
1654
- break;
1655
- }
1656
- case exports.PostProcessStepType.ScreenSpaceReflection:
1657
- {
1658
- const ssrParam = step;
1659
- const ssrPass = WebGPUPostProcessFactory.constructSSRPass(scenePass, ssrParam);
1660
- if (ssrPass) {
1661
- finalNode = finalNode.add(ssrPass);
1662
- }
1663
- else {
1664
- console.warn("[PostProcess] SSR 目前存在技术问题,暂不支持。");
1665
- }
1666
- break;
1667
- }
1668
- case exports.PostProcessStepType.GroundTruthAmbientOcclusion:
1669
- {
1670
- const gtaoParam = step;
1671
- const gtaoPass = WebGPUPostProcessFactory.constructGTAOPass(scenePass, gtaoParam);
1672
- if (gtaoParam.denoised) {
1673
- const denoisePass = WebGPUPostProcessFactory.constructGTAODenoisePass(scenePass, gtaoPass, gtaoParam);
1674
- finalNode = finalNode.mul(denoisePass);
1675
- }
1676
- else {
1677
- finalNode = finalNode.mul(gtaoPass);
1678
- }
1679
- break;
1680
- }
1681
- case exports.PostProcessStepType.Outline:
1682
- {
1683
- const outlineParam = step;
1684
- const outlinePass = WebGPUPostProcessFactory.constructOutlinePass(this.scene, scenePass.camera, this.outlineObjects, outlineParam);
1685
- const { visibleEdge, hiddenEdge } = outlinePass;
1686
- const pulsePeriod = tsl.uniform(outlineParam.pulsePeriod);
1687
- const safePulsePeriod = pulsePeriod.greaterThan(0).select(pulsePeriod, tsl.uniform(1));
1688
- const period = tsl.time.div(safePulsePeriod).mul(2);
1689
- const osc = tsl.oscSine(period).mul(.5).add(.5);
1690
- const outlineColor = visibleEdge
1691
- .mul(tsl.uniform(new webgpu.Color(outlineParam.visibleEdgeColor)))
1692
- .add(hiddenEdge.mul(tsl.uniform(new webgpu.Color(outlineParam.hiddenEdgeColor))))
1693
- .mul(outlineParam.edgeStrength);
1694
- const outlinePulse = pulsePeriod.greaterThan(0).select(outlineColor.mul(osc), outlineColor);
1695
- finalNode = outlinePulse.add(finalNode);
1696
- break;
1697
- }
1698
- case exports.PostProcessStepType.Antialiasing:
1699
- {
1700
- const aaParam = step;
1701
- if (aaParam.method === "fxaa") {
1702
- finalNode = WebGPUPostProcessFactory.constructFXAAPass(finalNode);
1703
- }
1704
- if (aaParam.method === "smaa") {
1705
- finalNode = WebGPUPostProcessFactory.constructSMAAPass(finalNode);
1706
- }
1707
- break;
1708
- }
1709
- }
1542
+ // Create uniforms
1543
+ this.effectUniforms = this.createEffectUniforms();
1544
+ // Build scene pass
1545
+ const scenePass = tsl.pass(this.scene, this.camera);
1546
+ scenePass.setMRT(tsl.mrt({
1547
+ output: tsl.output,
1548
+ normal: tsl.normalView,
1549
+ velocity: tsl.velocity
1550
+ }));
1551
+ const sceneColor = scenePass.getTextureNode('output');
1552
+ const sceneNormal = scenePass.getTextureNode('normal');
1553
+ const sceneDepth = scenePass.getTextureNode('depth');
1554
+ const sceneVelocity = scenePass.getTextureNode('velocity');
1555
+ const sceneViewZ = scenePass.getViewZNode();
1556
+ const u = this.effectUniforms;
1557
+ // Build Bloom - create with defaults, update via pass properties
1558
+ const bloomInitParam = (_a = this.getStepParam(exports.PostProcessStepType.Bloom)) !== null && _a !== void 0 ? _a : DefaultBloomParam;
1559
+ this.bloomPass = BloomNode_js.bloom(sceneColor);
1560
+ this.bloomPass.threshold.value = bloomInitParam.threshold;
1561
+ this.bloomPass.strength.value = bloomInitParam.strength;
1562
+ this.bloomPass.radius.value = bloomInitParam.radius;
1563
+ const bloomResult = sceneColor.add(this.bloomPass.mul(u.bloomStrength));
1564
+ const afterBloom = u.bloomEnabled.greaterThan(0.5).select(bloomResult, sceneColor);
1565
+ // Build LensFlare - requires bloom texture as input
1566
+ const lensflareInitParam = (_b = this.getStepParam(exports.PostProcessStepType.LensFlare)) !== null && _b !== void 0 ? _b : DefaultLensFlareParam;
1567
+ this.lensflarePass = LensflareNode_js.lensflare(this.bloomPass.getTextureNode(), {
1568
+ ghostTint: tsl.vec3(lensflareInitParam.ghostTint[0], lensflareInitParam.ghostTint[1], lensflareInitParam.ghostTint[2]),
1569
+ threshold: tsl.float(lensflareInitParam.threshold),
1570
+ ghostSamples: tsl.float(lensflareInitParam.ghostSamples),
1571
+ ghostSpacing: tsl.float(lensflareInitParam.ghostSpacing),
1572
+ ghostAttenuationFactor: tsl.float(lensflareInitParam.ghostAttenuationFactor),
1573
+ downSampleRatio: lensflareInitParam.downSampleRatio
1574
+ });
1575
+ const lensflareResult = afterBloom.add(this.lensflarePass.getTextureNode());
1576
+ const afterLensflare = u.lensflareEnabled.greaterThan(0.5).select(lensflareResult, afterBloom);
1577
+ // Build DOF - create with uniform nodes
1578
+ const dofInitParam = (_c = this.getStepParam(exports.PostProcessStepType.DepthOfField)) !== null && _c !== void 0 ? _c : DefaultDOFParam;
1579
+ this.dofPass = DepthOfFieldNode_js.dof(afterLensflare, sceneViewZ, tsl.uniform(dofInitParam.focus), tsl.uniform(dofInitParam.aperture), tsl.uniform(dofInitParam.maxblur));
1580
+ const afterDOF = u.dofEnabled.greaterThan(0.5).select(this.dofPass, afterLensflare);
1581
+ // Build GTAO
1582
+ const gtaoInitParam = (_d = this.getStepParam(exports.PostProcessStepType.GroundTruthAmbientOcclusion)) !== null && _d !== void 0 ? _d : DefaultGTAOParam;
1583
+ this.gtaoPass = GTAONode_js.ao(sceneDepth, sceneNormal, this.camera);
1584
+ this.gtaoPass.resolutionScale = 0.5;
1585
+ this.gtaoPass.distanceExponent.value = gtaoInitParam.distanceExponent;
1586
+ this.gtaoPass.distanceFallOff.value = gtaoInitParam.distanceFallOff;
1587
+ this.gtaoPass.radius.value = gtaoInitParam.radius;
1588
+ this.gtaoPass.scale.value = gtaoInitParam.scale;
1589
+ this.gtaoPass.thickness.value = gtaoInitParam.thickness;
1590
+ this.gtaoPass.samples.value = gtaoInitParam.samples;
1591
+ // 官方推荐使用 useTemporalFiltering 而不是 denoise
1592
+ this.gtaoPass.useTemporalFiltering = gtaoInitParam.useTemporalFiltering;
1593
+ // 获取 AO 纹理,使用 .r 获取单通道值
1594
+ const aoTexture = this.gtaoPass.getTextureNode();
1595
+ const aoValue = aoTexture.r;
1596
+ const gtaoResult = afterDOF.mul(aoValue);
1597
+ const afterGTAO = u.gtaoEnabled.greaterThan(0.5).select(gtaoResult, afterDOF);
1598
+ // Build Outline
1599
+ const outlineInitParam = (_e = this.getStepParam(exports.PostProcessStepType.Outline)) !== null && _e !== void 0 ? _e : DefaultOutlineParams;
1600
+ this.outlinePass = OutlineNode_js.outline(this.scene, this.camera, {
1601
+ selectedObjects: this.outlineObjects,
1602
+ edgeGlow: tsl.uniform(outlineInitParam.edgeGlow),
1603
+ edgeThickness: tsl.uniform(outlineInitParam.edgeThickness)
1710
1604
  });
1605
+ const { visibleEdge, hiddenEdge } = this.outlinePass;
1606
+ const safePulsePeriod = u.outlinePulsePeriod.greaterThan(0).select(u.outlinePulsePeriod, tsl.uniform(1));
1607
+ const period = tsl.time.div(safePulsePeriod).mul(2);
1608
+ const osc = tsl.oscSine(period).mul(0.5).add(0.5);
1609
+ const outlineColor = visibleEdge
1610
+ .mul(u.outlineVisibleEdgeColor)
1611
+ .add(hiddenEdge.mul(u.outlineHiddenEdgeColor))
1612
+ .mul(u.outlineEdgeStrength);
1613
+ const outlinePulse = u.outlinePulsePeriod.greaterThan(0).select(outlineColor.mul(osc), outlineColor);
1614
+ const outlineResult = outlinePulse.add(afterGTAO);
1615
+ const afterOutline = u.outlineEnabled.greaterThan(0.5).select(outlineResult, afterGTAO);
1616
+ // Build AA
1617
+ const fxaaResult = FXAANode_js.fxaa(afterOutline);
1618
+ const afterFXAA = u.fxaaEnabled.greaterThan(0.5).select(fxaaResult, afterOutline);
1619
+ const smaaResult = SMAANode_js.smaa(afterFXAA);
1620
+ const afterSMAA = u.smaaEnabled.greaterThan(0.5).select(smaaResult, afterFXAA);
1621
+ // Build TRAA - 仅在启用时创建,避免 depth texture sample count mismatch
1622
+ const aaParam = this.getStepParam(exports.PostProcessStepType.Antialiasing);
1623
+ let finalNode = afterSMAA;
1624
+ if (aaParam && aaParam.method === "traa") {
1625
+ this.traaPass = TRAANode_js.traa(afterSMAA, sceneDepth, sceneVelocity, this.camera);
1626
+ finalNode = this.traaPass.getTextureNode();
1627
+ }
1628
+ // Allow subclasses to modify the final node
1629
+ finalNode = this.onBuildFinalNode(finalNode);
1711
1630
  this.postProcessing.outputNode = finalNode;
1712
1631
  this.postProcessing.needsUpdate = true;
1713
- this.markDirty();
1632
+ }
1633
+ /** Hook for subclasses to modify the final output node. Override to add custom effects. */
1634
+ onBuildFinalNode(node) {
1635
+ return node;
1636
+ }
1637
+ createEffectUniforms() {
1638
+ var _a, _b, _c, _d;
1639
+ const bloomParam = (_a = this.getStepParam(exports.PostProcessStepType.Bloom)) !== null && _a !== void 0 ? _a : DefaultBloomParam;
1640
+ const dofParam = (_b = this.getStepParam(exports.PostProcessStepType.DepthOfField)) !== null && _b !== void 0 ? _b : DefaultDOFParam;
1641
+ const gtaoParam = (_c = this.getStepParam(exports.PostProcessStepType.GroundTruthAmbientOcclusion)) !== null && _c !== void 0 ? _c : DefaultGTAOParam;
1642
+ const outlineParam = (_d = this.getStepParam(exports.PostProcessStepType.Outline)) !== null && _d !== void 0 ? _d : DefaultOutlineParams;
1643
+ return {
1644
+ bloomEnabled: tsl.uniform(0),
1645
+ bloomStrength: tsl.uniform(bloomParam.strength),
1646
+ bloomThreshold: tsl.uniform(bloomParam.threshold),
1647
+ bloomRadius: tsl.uniform(bloomParam.radius),
1648
+ dofEnabled: tsl.uniform(0),
1649
+ dofFocus: tsl.uniform(dofParam.focus),
1650
+ dofAperture: tsl.uniform(dofParam.aperture),
1651
+ dofMaxBlur: tsl.uniform(dofParam.maxblur),
1652
+ gtaoEnabled: tsl.uniform(0),
1653
+ gtaoScale: tsl.uniform(gtaoParam.scale),
1654
+ gtaoDistanceExponent: tsl.uniform(gtaoParam.distanceExponent),
1655
+ gtaoDistanceFallOff: tsl.uniform(gtaoParam.distanceFallOff),
1656
+ gtaoRadius: tsl.uniform(gtaoParam.radius),
1657
+ gtaoThickness: tsl.uniform(gtaoParam.thickness),
1658
+ gtaoSamples: tsl.uniform(gtaoParam.samples),
1659
+ outlineEnabled: tsl.uniform(0),
1660
+ outlineEdgeStrength: tsl.uniform(outlineParam.edgeStrength),
1661
+ outlineEdgeGlow: tsl.uniform(outlineParam.edgeGlow),
1662
+ outlineEdgeThickness: tsl.uniform(outlineParam.edgeThickness),
1663
+ outlinePulsePeriod: tsl.uniform(outlineParam.pulsePeriod),
1664
+ outlineVisibleEdgeColor: tsl.uniform(new webgpu.Color(outlineParam.visibleEdgeColor)),
1665
+ outlineHiddenEdgeColor: tsl.uniform(new webgpu.Color(outlineParam.hiddenEdgeColor)),
1666
+ fxaaEnabled: tsl.uniform(0),
1667
+ smaaEnabled: tsl.uniform(0),
1668
+ lensflareEnabled: tsl.uniform(0),
1669
+ };
1670
+ }
1671
+ getStepParam(type) {
1672
+ var _a;
1673
+ return (_a = this.postProcessParam.steps.find(step => step.type === type)) !== null && _a !== void 0 ? _a : null;
1674
+ }
1675
+ updateAllUniforms() {
1676
+ if (!this.effectUniforms)
1677
+ return;
1678
+ const u = this.effectUniforms;
1679
+ const activeTypes = new Set(this.postProcessParam.steps.map(step => step.type));
1680
+ // Update enable/disable
1681
+ u.bloomEnabled.value = activeTypes.has(exports.PostProcessStepType.Bloom) ? 1 : 0;
1682
+ u.dofEnabled.value = activeTypes.has(exports.PostProcessStepType.DepthOfField) ? 1 : 0;
1683
+ u.gtaoEnabled.value = activeTypes.has(exports.PostProcessStepType.GroundTruthAmbientOcclusion) ? 1 : 0;
1684
+ u.outlineEnabled.value = activeTypes.has(exports.PostProcessStepType.Outline) ? 1 : 0;
1685
+ u.lensflareEnabled.value = activeTypes.has(exports.PostProcessStepType.LensFlare) ? 1 : 0;
1686
+ // Update AA
1687
+ const aaParam = this.getStepParam(exports.PostProcessStepType.Antialiasing);
1688
+ if (aaParam) {
1689
+ u.fxaaEnabled.value = aaParam.method === "fxaa" ? 1 : 0;
1690
+ u.smaaEnabled.value = aaParam.method === "smaa" ? 1 : 0;
1691
+ }
1692
+ else {
1693
+ u.fxaaEnabled.value = 0;
1694
+ u.smaaEnabled.value = 0;
1695
+ }
1696
+ // Update Bloom parameters
1697
+ const bloomParam = this.getStepParam(exports.PostProcessStepType.Bloom);
1698
+ if (bloomParam) {
1699
+ u.bloomStrength.value = bloomParam.strength;
1700
+ u.bloomThreshold.value = bloomParam.threshold;
1701
+ u.bloomRadius.value = bloomParam.radius;
1702
+ // Update Bloom pass properties
1703
+ if (this.bloomPass) {
1704
+ this.bloomPass.threshold.value = bloomParam.threshold;
1705
+ this.bloomPass.strength.value = bloomParam.strength;
1706
+ this.bloomPass.radius.value = bloomParam.radius;
1707
+ }
1708
+ }
1709
+ // Update LensFlare parameters - requires pipeline rebuild for parameter changes
1710
+ const lensflareParam = this.getStepParam(exports.PostProcessStepType.LensFlare);
1711
+ if (lensflareParam && this.lensflarePass) ;
1712
+ // Update DOF parameters
1713
+ const dofParam = this.getStepParam(exports.PostProcessStepType.DepthOfField);
1714
+ if (dofParam) {
1715
+ u.dofFocus.value = dofParam.focus;
1716
+ u.dofAperture.value = dofParam.aperture;
1717
+ u.dofMaxBlur.value = dofParam.maxblur;
1718
+ // Update DOF pass properties
1719
+ if (this.dofPass) {
1720
+ this.dofPass.focusDistanceNode.value = dofParam.focus;
1721
+ this.dofPass.focalLengthNode.value = dofParam.aperture;
1722
+ this.dofPass.bokehScaleNode.value = dofParam.maxblur;
1723
+ }
1724
+ }
1725
+ // Update GTAO parameters
1726
+ const gtaoParam = this.getStepParam(exports.PostProcessStepType.GroundTruthAmbientOcclusion);
1727
+ if (gtaoParam) {
1728
+ u.gtaoScale.value = gtaoParam.scale;
1729
+ u.gtaoDistanceExponent.value = gtaoParam.distanceExponent;
1730
+ u.gtaoDistanceFallOff.value = gtaoParam.distanceFallOff;
1731
+ u.gtaoRadius.value = gtaoParam.radius;
1732
+ u.gtaoThickness.value = gtaoParam.thickness;
1733
+ u.gtaoSamples.value = gtaoParam.samples;
1734
+ // Update GTAO pass properties
1735
+ if (this.gtaoPass) {
1736
+ this.gtaoPass.distanceExponent.value = gtaoParam.distanceExponent;
1737
+ this.gtaoPass.distanceFallOff.value = gtaoParam.distanceFallOff;
1738
+ this.gtaoPass.radius.value = gtaoParam.radius;
1739
+ this.gtaoPass.scale.value = gtaoParam.scale;
1740
+ this.gtaoPass.thickness.value = gtaoParam.thickness;
1741
+ this.gtaoPass.samples.value = gtaoParam.samples;
1742
+ this.gtaoPass.useTemporalFiltering = gtaoParam.useTemporalFiltering;
1743
+ }
1744
+ }
1745
+ // Update Outline parameters
1746
+ const outlineParam = this.getStepParam(exports.PostProcessStepType.Outline);
1747
+ if (outlineParam) {
1748
+ u.outlineEdgeStrength.value = outlineParam.edgeStrength;
1749
+ u.outlineEdgeGlow.value = outlineParam.edgeGlow;
1750
+ u.outlineEdgeThickness.value = outlineParam.edgeThickness;
1751
+ u.outlinePulsePeriod.value = outlineParam.pulsePeriod;
1752
+ u.outlineVisibleEdgeColor.value.set(outlineParam.visibleEdgeColor);
1753
+ u.outlineHiddenEdgeColor.value.set(outlineParam.hiddenEdgeColor);
1754
+ // Update outline pass
1755
+ if (this.outlinePass) {
1756
+ this.outlinePass.edgeGlowNode.value = outlineParam.edgeGlow;
1757
+ this.outlinePass.edgeThicknessNode.value = outlineParam.edgeThickness;
1758
+ this.outlinePass.selectedObjects = this.outlineObjects;
1759
+ }
1760
+ }
1714
1761
  }
1715
1762
  updateSteps(steps) {
1763
+ console.log("[PostProcessManager] updateSteps called", steps);
1764
+ console.trace("[PostProcessManager] updateSteps call stack");
1716
1765
  this.postProcessParam.steps = steps;
1717
- this.setup();
1766
+ console.log("updateSteps", steps);
1767
+ if (!this.effectUniforms || !this.postProcessing) {
1768
+ console.log("[PostProcessManager] Building pipeline because effectUniforms or postProcessing is null");
1769
+ this.buildPipeline();
1770
+ }
1771
+ this.updateAllUniforms();
1772
+ this.markDirty();
1718
1773
  }
1719
1774
  addOutlineObject(obj) {
1720
1775
  if (!this.outlineObjects.includes(obj)) {
1721
1776
  this.outlineObjects.push(obj);
1777
+ if (this.outlinePass) {
1778
+ this.outlinePass.selectedObjects = this.outlineObjects;
1779
+ }
1722
1780
  }
1723
1781
  this.markDirty();
1724
1782
  }
1725
1783
  setOutlineObjects(objects) {
1726
1784
  this.outlineObjects.length = 0;
1727
1785
  this.outlineObjects.push(...objects);
1786
+ if (this.outlinePass) {
1787
+ this.outlinePass.selectedObjects = this.outlineObjects;
1788
+ }
1728
1789
  this.markDirty();
1729
1790
  }
1730
1791
  removeOutlineObject(obj) {
1731
1792
  const index = this.outlineObjects.indexOf(obj);
1732
1793
  if (index > -1) {
1733
1794
  this.outlineObjects.splice(index, 1);
1795
+ if (this.outlinePass) {
1796
+ this.outlinePass.selectedObjects = this.outlineObjects;
1797
+ }
1734
1798
  }
1735
1799
  this.markDirty();
1736
1800
  }
1801
+ /**
1802
+ * 设置 3D LUT 纹理
1803
+ * @param lutTexture 3D LUT 纹理,传 null 清除
1804
+ */
1805
+ setLUT3DTexture(lutTexture) {
1806
+ this.lut3dTexture = lutTexture;
1807
+ // 需要重建管线以应用新的 LUT 纹理
1808
+ this.buildPipeline();
1809
+ this.updateAllUniforms();
1810
+ this.markDirty();
1811
+ }
1812
+ /**
1813
+ * 获取当前 3D LUT 纹理
1814
+ */
1815
+ getLUT3DTexture() {
1816
+ return this.lut3dTexture;
1817
+ }
1737
1818
  render() {
1738
1819
  if (this.postProcessing) {
1739
1820
  this.postProcessing.render();
@@ -1741,15 +1822,16 @@ class PostProcessManager {
1741
1822
  }
1742
1823
  return false;
1743
1824
  }
1744
- async renderAsync() {
1745
- if (this.postProcessing) {
1746
- await this.postProcessing.renderAsync();
1747
- return true;
1748
- }
1749
- return false;
1750
- }
1751
1825
  destroy() {
1752
1826
  this.outlineObjects = [];
1827
+ this.effectUniforms = null;
1828
+ this.outlinePass = null;
1829
+ this.bloomPass = null;
1830
+ this.dofPass = null;
1831
+ this.gtaoPass = null;
1832
+ this.traaPass = null;
1833
+ this.lensflarePass = null;
1834
+ this.lut3dTexture = null;
1753
1835
  if (this.postProcessing) {
1754
1836
  this.postProcessing.dispose();
1755
1837
  this.postProcessing = null;
@@ -1859,6 +1941,7 @@ class Viewport {
1859
1941
  this._renderer.shadowMap.type = rendererParam.shadowMapType;
1860
1942
  this._renderer.toneMapping = rendererParam.toneMapping;
1861
1943
  this._renderer.toneMappingExposure = rendererParam.toneMappingExposure;
1944
+ this._renderer.setClearAlpha(0);
1862
1945
  if (element) {
1863
1946
  element.appendChild(this._renderer.domElement);
1864
1947
  }
@@ -1908,10 +1991,14 @@ class Viewport {
1908
1991
  }
1909
1992
  setupPostProcess() {
1910
1993
  if (!this.postProcessManager) {
1911
- this.postProcessManager = new PostProcessManager(this.renderer, this.app.world.scene, this.app.camera, this.postProcessParam, () => this.markRenderStateDirty());
1994
+ this.postProcessManager = this.createPostProcessManager();
1912
1995
  }
1913
1996
  this.postProcessManager.setup();
1914
1997
  }
1998
+ /** Create the PostProcessManager instance. Override in subclass to use custom manager. */
1999
+ createPostProcessManager() {
2000
+ return new PostProcessManager(this.renderer, this.app.world.scene, this.app.camera, this.postProcessParam, () => this.markRenderStateDirty());
2001
+ }
1915
2002
  updatePostProcess(steps) {
1916
2003
  if (this.postProcessManager) {
1917
2004
  this.postProcessManager.updateSteps(steps);
@@ -1965,14 +2052,20 @@ class Viewport {
1965
2052
  else {
1966
2053
  this.renderer.render(this.app.world.scene, this.app.camera);
1967
2054
  }
2055
+ // Hook for subclasses to render additional content after post-processing
2056
+ this.onAfterPostProcessRender();
1968
2057
  if (this.labelRenderer) {
1969
2058
  this.labelRenderer.render(this.app.world.scene, this.app.camera);
1970
2059
  }
1971
2060
  this.isRenderStateDirty = false;
1972
2061
  }
2062
+ /** Called after post-processing render, before label renderer. Override in subclass to render additional content. */
2063
+ onAfterPostProcessRender() {
2064
+ // Override in subclass
2065
+ }
1973
2066
  async renderAsImage(width = 1024, height = 1024) {
1974
2067
  try {
1975
- if (this.postProcessManager && await this.postProcessManager.renderAsync()) {
2068
+ if (this.postProcessManager && this.postProcessManager.render()) {
1976
2069
  // Post processing rendered
1977
2070
  }
1978
2071
  else {
@@ -2681,7 +2774,7 @@ const DefaultRendererParameters = {
2681
2774
  depth: true,
2682
2775
  stencil: false,
2683
2776
  antialias: false,
2684
- samples: 4,
2777
+ samples: 1,
2685
2778
  forceWebGL: false,
2686
2779
  outputBufferType: 1016,
2687
2780
  toneMapping: 0,
@@ -3600,47 +3693,6 @@ class LabelComponent extends SceneComponent {
3600
3693
  // labelStyle.style.fontSize = "10px";
3601
3694
  // labelStyle.style.pointerEvents = 'auto';
3602
3695
 
3603
- const DefaultBloomParam = {
3604
- type: exports.PostProcessStepType.Bloom,
3605
- threshold: 0,
3606
- strength: 1,
3607
- radius: 0,
3608
- };
3609
-
3610
- const DefaultDenoiseParam = {
3611
- denoiseRadius: 5,
3612
- lumaPhi: 5,
3613
- depthPhi: 5,
3614
- normalPhi: 5
3615
- };
3616
- const DefaultGTAOParam = {
3617
- type: exports.PostProcessStepType.GroundTruthAmbientOcclusion,
3618
- distanceExponent: 1,
3619
- distanceFallOff: 1,
3620
- radius: 0.25,
3621
- scale: 1,
3622
- thickness: 1,
3623
- denoised: true,
3624
- denoiseParam: DefaultDenoiseParam,
3625
- };
3626
-
3627
- const DefaultDOFParam = {
3628
- type: exports.PostProcessStepType.DepthOfField,
3629
- focus: 500.0,
3630
- aperture: 5,
3631
- maxblur: 0.01
3632
- };
3633
-
3634
- const DefaultOutlineParams = {
3635
- type: exports.PostProcessStepType.Outline,
3636
- edgeStrength: 3.0,
3637
- edgeGlow: 1.0,
3638
- edgeThickness: 1.0,
3639
- pulsePeriod: 0.0,
3640
- visibleEdgeColor: 0xffffff,
3641
- hiddenEdgeColor: 0xffffff,
3642
- };
3643
-
3644
3696
  const DefaultSSRParam = {
3645
3697
  type: exports.PostProcessStepType.ScreenSpaceReflection,
3646
3698
  maxDistance: 0.5,
@@ -3683,13 +3735,16 @@ class TransformGizmo extends Pawn {
3683
3735
  }
3684
3736
  return this._control;
3685
3737
  }
3686
- constructor(controller) {
3738
+ constructor(controller, options) {
3739
+ var _a;
3687
3740
  super(controller);
3688
3741
  this._control = null;
3689
3742
  this.helperObject = new webgpu.Object3D();
3690
3743
  this.targets = [];
3691
3744
  this.primaryTarget = null;
3692
3745
  this.targetMatrixMap = new Map();
3746
+ /** Scene where gizmo is rendered (can be separate from main scene to avoid post-processing) */
3747
+ this.gizmoScene = null;
3693
3748
  this.onDraggingChangedEvent = (param) => { this.onDraggingChanged(param); };
3694
3749
  this.onObjectChangeEvent = () => { this.onObjectChanged(); };
3695
3750
  this.onChangeEvent = () => { this.onChange(); };
@@ -3704,35 +3759,43 @@ class TransformGizmo extends Pawn {
3704
3759
  elem.userData["rayIgnored"] = true;
3705
3760
  });
3706
3761
  this.helperObject.name = "TransformHelperObject";
3762
+ this.gizmoScene = (_a = options === null || options === void 0 ? void 0 : options.helperScene) !== null && _a !== void 0 ? _a : null;
3707
3763
  }
3708
- possess() {
3764
+ /** Get the scene where gizmo should be added */
3765
+ getTargetScene() {
3709
3766
  var _a;
3710
- (_a = this.controller.world.scene) === null || _a === void 0 ? void 0 : _a.add(this.helperObject);
3767
+ return (_a = this.gizmoScene) !== null && _a !== void 0 ? _a : this.controller.world.scene;
3768
+ }
3769
+ possess() {
3770
+ const targetScene = this.getTargetScene();
3771
+ targetScene.add(this.helperObject);
3772
+ targetScene.add(this.control.getHelper());
3711
3773
  this.control.attach(this.helperObject);
3712
3774
  this.control.addEventListener('change', this.onChangeEvent);
3713
3775
  this.control.addEventListener('dragging-changed', this.onDraggingChangedEvent);
3714
3776
  this.control.addEventListener('objectChange', this.onObjectChangeEvent);
3715
3777
  }
3716
3778
  unpossess() {
3717
- var _a;
3718
3779
  this.control.removeEventListener('change', this.onChangeEvent);
3719
3780
  this.control.removeEventListener('dragging-changed', this.onDraggingChangedEvent);
3720
3781
  this.control.removeEventListener('objectChange', this.onObjectChangeEvent);
3721
3782
  this.control.detach();
3722
- (_a = this.controller.world.scene) === null || _a === void 0 ? void 0 : _a.remove(this.helperObject);
3783
+ const targetScene = this.getTargetScene();
3784
+ targetScene.remove(this.helperObject);
3785
+ targetScene.remove(this.control.getHelper());
3723
3786
  }
3724
3787
  refresh() {
3725
- var _a, _b, _c;
3726
3788
  if (!this.primaryTarget) {
3727
3789
  return;
3728
3790
  }
3729
3791
  this.control.detach();
3730
- (_a = this.controller.world.scene) === null || _a === void 0 ? void 0 : _a.remove(this.helperObject);
3792
+ const targetScene = this.getTargetScene();
3793
+ targetScene.remove(this.helperObject);
3731
3794
  this.targetMatrixMap.clear();
3732
3795
  let tMatrix = this.primaryTarget.getMatrixInWorld();
3733
3796
  tMatrix.decompose(this.helperObject.position, this.helperObject.quaternion, this.helperObject.scale);
3734
- (_b = this.controller.world.scene) === null || _b === void 0 ? void 0 : _b.add(this.control.getHelper());
3735
- (_c = this.controller.world.scene) === null || _c === void 0 ? void 0 : _c.add(this.helperObject);
3797
+ targetScene.add(this.control.getHelper());
3798
+ targetScene.add(this.helperObject);
3736
3799
  this.control.attach(this.helperObject);
3737
3800
  this.targets.forEach((elem) => {
3738
3801
  const tarMatrix = elem.getMatrixInWorld();
@@ -3774,11 +3837,11 @@ class TransformGizmo extends Pawn {
3774
3837
  this.control.enabled = newEnable;
3775
3838
  }
3776
3839
  setTarget(primaryTarget, multiTargets, onUpdate = null, onDragging = null) {
3777
- var _a;
3778
3840
  this.targetMatrixMap.clear();
3779
3841
  let tMatrix = primaryTarget.getMatrixInWorld();
3780
3842
  tMatrix.decompose(this.helperObject.position, this.helperObject.quaternion, this.helperObject.scale);
3781
- (_a = this.controller.world.scene) === null || _a === void 0 ? void 0 : _a.add(this.control.getHelper());
3843
+ const targetScene = this.getTargetScene();
3844
+ targetScene.add(this.control.getHelper());
3782
3845
  // this.control.attach(this.helperObject);
3783
3846
  this.primaryTarget = primaryTarget;
3784
3847
  this.targets = multiTargets;
@@ -3858,8 +3921,8 @@ exports.DefaultAppParam = DefaultAppParam;
3858
3921
  exports.DefaultBloomParam = DefaultBloomParam;
3859
3922
  exports.DefaultCameraParam = DefaultCameraParam;
3860
3923
  exports.DefaultDOFParam = DefaultDOFParam;
3861
- exports.DefaultDenoiseParam = DefaultDenoiseParam;
3862
3924
  exports.DefaultGTAOParam = DefaultGTAOParam;
3925
+ exports.DefaultLensFlareParam = DefaultLensFlareParam;
3863
3926
  exports.DefaultOrthographicCameraParam = DefaultOrthographicCameraParam;
3864
3927
  exports.DefaultOutlineParams = DefaultOutlineParams;
3865
3928
  exports.DefaultPerspectiveCameraParam = DefaultPerspectiveCameraParam;
@@ -3883,6 +3946,7 @@ exports.MeshComponent = MeshComponent;
3883
3946
  exports.Orbital = Orbital;
3884
3947
  exports.PlaneActor = PlaneActor;
3885
3948
  exports.PlaneComponent = PlaneComponent;
3949
+ exports.PostProcessManager = PostProcessManager;
3886
3950
  exports.SceneComponent = SceneComponent;
3887
3951
  exports.SkyActor = SkyActor;
3888
3952
  exports.SkyComponent = SkyComponent;
@@ -3894,6 +3958,5 @@ exports.ThreeJsApp = ThreeJsApp;
3894
3958
  exports.ThreeObjectLibrary = ThreeObjectLibrary;
3895
3959
  exports.TransformGizmo = TransformGizmo;
3896
3960
  exports.Viewport = Viewport;
3897
- exports.WebGPUPostProcessFactory = WebGPUPostProcessFactory;
3898
3961
  exports.World = World;
3899
3962
  //# sourceMappingURL=bundle.cjs.js.map