@rings-webgpu/core 1.0.42 → 1.0.43

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.
@@ -1679,21 +1679,47 @@ class Context3D extends CEventDispatcher {
1679
1679
  this.adapter = await navigator.gpu.requestAdapter({
1680
1680
  powerPreference: "high-performance"
1681
1681
  // 或 low-power
1682
+ // xrCompatible: canvasConfig?.xrCompatible, // 可选:如果需要 XR 支持
1682
1683
  });
1683
1684
  if (this.adapter == null) {
1684
1685
  throw new Error("Your browser does not support WebGPU!");
1685
1686
  }
1687
+ const requiredFeatures = [];
1688
+ const requireFeature = (feature) => {
1689
+ const supported = this.adapter.features.has(feature);
1690
+ if (supported) {
1691
+ requiredFeatures.push(feature);
1692
+ }
1693
+ return supported;
1694
+ };
1695
+ requireFeature("bgra8unorm-storage");
1696
+ requireFeature("depth-clip-control");
1697
+ requireFeature("depth32float-stencil8");
1698
+ requireFeature("indirect-first-instance");
1699
+ requireFeature("rg11b10ufloat-renderable");
1700
+ requireFeature("float32-filterable");
1701
+ requireFeature("float32-blendable");
1702
+ requireFeature("timestamp-query");
1703
+ requireFeature("shader-f16");
1704
+ requireFeature("clip-distances");
1705
+ requireFeature("texture-compression-bc");
1706
+ requireFeature("texture-compression-etc2");
1707
+ requireFeature("texture-compression-astc");
1708
+ const adapterLimits = this.adapter?.limits;
1709
+ const requiredLimits = {};
1710
+ if (adapterLimits) {
1711
+ for (const limitName in adapterLimits) {
1712
+ if (limitName === "minSubgroupSize" || limitName === "maxSubgroupSize") {
1713
+ continue;
1714
+ }
1715
+ requiredLimits[limitName] = adapterLimits[limitName];
1716
+ }
1717
+ }
1686
1718
  this.device = await this.adapter.requestDevice({
1687
- requiredFeatures: [
1688
- "bgra8unorm-storage",
1689
- "depth-clip-control",
1690
- "depth32float-stencil8",
1691
- "indirect-first-instance",
1692
- "rg11b10ufloat-renderable"
1693
- ],
1694
- requiredLimits: {
1695
- minUniformBufferOffsetAlignment: 256,
1696
- maxStorageBufferBindingSize: this.adapter.limits.maxStorageBufferBindingSize
1719
+ requiredFeatures,
1720
+ requiredLimits,
1721
+ defaultQueue: {
1722
+ label: "RingsDefaultQueue"
1697
1723
  }
1698
1724
  });
1699
1725
  if (this.device == null) {
@@ -1701,15 +1727,18 @@ class Context3D extends CEventDispatcher {
1701
1727
  }
1702
1728
  this._pixelRatio = this.canvasConfig?.devicePixelRatio || window.devicePixelRatio || 1;
1703
1729
  this._pixelRatio = Math.min(this._pixelRatio, 2);
1704
- this.device.label = "device";
1730
+ this.device.label = "RingsWebGPUDevice";
1705
1731
  this.presentationFormat = navigator.gpu.getPreferredCanvasFormat();
1706
1732
  this.context = this.canvas.getContext("webgpu");
1707
1733
  this.context.configure({
1708
1734
  device: this.device,
1709
1735
  format: this.presentationFormat,
1710
- usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
1736
+ // RENDER_ATTACHMENT is required, COPY_SRC allows scene grab/copy operations
1737
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
1711
1738
  alphaMode: "premultiplied",
1712
- colorSpace: `srgb`
1739
+ colorSpace: "srgb"
1740
+ // Optional: viewFormats can be added here if needed for SRGB views
1741
+ // viewFormats: [this.presentationFormat + '-srgb']
1713
1742
  });
1714
1743
  this._resizeEvent = new CResizeEvent(CResizeEvent.RESIZE, {
1715
1744
  width: this.windowWidth,
@@ -22879,11 +22908,23 @@ const GSplat_VS = (
22879
22908
  let radius = length(vec2f((diagonal1 - diagonal2) * 0.5, offDiagonal));
22880
22909
  let lambda1 = mid + radius;
22881
22910
  let lambda2 = max(mid - radius, MIN_LAMBDA);
22911
+
22912
+ let vmin = min(MAX_SPLAT_SIZE, min(viewport.x, viewport.y));
22913
+ let l1 = 2.0 * min(sqrt(2.0 * lambda1), vmin);
22914
+ let l2 = 2.0 * min(sqrt(2.0 * lambda2), vmin);
22915
+
22916
+ // if (l1 < 2.0 && l2 < 2.0) {
22917
+ // return discardSplat();
22918
+ // }
22919
+
22920
+ let centerProj = projMat * vec4f(splat_cam, 1.0);
22921
+ let c = centerProj.ww * vec2f(1.0 / viewport.x, 1.0 / viewport.y);
22922
+
22882
22923
  let diagonalVector = normalize(vec2f(offDiagonal, lambda1 - diagonal1));
22883
22924
 
22884
22925
  // Calculate axis vectors with size clamping
22885
- let v1 = min(sqrt(2.0 * lambda1), MAX_SPLAT_SIZE) * diagonalVector;
22886
- let v2 = min(sqrt(2.0 * lambda2), MAX_SPLAT_SIZE) * vec2f(diagonalVector.y, -diagonalVector.x);
22926
+ let v1 = l1 * diagonalVector;
22927
+ let v2 = l2 * vec2f(diagonalVector.y, -diagonalVector.x);
22887
22928
 
22888
22929
  // WebGPU Y-axis flip: WebGPU NDC Y goes from top(-1) to bottom(1), opposite of WebGL
22889
22930
  return vec4f(v1.x, -v1.y, v2.x, -v2.y);
@@ -22949,11 +22990,13 @@ const GSplat_VS = (
22949
22990
  let v1v2 = calcV1V2(splat_cam.xyz, splatData.covA, splatData.covB, W, viewport, matrix_projection);
22950
22991
 
22951
22992
  // Calculate scale based on alpha (optimized formula)
22952
- let scale = min(1.0, sqrt(LOG_255 + log(color.a)) * 0.5);
22993
+ let t = pow(splat_cam.z + 0.5, 5);
22994
+ let scale = min(1.0, sqrt(-log(1.0 / (255.0 * color.a))) / 2.0);
22953
22995
 
22954
22996
  // Apply visBoost (size multiplier)
22955
22997
  let visBoost = materialUniform.tex_params.w;
22956
- let v1v2_scaled = v1v2 * (scale * visBoost);
22998
+ let expt = exp(-1.0 / t);
22999
+ let v1v2_scaled = v1v2 * (scale * visBoost * expt);
22957
23000
 
22958
23001
  // Pixel coverage culling (vectorized squared length calculation)
22959
23002
  let v1v2_sq = v1v2_scaled * v1v2_scaled;
@@ -22987,7 +23030,7 @@ const GSplat_VS = (
22987
23030
 
22988
23031
  var o: VSOut;
22989
23032
  o.member = splat_proj + vec4f(offset, 0.0, 0.0);
22990
- o.vTexCoord = vertex_pos * (scale * 0.5);
23033
+ o.vTexCoord = vertex_pos * (scale);
22991
23034
  o.vColor = color;
22992
23035
 
22993
23036
  return o;
@@ -23001,16 +23044,30 @@ const GSplat_FS = (
23001
23044
 
23002
23045
  // Constants
23003
23046
  const ALPHA_THRESHOLD: f32 = 0.00392156863; // 1.0 / 255.0
23004
- const GAUSSIAN_SCALE: f32 = 4.0;
23047
+ // const GAUSSIAN_SCALE: f32 = 4.0;
23048
+ const EXP4 = exp(-4.0);
23049
+ const INV_EXP4 = 1.0 / (1.0 - EXP4);
23050
+
23051
+ fn normExp(x: f32) -> f32 {
23052
+ return (exp(x * -4.0) - EXP4) * INV_EXP4;
23053
+ }
23005
23054
 
23006
23055
  // === evalSplat() - optimized gaussian evaluation ===
23007
23056
  fn evalSplat(texCoord: vec2f, color: vec4f) -> vec4f {
23008
23057
  let A = dot(texCoord, texCoord);
23058
+
23059
+ if (A > 1.0) {
23060
+ discard;
23061
+ // return vec4f(1.0, 0.0, 0.0, 0.5);
23062
+ }
23009
23063
 
23010
23064
  // Branch-less optimization using select
23011
- let gaussian = exp(-A * GAUSSIAN_SCALE) * color.a;
23012
- let alpha = select(gaussian, 0.0, A > 1.0 || gaussian < ALPHA_THRESHOLD);
23013
-
23065
+ var alpha = normExp(A) * color.a;
23066
+
23067
+ if (alpha < ALPHA_THRESHOLD) {
23068
+ discard;
23069
+ // alpha = 0.5;
23070
+ }
23014
23071
  return vec4f(color.rgb, alpha);
23015
23072
  }
23016
23073
 
@@ -23257,8 +23314,9 @@ let GSplatShader = class extends Shader {
23257
23314
  pass.cullMode = GPUCullMode.none;
23258
23315
  pass.shaderState.transparent = true;
23259
23316
  pass.shaderState.blendMode = BlendMode.NORMAL;
23260
- pass.shaderState.writeMasks = [15, 15];
23317
+ pass.shaderState.writeMasks = [15, 0];
23261
23318
  pass.shaderState.castReflection = false;
23319
+ pass.shaderState.depthCompare = GPUCompareFunction.less;
23262
23320
  this.addRenderPass(pass);
23263
23321
  this.setDefault();
23264
23322
  }
@@ -24007,17 +24065,17 @@ class GSplatGeometry extends GeometryBase {
24007
24065
  const meshPositions = new Float32Array(12 * batchSize);
24008
24066
  for (let i = 0; i < batchSize; ++i) {
24009
24067
  meshPositions.set([
24010
- -2,
24011
- -2,
24068
+ -1,
24069
+ -1,
24012
24070
  i,
24013
- 2,
24014
- -2,
24071
+ 1,
24072
+ -1,
24015
24073
  i,
24016
- 2,
24017
- 2,
24074
+ 1,
24075
+ 1,
24018
24076
  i,
24019
- -2,
24020
- 2,
24077
+ -1,
24078
+ 1,
24021
24079
  i
24022
24080
  ], i * 12);
24023
24081
  }
@@ -27481,6 +27539,8 @@ class GPUContext {
27481
27539
  static matrixCount = 0;
27482
27540
  static lastRenderPassState;
27483
27541
  static LastCommand;
27542
+ static multiTextureViewCache = /* @__PURE__ */ new WeakMap();
27543
+ static swapchainTextureCache = { texture: null, view: null };
27484
27544
  static bindPipeline(encoder, renderShader) {
27485
27545
  if (GPUContext.lastShader != renderShader) {
27486
27546
  GPUContext.lastShader = renderShader;
@@ -27568,21 +27628,40 @@ class GPUContext {
27568
27628
  const renderTarget = renderPassState.renderTargets[i];
27569
27629
  let att = renderPassState.renderPassDescriptor.colorAttachments[i];
27570
27630
  if (renderPassState.multisample > 0 && renderPassState.renderTargets.length == 1) {
27571
- att.view = renderPassState.multiTexture.createView();
27631
+ let multiView = this.multiTextureViewCache.get(renderPassState.multiTexture);
27632
+ if (!multiView) {
27633
+ multiView = renderPassState.multiTexture.createView();
27634
+ this.multiTextureViewCache.set(renderPassState.multiTexture, multiView);
27635
+ }
27636
+ att.view = multiView;
27572
27637
  att.resolveTarget = renderTarget.getGPUView();
27573
27638
  } else {
27574
- att.view = renderTarget.getGPUTexture().createView();
27639
+ att.view = renderTarget.getGPUView();
27575
27640
  }
27576
27641
  }
27577
27642
  return command.beginRenderPass(renderPassState.renderPassDescriptor);
27578
27643
  } else {
27579
27644
  let att0 = renderPassState.renderPassDescriptor.colorAttachments[0];
27580
27645
  if (att0) {
27646
+ const swapchainTexture = webGPUContext.context.getCurrentTexture();
27581
27647
  if (renderPassState.multisample > 0) {
27582
- att0.view = renderPassState.multiTexture.createView();
27583
- att0.resolveTarget = webGPUContext.context.getCurrentTexture().createView();
27648
+ let multiView = this.multiTextureViewCache.get(renderPassState.multiTexture);
27649
+ if (!multiView) {
27650
+ multiView = renderPassState.multiTexture.createView();
27651
+ this.multiTextureViewCache.set(renderPassState.multiTexture, multiView);
27652
+ }
27653
+ att0.view = multiView;
27654
+ if (this.swapchainTextureCache.texture !== swapchainTexture) {
27655
+ this.swapchainTextureCache.texture = swapchainTexture;
27656
+ this.swapchainTextureCache.view = swapchainTexture.createView();
27657
+ }
27658
+ att0.resolveTarget = this.swapchainTextureCache.view;
27584
27659
  } else {
27585
- att0.view = webGPUContext.context.getCurrentTexture().createView();
27660
+ if (this.swapchainTextureCache.texture !== swapchainTexture) {
27661
+ this.swapchainTextureCache.texture = swapchainTexture;
27662
+ this.swapchainTextureCache.view = swapchainTexture.createView();
27663
+ }
27664
+ att0.view = this.swapchainTextureCache.view;
27586
27665
  }
27587
27666
  }
27588
27667
  return command.beginRenderPass(renderPassState.renderPassDescriptor);