I am using Line2, LineGeometry, LineMaterial to create lines with some thickness that can work across all browsers. However, I am struggling with getting the line resolution right. There is always some flickering of the lines. I am using SMAA, but even without it the behavior is the same.
Any idea how can I keep a clean line without the flickering behavior?
That doesn’t look right. Your setting the pixelRatio as the aspect ratio. I would comment that line out.
The aspect ratio is used to set the camera aspect, not pixel ratio.
You also don’t have a resize handler so your renderer is set to a fixed size… which is ok, but just make sure the canvas isn’t being resized by CSS etc.
Its also unclear what the size of the EffectComposer is being set to… I’m guessing by default it adopts the size of the renderer passed in… so that’s probably fine… but if you do add a resize handler later, you will need to both:
I removed the pixelRatio thing, but that makes it worse. The strange thing is, if I set the pixelRatio to 2.0 it gets much better, but the sizzling is still there.
I am just using renderer.render(scene, camera) in the loop, not the composer. Using the composer actually makes it much worse.
By the way, “threejs_container” is just a div in the HTML that I am adding the renderer to. Do I need to do that differently?
const canvas = document.createElement('canvas');
let gl = canvas.getContext('webgl2') || canvas.getContext('webgl');
const isWebGL2 = !!canvas.getContext('webgl2');
canvas.width = CANVAS_WIDTH;
canvas.height = CANVAS_HEIGHT;
container = document.getElementById('threejs_container');
const width = CANVAS_WIDTH;
const height = CANVAS_HEIGHT;
setInteractivity(true);
ui.hideSpinner();
camera = new THREE.OrthographicCamera(width / - 5.5, width / 5.5, height / 5.5, height / - 5.5, -500, 500);
camera.position.z = DEFAULT_CAMERA_DIST * 0.01;
camera.position.x = 0.0;
camera.position.y = 0.0;
camera.updateProjectionMatrix();
let loader = new THREE.BufferGeometryLoader();
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
// renderer.autoClear = false; // Disable automatic clearing
// renderer.setPixelRatio(2.0);
renderer.setSize(width, height);
renderer.setClearColor(0xffffff, 0.0);
renderer.shadowMap.enabled = false;
container.appendChild(renderer.domElement);
controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.15;
controls.zoomSpeed = 1.0;
transform = new TransformControls(camera, renderer.domElement);
transform.setMode("translate");
let ambLight = new THREE.AmbientLight(0xffffff);
ambLight.intensity = 2.0;
scene.add(ambLight);
directionalLight = new THREE.DirectionalLight(0xE08222, 1);
targetObject = new THREE.Object3D();
targetObject.position.set(5, 0, 5);
scene.add(targetObject);
cameraLight = new THREE.DirectionalLight(0xffffff, 3.0);
scene.add(cameraLight);
Snapping.initializeSnapGizmos();
// const outputPass = new OutputPass();
composer = new EffectComposer(renderer);
// var pixelRatio = renderer.getPixelRatio();
// var renderPass = new RenderPass(scene, camera);
// composer.addPass(renderPass);
// composer.setSize(width, height);
outlinePass = new OutlinePass(new THREE.Vector2(width, height), scene, camera);
outlinePass.edgeGlow = 0.0;
outlinePass.edgeStrength = 5.0;
outlinePass.edgeThickness = 0.5;
outlinePass.visibleEdgeColor.set(0xf7f7f7);
outlinePass.hiddenEdgeColor.set(0xae0000);
// composer.addPass(outlinePass);
// var smaaPass = new SMAAPass(CANVAS_WIDTH * pixelRatio, CANVAS_HEIGHT * pixelRatio);
// composer.addPass(smaaPass);
// composer.addPass(outputPass);
Here’s what it looks like with setPixelRatio(2.0)
And here it is without it. Notice the pronounced sizzling:
You gotta make sure that CANVAS_WIDTH
and CANVAS_HEIGHT
Match the width and height of “container” in your setup.
Normally we don’t create a canvas, we just let threes create it for us with the renderer constructor, and then add it to the dom after renderer creation with something like:
document.body.appendChild(renderer.domElement)
Normally we also have a window “resize” handler that takes special care to call renderer.resize(
with the width and height of the display or window, and, importantly, resizes camera being used to match the current display size, and then updating the cameras projection matrix.
If you don’t have these things, your rendering is going to look messed up and sizzly because the renderer is rendering a different set of pixels than is on your display.
If you’re forcably setting devicePIxel ratio to 2, you may just be hiding/warping the problem you’re having, by forcing the rendererer to renderer 4x more pixels than neccesary.
Look at the source code for any of the examples and follow the initialization patterns there.