After Outlinepass render quality dropped! How can i fix it?

Hi everyone,
Actually i have two questions about it.

  1. Question
    I tried to use outlinepass for my project. According to example outlinepass there is a new composer. and if i use it in my project outlinepass works. But render quality drops. How can i fix it.
    Reference: https://prnt.sc/tfxyeq

2.Question
Outline appears around child meshes so actually i want it to be appear whole object. How can i make it i couldnt figure it out.

My Codes:

var scene, camera, renderer, controls, container;

var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var selectedObjects = [];
var composer, effectFXAA, outlinePass;
var model;
var models = new THREE.Group();

init();
animate();

function init() {
scene = new THREE.Scene();

// Environment
loadEnvironment("textures/venice_sunset_1k.hdr").then(function (envMap) {
    scene.background = envMap;
    scene.environment = envMap;
});

camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    1,
    2000
);

var ambient = new THREE.AmbientLight(0x404040, 5); // soft white light
scene.add(ambient);

renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container = document.getElementById("container");
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 0.85;
container.appendChild(renderer.domElement);

controls = new IndoorControls(camera, renderer.domElement);

//Mouse Helper
let helperMaterial = new THREE.MeshBasicMaterial();
helperMaterial.transparent = true;
helperMaterial.opacity = 0.2;
let helperGeometry = new THREE.CircleBufferGeometry(0.2, 64);
let mouseHelper = new THREE.Mesh(helperGeometry, helperMaterial);

let ringMaterial = new THREE.MeshBasicMaterial();
ringMaterial.transparent = true;
ringMaterial.opacity = 0.8;
let ringGeometry = new THREE.RingBufferGeometry(0.2, 0.22, 64);
let ring = new THREE.Mesh(ringGeometry, ringMaterial);
mouseHelper.add(ring);
mouseHelper.visible = false;
mouseHelper.renderOrder = 1;
scene.add(mouseHelper);

//
controls.addEventListener("move", function (event) {
    let intersect = event.intersect;
    let normal = intersect.face.normal;

    if (normal.y !== 1) {
    mouseHelper.visible = false;
    controls.enabled_move = false;
    } else {
    mouseHelper.position.set(0, 0, 0);
    mouseHelper.lookAt(normal);

    mouseHelper.position.copy(intersect.point);
    mouseHelper.position.addScaledVector(normal, 0.001);

    mouseHelper.visible = true;
    controls.enabled_move = true;
    }
});

//Load meshes here
// Sahne Oda
const loader = new GLTFLoader();
loader.load("models/room5.glb", function (object) {
    object.scene.traverse(function (child) {
    if (child.isMesh) {
        child.casæßtShadow = true;
        child.receiveShadow = true;
    }
    if (child.name === "Floor") controls.ground.push(child);
    });
    var showroom = new THREE.Object3D();
    scene.add(showroom);
    showroom.add(object.scene);
    setModelConfig(showroom);
});

//Modeller

//setModel("models/products/ritual-luxury1.glb", "Ritual", -3.2, 9);
var manager = new THREE.LoadingManager();

manager.onProgress = function (item, loaded, total) {
    console.log(item, loaded, total);
};

loader.load("models/products/ritual-luxury1.glb", function (object) {
    var ritual = object.scene;
    ritual.traverse(function (child) {
    if (child.isMesh) {
        child.receiveShadow = true;
        child.castShadow = true;
    }
    });
    ritual.name = "Ritual";
    ritual.position.z = 9;
    ritual.position.x = -3.2;
    models.add(ritual);
    scene.add(models);
});

setModel("models/products/tv.glb", "Tv", -5.5, 11.2, 0);

console.log(models);

composer = new EffectComposer(renderer);

var renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);

outlinePass = new OutlinePass(
    new THREE.Vector2(window.innerWidth, window.innerHeight),
    scene,
    camera
);
composer.addPass(outlinePass);

window.addEventListener("resize", onWindowResize, false);

window.addEventListener("mousemove", onTouchMove);
window.addEventListener("touchmove", onTouchMove);

function onTouchMove(event) {
    var x, y;

    if (event.changedTouches) {
    x = event.changedTouches[0].pageX;
    y = event.changedTouches[0].pageY;
    } else {
    x = event.clientX;
    y = event.clientY;
    }

    mouse.x = (x / window.innerWidth) * 2 - 1;
    mouse.y = -(y / window.innerHeight) * 2 + 1;

    checkIntersection();
}

function addSelectedObject(object) {
    selectedObjects = [];
    selectedObjects.push(object);
}

function checkIntersection() {
    raycaster.setFromCamera(mouse, camera);

    var intersects = raycaster.intersectObjects([models], true);

    if (intersects.length > 0) {
    var selectedObject = intersects[0].object;
    addSelectedObject(selectedObject);
    outlinePass.selectedObjects = selectedObjects;
    } else {
    // outlinePass.selectedObjects = [];
    }
}
}

function setModel(url, modelName, pX = 0, pZ = 0, rY = 0) {
const gltfLoader = new GLTFLoader();
gltfLoader.load(url, function (object) {
    let gltf = object.scene || object.scenes[0];
    gltf.traverse(function (node) {
    // Gölge almak ve oluşturmak için modelin tüm düğümlerini ayarlayın
    node.receiveShadow = true;
    if (node.isMesh || node.isLight) node.castShadow = true;
    });
    gltf.position.x = pX;
    gltf.position.z = pZ;
    gltf.rotation.y = rY;
    model = gltf;
    gltf.name = modelName;
    models.add(gltf);
});
}

function setModelConfig(sceneImport) {
// İçe aktarılan modele aralık kutusu alın
let boxSize = new THREE.Vector3();
const roomBox = new THREE.Box3().setFromObject(sceneImport);
const size = roomBox.getSize(boxSize).length();
const center = roomBox.getCenter(new THREE.Vector3());

camera.near = size / 100;
camera.far = size * 100;
camera.position.copy(center);

// Nesnenin İçinde
camera.position.y -= 0.9;
camera.position.z += 14; //Dikine sahne uzaklığını belirle
let cameraLook = camera.position.clone();
cameraLook.x += boxSize.x * 0.02;
cameraLook.y -= boxSize.y * 0.02;
cameraLook.z += boxSize.z * -1; // Sağa sola kamera dönüşü sağla
camera.lookAt(cameraLook);
camera.updateProjectionMatrix();
}

function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
controls.reset(camera, renderer.domElement);
}

// Environment Loader
function loadEnvironment(url) {
let rgbeLoader = new RGBELoader();
rgbeLoader.setDataType(THREE.UnsignedByteType);
return new Promise((resolve) => {
    rgbeLoader.load(url, function (texture) {
    let pmremGenerator = new THREE.PMREMGenerator(renderer);
    pmremGenerator.compileEquirectangularShader();
    let envMap = pmremGenerator.fromEquirectangular(texture).texture;
    pmremGenerator.dispose();
    resolve(envMap);
    });
});
}

function animate() {
requestAnimationFrame(animate);
controls.update();
composer.render();
renderer.render(camera, scene);
}

Thanks…

Dediğin gibi envmap yüksek kalite denedim ve kodu ekledim ama olmuyor maalesef.

I tried your solution but it didnt work. The problem comes from composer.render();
the composer includes otlinepass. so when use it in my codes outlinepass works. but quality is not good at this time. If i remove it from the point of quality everything is fine.

According to your screenshot, it seems that you are complaining about missing anti-aliasing. If so, try to add an FXAA pass to your scene.

Notice that when using post-processing, the default MSAA (enabled via the antialias parameter) has no effect.

1 Like

yes it solved the problem a little bit. But still there are some anti aliasing problem.

do you have any solution for my second question. Probably i need to change something from this code. There is a group called “models”. And i put the objects in this group. I tried to reach an object in models by using models.children but it didnt work.

function checkIntersection() {
    raycaster.setFromCamera(mouse, camera);

    var intersects = raycaster.intersectObjects([models], true);
    if (intersects.length > 0) {
    var selectedObject = intersects[0].object;
    addSelectedObject(selectedObject);
    outlinePass.selectedObjects = selectedObjects;
    } else {
    // outlinePass.selectedObjects = [];
    }
}

This question was already discussed here:

I’ve shared a modified version of OutlinePass that you can use.