Reflections in MeshPhysicalMaterial with runtime generated envMap not looking right

I have a scene with some glass cabinets, and I’m trying to use MeshPhysicalMaterial with envMap reflections generated from surrounding geometry when the scene loads.

It looks as though the uv/reflection vector isn’t being computed properly. Normals look fine with MeshNormalMaterial… I’m replacing the geometry of the targeted meshes with BoxGeometry the size & position of the bounding boxes of the original geometry, and explicitly calling computeVertexNormals() etc for good measure, but I don’t think that’s making any difference.

The environment map is made with a CubeCamera / WebGLCubeRenderTarget & PMREMGenerator.fromCubemap(). I tried fromScene() as well, which also doesn’t help.

You can see the work-in-progress here Shemza - Virtual Gallery
It’ll take a little while to load, and then you can use FPS controls to better see the glass cabinets in the room ahead of you when it starts. There’s some really nasty artefacts from z-fighting with some of the other geometry, but that’ll be taken care of at some point…

This is what I call for the relevant meshes (hopefully not mis-edited as I took out a few lines of dead code):

function setGlassMaterial(mesh: Mesh) {
    const pmremGen = new THREE.PMREMGenerator(renderer);
    pmremGen.compileCubemapShader();
    const envMap = new THREE.WebGLCubeRenderTarget(1024, {
        format: THREE.RGBAFormat,
        type: THREE.HalfFloatType,
    });
    const mat = mesh.material = new MeshPhysicalMaterial({
        transparent: true,
        roughness: 0.02,
        // thickness: 10,
        transmission: 1,
        reflectivity: 1,
        metalness: 0.1,
        ior: 1.44,
        side: DoubleSide,
        // envMap: envMap.texture,
    });
    (mesh.material as any).thickness = 10; //some issue with typescript
    mesh.geometry.computeBoundingBox();
    const box = mesh.geometry.boundingBox!;
    mesh.geometry = new THREE.BoxGeometry(box.max.x - box.min.x, box.max.y - box.min.y, box.max.z - box.min.z);
    mesh.geometry.computeVertexNormals();
    mesh.geometry.computeTangents();
    mesh.geometry.computeBoundingSphere();
    //TODO: use Layers to hide things that intersect with the bounding box
    const bSphere = mesh.geometry.boundingSphere!;
    const cam = new THREE.CubeCamera(bSphere!.radius, 10000, envMap);
    cam.position.copy(mesh.position);
    const p = new THREE.Vector3();
    p.copy(bSphere.center);
    mesh.getWorldPosition(cam.position);
    mesh.getWorldQuaternion(cam.quaternion);
    cam.rotateY(Math.PI);
    cam.position.add(p);
    
    // consider using Layers to hide the mesh
    // also want to hide things like books inside the glass
    mesh.visible = false;
    const oldRt = renderer.getRenderTarget();
    renderer.setRenderTarget(envMap);
    cam.update(renderer, scene);
    renderer.setRenderTarget(oldRt);
    mesh.visible = true;
    scene.position.copy(cam.position);
    scene.position.multiplyScalar(-1);
    const pmrem = pmremGen.fromCubemap(envMap.texture);
    // const pmrem = pmremGen.fromScene(scene, 0, bSphere!.radius, 10000);
    envMap.dispose();
    scene.position.set(0, 0, 0);
    // pmrem.texture.mapping = THREE.CubeReflectionMapping;
    pmrem.texture.mapping = THREE.CubeUVReflectionMapping;
    mat.envMap = pmrem.texture;
    mat.needsUpdate = true;
    mesh.updateMatrixWorld();
    // mesh.material = new THREE.MeshNormalMaterial();
}
1 Like

I found the same problem:

but also no responses.

Just for testing, does the generated envMap reflection look correct with transmission set to 0 ?

1 Like

Just noticed this.

It doesn’t seem to make any difference setting transmission to 0. I ended up not using a glass material for that project - it was a bit expensive, and I had some other issues with transmission, but I’d like to get this sorted at some point.