Error when manually creating edges for tetrahedrons on a Mesh using LineGeometry

Hello everyone!

I have been working on a project to be able to render a mesh depending on same data I have. My first way of visualizing this data was creating a mesh using EdgesGeometry, to automatically create edges for the tetrahedrons on my mesh. Which worked mostly perfectly, other than the small chance of error on coplanar triangle edges not showing.

But, I’ve been wanting to allow the user to edit line thickness, for better visualization. I’ve gone ahead and looked at LineGeometry, so that I am able to create a slider, as shown in some of the fatLines examples on threeJS docs. However, I’ve run into the error , since edgesGeometry doesn’t support the editing of line thickness, I have to manually create the edges for the tetrahedrons depending on the vertices of the sides, causing large visualization errors and inaccurate lines.

Has anyone had experience with this? And if so, any tips?

Original Code:

function createOuterTetrahedralMesh(
  vertices,
  outerElements,
  conductivityValues
) {
  const positions = []; // Array to hold vertex positions
  const indices = []; // Array to hold indices for the geometry
  const colors = []; // Array to hold colors for each vertex
  const { min: minConductivityValue, max: maxConductivityValue } =
    findMinMax(conductivityValues);
  outerElements.forEach((element) => {
    // Get the vertices for the current tetrahedron
    const v1 = vertices[element[1] - 1];
    const v2 = vertices[element[2] - 1];
    const v3 = vertices[element[3] - 1];
    const v4 = vertices[element[4] - 1];

    // Calculate the positions for the tetrahedron's vertices
    const startIndex = positions.length / 3; // Current number of vertices

    positions.push(...v1, ...v2, ...v3, ...v4); // Push the vertex positions into the array

    // Define the indices for the tetrahedron's faces (triangles)
    indices.push(
      startIndex,
      startIndex + 1,
      startIndex + 2, // Face 1
      startIndex,
      startIndex + 1,
      startIndex + 3, // Face 2
      startIndex,
      startIndex + 2,
      startIndex + 3, // Face 3
      startIndex + 1,
      startIndex + 2,
      startIndex + 3 // Face 4
    );
    const conductivity = conductivityValues[element[0] - 1];
    const color = getColorFromConductivity(
      conductivity,
      minConductivityValue,
      maxConductivityValue,
      colorScale
    );
    colors.push(
      ...color.toArray(),
      ...color.toArray(),
      ...color.toArray(),
      ...color.toArray()
    );
  });

  // Create the tetrahedron geometry
  const combinedGeometry = new THREE.BufferGeometry();
  combinedGeometry.setAttribute(
    "position",
    new THREE.Float32BufferAttribute(positions, 3)
  );
  combinedGeometry.setIndex(indices);
  combinedGeometry.setAttribute(
    "color",
    new THREE.Float32BufferAttribute(colors, 3)
  );

  // Create the tetrahedron mesh
  const tetrahedronMesh = new THREE.Mesh(
    combinedGeometry,
    new THREE.MeshPhongMaterial({
      vertexColors: true,
      flatShading: true,
      shininess: 50,
      side: THREE.DoubleSide,
    })
  );

  // Create outline geometry
  const outlineGeometry = new THREE.EdgesGeometry(combinedGeometry);

  // Create an outline material
  const outlineMaterial = new THREE.MeshBasicMaterial({
    color: 0x000000, // Outline color (Black)
    side: THREE.FrontSide,
    depthTest: true,
  });

  // Create a line segments object using the outline geometry and outline material
  const outlineMesh = new THREE.LineSegments(outlineGeometry, outlineMaterial);
  // group the mesh and outline together
  const group = new THREE.Group();
  group.add(tetrahedronMesh);
  group.add(outlineMesh);

  return group; // Return the group containing both the mesh and the outline
}

LineGeometry code, which allows editing of lines, but causes visualization errors when manually creating edges:

function createOuterTetrahedralMesh(
  vertices,
  outerElements,
  conductivityValues
) {
  const positions = []; // Array to hold vertex positions
  const indices = []; // Array to hold indices for the geometry
  const colors = []; // Array to hold colors for each vertex
  const edgePositions = []; // Array to hold positions for edges

  const { min: minConductivityValue, max: maxConductivityValue } =
    findMinMax(conductivityValues);
  outerElements.forEach((element) => {
    // Get the vertices for the current tetrahedron
    const v1 = vertices[element[1] - 1];
    const v2 = vertices[element[2] - 1];
    const v3 = vertices[element[3] - 1];
    const v4 = vertices[element[4] - 1];
    console.log("Tetrahedron vertices:", v1, v2, v3, v4);

    // Calculate the positions for the tetrahedron's vertices
    const startIndex = positions.length / 3; // Current number of vertices

    positions.push(...v1, ...v2, ...v3, ...v4); // Push the vertex positions into the array

    // Define the indices for the tetrahedron's faces (triangles)
    indices.push(
      startIndex,
      startIndex + 1,
      startIndex + 2, // Face 1
      startIndex,
      startIndex + 1,
      startIndex + 3, // Face 2
      startIndex,
      startIndex + 2,
      startIndex + 3, // Face 3
      startIndex + 1,
      startIndex + 2,
      startIndex + 3 // Face 4
    );
    edgePositions.push(
      ...v1,
      ...v2,
      ...v1,
      ...v3,
      ...v1,
      ...v4,
      ...v2,
      ...v3,
      ...v2,
      ...v4,
      ...v3,
      ...v4
    );
    const conductivity = conductivityValues[element[0] - 1];
    const color = getColorFromConductivity(
      conductivity,
      minConductivityValue,
      maxConductivityValue,
      colorScale
    );
    colors.push(
      ...color.toArray(),
      ...color.toArray(),
      ...color.toArray(),
      ...color.toArray()
    );
  });

  // Create the tetrahedron geometry
  const combinedGeometry = new THREE.BufferGeometry();
  combinedGeometry.setAttribute(
    "position",
    new THREE.Float32BufferAttribute(positions, 3)
  );
  combinedGeometry.setIndex(indices);
  combinedGeometry.setAttribute(
    "color",
    new THREE.Float32BufferAttribute(colors, 3)
  );

  // Create the tetrahedron mesh
  const tetrahedronMesh = new THREE.Mesh(
    combinedGeometry,
    new THREE.MeshPhongMaterial({
      vertexColors: true,
      flatShading: true,
      shininess: 50,
      side: THREE.DoubleSide,
    })
  );

  // Create outline geometry
  const outlineGeometry = new LineGeometry();
  outlineGeometry.setPositions(edgePositions);

  // Create an outline material
  const outlineMaterial = new LineMaterial({
    color: 0x000000,
    linewidth: 1, // Default line width
    resolution: new THREE.Vector2(
      container.clientWidth,
      container.clientHeight
    ),
  });

  // Create a line segments object using the outline geometry and outline material
  outlineMesh = new LineSegments2(outlineGeometry, outlineMaterial);
  // group the mesh and outline together
  const group = new THREE.Group();
  group.add(tetrahedronMesh);
  group.add(outlineMesh);

  return group; // Return the group containing both the mesh and the outline
}

rangeInput.addEventListener("input", () => {
  const currentLineWidth = Math.max(rangeInput.value / 10, 0.1);
  if (outlineMesh && outlineMesh.material) {
    outlineMesh.material.linewidth = currentLineWidth;
  }
});