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;
}
});