Fragment Shader Artifacts with Instance Mesh

Hi All,

I have project (using three.js 178) where I am using InstancedMeshes for all meshes and shaders to perform attribute adjustments for a specific instance when needed. One object I’ve created is a bidirectional arrow that can be adjusted such that the shader assigned to the InstancedMesh can display the arrow as single directional or simply a line with no arrow heads. This is achieved by using a fragment shader that discards when the vertex position is on the appropriate coordinate positions.

The problem I am experiencing is that the removed part of the mesh shows up something like a funky wireframe from most viewing angles:

Mostly disappears at a very specific angle:

I’ve tried making adjustments to the material to tweak the alpha, alpha test, depth write, depth test, transparency with no visible change. The material comes from a Blender GLB (more on that below). I’ve also tweaked the WebGLRenderer setup regarding alpha values with no visible change caused after those adjustments.

Fragment Shader Replacement:

#include <dithering_fragment>
bool discardFragment = false;
float thresholdZ = 0.05;

if (vHideToArrow >= 1.0
    && vArrowPosition.x > 0.7
    && (vArrowPosition.z > thresholdZ
        || vArrowPosition.z < -thresholdZ)) {
  discardFragment = true;
}
if (vHideFromArrow >= 1.0
    && vArrowPosition.x < 0.7
    && (vArrowPosition.z > thresholdZ
        || vArrowPosition.z < -thresholdZ)) {
  discardFragment = true;
}
if (discardFragment) {
  discard;
}

Blender GLB:

I’m using a simple mesh and material created and exported from Blender as a GLB.

Here is the debug of the material setup as loaded from the GLB.

Instanced Mesh:

const instancedMesh = new InstancedMesh(geometry, material, instances);
instancedMesh.boundingSphere = systemBounds;
instancedMesh.layers.set(PATHING_LAYER);
instancedMesh.instanceMatrix.setUsage(DynamicDrawUsage);
instancedMesh.name = LAYOUT_EDGE;
instancedMesh.receiveShadow = false;
instancedMesh.castShadow = false;

I am aware that I could make three individual meshes to do something similar, but I was hoping I could get this method to work just to make the management of the meshes simpler and to an extent I also want to understand what I am doing wrong with this method.

I’ve tried to include as much information as possible here, but if that isn’t enough I could spend some time putting together a hosted version that illustrates the problem in a simpler environment.

In a project of mine I had a similar issue. And the easiest solution (for my case) was just to collapse the extra vertices on or in the main body in the vertex shader. The same idea applied to your arrow would mean to shift the red vertices to the yellow positions:

1 Like

Hey, thanks for the recommendation. I’ll give that a try.

With this method I was able to fix the issue.

Thanks again for the direction.

I also noticed while debugging that my mesh wasn’t clean (extra vertices, edges, faces and incorrect normal directions) so I cleaned those up. That had no impact on the issue, but it was affecting the render when I overrode the blender material with a MeshStandardMaterial to debug.

New Shader Code:

    material.onBeforeCompile = (shader): void =>
    {
      shader.vertexShader = shader.vertexShader
        .replace("#include <common>",
                 `
#include <common>
attribute float hideFromArrow;
attribute float hideToArrow;
`);
      shader.vertexShader = shader.vertexShader
        .replace("#include <morphtarget_vertex>",
                 `
float thresholdZ = 0.05;

if (hideFromArrow >= 1.0
    && position.x <= 0.5
    && position.z >= thresholdZ) {
  transformed.z = thresholdZ;
}

if (hideFromArrow >= 1.0
    && position.x <= 0.5
    && position.z <= -thresholdZ) {
  transformed.z = -thresholdZ;
}

if (hideToArrow >= 1.0
    && position.x >= 0.5
    && position.z >= thresholdZ) {
  transformed.z = thresholdZ;
}

if (hideToArrow >= 1.0
    && position.x >= 0.5
    && position.z <= -thresholdZ) {
  transformed.z = -thresholdZ;
}
#include <morphtarget_vertex>
`);
      material.userData["shader"] = shader;
    };

Result: