@quake2ts/engine 0.0.849 → 0.0.850

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.
@@ -10737,7 +10737,7 @@ var SpriteRenderer2 = class {
10737
10737
  };
10738
10738
 
10739
10739
  // raw-loader:/home/runner/work/quake2/quake2/quake2ts/packages/engine/src/render/webgpu/shaders/skybox.wgsl
10740
- var skybox_default = "struct Uniforms {\n viewProjection: mat4x4<f32>,\n scroll: vec2<f32>,\n}\n\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\n@group(0) @binding(1) var t_skybox: texture_cube<f32>;\n@group(0) @binding(2) var s_skybox: sampler;\n\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) direction: vec3<f32>,\n}\n\n@vertex\nfn vertexMain(@location(0) position: vec3<f32>) -> VertexOutput {\n var output: VertexOutput;\n\n // Pass the RAW position (not normalized) as direction\n // This preserves the face-relative direction and avoids corner tie issues\n // The cubemap sampler handles normalization internally\n var dir = position;\n\n // Apply scrolling in Quake horizontal plane (X/Y)\n // Small scrolling offset that doesn't break dominant component detection\n dir.x += uniforms.scroll.x * 0.01;\n dir.y += uniforms.scroll.y * 0.01;\n\n output.direction = dir;\n output.position = uniforms.viewProjection * vec4<f32>(position, 1.0);\n return output;\n}\n\n@fragment\nfn fragmentMain(@location(0) direction: vec3<f32>) -> @location(0) vec4<f32> {\n // Transform from Quake coordinates to GL/WebGPU cubemap coordinates\n // Quake: +X forward, +Y left, +Z up\n // GL cubemap: +X right, +Y up, -Z forward\n var cubemapDir: vec3<f32>;\n cubemapDir.x = -direction.y; // Quake +Y (left) \u2192 GL -X (left)\n cubemapDir.y = direction.z; // Quake +Z (up) \u2192 GL +Y (up)\n cubemapDir.z = -direction.x; // Quake +X (forward) \u2192 GL -Z (forward)\n\n return textureSample(t_skybox, s_skybox, cubemapDir);\n}\n";
10740
+ var skybox_default = "// Skybox shader using full-screen triangle approach\n// This avoids the w\u22480 issue with cube geometry at diagonal view angles\n// by computing the world-space direction analytically per-pixel\n\nstruct Uniforms {\n // Inverse view rotation matrix (view\u2192world transform for directions)\n // Stored as 3 vec4s due to std140 padding\n inverseViewRotation_col0: vec4<f32>,\n inverseViewRotation_col1: vec4<f32>,\n inverseViewRotation_col2: vec4<f32>,\n tanHalfFov: f32,\n aspect: f32,\n scroll: vec2<f32>,\n}\n\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\n@group(0) @binding(1) var t_skybox: texture_cube<f32>;\n@group(0) @binding(2) var s_skybox: sampler;\n\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n}\n\n@vertex\nfn vertexMain(@location(0) position: vec2<f32>) -> VertexOutput {\n var output: VertexOutput;\n\n // Position is already in NDC space (-1 to 1)\n output.position = vec4<f32>(position, 0.999, 1.0); // z near 1.0 for far plane\n\n return output;\n}\n\n// Hard-coded screen size for now (should be passed as uniform)\nconst SCREEN_SIZE: vec2<f32> = vec2<f32>(256.0, 256.0);\n\n@fragment\nfn fragmentMain(@builtin(position) fragCoord: vec4<f32>) -> @location(0) vec4<f32> {\n // Compute NDC from fragment coordinates\n // fragCoord.xy is in framebuffer coordinates (0 to width, 0 to height)\n // NDC.x: 0 -> -1, width -> +1\n // NDC.y: 0 -> +1, height -> -1 (Y is flipped in WebGPU framebuffer)\n let ndc = vec2<f32>(\n (fragCoord.x / SCREEN_SIZE.x) * 2.0 - 1.0,\n 1.0 - (fragCoord.y / SCREEN_SIZE.y) * 2.0\n );\n // Get columns directly from uniforms\n let col0 = uniforms.inverseViewRotation_col0.xyz;\n let col1 = uniforms.inverseViewRotation_col1.xyz;\n let col2 = uniforms.inverseViewRotation_col2.xyz;\n\n // Compute view-space direction from NDC\n // The view-space ray direction for a pixel at NDC (x, y) with perspective projection:\n // viewDir = normalize(vec3(x * aspect * tanHalfFov, y * tanHalfFov, -1.0))\n // Note: -1.0 for Z because we look down -Z in view space\n let viewDir = normalize(vec3<f32>(\n ndc.x * uniforms.aspect * uniforms.tanHalfFov,\n ndc.y * uniforms.tanHalfFov,\n -1.0\n ));\n\n // Transform view-space direction to world-space (Quake coordinates)\n // Manually unroll: worldDir = col0 * viewDir.x + col1 * viewDir.y + col2 * viewDir.z\n var worldDir = col0 * viewDir.x + col1 * viewDir.y + col2 * viewDir.z;\n\n // Apply small scroll offset in Quake horizontal plane\n worldDir.x += uniforms.scroll.x * 0.01;\n worldDir.y += uniforms.scroll.y * 0.01;\n\n // Transform from Quake coordinates to GL/WebGPU cubemap coordinates\n // Quake: +X forward, +Y left, +Z up\n // GL cubemap: +X right, +Y up, -Z forward\n var cubemapDir: vec3<f32>;\n cubemapDir.x = -worldDir.y; // Quake +Y (left) \u2192 GL -X (left)\n cubemapDir.y = worldDir.z; // Quake +Z (up) \u2192 GL +Y (up)\n cubemapDir.z = -worldDir.x; // Quake +X (forward) \u2192 GL -Z (forward)\n\n return textureSample(t_skybox, s_skybox, cubemapDir);\n}\n";
10741
10741
 
10742
10742
  // src/render/types/coordinates.ts
10743
10743
  var CoordinateSystem = /* @__PURE__ */ ((CoordinateSystem2) => {
@@ -10832,121 +10832,27 @@ var WebGPUMatrixBuilder = class {
10832
10832
  return view;
10833
10833
  }
10834
10834
  };
10835
- var SKYBOX_POSITIONS2 = new Float32Array([
10836
- // Front face (+X) - Quake forward direction
10837
- 1,
10838
- -1,
10839
- -1,
10840
- 1,
10841
- 1,
10842
- -1,
10843
- 1,
10844
- 1,
10845
- 1,
10846
- 1,
10847
- -1,
10848
- -1,
10849
- 1,
10850
- 1,
10851
- 1,
10852
- 1,
10853
- -1,
10854
- 1,
10855
- // Back face (-X) - Quake backward direction
10856
- -1,
10857
- 1,
10858
- -1,
10859
- -1,
10860
- -1,
10861
- -1,
10862
- -1,
10863
- -1,
10864
- 1,
10865
- -1,
10866
- 1,
10867
- -1,
10868
- -1,
10869
- -1,
10870
- 1,
10871
- -1,
10872
- 1,
10873
- 1,
10874
- // Left face (+Y) - Quake left direction
10875
- -1,
10876
- 1,
10877
- -1,
10878
- -1,
10879
- 1,
10880
- 1,
10881
- 1,
10882
- 1,
10883
- 1,
10884
- -1,
10885
- 1,
10886
- -1,
10887
- 1,
10888
- 1,
10889
- 1,
10890
- 1,
10891
- 1,
10892
- -1,
10893
- // Right face (-Y) - Quake right direction
10894
- 1,
10895
- -1,
10896
- -1,
10897
- 1,
10898
- -1,
10899
- 1,
10900
- -1,
10901
- -1,
10902
- 1,
10903
- 1,
10904
- -1,
10905
- -1,
10835
+ var FULLSCREEN_QUAD = new Float32Array([
10836
+ // Triangle 1: bottom-left, bottom-right, top-right
10906
10837
  -1,
10907
10838
  -1,
10839
+ // vertex 0: bottom-left
10908
10840
  1,
10909
10841
  -1,
10910
- -1,
10911
- -1,
10912
- // Top face (+Z) - Quake up direction
10913
- -1,
10914
- -1,
10842
+ // vertex 1: bottom-right
10915
10843
  1,
10916
10844
  1,
10845
+ // vertex 2: top-right
10846
+ // Triangle 2: bottom-left, top-right, top-left
10917
10847
  -1,
10918
- 1,
10919
- 1,
10920
- 1,
10921
- 1,
10922
10848
  -1,
10923
- -1,
10924
- 1,
10925
- 1,
10849
+ // vertex 3: bottom-left
10926
10850
  1,
10927
10851
  1,
10852
+ // vertex 4: top-right
10928
10853
  -1,
10929
- 1,
10930
- 1,
10931
- // Bottom face (-Z) - Quake down direction
10932
- -1,
10933
- 1,
10934
- -1,
10935
- 1,
10936
- 1,
10937
- -1,
10938
- 1,
10939
- -1,
10940
- -1,
10941
- -1,
10942
- 1,
10943
- -1,
10944
- 1,
10945
- -1,
10946
- -1,
10947
- -1,
10948
- -1,
10949
- -1
10854
+ 1
10855
+ // vertex 5: top-left
10950
10856
  ]);
10951
10857
  var SkyboxPipeline3 = class {
10952
10858
  constructor(device, format) {
@@ -10959,15 +10865,15 @@ var SkyboxPipeline3 = class {
10959
10865
  });
10960
10866
  this.vertexBuffer = device.createBuffer({
10961
10867
  label: "skybox-vertex-buffer",
10962
- size: SKYBOX_POSITIONS2.byteLength,
10868
+ size: FULLSCREEN_QUAD.byteLength,
10963
10869
  usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
10964
10870
  mappedAtCreation: true
10965
10871
  });
10966
- new Float32Array(this.vertexBuffer.getMappedRange()).set(SKYBOX_POSITIONS2);
10872
+ new Float32Array(this.vertexBuffer.getMappedRange()).set(FULLSCREEN_QUAD);
10967
10873
  this.vertexBuffer.unmap();
10968
10874
  this.uniformBuffer = device.createBuffer({
10969
10875
  label: "skybox-uniform-buffer",
10970
- size: 80,
10876
+ size: 64,
10971
10877
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
10972
10878
  });
10973
10879
  this.sampler = device.createSampler({
@@ -10983,7 +10889,7 @@ var SkyboxPipeline3 = class {
10983
10889
  entries: [
10984
10890
  {
10985
10891
  binding: 0,
10986
- visibility: GPUShaderStage.VERTEX,
10892
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
10987
10893
  buffer: { type: "uniform" }
10988
10894
  },
10989
10895
  {
@@ -11007,12 +10913,12 @@ var SkyboxPipeline3 = class {
11007
10913
  module,
11008
10914
  entryPoint: "vertexMain",
11009
10915
  buffers: [{
11010
- arrayStride: 12,
11011
- // vec3<f32>
10916
+ arrayStride: 8,
10917
+ // vec2<f32> for full-screen triangle
11012
10918
  attributes: [{
11013
10919
  shaderLocation: 0,
11014
10920
  offset: 0,
11015
- format: "float32x3"
10921
+ format: "float32x2"
11016
10922
  }]
11017
10923
  }]
11018
10924
  },
@@ -11038,48 +10944,63 @@ var SkyboxPipeline3 = class {
11038
10944
  },
11039
10945
  depthStencil: {
11040
10946
  format: "depth24plus",
11041
- depthWriteEnabled: true,
11042
- depthCompare: "less-equal"
11043
- // Proper depth testing ensures front faces occlude back faces
10947
+ depthWriteEnabled: false,
10948
+ // Skybox at infinite distance, don't affect depth
10949
+ depthCompare: "always"
10950
+ // Always draw skybox (rendered first as background)
11044
10951
  },
11045
10952
  primitive: {
11046
10953
  topology: "triangle-list",
11047
10954
  cullMode: "none"
11048
- // Inside the box
11049
10955
  }
11050
10956
  });
11051
10957
  this.bindGroupHelper = new SkyboxBindGroupHelper(device, bindGroupLayout, this.uniformBuffer, this.sampler);
11052
10958
  }
11053
10959
  draw(passEncoder, options) {
11054
- let viewProjection;
11055
- let useNative = 0;
11056
- if (options.cameraState) {
11057
- const view = this.matrixBuilder.buildViewMatrix(options.cameraState);
11058
- const projection = this.matrixBuilder.buildProjectionMatrix(options.cameraState);
11059
- view[12] = 0;
11060
- view[13] = 0;
11061
- view[14] = 0;
11062
- const vp = glMatrix.mat4.create();
11063
- glMatrix.mat4.multiply(vp, projection, view);
11064
- viewProjection = vp;
11065
- useNative = 1;
11066
- } else if (options.viewProjection) {
11067
- viewProjection = options.viewProjection;
11068
- useNative = 0;
11069
- } else {
11070
- throw new Error("SkyboxPipeline: Either cameraState or viewProjection must be provided");
11071
- }
11072
- const uniformData = new Float32Array(20);
11073
- uniformData.set(viewProjection);
11074
- uniformData[16] = options.scroll[0];
11075
- uniformData[17] = options.scroll[1];
11076
- uniformData[18] = useNative;
10960
+ if (!options.cameraState) {
10961
+ throw new Error("SkyboxPipeline: cameraState is required for full-screen skybox rendering");
10962
+ }
10963
+ const camera = options.cameraState;
10964
+ const view = this.matrixBuilder.buildViewMatrix(camera);
10965
+ const inverseViewRotation = glMatrix.mat3.fromValues(
10966
+ view[0],
10967
+ view[4],
10968
+ view[8],
10969
+ // First column becomes first row
10970
+ view[1],
10971
+ view[5],
10972
+ view[9],
10973
+ // Second column becomes second row
10974
+ view[2],
10975
+ view[6],
10976
+ view[10]
10977
+ // Third column becomes third row
10978
+ );
10979
+ const tanHalfFov = Math.tan(camera.fov * shared.DEG2RAD / 2);
10980
+ const aspect = camera.aspect;
10981
+ const uniformData = new Float32Array(16);
10982
+ uniformData[0] = inverseViewRotation[0];
10983
+ uniformData[1] = inverseViewRotation[1];
10984
+ uniformData[2] = inverseViewRotation[2];
10985
+ uniformData[3] = 0;
10986
+ uniformData[4] = inverseViewRotation[3];
10987
+ uniformData[5] = inverseViewRotation[4];
10988
+ uniformData[6] = inverseViewRotation[5];
10989
+ uniformData[7] = 0;
10990
+ uniformData[8] = inverseViewRotation[6];
10991
+ uniformData[9] = inverseViewRotation[7];
10992
+ uniformData[10] = inverseViewRotation[8];
10993
+ uniformData[11] = 0;
10994
+ uniformData[12] = tanHalfFov;
10995
+ uniformData[13] = aspect;
10996
+ uniformData[14] = options.scroll[0];
10997
+ uniformData[15] = options.scroll[1];
11077
10998
  this.device.queue.writeBuffer(this.uniformBuffer, 0, uniformData);
11078
10999
  const bindGroup = this.bindGroupHelper.getBindGroup(options.cubemap);
11079
11000
  passEncoder.setPipeline(this.pipeline);
11080
11001
  passEncoder.setBindGroup(0, bindGroup);
11081
11002
  passEncoder.setVertexBuffer(0, this.vertexBuffer);
11082
- passEncoder.draw(SKYBOX_POSITIONS2.length / 3);
11003
+ passEncoder.draw(6);
11083
11004
  }
11084
11005
  destroy() {
11085
11006
  this.vertexBuffer.destroy();