From 57a2e1181ae13cdb4955eb0b10ada97b66bcdf2b Mon Sep 17 00:00:00 2001 From: Dave Pagurek Date: Sun, 24 Mar 2024 14:12:22 -0400 Subject: [PATCH] Fix vertices with different texture coordinates in imported models getting collapsed --- src/webgl/loading.js | 10 +++---- test/unit/assets/cube-textures.obj | 26 ++++++++++++++++++ test/unit/visual/cases/webgl.js | 18 +++++++++++- .../000.png | Bin 0 -> 7309 bytes .../metadata.json | 3 ++ 5 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 test/unit/assets/cube-textures.obj create mode 100644 test/unit/visual/screenshots/WebGL/3DModel/Object with different texture coordinates per use of vertex keeps the coordinates intact/000.png create mode 100644 test/unit/visual/screenshots/WebGL/3DModel/Object with different texture coordinates per use of vertex keeps the coordinates intact/metadata.json diff --git a/src/webgl/loading.js b/src/webgl/loading.js index 2ae734d6a3..202cf9df69 100755 --- a/src/webgl/loading.js +++ b/src/webgl/loading.js @@ -410,11 +410,11 @@ function parseObj(model, lines, materials= {}) { vertParts[i] = parseInt(vertParts[i]) - 1; } - if (!usedVerts[vertParts[0]]) { - usedVerts[vertParts[0]] = {}; + if (!usedVerts[vertString]) { + usedVerts[vertString] = {}; } - if (usedVerts[vertParts[0]][currentMaterial] === undefined) { + if (usedVerts[vertString][currentMaterial] === undefined) { const vertIndex = model.vertices.length; model.vertices.push(loadedVerts.v[vertParts[0]].copy()); model.uvs.push(loadedVerts.vt[vertParts[1]] ? @@ -422,7 +422,7 @@ function parseObj(model, lines, materials= {}) { model.vertexNormals.push(loadedVerts.vn[vertParts[2]] ? loadedVerts.vn[vertParts[2]].copy() : new p5.Vector()); - usedVerts[vertParts[0]][currentMaterial] = vertIndex; + usedVerts[vertString][currentMaterial] = vertIndex; face.push(vertIndex); if (currentMaterial && materials[currentMaterial] @@ -431,7 +431,7 @@ function parseObj(model, lines, materials= {}) { coloredVerts.add(loadedVerts.v[vertParts[0]]); //since a set would only push unique values } } else { - face.push(usedVerts[vertParts[0]][currentMaterial]); + face.push(usedVerts[vertString][currentMaterial]); } } diff --git a/test/unit/assets/cube-textures.obj b/test/unit/assets/cube-textures.obj new file mode 100644 index 0000000000..e5e7b08114 --- /dev/null +++ b/test/unit/assets/cube-textures.obj @@ -0,0 +1,26 @@ +# Simple Cube OBJ File that maps each face +# to a texture + +# Vertices +v 0.0 0.0 0.0 +v 1.0 0.0 0.0 +v 1.0 1.0 0.0 +v 0.0 1.0 0.0 +v 0.0 0.0 1.0 +v 1.0 0.0 1.0 +v 1.0 1.0 1.0 +v 0.0 1.0 1.0 + +# Texture coords +vt 0 0 +vt 1 0 +vt 1 1 +vt 0 1 + +# Faces +f 1/1 2/2 3/3 4/4 +f 5/1 6/2 7/3 8/4 +f 1/1 5/2 8/3 4/4 +f 2/1 6/2 7/3 3/4 +f 4/1 3/2 7/3 8/4 +f 1/1 2/2 6/3 5/4 diff --git a/test/unit/visual/cases/webgl.js b/test/unit/visual/cases/webgl.js index 6b811807d8..2822b1ead8 100644 --- a/test/unit/visual/cases/webgl.js +++ b/test/unit/visual/cases/webgl.js @@ -111,5 +111,21 @@ visualSuite('WebGL', function() { }); }); }); + visualTest( + 'Object with different texture coordinates per use of vertex keeps the coordinates intact', + async function(p5, screenshot) { + p5.createCanvas(50, 50, p5.WEBGL); + const tex = await new Promise(resolve => p5.loadImage('unit/assets/cat.jpg', resolve)); + const cube = await new Promise(resolve => p5.loadModel('unit/assets/cube-textures.obj', resolve)); + cube.normalize(); + p5.background(255); + p5.texture(tex); + p5.rotateX(p5.PI / 4); + p5.rotateY(p5.PI / 4); + p5.scale(80/400); + p5.model(cube); + screenshot(); + } + ); }); -}); \ No newline at end of file +}); diff --git a/test/unit/visual/screenshots/WebGL/3DModel/Object with different texture coordinates per use of vertex keeps the coordinates intact/000.png b/test/unit/visual/screenshots/WebGL/3DModel/Object with different texture coordinates per use of vertex keeps the coordinates intact/000.png new file mode 100644 index 0000000000000000000000000000000000000000..dcba4010ac37c7c320ca4402fbb0578585ce53ac GIT binary patch literal 7309 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 literal 0 HcmV?d00001 diff --git a/test/unit/visual/screenshots/WebGL/3DModel/Object with different texture coordinates per use of vertex keeps the coordinates intact/metadata.json b/test/unit/visual/screenshots/WebGL/3DModel/Object with different texture coordinates per use of vertex keeps the coordinates intact/metadata.json new file mode 100644 index 0000000000..2d4bfe30da --- /dev/null +++ b/test/unit/visual/screenshots/WebGL/3DModel/Object with different texture coordinates per use of vertex keeps the coordinates intact/metadata.json @@ -0,0 +1,3 @@ +{ + "numScreenshots": 1 +} \ No newline at end of file