Hi. My goal is to display several thousand meshes and their wireframes (created with WireframeGeometry
) efficiently. Each has a color and an alpha, but otherwise the same material. To do this I’ve taken the route of merging all the objects and, separately, all the wires, together with BufferGeometryUtils.mergeBufferGeometries
. To control the appearance of each object within the merged geometry I created a node material that sets the color
and alpha
properties of PhongNodeMaterial
based on which object a given vertex originated in. This works great! Vast speed improvements.
However, when I use the same material on the LineSegments
wireframe object, I get only black lines. How might I use the same approach for the wireframes? Here’s a simple version demonstrating that the color input doesn’t affect lines: three-js-nodes-wires-colors - CodeSandbox. Do I need to create a node material version of LineBasicMaterial
? I got lost trying to compare PhongNodeMaterial
with meshphong.glsl.js
, it looks like there’s more difference than just a straight translation?
Here’s some code from the working node material for the meshes, if it’s helpful:
import { Color, DataTexture, RGBAFormat } from "three";
import * as Nodes from "three/examples/jsm/nodes/Nodes";
import { PhongNodeMaterial } from "three/examples/jsm/nodes/Nodes";
export class MergedMaterial extends PhongNodeMaterial
{
private colorData: DataTexture;
constructor(colors: { color: Color; alpha?: boolean }[]) {
super();
// Geometry has a buffer attribute matching vertices to object id.
const objectId = new Nodes.AttributeNode("object", "float");
const pixelCount = colors.length;
const size = Math.ceil(Math.sqrt(pixelCount));
this.colorData = new DataTexture(
new Uint8Array(4 * size * size),
size,
size,
RGBAFormat
);
this.updateColors(colors);
const objectColors = new Nodes.TextureNode(this.colorData);
const objectColorFunction = new Nodes.FunctionNode(
`vec3 objectColor( float objectId, sampler2D colors ) {
int index = int(objectId);
int x = index % ${size};
int y = index / ${size};
return texelFetch(colors, ivec2(x,y), 0).rgb;
}`
);
const objectAlphaFunction = new Nodes.FunctionNode(
`float objectAlpha( float objectId, sampler2D colors ) {
int index = int(objectId);
int x = index % ${size};
int y = index / ${size};
return texelFetch(colors, ivec2(x,y), 0).a;
}`
);
this.color = new Nodes.FunctionCallNode(objectColorFunction, [
objectId,
objectColors,
]);
this.alpha = new Nodes.FunctionCallNode(objectAlphaFunction, [
objectId,
objectColors,
]);
}
public updateColors(colors: { color: Color; alpha?: boolean }[]): void {
const colorArray = this.colorData.image.data;
for (let i = 0; i < colors.length; i++) {
const color = colors[i];
const stride = i * 4;
colorArray[stride] = Math.floor(color.color.r * 255);
colorArray[stride + 1] = Math.floor(color.color.g * 255);
colorArray[stride + 2] = Math.floor(color.color.b * 255);
colorArray[stride + 3] = Math.floor(color.alpha * 255);
}
this.colorData.needsUpdate = true;
}
}