Repository: playcanvas/engine
Pull request #5715 (2023-10-04 17:06:59)

WebGPU texture anisotropy validation fix
According to the WebGPU spec anisotropy can only be enabled when filtering is linear for both min and mag.

This PR adds changes the WebGPU sampler builder to only set valid anisotropy value.


Patch:
diff --git a/src/core/math/vec2.js b/src/core/math/vec2.js
index 10add95fa..97765fbe2 100644
--- a/src/core/math/vec2.js
+++ b/src/core/math/vec2.js
@@ -103,6 +103,27 @@ class Vec2 {
         return this;
     }
 
+    /**
+     * Adds a 2-dimensional vector scaled by scalar value. Does not modify the vector being added.
+     *
+     * @param {Vec2} rhs - The vector to add to the specified vector.
+     * @param {number} scalar - The number to multiply the added vector with.
+     * @returns {Vec2} Self for chaining.
+     * @example
+     * const vec = new pc.Vec2(1, 2);
+     *
+     * vec.addScaled(pc.Vec2.UP, 2);
+     *
+     * // Outputs [1, 4]
+     * console.log("The result of the addition is: " + vec.toString());
+     */
+    addScaled(rhs, scalar) {
+        this.x += rhs.x * scalar;
+        this.y += rhs.y * scalar;
+
+        return this;
+    }
+
     /**
      * Returns an identical copy of the specified 2-dimensional vector.
      *
diff --git a/src/core/math/vec3.js b/src/core/math/vec3.js
index 7ebd8f9d3..e5b3b79b3 100644
--- a/src/core/math/vec3.js
+++ b/src/core/math/vec3.js
@@ -114,6 +114,28 @@ class Vec3 {
         return this;
     }
 
+    /**
+     * Adds a 3-dimensional vector scaled by scalar value. Does not modify the vector being added.
+     *
+     * @param {Vec3} rhs - The vector to add to the specified vector.
+     * @param {number} scalar - The number to multiply the added vector with.
+     * @returns {Vec3} Self for chaining.
+     * @example
+     * const vec = new pc.Vec3(1, 2, 3);
+     *
+     * vec.addScaled(pc.Vec3.UP, 2);
+     *
+     * // Outputs [1, 4, 3]
+     * console.log("The result of the addition is: " + vec.toString());
+     */
+    addScaled(rhs, scalar) {
+        this.x += rhs.x * scalar;
+        this.y += rhs.y * scalar;
+        this.z += rhs.z * scalar;
+
+        return this;
+    }
+
     /**
      * Returns an identical copy of the specified 3-dimensional vector.
      *
diff --git a/src/core/math/vec4.js b/src/core/math/vec4.js
index ea56ecca1..2e17f1931 100644
--- a/src/core/math/vec4.js
+++ b/src/core/math/vec4.js
@@ -127,6 +127,29 @@ class Vec4 {
         return this;
     }
 
+    /**
+     * Adds a 4-dimensional vector scaled by scalar value. Does not modify the vector being added.
+     *
+     * @param {Vec4} rhs - The vector to add to the specified vector.
+     * @param {number} scalar - The number to multiply the added vector with.
+     * @returns {Vec4} Self for chaining.
+     * @example
+     * const vec = new pc.Vec4(1, 2, 3, 4);
+     *
+     * vec.addScaled(pc.Vec4.ONE, 2);
+     *
+     * // Outputs [3, 4, 5, 6]
+     * console.log("The result of the addition is: " + vec.toString());
+     */
+    addScaled(rhs, scalar) {
+        this.x += rhs.x * scalar;
+        this.y += rhs.y * scalar;
+        this.z += rhs.z * scalar;
+        this.w += rhs.w * scalar;
+
+        return this;
+    }
+
     /**
      * Returns an identical copy of the specified 4-dimensional vector.
      *
diff --git a/src/platform/graphics/webgpu/webgpu-texture.js b/src/platform/graphics/webgpu/webgpu-texture.js
index 23dfe004b..11f62a980 100644
--- a/src/platform/graphics/webgpu/webgpu-texture.js
+++ b/src/platform/graphics/webgpu/webgpu-texture.js
@@ -240,8 +240,7 @@ class WebgpuTexture {
             const descr = {
                 addressModeU: gpuAddressModes[texture.addressU],
                 addressModeV: gpuAddressModes[texture.addressV],
-                addressModeW: gpuAddressModes[texture.addressW],
-                maxAnisotropy: math.clamp(Math.round(texture._anisotropy), 1, device.maxTextureAnisotropy)
+                addressModeW: gpuAddressModes[texture.addressW]
             };
 
             // default for compare sampling of texture
@@ -285,6 +284,15 @@ class WebgpuTexture {
                 }
             }
 
+            // ensure anisotropic filtering is only set when filtering is correctly
+            // set up
+            const allLinear = (descr.minFilter === 'linear' &&
+                               descr.magFilter === 'linear' &&
+                               descr.mipmapFilter === 'linear');
+            descr.maxAnisotropy = allLinear ?
+                math.clamp(Math.round(texture._anisotropy), 1, device.maxTextureAnisotropy) :
+                1;
+
             sampler = device.wgpu.createSampler(descr);
             DebugHelper.setLabel(sampler, label);
             this.samplers[sampleType] = sampler;
diff --git a/src/scene/mesh.js b/src/scene/mesh.js
index 0f08bd2fd..a43249c29 100644
--- a/src/scene/mesh.js
+++ b/src/scene/mesh.js
@@ -723,7 +723,9 @@ class Mesh extends RefCountedObject {
             } else {
                 // destination data is array
                 indices.length = 0;
-                indices.push(streamIndices);
+                for (let i = 0, il = streamIndices.length; i < il; i++) {
+                    indices.push(streamIndices[i]);
+                }
             }
         } else {
             // get data from IndexBuffer


Test patch:
diff --git a/test/core/math/vec2.test.mjs b/test/core/math/vec2.test.mjs
index 843f66a2c..9aa91803b 100644
--- a/test/core/math/vec2.test.mjs
+++ b/test/core/math/vec2.test.mjs
@@ -76,6 +76,17 @@ describe('Vec2', function () {
 
     });
 
+    describe('#addScaled', function () {
+
+        it('adds a scaled vector', function () {
+            const v = new Vec2(1, 2);
+            v.addScaled(Vec2.UP, 2);
+            expect(v.x).to.equal(1);
+            expect(v.y).to.equal(4);
+        });
+
+    });
+
     describe('#ceil', function () {
 
         it('leaves integers unchanged', function () {
diff --git a/test/core/math/vec3.test.mjs b/test/core/math/vec3.test.mjs
index f0270b943..6678dbf3f 100644
--- a/test/core/math/vec3.test.mjs
+++ b/test/core/math/vec3.test.mjs
@@ -84,6 +84,18 @@ describe('Vec3', function () {
 
     });
 
+    describe('#addScaled', function () {
+
+        it('adds a scaled vector', function () {
+            const v = new Vec3(1, 2, 3);
+            v.addScaled(Vec3.UP, 2);
+            expect(v.x).to.equal(1);
+            expect(v.y).to.equal(4);
+            expect(v.z).to.equal(3);
+        });
+
+    });
+
     describe('#ceil', function () {
 
         it('leaves integers unchanged', function () {
diff --git a/test/core/math/vec4.test.mjs b/test/core/math/vec4.test.mjs
index 5b8dfa40f..166ddbaae 100644
--- a/test/core/math/vec4.test.mjs
+++ b/test/core/math/vec4.test.mjs
@@ -92,6 +92,19 @@ describe('Vec4', function () {
 
     });
 
+    describe('#addScaled', function () {
+
+        it('adds a scaled vector', function () {
+            const v = new Vec4(1, 2, 3, 4);
+            v.addScaled(Vec4.ONE, 2);
+            expect(v.x).to.equal(3);
+            expect(v.y).to.equal(4);
+            expect(v.z).to.equal(5);
+            expect(v.w).to.equal(6);
+        });
+
+    });
+
     describe('#ceil', function () {
 
         it('leaves integers unchanged', function () {