Canvas Texture Seams/Artifact Lines at Repeat Border

Good news, I fixed it! :slight_smile:


The solution involved 2 things:

let canvasTexture = new THREE.CanvasTexture(context.canvas,
    THREE.UVMapping,
    THREE.RepeatWrapping, THREE.RepeatWrapping,
    THREE.NearestFilter, THREE.NearestMipmapNearestFilter);

AND I had to use my SMAAPass post-processing filter, e.g.:

this.effectComposer = new EffectComposer(this.renderer);
...
let renderPass = new RenderPass(this.scene, this.camera);
this.effectComposer.addPass(renderPass);
let smaaPass = new SMAAPass(window.innerWidth * this.renderer.getPixelRatio(), window.innerHeight * this.renderer.getPixelRatio());
smaaPass.renderToScreen = true;
this.effectComposer.addPass(smaaPass);

(P.S.: Antialiasing had no effect either way.)


So I did in fact want RepeatWrapping, but I had to use NearestFilter to stop it from sampling multiple pixels.

This article helped to clear up a lot. I had seen it earlier - and I had tried all these - but I wasn’t using the SMAAPass at the time. It says:

THREE.NearestFilter

same as above, choose the closest pixel in the texture

THREE.LinearFilter

same as above, choose 4 pixels from the texture and blend them

THREE.NearestMipmapNearestFilter

choose the appropriate mip then choose one pixel

THREE.NearestMipmapLinearFilter

choose 2 mips, choose one pixel from each, blend the 2 pixels

THREE.LinearMipmapNearestFilter

chose the appropriate mip then choose 4 pixels and blend them

THREE.LinearMipmapLinearFilter

choose 2 mips, choose 4 pixels from each and blend all 8 into 1 pixel

So as you can see, my choices of THREE.NearestFilter, THREE.NearestMipmapNearestFilter are the only options that would fix this, since they do not blend together any extra pixels. (FYI, I had tried messing around with the RepeatWrapping math in Three’s code in a bunch of different ways after making this post; nothing I tried had any effect.)

Also I didn’t need any of my canvas clipping/redrawing tests, the problem had nothing to do with the canvas graphics or bounds.

Thanks for your help, you at least pointed me at the right general settings to look at.


On a separate note, through more digging through the Three JS docs, the actual Three JS code, and this article (only article I know of on the entire internet that somewhat helpfully explains Three JS UV mapping…), and then comparing all that information with the faceVertexUvs code, I added some comments:

//All of this code only needs to be evaluated once because the X and Z coordinates don't change.
//Need normals to be calculated before calculating faceVertexUvs.
this.topGeometry.computeFaceNormals();
this.topGeometry.faces.forEach(function(face) {
    //Sort the normals, the direction of the face XYZ components.
    //Only the highest 2 will be utilized; Y has been ommitted for optimization.
    let components = ['x', 'z'].sort(function(a, b) {
        return Math.abs(face.normal[a]) > Math.abs(face.normal[b]);
    });

    //Get the vertices for each point of the face triangle.
    let v1 = this.topGeometry.vertices[face.a];
    let v2 = this.topGeometry.vertices[face.b];
    let v3 = this.topGeometry.vertices[face.c];

    //Specify the U & V texture mapping coordinate for each vertex of the face triangle.
    //U & V values range from 0.0-1.0 as a percentage of the texture width and height, but
    //RepeatWrapping will take care of this math just fine, since this is a "regular grid".
    this.topGeometry.faceVertexUvs[0].push([
        new THREE.Vector2(v1[components[0]], v1[components[1]]),
        new THREE.Vector2(v2[components[0]], v2[components[1]]),
        new THREE.Vector2(v3[components[0]], v3[components[1]])
    ]);
}.bind(this));