@rings-webgpu/core 1.0.12 → 1.0.14

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.
@@ -22685,140 +22685,119 @@ struct InstanceData {
22685
22685
  /* wgsl */
22686
22686
  `
22687
22687
  #include "GlobalUniform"
22688
-
22689
- struct VSOut {
22690
- @location(auto) vColor : vec4f,
22691
- @location(auto) vTexCoord : vec2f,
22692
- @builtin(position) member : vec4f
22693
- };
22694
-
22695
- // ===== SPLAT CORE VS (from PlayCanvas shader-generator-gsplat.js) =====
22696
-
22697
- // Uniforms (mapped to WebGPU bindings)
22698
- // matrix_model, matrix_view, matrix_projection -> GlobalUniform + MaterialUniform
22699
- // viewport -> calculated from globalUniform.windowWidth/Height
22700
- // tex_params -> materialUniform.tex_params
22701
22688
 
22702
- @group(1) @binding(0) var splatColor : texture_2d<f32>;
22703
- @group(1) @binding(1) var transformA : texture_2d<u32>;
22704
- @group(1) @binding(2) var transformB : texture_2d<f32>;
22705
- @group(1) @binding(4) var splatOrder : texture_2d<u32>;
22689
+ // Constants
22690
+ const ALPHA_THRESHOLD: f32 = 0.00392156863; // 1.0 / 255.0
22691
+ const COV_COMPENSATION: f32 = 0.3;
22692
+ const MAX_SPLAT_SIZE: f32 = 1024.0;
22693
+ const MIN_LAMBDA: f32 = 0.1;
22694
+ const LOG_255: f32 = 5.541263545; // log(255.0) - natural log for WGSL
22706
22695
 
22707
22696
  struct MaterialUniform {
22708
- tex_params: vec4f, // numSplats, textureWidth, validCount, visBoost
22709
22697
  modelMatrix: mat4x4<f32>,
22710
- pixelCull: vec4f, // minPixels, maxPixels, maxPixelCullDistance, reserved
22698
+ tex_params: vec4<f32>, // [numSplats, texWidth, validCount, visBoost]
22699
+ pixelCull: vec4<f32>, // [minPixels, maxPixels, maxPixelCullDistance, batchSize]
22700
+ };
22701
+ @group(1) @binding(0) var<uniform> materialUniform: MaterialUniform;
22702
+
22703
+ struct VSOut {
22704
+ @builtin(position) member: vec4<f32>,
22705
+ @location(0) vColor: vec4<f32>,
22706
+ @location(1) vTexCoord: vec2<f32>,
22711
22707
  };
22712
- @group(1) @binding(3) var<uniform> materialUniform : MaterialUniform;
22713
22708
 
22714
- // Global variables (like PlayCanvas)
22715
- var<private> orderId: u32;
22716
- var<private> splatId: u32;
22717
- var<private> splatUV: vec2<i32>;
22718
- var<private> tA: vec4<u32>;
22709
+ // Textures (like PlayCanvas)
22710
+ @group(1) @binding(1) var splatColor: texture_2d<f32>;
22711
+ @group(1) @binding(2) var transformA: texture_2d<u32>;
22712
+ @group(1) @binding(3) var transformB: texture_2d<f32>;
22713
+ @group(1) @binding(4) var splatOrder: texture_2d<u32>;
22719
22714
 
22720
- // Helper: decode 16-bit half float
22721
- fn unpackHalf(h: u32) -> f32 {
22722
- let s = (h >> 15u) & 0x1u;
22723
- let e = (h >> 10u) & 0x1fu;
22724
- let m = h & 0x3ffu;
22725
- let sign = select(1.0, -1.0, s == 1u);
22726
- if (e == 0u) {
22727
- if (m == 0u) { return 0.0; }
22728
- return sign * (f32(m) * exp2(-24.0));
22729
- } else if (e == 31u) {
22730
- return sign * 65504.0;
22731
- } else {
22732
- return sign * (1.0 + f32(m) / 1024.0) * exp2(f32(i32(e) - 15));
22733
- }
22715
+ struct SplatData {
22716
+ center: vec3f,
22717
+ covA: vec3f,
22718
+ covB: vec3f,
22719
+ };
22720
+
22721
+ // Helper function to discard splat
22722
+ fn discardSplat() -> VSOut {
22723
+ var o: VSOut;
22724
+ o.member = vec4f(0.0, 0.0, 2.0, 1.0);
22725
+ o.vColor = vec4f(0.0);
22726
+ o.vTexCoord = vec2f(0.0);
22727
+ return o;
22734
22728
  }
22735
22729
 
22736
- // === calcSplatUV() - returns bool ===
22737
- fn calcSplatUV(instance_id: u32) -> bool {
22738
- let numSplats = u32(materialUniform.tex_params.x);
22739
- let textureWidth = u32(materialUniform.tex_params.y);
22740
-
22741
- // calculate splat index
22742
- orderId = instance_id;
22743
-
22744
- if (orderId >= numSplats) {
22745
- return false;
22746
- }
22747
-
22730
+ // === calcSplatUV() - returns optional UV ===
22731
+ fn calcSplatUV(orderId: u32, textureWidth: u32, numSplats: u32) -> vec2<i32> {
22748
22732
  let orderUV = vec2<i32>(
22749
22733
  i32(orderId % textureWidth),
22750
22734
  i32(orderId / textureWidth)
22751
22735
  );
22752
22736
 
22753
- // calculate splatUV
22754
- splatId = textureLoad(splatOrder, orderUV, 0).r;
22755
- splatUV = vec2<i32>(
22737
+ let splatId = textureLoad(splatOrder, orderUV, 0).r;
22738
+ return vec2<i32>(
22756
22739
  i32(splatId % textureWidth),
22757
22740
  i32(splatId / textureWidth)
22758
22741
  );
22759
-
22760
- return true;
22761
22742
  }
22762
22743
 
22763
- // === getCenter() - returns vec3 ===
22764
- fn getCenter() -> vec3f {
22765
- tA = textureLoad(transformA, splatUV, 0);
22766
- return vec3f(bitcast<f32>(tA.x), bitcast<f32>(tA.y), bitcast<f32>(tA.z));
22767
- }
22768
-
22769
- // Struct to return covA and covB
22770
- struct CovarianceData {
22771
- covA: vec3f,
22772
- covB: vec3f,
22773
- };
22774
-
22775
- // === getCovariance() - returns struct ===
22776
- fn getCovariance() -> CovarianceData {
22777
- let tB = textureLoad(transformB, splatUV, 0);
22744
+ // === getSplatData() - unified texture loading ===
22745
+ fn getSplatData(splatUV: vec2<i32>) -> SplatData {
22746
+ var data: SplatData;
22778
22747
 
22779
- // Use WGSL built-in unpack2x16float (equivalent to GLSL unpackHalf2x16)
22748
+ // Load both textures once
22749
+ let tA = textureLoad(transformA, splatUV, 0);
22750
+ let tB = textureLoad(transformB, splatUV, 0);
22780
22751
  let tC = unpack2x16float(tA.w);
22781
22752
 
22782
- var result: CovarianceData;
22783
- result.covA = tB.xyz;
22784
- result.covB = vec3f(tC.x, tC.y, tB.w);
22753
+ // Extract center
22754
+ data.center = vec3f(bitcast<f32>(tA.x), bitcast<f32>(tA.y), bitcast<f32>(tA.z));
22785
22755
 
22786
- return result;
22756
+ // Extract covariance
22757
+ data.covA = tB.xyz;
22758
+ data.covB = vec3f(tC.x, tC.y, tB.w);
22759
+
22760
+ return data;
22787
22761
  }
22788
22762
 
22789
22763
  // === calcV1V2() - returns vec4 ===
22790
22764
  fn calcV1V2(splat_cam: vec3f, covA: vec3f, covB: vec3f, W: mat3x3f, viewport: vec2f, projMat: mat4x4f) -> vec4f {
22765
+ // Construct symmetric covariance matrix
22791
22766
  let Vrk = mat3x3f(
22792
22767
  vec3f(covA.x, covA.y, covA.z),
22793
22768
  vec3f(covA.y, covB.x, covB.y),
22794
22769
  vec3f(covA.z, covB.y, covB.z)
22795
22770
  );
22796
22771
 
22772
+ // Calculate Jacobian
22797
22773
  let focal = viewport.x * projMat[0][0];
22798
-
22799
- let J1 = focal / splat_cam.z;
22800
- let J2 = -J1 / splat_cam.z * splat_cam.xy;
22774
+ let inv_z = 1.0 / splat_cam.z;
22775
+ let J1 = focal * inv_z;
22776
+ let J2 = -J1 * inv_z * splat_cam.xy;
22801
22777
  let J = mat3x3f(
22802
22778
  vec3f(J1, 0.0, J2.x),
22803
22779
  vec3f(0.0, J1, J2.y),
22804
22780
  vec3f(0.0, 0.0, 0.0)
22805
22781
  );
22806
22782
 
22783
+ // Project covariance to screen space
22807
22784
  let T = W * J;
22808
22785
  let cov = transpose(T) * Vrk * T;
22809
22786
 
22810
- let diagonal1 = cov[0][0] + 0.3;
22787
+ // Eigenvalue decomposition with compensation
22788
+ let diagonal1 = cov[0][0] + COV_COMPENSATION;
22811
22789
  let offDiagonal = cov[0][1];
22812
- let diagonal2 = cov[1][1] + 0.3;
22790
+ let diagonal2 = cov[1][1] + COV_COMPENSATION;
22813
22791
 
22814
22792
  let mid = 0.5 * (diagonal1 + diagonal2);
22815
- let radius = length(vec2f((diagonal1 - diagonal2) / 2.0, offDiagonal));
22793
+ let radius = length(vec2f((diagonal1 - diagonal2) * 0.5, offDiagonal));
22816
22794
  let lambda1 = mid + radius;
22817
- let lambda2 = max(mid - radius, 0.1);
22795
+ let lambda2 = max(mid - radius, MIN_LAMBDA);
22818
22796
  let diagonalVector = normalize(vec2f(offDiagonal, lambda1 - diagonal1));
22819
22797
 
22820
- let v1 = min(sqrt(2.0 * lambda1), 1024.0) * diagonalVector;
22821
- let v2 = min(sqrt(2.0 * lambda2), 1024.0) * vec2f(diagonalVector.y, -diagonalVector.x);
22798
+ // Calculate axis vectors with size clamping
22799
+ let v1 = min(sqrt(2.0 * lambda1), MAX_SPLAT_SIZE) * diagonalVector;
22800
+ let v2 = min(sqrt(2.0 * lambda2), MAX_SPLAT_SIZE) * vec2f(diagonalVector.y, -diagonalVector.x);
22822
22801
 
22823
22802
  // WebGPU Y-axis flip: WebGPU NDC Y goes from top(-1) to bottom(1), opposite of WebGL
22824
22803
  return vec4f(v1.x, -v1.y, v2.x, -v2.y);
@@ -22829,117 +22808,100 @@ struct InstanceData {
22829
22808
  @vertex
22830
22809
  fn VertMain(
22831
22810
  @builtin(vertex_index) vid : u32,
22832
- @builtin(instance_index) iid : u32
22811
+ @builtin(instance_index) iid : u32,
22812
+ @location(0) position: vec3<f32> // vertex_position from mesh (x, y, local_index)
22833
22813
  ) -> VSOut {
22834
- var o: VSOut;
22835
- let discardVec = vec4f(0.0, 0.0, 2.0, 1.0);
22836
-
22837
- // Vertex position array (PlayCanvas uses attribute vec3 with x,y in [-1,1])
22838
- let vertex_position = array<vec2f, 4>(
22839
- vec2f(-2.0, -2.0),
22840
- vec2f( 2.0, -2.0),
22841
- vec2f(-2.0, 2.0),
22842
- vec2f( 2.0, 2.0)
22843
- );
22844
- let vertex_pos = vertex_position[vid & 3u];
22814
+ // Calculate splat ID
22815
+ let batchSize = u32(materialUniform.pixelCull.w);
22816
+ let orderId = iid * batchSize + u32(position.z);
22845
22817
 
22846
- // calculate splat uv
22847
- if (!calcSplatUV(iid)) {
22848
- o.member = discardVec;
22849
- o.vColor = vec4f(0.0);
22850
- o.vTexCoord = vec2f(0.0);
22851
- return o;
22818
+ // Early bounds check
22819
+ let textureWidth = u32(materialUniform.tex_params.y);
22820
+ let numSplats = u32(materialUniform.tex_params.x);
22821
+ if (orderId >= numSplats) {
22822
+ return discardSplat();
22852
22823
  }
22853
22824
 
22854
- // get center
22855
- let center = getCenter();
22825
+ // Calculate splat UV and load all data in one go
22826
+ let splatUV = calcSplatUV(orderId, textureWidth, numSplats);
22827
+ let splatData = getSplatData(splatUV);
22828
+
22829
+ // Load color early for alpha test
22830
+ let color = textureLoad(splatColor, splatUV, 0);
22831
+ if (color.a < ALPHA_THRESHOLD) {
22832
+ return discardSplat();
22833
+ }
22856
22834
 
22857
- // handle transforms
22835
+ // Transform matrices
22836
+ let matrix_model = materialUniform.modelMatrix;
22858
22837
  let matrix_view = globalUniform.viewMat;
22859
22838
  let matrix_projection = globalUniform.projMat;
22860
- let matrix_model = materialUniform.modelMatrix;
22861
-
22862
22839
  let model_view = matrix_view * matrix_model;
22863
- let splat_cam = model_view * vec4f(center, 1.0);
22864
- let splat_proj = matrix_projection * splat_cam;
22865
22840
 
22866
- // Frustum culling: cull splats behind camera
22867
- if (splat_proj.z < 0.0) {
22868
- o.member = discardVec;
22869
- o.vColor = vec4f(0.0);
22870
- o.vTexCoord = vec2f(0.0);
22871
- return o;
22841
+ // Transform center to camera and clip space
22842
+ let splat_cam = model_view * vec4f(splatData.center, 1.0);
22843
+
22844
+ // Early depth culling
22845
+ if (splat_cam.z <= 0.0) {
22846
+ return discardSplat();
22872
22847
  }
22873
22848
 
22874
- // Frustum culling: cull splats outside screen bounds
22875
- // Add margin for splat radius (conservative: ~2x max splat size)
22876
- let ndc = splat_proj.xyz / splat_proj.w;
22877
- let margin = 0.5; // Allow splats near edges to be visible
22878
- if (ndc.x < -1.0 - margin || ndc.x > 1.0 + margin ||
22879
- ndc.y < -1.0 - margin || ndc.y > 1.0 + margin ||
22849
+ let splat_proj = matrix_projection * splat_cam;
22850
+
22851
+ // Frustum culling with NDC check
22852
+ let inv_w = 1.0 / splat_proj.w;
22853
+ let ndc = splat_proj.xyz * inv_w;
22854
+ if (ndc.x < -1.0 || ndc.x > 1.0 ||
22855
+ ndc.y < -1.0 || ndc.y > 1.0 ||
22880
22856
  ndc.z < 0.0 || ndc.z > 1.0) {
22881
- o.member = discardVec;
22882
- o.vColor = vec4f(0.0);
22883
- o.vTexCoord = vec2f(0.0);
22884
- return o;
22857
+ return discardSplat();
22885
22858
  }
22886
22859
 
22887
- // get covariance
22888
- let cov_data = getCovariance();
22889
-
22860
+ // Calculate v1v2 (screen-space ellipse axes)
22890
22861
  let viewport = vec2f(globalUniform.windowWidth, globalUniform.windowHeight);
22891
- let v1v2 = calcV1V2(splat_cam.xyz, cov_data.covA, cov_data.covB, transpose(mat3x3f(model_view[0].xyz, model_view[1].xyz, model_view[2].xyz)), viewport, matrix_projection);
22862
+ let W = transpose(mat3x3f(model_view[0].xyz, model_view[1].xyz, model_view[2].xyz));
22863
+ let v1v2 = calcV1V2(splat_cam.xyz, splatData.covA, splatData.covB, W, viewport, matrix_projection);
22892
22864
 
22893
- // get color
22894
- let color = textureLoad(splatColor, splatUV, 0);
22895
-
22896
- // calculate scale based on alpha
22897
- let scale = min(1.0, sqrt(-log(1.0 / 255.0 / color.a)) / 2.0);
22865
+ // Calculate scale based on alpha (optimized formula)
22866
+ let scale = min(1.0, sqrt(LOG_255 + log(color.a)) * 0.5);
22898
22867
 
22899
- // apply visBoost (size multiplier)
22868
+ // Apply visBoost (size multiplier)
22900
22869
  let visBoost = materialUniform.tex_params.w;
22901
- var v1v2_scaled = v1v2 * scale * visBoost;
22870
+ let v1v2_scaled = v1v2 * (scale * visBoost);
22902
22871
 
22903
- // Pixel coverage culling (min and max thresholds)
22904
- let v1_len_sq = dot(v1v2_scaled.xy, v1v2_scaled.xy);
22905
- let v2_len_sq = dot(v1v2_scaled.zw, v1v2_scaled.zw);
22872
+ // Pixel coverage culling (vectorized squared length calculation)
22873
+ let v1v2_sq = v1v2_scaled * v1v2_scaled;
22874
+ let v1_len_sq = v1v2_sq.x + v1v2_sq.y;
22875
+ let v2_len_sq = v1v2_sq.z + v1v2_sq.w;
22906
22876
 
22907
22877
  let minPixels = materialUniform.pixelCull.x;
22908
22878
  let maxPixels = materialUniform.pixelCull.y;
22909
- let maxPixelCullDistance = materialUniform.pixelCull.z;
22910
22879
 
22911
- // Early out tiny splats (below minimum pixel coverage)
22880
+ // Early out tiny splats
22912
22881
  if (v1_len_sq < minPixels && v2_len_sq < minPixels) {
22913
- o.member = discardVec;
22914
- o.vColor = vec4f(0.0);
22915
- o.vTexCoord = vec2f(0.0);
22916
- return o;
22882
+ return discardSplat();
22917
22883
  }
22918
22884
 
22919
- // Cull oversized splats (above maximum pixel coverage)
22920
- // Only apply to splats close to camera (distance-based condition)
22885
+ // Cull oversized splats
22921
22886
  if (maxPixels > 0.0) {
22922
- // Calculate distance from splat to camera
22887
+ let maxPixelCullDistance = materialUniform.pixelCull.z;
22923
22888
  let splatDistance = length(splat_cam.xyz);
22924
-
22925
- // Only cull oversized splats if they are close to camera
22926
22889
  if (maxPixelCullDistance <= 0.0 || splatDistance < maxPixelCullDistance) {
22927
22890
  let maxAxisSq = maxPixels * maxPixels;
22928
22891
  if (v1_len_sq > maxAxisSq || v2_len_sq > maxAxisSq) {
22929
- o.member = discardVec;
22930
- o.vColor = vec4f(0.0);
22931
- o.vTexCoord = vec2f(0.0);
22932
- return o;
22892
+ return discardSplat();
22933
22893
  }
22934
22894
  }
22935
22895
  }
22936
22896
 
22937
- // gl_Position = splat_proj + vec4((vertex_position.x * v1v2.xy + vertex_position.y * v1v2.zw) / viewport * splat_proj.w, 0, 0);
22938
- o.member = splat_proj + vec4f((vertex_pos.x * v1v2_scaled.xy + vertex_pos.y * v1v2_scaled.zw) / viewport * splat_proj.w, 0.0, 0.0);
22939
-
22940
- // texCoord = vertex_position.xy * scale / 2.0;
22941
- o.vTexCoord = vertex_pos * scale / 2.0;
22897
+ // Final position calculation (optimized)
22898
+ let vertex_pos = position.xy;
22899
+ let inv_viewport = 1.0 / viewport;
22900
+ let offset = (vertex_pos.x * v1v2_scaled.xy + vertex_pos.y * v1v2_scaled.zw) * inv_viewport * splat_proj.w;
22942
22901
 
22902
+ var o: VSOut;
22903
+ o.member = splat_proj + vec4f(offset, 0.0, 0.0);
22904
+ o.vTexCoord = vertex_pos * (scale * 0.5);
22943
22905
  o.vColor = color;
22944
22906
 
22945
22907
  return o;
@@ -22950,31 +22912,29 @@ struct InstanceData {
22950
22912
  /* wgsl */
22951
22913
  `
22952
22914
  #include "FragmentOutput"
22915
+
22916
+ // Constants
22917
+ const ALPHA_THRESHOLD: f32 = 0.00392156863; // 1.0 / 255.0
22918
+ const GAUSSIAN_SCALE: f32 = 4.0;
22953
22919
 
22954
- // === evalSplat() - like PlayCanvas splatCoreFS ===
22920
+ // === evalSplat() - optimized gaussian evaluation ===
22955
22921
  fn evalSplat(texCoord: vec2f, color: vec4f) -> vec4f {
22956
22922
  let A = dot(texCoord, texCoord);
22957
- if (A > 1.0) {
22958
- discard;
22959
- }
22960
22923
 
22961
- let B = exp(-A * 4.0) * color.a;
22962
- if (B < 1.0 / 255.0) {
22963
- discard;
22964
- }
22924
+ // Branch-less optimization using select
22925
+ let gaussian = exp(-A * GAUSSIAN_SCALE) * color.a;
22926
+ let alpha = select(gaussian, 0.0, A > 1.0 || gaussian < ALPHA_THRESHOLD);
22965
22927
 
22966
- // TONEMAP_ENABLED branch not implemented (would call toneMap() and gammaCorrectOutput())
22967
- return vec4f(color.rgb, B);
22928
+ return vec4f(color.rgb, alpha);
22968
22929
  }
22969
-
22970
- // === main() - like PlayCanvas splatMainFS ===
22930
+
22971
22931
  @fragment
22972
- fn FragMain(@location(auto) vColor: vec4f, @location(auto) vTexCoord: vec2f) -> FragmentOutput {
22973
- let result = evalSplat(vTexCoord, vColor);
22974
-
22932
+ fn FragMain(
22933
+ @location(0) vColor: vec4<f32>,
22934
+ @location(1) vTexCoord: vec2<f32>
22935
+ ) -> FragmentOutput {
22975
22936
  var o: FragmentOutput;
22976
- o.color = result;
22977
- o.gBuffer = vec4f(0.0);
22937
+ o.color = evalSplat(vTexCoord, vColor);
22978
22938
  return o;
22979
22939
  }
22980
22940
  `
@@ -23199,12 +23159,13 @@ struct InstanceData {
23199
23159
  const pass = new RenderShaderPass("gsplat_vs_dc", "gsplat_fs_dc");
23200
23160
  pass.passType = PassType.COLOR;
23201
23161
  pass.setShaderEntry("VertMain", "FragMain");
23202
- pass.topology = GPUPrimitiveTopology.triangle_strip;
23162
+ pass.topology = GPUPrimitiveTopology.triangle_list;
23203
23163
  pass.depthWriteEnabled = false;
23204
- pass.cullMode = "none";
23164
+ pass.cullMode = GPUCullMode.none;
23205
23165
  pass.shaderState.transparent = true;
23206
23166
  pass.shaderState.blendMode = BlendMode.NORMAL;
23207
23167
  pass.shaderState.writeMasks = [15, 15];
23168
+ pass.shaderState.castReflection = false;
23208
23169
  this.addRenderPass(pass);
23209
23170
  this.setDefault();
23210
23171
  }
@@ -23223,6 +23184,7 @@ struct InstanceData {
23223
23184
  ], exports.GSplatShader);
23224
23185
 
23225
23186
  class GSplatMaterial extends Material {
23187
+ _pixelCullArray = new Float32Array(4);
23226
23188
  constructor() {
23227
23189
  super();
23228
23190
  ShaderLib.register("gsplat_vs_dc", GSplat_VS);
@@ -23238,6 +23200,7 @@ struct InstanceData {
23238
23200
  if (splatOrder) {
23239
23201
  pass.setTexture("splatOrder", splatOrder);
23240
23202
  }
23203
+ pass.shaderState.depthCompare = GPUCompareFunction.less;
23241
23204
  }
23242
23205
  /**
23243
23206
  * Set the model matrix for transforming splats to world space
@@ -23252,9 +23215,13 @@ struct InstanceData {
23252
23215
  * @param maxPixels Maximum pixel coverage (cull oversized splats), default: 0 (disabled)
23253
23216
  * @param maxPixelCullDistance Only cull oversized splats within this distance, 0 = always cull
23254
23217
  */
23255
- setPixelCulling(minPixels, maxPixels, maxPixelCullDistance = 0) {
23218
+ setPixelCulling(minPixels, maxPixels, maxPixelCullDistance = 0, batchSize = 128) {
23219
+ this._pixelCullArray[0] = minPixels;
23220
+ this._pixelCullArray[1] = maxPixels;
23221
+ this._pixelCullArray[2] = maxPixelCullDistance;
23222
+ this._pixelCullArray[3] = batchSize;
23256
23223
  const pass = this.shader.getDefaultColorShader();
23257
- pass.setUniform("pixelCull", new Float32Array([minPixels, maxPixels, maxPixelCullDistance, 0]));
23224
+ pass.setUniform("pixelCull", this._pixelCullArray);
23258
23225
  }
23259
23226
  }
23260
23227
 
@@ -23912,108 +23879,47 @@ struct InstanceData {
23912
23879
  }
23913
23880
  }
23914
23881
 
23915
- class PlaneGeometry extends GeometryBase {
23916
- width;
23917
- height;
23918
- segmentW;
23919
- segmentH;
23920
- up;
23921
- constructor(width, height, segmentW = 1, segmentH = 1, up = Vector3.Y_AXIS) {
23882
+ class GSplatGeometry extends GeometryBase {
23883
+ batchSize;
23884
+ constructor(batchSize = 128) {
23922
23885
  super();
23923
- this.width = width;
23924
- this.height = height;
23925
- this.segmentW = segmentW;
23926
- this.segmentH = segmentH;
23927
- this.up = up;
23928
- this.buildGeometry(this.up);
23929
- }
23930
- buildGeometry(axis) {
23931
- var x, y;
23932
- var numIndices;
23933
- var base;
23934
- var tw = this.segmentW + 1;
23935
- (this.segmentH + 1) * tw;
23936
- this.bounds = new BoundingBox(
23937
- Vector3.ZERO.clone(),
23938
- new Vector3(this.width, 1, this.height)
23939
- );
23940
- numIndices = this.segmentH * this.segmentW * 6;
23941
- let vertexCount = (this.segmentW + 1) * (this.segmentH + 1);
23942
- let position_arr = new Float32Array(vertexCount * 3);
23943
- let normal_arr = new Float32Array(vertexCount * 3);
23944
- let uv_arr = new Float32Array(vertexCount * 2);
23945
- let indices_arr;
23946
- let totalIndexCount = this.segmentW * this.segmentH * 2 * 3;
23947
- if (totalIndexCount >= Uint16Array.length) {
23948
- indices_arr = new Uint32Array(this.segmentW * this.segmentH * 2 * 3);
23949
- } else {
23950
- indices_arr = new Uint16Array(this.segmentW * this.segmentH * 2 * 3);
23951
- }
23952
- numIndices = 0;
23953
- var indexP = 0;
23954
- var indexN = 0;
23955
- var indexU = 0;
23956
- for (var yi = 0; yi <= this.segmentH; ++yi) {
23957
- for (var xi = 0; xi <= this.segmentW; ++xi) {
23958
- x = (xi / this.segmentW - 0.5) * this.width;
23959
- y = (yi / this.segmentH - 0.5) * this.height;
23960
- switch (axis) {
23961
- case Vector3.Y_AXIS:
23962
- position_arr[indexP++] = x;
23963
- position_arr[indexP++] = 0;
23964
- position_arr[indexP++] = y;
23965
- normal_arr[indexN++] = 0;
23966
- normal_arr[indexN++] = 1;
23967
- normal_arr[indexN++] = 0;
23968
- break;
23969
- case Vector3.Z_AXIS:
23970
- position_arr[indexP++] = x;
23971
- position_arr[indexP++] = -y;
23972
- position_arr[indexP++] = 0;
23973
- normal_arr[indexN++] = 0;
23974
- normal_arr[indexN++] = 0;
23975
- normal_arr[indexN++] = 1;
23976
- break;
23977
- case Vector3.X_AXIS:
23978
- position_arr[indexP++] = 0;
23979
- position_arr[indexP++] = x;
23980
- position_arr[indexP++] = y;
23981
- normal_arr[indexN++] = 1;
23982
- normal_arr[indexN++] = 0;
23983
- normal_arr[indexN++] = 0;
23984
- break;
23985
- default:
23986
- position_arr[indexP++] = x;
23987
- position_arr[indexP++] = 0;
23988
- position_arr[indexP++] = y;
23989
- normal_arr[indexN++] = 0;
23990
- normal_arr[indexN++] = 1;
23991
- normal_arr[indexN++] = 0;
23992
- break;
23993
- }
23994
- uv_arr[indexU++] = xi / this.segmentW;
23995
- uv_arr[indexU++] = yi / this.segmentH;
23996
- if (xi != this.segmentW && yi != this.segmentH) {
23997
- base = xi + yi * tw;
23998
- indices_arr[numIndices++] = base + 1;
23999
- indices_arr[numIndices++] = base;
24000
- indices_arr[numIndices++] = base + tw;
24001
- indices_arr[numIndices++] = base + 1;
24002
- indices_arr[numIndices++] = base + tw;
24003
- indices_arr[numIndices++] = base + tw + 1;
24004
- }
24005
- }
24006
- }
24007
- this.setIndices(indices_arr);
24008
- this.setAttribute(VertexAttributeName.position, position_arr);
24009
- this.setAttribute(VertexAttributeName.normal, normal_arr);
24010
- this.setAttribute(VertexAttributeName.uv, uv_arr);
24011
- this.setAttribute(VertexAttributeName.TEXCOORD_1, uv_arr);
23886
+ this.batchSize = batchSize;
23887
+ const meshPositions = new Float32Array(12 * batchSize);
23888
+ for (let i = 0; i < batchSize; ++i) {
23889
+ meshPositions.set([
23890
+ -2,
23891
+ -2,
23892
+ i,
23893
+ 2,
23894
+ -2,
23895
+ i,
23896
+ 2,
23897
+ 2,
23898
+ i,
23899
+ -2,
23900
+ 2,
23901
+ i
23902
+ ], i * 12);
23903
+ }
23904
+ const meshIndices = new Uint32Array(6 * batchSize);
23905
+ for (let i = 0; i < batchSize; ++i) {
23906
+ const b = i * 4;
23907
+ meshIndices.set([
23908
+ 0 + b,
23909
+ 1 + b,
23910
+ 2 + b,
23911
+ 0 + b,
23912
+ 2 + b,
23913
+ 3 + b
23914
+ ], i * 6);
23915
+ }
23916
+ this.setAttribute(VertexAttributeName.position, meshPositions);
23917
+ this.setIndices(meshIndices);
24012
23918
  this.addSubGeometry({
24013
23919
  indexStart: 0,
24014
- indexCount: indices_arr.length,
23920
+ indexCount: meshIndices.length,
24015
23921
  vertexStart: 0,
24016
- vertexCount: 0,
23922
+ vertexCount: meshPositions.length / 3,
24017
23923
  firstStart: 0,
24018
23924
  index: 0,
24019
23925
  topology: 0
@@ -24117,18 +24023,49 @@ struct InstanceData {
24117
24023
  updateTexture(width, height, data) {
24118
24024
  let device = webGPUContext.device;
24119
24025
  const bytesPerRow = width * 4 * 4;
24120
- const staging = device.createBuffer({
24026
+ device.queue.writeTexture(
24027
+ { texture: this.getGPUTexture() },
24028
+ data.buffer,
24029
+ { bytesPerRow },
24030
+ { width, height, depthOrArrayLayers: 1 }
24031
+ );
24032
+ }
24033
+ }
24034
+
24035
+ class R32UintTexture extends Texture {
24036
+ _dataBuffer;
24037
+ create(width, height, data) {
24038
+ let device = webGPUContext.device;
24039
+ const bytesPerRow = width * 4;
24040
+ this.format = GPUTextureFormat.r32uint;
24041
+ const mipmapCount = 1;
24042
+ this.createTextureDescriptor(width, height, mipmapCount, this.format);
24043
+ const textureDataBuffer = this._dataBuffer = device.createBuffer({
24121
24044
  size: data.byteLength,
24122
24045
  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC
24123
24046
  });
24124
- device.queue.writeBuffer(staging, 0, data.buffer);
24047
+ device.queue.writeBuffer(textureDataBuffer, 0, data.buffer);
24125
24048
  const encoder = device.createCommandEncoder();
24126
24049
  encoder.copyBufferToTexture(
24127
- { buffer: staging, bytesPerRow },
24050
+ { buffer: textureDataBuffer, bytesPerRow },
24128
24051
  { texture: this.getGPUTexture() },
24129
24052
  { width, height, depthOrArrayLayers: 1 }
24130
24053
  );
24131
24054
  device.queue.submit([encoder.finish()]);
24055
+ this.samplerBindingLayout.type = `non-filtering`;
24056
+ this.textureBindingLayout.sampleType = `uint`;
24057
+ this.gpuSampler = device.createSampler({});
24058
+ return this;
24059
+ }
24060
+ updateTexture(width, height, data) {
24061
+ let device = webGPUContext.device;
24062
+ const bytesPerRow = width * 4;
24063
+ device.queue.writeTexture(
24064
+ { texture: this.getGPUTexture() },
24065
+ data.buffer,
24066
+ { bytesPerRow },
24067
+ { width, height, depthOrArrayLayers: 1 }
24068
+ );
24132
24069
  }
24133
24070
  }
24134
24071
 
@@ -24270,14 +24207,15 @@ struct InstanceData {
24270
24207
  // Web Worker for sorting
24271
24208
  _sortWorker;
24272
24209
  _lastSentTime = 0;
24273
- _minIntervalMs = 0;
24274
- // No throttle for immediate sorting
24210
+ _minIntervalMs = 16;
24275
24211
  _centersSent = false;
24276
24212
  _lastViewMatrixHash = 0;
24277
24213
  // Adaptive sorting optimization
24278
24214
  _lastCameraSpeed = 0;
24279
24215
  _adaptiveSorting = true;
24280
24216
  // Enable adaptive sorting by default
24217
+ _lastPixelCullParams = "";
24218
+ _texturesInitialized = false;
24281
24219
  // LOD (Level of Detail) system
24282
24220
  _lodEnabled = false;
24283
24221
  _lodDistances = [5, 10, 20, 40];
@@ -24299,6 +24237,11 @@ struct InstanceData {
24299
24237
  get fullCount() {
24300
24238
  return this._fullCount;
24301
24239
  }
24240
+ // Batched rendering
24241
+ _batchSize = 128;
24242
+ // Splats per draw call
24243
+ instanceCount = 0;
24244
+ // For InstanceDrawComponent compatibility
24302
24245
  constructor() {
24303
24246
  super();
24304
24247
  }
@@ -24314,24 +24257,20 @@ struct InstanceData {
24314
24257
  this.texParams = new Float32Array([this.count, this.size.x, this.count, 1]);
24315
24258
  this._positions = asset.position;
24316
24259
  const total = this.size.x * this.size.y;
24317
- this._orderData = new Uint32Array(total * 4);
24260
+ this._orderData = new Uint32Array(total);
24318
24261
  for (let i = 0; i < total; i++) {
24319
- const src = i < this.count ? i : this.count > 0 ? this.count - 1 : 0;
24320
- const base = i * 4;
24321
- this._orderData[base + 0] = src;
24322
- this._orderData[base + 1] = 0;
24323
- this._orderData[base + 2] = 0;
24324
- this._orderData[base + 3] = 0;
24325
- }
24326
- this.splatOrder = new Uint32ArrayTexture().create(this.size.x, this.size.y, this._orderData);
24262
+ this._orderData[i] = i < this.count ? i : this.count > 0 ? this.count - 1 : 0;
24263
+ }
24264
+ this.splatOrder = new R32UintTexture().create(this.size.x, this.size.y, this._orderData);
24327
24265
  this.splatOrder.name = "splatOrder";
24328
24266
  this.splatOrder.minFilter = "nearest";
24329
24267
  this.splatOrder.magFilter = "nearest";
24330
24268
  this.splatOrder.addressModeU = "clamp-to-edge";
24331
24269
  this.splatOrder.addressModeV = "clamp-to-edge";
24332
24270
  this.gsplatMaterial = new GSplatMaterial();
24333
- this.geometry = new PlaneGeometry(1, 1, 1, 1);
24271
+ this.geometry = new GSplatGeometry(this._batchSize);
24334
24272
  this.materials = [this.gsplatMaterial];
24273
+ this.instanceCount = 0;
24335
24274
  }
24336
24275
  /**
24337
24276
  * Update splat sorting before rendering
@@ -24408,12 +24347,7 @@ struct InstanceData {
24408
24347
  this.texParams[2] = Math.min(this.texParams[0], this.count);
24409
24348
  const total = this.size.x * this.size.y;
24410
24349
  for (let i = 0; i < total; i++) {
24411
- const src = i < this.count ? i : this.count > 0 ? this.count - 1 : 0;
24412
- const base = i * 4;
24413
- this._orderData[base + 0] = src;
24414
- this._orderData[base + 1] = 0;
24415
- this._orderData[base + 2] = 0;
24416
- this._orderData[base + 3] = 0;
24350
+ this._orderData[i] = i < this.count ? i : this.count > 0 ? this.count - 1 : 0;
24417
24351
  }
24418
24352
  this.splatOrder.updateTexture(this.size.x, this.size.y, this._orderData);
24419
24353
  if (this._sortWorker) {
@@ -24440,6 +24374,7 @@ struct InstanceData {
24440
24374
  } else {
24441
24375
  this._centersSent = false;
24442
24376
  }
24377
+ this.instanceCount = 0;
24443
24378
  }
24444
24379
  /**
24445
24380
  * Set visibility boost factor (material uniform tex_params.w)
@@ -24503,6 +24438,18 @@ struct InstanceData {
24503
24438
  distanceEnabled: this._maxPixelCullDistance > 0
24504
24439
  };
24505
24440
  }
24441
+ /**
24442
+ * Get batching statistics
24443
+ */
24444
+ getBatchingStats() {
24445
+ return {
24446
+ enabled: true,
24447
+ batchSize: this._batchSize,
24448
+ instanceCount: this.instanceCount,
24449
+ splatCount: this.count,
24450
+ reduction: this.count > 0 ? (1 - this.instanceCount / this.count) * 100 : 0
24451
+ };
24452
+ }
24506
24453
  /**
24507
24454
  * Calculate texture size for given splat count
24508
24455
  */
@@ -24725,18 +24672,20 @@ struct InstanceData {
24725
24672
  const indices = new Uint32Array(newOrder);
24726
24673
  const total = this.size.x * this.size.y;
24727
24674
  const count = this.count;
24728
- this._orderData = new Uint32Array(total * 4);
24729
- for (let i = 0; i < total; i++) {
24730
- const src = i < count ? indices[i] : count > 0 ? count - 1 : 0;
24731
- const base = i * 4;
24732
- this._orderData[base + 0] = src;
24733
- this._orderData[base + 1] = 0;
24734
- this._orderData[base + 2] = 0;
24735
- this._orderData[base + 3] = 0;
24675
+ if (!this._orderData || this._orderData.length !== total) {
24676
+ this._orderData = new Uint32Array(total);
24677
+ }
24678
+ const validCount = Math.min(count, indices.length);
24679
+ this._orderData.set(indices.subarray(0, validCount), 0);
24680
+ if (validCount < total) {
24681
+ const lastIndex = count > 0 ? count - 1 : 0;
24682
+ this._orderData.fill(lastIndex, validCount, total);
24736
24683
  }
24737
24684
  this.splatOrder.updateTexture(this.size.x, this.size.y, this._orderData);
24738
24685
  const valid = Math.max(0, Math.min(this.count, ev.data.count | 0));
24739
24686
  this.texParams[2] = valid;
24687
+ const newInstanceCount = Math.ceil(valid / this._batchSize);
24688
+ this.instanceCount = newInstanceCount;
24740
24689
  };
24741
24690
  const worldPos = this._worldPositions || this._positions;
24742
24691
  const centers = this._mapping ? new Float32Array(this._mapping.length * 3) : new Float32Array(worldPos);
@@ -24939,30 +24888,22 @@ struct InstanceData {
24939
24888
  nodeUpdate(view, passType, renderPassState, clusterLightingBuffer) {
24940
24889
  const worldMatrix = this.object3D.transform.worldMatrix;
24941
24890
  this.gsplatMaterial.setTransformMatrix(worldMatrix);
24942
- this.gsplatMaterial.setPixelCulling(this._minPixelCoverage, this._maxPixelCoverage, this._maxPixelCullDistance);
24943
- this.gsplatMaterial.setSplatTextures(
24944
- this.splatColor,
24945
- this.transformA,
24946
- this.transformB,
24947
- this.texParams,
24948
- this.splatOrder
24949
- );
24950
- super.nodeUpdate(view, passType, renderPassState, clusterLightingBuffer);
24951
- }
24952
- /**
24953
- * Render pass
24954
- */
24955
- renderPass2(view, passType, rendererPassState, clusterLightingBuffer, encoder, useBundle = false) {
24956
- for (let mat of this.materials) {
24957
- const passes = mat.getPass(passType);
24958
- if (!passes || passes.length === 0) continue;
24959
- for (const pass of passes) {
24960
- if (!pass.pipeline) continue;
24961
- pass.apply(this.geometry, rendererPassState);
24962
- GPUContext.bindPipeline(encoder, pass);
24963
- GPUContext.draw(encoder, 4, this.count, 0, 0);
24964
- }
24891
+ const currentParams = `${this._minPixelCoverage},${this._maxPixelCoverage},${this._maxPixelCullDistance},${this._batchSize}`;
24892
+ if (currentParams !== this._lastPixelCullParams) {
24893
+ this.gsplatMaterial.setPixelCulling(this._minPixelCoverage, this._maxPixelCoverage, this._maxPixelCullDistance, this._batchSize);
24894
+ this._lastPixelCullParams = currentParams;
24895
+ }
24896
+ if (!this._texturesInitialized) {
24897
+ this.gsplatMaterial.setSplatTextures(
24898
+ this.splatColor,
24899
+ this.transformA,
24900
+ this.transformB,
24901
+ this.texParams,
24902
+ this.splatOrder
24903
+ );
24904
+ this._texturesInitialized = true;
24965
24905
  }
24906
+ super.nodeUpdate(view, passType, renderPassState, clusterLightingBuffer);
24966
24907
  }
24967
24908
  /**
24968
24909
  * Render pass (fallback)
@@ -24976,7 +24917,28 @@ struct InstanceData {
24976
24917
  if (!pass.pipeline) continue;
24977
24918
  pass.apply(this.geometry, renderContext.rendererPassState || renderContext);
24978
24919
  GPUContext.bindPipeline(encoder, pass);
24979
- GPUContext.draw(encoder, 4, this.count, 0, 0);
24920
+ GPUContext.bindGeometryBuffer(encoder, this.geometry);
24921
+ const subGeometry = this.geometry.subGeometries[0];
24922
+ const lodInfo = subGeometry.lodLevels[0];
24923
+ if (this.instanceCount > 0) {
24924
+ GPUContext.drawIndexed(
24925
+ encoder,
24926
+ lodInfo.indexCount,
24927
+ this.instanceCount,
24928
+ lodInfo.indexStart,
24929
+ 0,
24930
+ 0
24931
+ );
24932
+ } else {
24933
+ GPUContext.drawIndexed(
24934
+ encoder,
24935
+ lodInfo.indexCount,
24936
+ 1,
24937
+ lodInfo.indexStart,
24938
+ 0,
24939
+ 0
24940
+ );
24941
+ }
24980
24942
  }
24981
24943
  }
24982
24944
  }
@@ -24988,6 +24950,31 @@ struct InstanceData {
24988
24950
  this._sortWorker.terminate();
24989
24951
  this._sortWorker = null;
24990
24952
  }
24953
+ if (this.splatColor) {
24954
+ this.splatColor.destroy(force);
24955
+ this.splatColor = null;
24956
+ }
24957
+ if (this.transformA) {
24958
+ this.transformA.destroy(force);
24959
+ this.transformA = null;
24960
+ }
24961
+ if (this.transformB) {
24962
+ this.transformB.destroy(force);
24963
+ this.transformB = null;
24964
+ }
24965
+ if (this.splatOrder) {
24966
+ this.splatOrder.destroy(force);
24967
+ this.splatOrder = null;
24968
+ }
24969
+ if (this.gsplatMaterial) {
24970
+ this.gsplatMaterial.destroy(force);
24971
+ this.gsplatMaterial = null;
24972
+ }
24973
+ this._positions = null;
24974
+ this._worldPositions = null;
24975
+ this._orderData = null;
24976
+ this.texParams = null;
24977
+ this._mapping = null;
24991
24978
  super.destroy(force);
24992
24979
  }
24993
24980
  };
@@ -26895,6 +26882,43 @@ struct InstanceData {
26895
26882
  usage
26896
26883
  );
26897
26884
  }
26885
+ destroy(force) {
26886
+ if (this._computeConfigBuffer) {
26887
+ this._computeConfigBuffer.destroy(force);
26888
+ this._computeConfigBuffer = null;
26889
+ }
26890
+ if (this._morphInfluenceBuffer) {
26891
+ this._morphInfluenceBuffer.destroy(force);
26892
+ this._morphInfluenceBuffer = null;
26893
+ }
26894
+ if (this._computeShader) {
26895
+ this._computeShader.destroy(force);
26896
+ this._computeShader = null;
26897
+ }
26898
+ if (this._positionAttrDataGroup) {
26899
+ if (this._positionAttrDataGroup.input) {
26900
+ this._positionAttrDataGroup.input.destroy(force);
26901
+ }
26902
+ if (this._positionAttrDataGroup.output) {
26903
+ this._positionAttrDataGroup.output.destroy(force);
26904
+ }
26905
+ this._positionAttrDataGroup = null;
26906
+ }
26907
+ if (this._normalAttrDataGroup) {
26908
+ if (this._normalAttrDataGroup.input) {
26909
+ this._normalAttrDataGroup.input.destroy(force);
26910
+ }
26911
+ if (this._normalAttrDataGroup.output) {
26912
+ this._normalAttrDataGroup.output.destroy(force);
26913
+ }
26914
+ this._normalAttrDataGroup = null;
26915
+ }
26916
+ this._computeConfigArray = null;
26917
+ this._morphInfluenceArray = null;
26918
+ this._collectMorphTargetData = null;
26919
+ this._blendTarget = null;
26920
+ this._computeShaders = null;
26921
+ }
26898
26922
  }
26899
26923
 
26900
26924
  var __defProp = Object.defineProperty;
@@ -27006,6 +27030,10 @@ struct InstanceData {
27006
27030
  super.nodeUpdate(view, passType, renderPassState, clusterLightingBuffer);
27007
27031
  }
27008
27032
  destroy(force) {
27033
+ if (this.morphData) {
27034
+ this.morphData.destroy(force);
27035
+ this.morphData = null;
27036
+ }
27009
27037
  super.destroy(force);
27010
27038
  }
27011
27039
  };
@@ -27512,6 +27540,115 @@ struct InstanceData {
27512
27540
  }
27513
27541
  }
27514
27542
 
27543
+ class PlaneGeometry extends GeometryBase {
27544
+ width;
27545
+ height;
27546
+ segmentW;
27547
+ segmentH;
27548
+ up;
27549
+ constructor(width, height, segmentW = 1, segmentH = 1, up = Vector3.Y_AXIS) {
27550
+ super();
27551
+ this.width = width;
27552
+ this.height = height;
27553
+ this.segmentW = segmentW;
27554
+ this.segmentH = segmentH;
27555
+ this.up = up;
27556
+ this.buildGeometry(this.up);
27557
+ }
27558
+ buildGeometry(axis) {
27559
+ var x, y;
27560
+ var numIndices;
27561
+ var base;
27562
+ var tw = this.segmentW + 1;
27563
+ (this.segmentH + 1) * tw;
27564
+ this.bounds = new BoundingBox(
27565
+ Vector3.ZERO.clone(),
27566
+ new Vector3(this.width, 1, this.height)
27567
+ );
27568
+ numIndices = this.segmentH * this.segmentW * 6;
27569
+ let vertexCount = (this.segmentW + 1) * (this.segmentH + 1);
27570
+ let position_arr = new Float32Array(vertexCount * 3);
27571
+ let normal_arr = new Float32Array(vertexCount * 3);
27572
+ let uv_arr = new Float32Array(vertexCount * 2);
27573
+ let indices_arr;
27574
+ let totalIndexCount = this.segmentW * this.segmentH * 2 * 3;
27575
+ if (totalIndexCount >= Uint16Array.length) {
27576
+ indices_arr = new Uint32Array(this.segmentW * this.segmentH * 2 * 3);
27577
+ } else {
27578
+ indices_arr = new Uint16Array(this.segmentW * this.segmentH * 2 * 3);
27579
+ }
27580
+ numIndices = 0;
27581
+ var indexP = 0;
27582
+ var indexN = 0;
27583
+ var indexU = 0;
27584
+ for (var yi = 0; yi <= this.segmentH; ++yi) {
27585
+ for (var xi = 0; xi <= this.segmentW; ++xi) {
27586
+ x = (xi / this.segmentW - 0.5) * this.width;
27587
+ y = (yi / this.segmentH - 0.5) * this.height;
27588
+ switch (axis) {
27589
+ case Vector3.Y_AXIS:
27590
+ position_arr[indexP++] = x;
27591
+ position_arr[indexP++] = 0;
27592
+ position_arr[indexP++] = y;
27593
+ normal_arr[indexN++] = 0;
27594
+ normal_arr[indexN++] = 1;
27595
+ normal_arr[indexN++] = 0;
27596
+ break;
27597
+ case Vector3.Z_AXIS:
27598
+ position_arr[indexP++] = x;
27599
+ position_arr[indexP++] = -y;
27600
+ position_arr[indexP++] = 0;
27601
+ normal_arr[indexN++] = 0;
27602
+ normal_arr[indexN++] = 0;
27603
+ normal_arr[indexN++] = 1;
27604
+ break;
27605
+ case Vector3.X_AXIS:
27606
+ position_arr[indexP++] = 0;
27607
+ position_arr[indexP++] = x;
27608
+ position_arr[indexP++] = y;
27609
+ normal_arr[indexN++] = 1;
27610
+ normal_arr[indexN++] = 0;
27611
+ normal_arr[indexN++] = 0;
27612
+ break;
27613
+ default:
27614
+ position_arr[indexP++] = x;
27615
+ position_arr[indexP++] = 0;
27616
+ position_arr[indexP++] = y;
27617
+ normal_arr[indexN++] = 0;
27618
+ normal_arr[indexN++] = 1;
27619
+ normal_arr[indexN++] = 0;
27620
+ break;
27621
+ }
27622
+ uv_arr[indexU++] = xi / this.segmentW;
27623
+ uv_arr[indexU++] = yi / this.segmentH;
27624
+ if (xi != this.segmentW && yi != this.segmentH) {
27625
+ base = xi + yi * tw;
27626
+ indices_arr[numIndices++] = base + 1;
27627
+ indices_arr[numIndices++] = base;
27628
+ indices_arr[numIndices++] = base + tw;
27629
+ indices_arr[numIndices++] = base + 1;
27630
+ indices_arr[numIndices++] = base + tw;
27631
+ indices_arr[numIndices++] = base + tw + 1;
27632
+ }
27633
+ }
27634
+ }
27635
+ this.setIndices(indices_arr);
27636
+ this.setAttribute(VertexAttributeName.position, position_arr);
27637
+ this.setAttribute(VertexAttributeName.normal, normal_arr);
27638
+ this.setAttribute(VertexAttributeName.uv, uv_arr);
27639
+ this.setAttribute(VertexAttributeName.TEXCOORD_1, uv_arr);
27640
+ this.addSubGeometry({
27641
+ indexStart: 0,
27642
+ indexCount: indices_arr.length,
27643
+ vertexStart: 0,
27644
+ vertexCount: 0,
27645
+ firstStart: 0,
27646
+ index: 0,
27647
+ topology: 0
27648
+ });
27649
+ }
27650
+ }
27651
+
27515
27652
  var __getOwnPropDesc$g = Object.getOwnPropertyDescriptor;
27516
27653
  var __decorateClass$g = (decorators, target, key, kind) => {
27517
27654
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$g(target, key) : target;
@@ -30486,7 +30623,15 @@ struct InstanceData {
30486
30623
  shadowMapPassRenderer;
30487
30624
  pointLightShadowRenderer;
30488
30625
  ddgiProbeRenderer;
30489
- postRenderer;
30626
+ _postRenderer;
30627
+ get postRenderer() {
30628
+ if (!this._postRenderer) {
30629
+ let gbufferFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer");
30630
+ this._postRenderer = this.addRenderer(PostRenderer);
30631
+ this._postRenderer.setRenderStates(gbufferFrame);
30632
+ }
30633
+ return this._postRenderer;
30634
+ }
30490
30635
  clusterLightingRender;
30491
30636
  reflectionRenderer;
30492
30637
  occlusionSystem;
@@ -30510,7 +30655,9 @@ struct InstanceData {
30510
30655
  }
30511
30656
  this.shadowMapPassRenderer = new ShadowMapPassRenderer();
30512
30657
  this.pointLightShadowRenderer = new PointLightShadowRenderer();
30513
- this.addPost(new FXAAPost());
30658
+ if (Engine3D.setting.render.postProcessing.fxaa.enable) {
30659
+ this.addPost(new FXAAPost());
30660
+ }
30514
30661
  }
30515
30662
  addRenderer(c, param) {
30516
30663
  let renderer;
@@ -30540,11 +30687,6 @@ struct InstanceData {
30540
30687
  this.pauseRender = false;
30541
30688
  }
30542
30689
  addPost(post) {
30543
- if (!this.postRenderer) {
30544
- let gbufferFrame = GBufferFrame.getGBufferFrame("ColorPassGBuffer");
30545
- this.postRenderer = this.addRenderer(PostRenderer);
30546
- this.postRenderer.setRenderStates(gbufferFrame);
30547
- }
30548
30690
  if (post instanceof PostBase) {
30549
30691
  this.postRenderer.attachPost(this.view, post);
30550
30692
  }
@@ -30562,15 +30704,21 @@ struct InstanceData {
30562
30704
  renderFrame() {
30563
30705
  let view = this._view;
30564
30706
  ProfilerUtil.startView(view);
30565
- GlobalBindGroup.getLightEntries(view.scene).update(view);
30566
- GlobalBindGroup.getReflectionEntries(view.scene).update(view);
30567
- this.occlusionSystem.update(view.camera, view.scene);
30568
- this.clusterLightingRender.render(view, this.occlusionSystem);
30569
- if (this.shadowMapPassRenderer) {
30707
+ if (this.clusterLightingRender) {
30708
+ GlobalBindGroup.getLightEntries(view.scene).update(view);
30709
+ GlobalBindGroup.getReflectionEntries(view.scene).update(view);
30710
+ }
30711
+ if (Engine3D.setting.occlusionQuery.enable && this.occlusionSystem) {
30712
+ this.occlusionSystem.update(view.camera, view.scene);
30713
+ }
30714
+ if (this.clusterLightingRender) {
30715
+ this.clusterLightingRender.render(view, this.occlusionSystem);
30716
+ }
30717
+ if (Engine3D.setting.shadow.enable && this.shadowMapPassRenderer) {
30570
30718
  ShadowLightsCollect.update(view);
30571
30719
  this.shadowMapPassRenderer.render(view, this.occlusionSystem);
30572
30720
  }
30573
- if (this.pointLightShadowRenderer) {
30721
+ if (Engine3D.setting.shadow.enable && this.pointLightShadowRenderer) {
30574
30722
  this.pointLightShadowRenderer.render(view, this.occlusionSystem);
30575
30723
  }
30576
30724
  if (this.depthPassRenderer) {
@@ -40791,7 +40939,7 @@ fn CsMain( @builtin(workgroup_id) workgroup_id : vec3<u32> , @builtin(global_inv
40791
40939
  }
40792
40940
  }
40793
40941
 
40794
- const version = "1.0.12";
40942
+ const version = "1.0.14";
40795
40943
 
40796
40944
  class Engine3D {
40797
40945
  /**
@@ -66579,6 +66727,7 @@ fn frag(){
66579
66727
  exports.GPUVertexFormat = GPUVertexFormat;
66580
66728
  exports.GPUVertexStepMode = GPUVertexStepMode;
66581
66729
  exports.GSplatFormat = GSplatFormat;
66730
+ exports.GSplatGeometry = GSplatGeometry;
66582
66731
  exports.GSplatMaterial = GSplatMaterial;
66583
66732
  exports.GSplat_FS = GSplat_FS;
66584
66733
  exports.GSplat_VS = GSplat_VS;
@@ -66827,6 +66976,7 @@ fn frag(){
66827
66976
  exports.Quad_frag_wgsl = Quad_frag_wgsl;
66828
66977
  exports.Quad_vert_wgsl = Quad_vert_wgsl;
66829
66978
  exports.Quaternion = Quaternion;
66979
+ exports.R32UintTexture = R32UintTexture;
66830
66980
  exports.RADIANS_TO_DEGREES = RADIANS_TO_DEGREES;
66831
66981
  exports.RGBEErrorCode = RGBEErrorCode;
66832
66982
  exports.RGBEHeader = RGBEHeader;