I am using LineSegments2 along with LineGeometry and LineMaterial to display the fat lines. The count of vertices for each line may differ. The problem I am facing is, if the count of lines increases to 1000 and more, the fps drops to 10. How can I improve the performance?
Are you doing multiple lines in a single geometry?
1000 sounds low, unless you’re doing a single geometry+material for each one.
You should be using 1 geometry and 1 material if possible.
Thanks for your response @manthrax. Yes, I am using single geometry+material for each one. Is there any example which shows how to use single geometry and material for all the lines? The reason I was using single geometry+material for each line is because I am creating them on the go i.e., based on the mouse clicks. The user clicks to create vertex and join those vertices to create lines.
I am not sure how can I optimize this since I am new to Threejs.
You might be better off just using an array of [start,end,start,end] points, and then when the list is changed, rebuild the geometry.
Here’s a class I use for dynamic debug line drawing:
It’s not super efficient but its sorta meant to be quick and dirty.
I preallocate a buffer of 1 million lines, and then just update the count and rewrite the array when its flagged as needing update:
export default class DebugDrawer {
set color(v) {
this._currentColor = v;
this._color.set(v)
}
get color() {
return this._currentColor
}
constructor({THREE}) {
let {sin, cos, PI, max, min, abs} = Math;
let vec3 = (x,y,z)=>new THREE.Vector3(x,y,z)
let v0 = vec3()
let v1 = vec3()
let v2 = vec3()
let cursor = vec3()
this._color = new THREE.Color('white');
let material = new THREE.LineBasicMaterial({
color: 0xffffff,
vertexColors: true,
toneMapped: false,
//opacity:.2,
transparent:true,
blending:THREE.AdditiveBlending
});
this.lines = new THREE.LineSegments(new THREE.BufferGeometry(),material);
this.lines.frustumCulled = false;
let geometry = this.geometry = this.lines.geometry;
let points = new THREE.BufferAttribute(new Float32Array(3000000),3).setUsage(THREE.DynamicDrawUsage)
let colors = new THREE.BufferAttribute(new Float32Array(3000000),3).setUsage(THREE.DynamicDrawUsage)
geometry.setAttribute('position', points)
geometry.setAttribute('color', colors)
let top = 0;
let lastVersion=0;
let version=0;
this.lines.onBeforeRender=()=>{
if(version==lastVersion)return
geometry.setDrawRange(0, top>points.count ? Infinity : top)
points.needsUpdate = true;
colors.needsUpdate = true;
lastVersion = version;
}
let vt = (p,c=this._color)=>{
points.setXYZ(top%points.count, p.x, p.y, p.z)
colors.setXYZ(top%points.count, c.r, c.g, c.b)
top++;
}
let moveto = this.moveto = (p,d,q)=>((d !== undefined) && cursor.set(p, d, q)) || cursor.copy(p)
let lineto = this.lineto = (p,d,q)=>{
vt(cursor);
moveto(p, d, q);
vt(cursor);
version++;
}
this.cls = ()=>{
top = 0;
version++;
}
this.circle = (radius=.1,sides=16)=>{
v2.copy(cursor)
for (let i = 0; i <= sides; i++) {
v1.copy(v2);
let th = i * PI * 2 / sides
v1.x += sin(th) * radius
v1.z += cos(th) * radius
if (!i)
moveto(v1);
else
lineto(v1);
}
cursor.copy(v2);
}
}
Then you can call it like:
let dd = new DebugDrawer({THREE})
scene.add(dd.lines);
dd.color = 'red';
dd.moveto(0,0,0);
dd.lineto(10,10,10);