I’m using meshline in R3F to draw 3D ropes, but I’m running into two annoying issues with MeshLineMaterial when using sizeAttenuation={1}
1st Horizontal vs Vertical Thinning - when i rotate the camera, the line’s thickness changes (it appears much thinner than when it spans vertically.)
2nd Resolution Flickering- I read on threejs discourse that passing resolution={[width, height]} to the material fixes the aspect ratio bug. but R3F causes the line to violently flicker as the camera moves.
Here is a stripped-down version of our component. can someone please help me with this?
Code:
import { useMemo, useRef } from 'react';
import { Vector3 } from 'three';
import { extend, useFrame, Object3DNode } from '@react-three/fiber';
import { MeshLineGeometry, MeshLineMaterial } from 'meshline';
extend({ MeshLineGeometry, MeshLineMaterial });
declare module '@react-three/fiber' {
interface ThreeElements {
meshLineGeometry: Object3DNode<MeshLineGeometry, typeof MeshLineGeometry>;
meshLineMaterial: Object3DNode<MeshLineMaterial, typeof MeshLineMaterial>;
}
}
export const LineMesh = ({ points, baseWidth }: { points: Vector3[], baseWidth: number }) => {
const materialRef = useRef<MeshLineMaterial>(null);
const flatCoordinates = useMemo(() => points.flatMap((p) => [p.x, p.y, p.z]), [points]);
useFrame((state) => {
if (!materialRef.current) return;
// We scale line width based on distance so it doesn't disappear when zoomed out
const midPoint = points[Math.floor(points.length / 2)];
const distance = state.camera.position.distanceTo(midPoint);
const distanceWidthMultiplier = Math.max(1, (distance / 50) ** 0.5);
materialRef.current.lineWidth = baseWidth * distanceWidthMultiplier;
// NOTE: Setting materialRef.current.resolution imperatively here
// or as a prop on <meshLineMaterial> causes severe flickering.
});
return (
<mesh>
<meshLineGeometry points={flatCoordinates} />
<meshLineMaterial
ref={materialRef}
color="red"
sizeAttenuation={1}
// resolution={[size.width, size.height]} // Causes flickering!
/>
</mesh>
);
};