最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Three.js: How to add envMap correctly? - Stack Overflow

programmeradmin1浏览0评论

I'm looking for a material like here:

So I would try it this way:

* {
margin: 0;
padding: 0;
}

.object {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
pointer-events: none;
background-color: rgb(200, 200, 200);
}
<script type="module">
import * as THREE from ".module.js";

import { OBJLoader } from ".js";

var container;

var camera, scene, renderer;

var mouseX = 0,
    mouseY = 0;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

var object;

init();
animate();

function init() {
    container = document.createElement("div");
    container.className = "object";
    document.body.appendChild(container);

    camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        1,
        2000
    );
    camera.position.z = 250;

    // scene

    scene = new THREE.Scene();

    var ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
    scene.add(ambientLight);

    var pointLight = new THREE.PointLight(0xffffff, 2);
    pointLight.position.set(100, 100, 50);

    camera.add(pointLight);
    scene.add(camera);

    // manager

    function loadModel() {
        object.traverse(function (child) {
            //This allow us to check if the children is an instance of the Mesh constructor
            if (child instanceof THREE.Mesh) {
                child.material = new THREE.MeshStandardMaterial({
                    color: "#555",
                    roughness: 0.1,
                    metalness: 0.4
                });
                child.material.flatShading = false;

                //Sometimes there are some vertex normals missing in the .obj files, ThreeJs will compute them
            }
        });
        object.position.y = -90;
        scene.add(object);
    }

    var manager = new THREE.LoadingManager(loadModel);

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

    // model

    function onProgress(xhr) {
        if (xhr.lengthComputable) {
            var percentComplete = (xhr.loaded / xhr.total) * 100;
            console.log("model " + Math.round(percentComplete, 2) + "% downloaded");
        }
    }

    function onError() {}

    var loader = new OBJLoader(manager);

    loader.load(
        ".obj",
        function (obj) {
            object = obj;
        },
        onProgress,
        onError
    );

    //

    renderer = new THREE.WebGLRenderer({ alpha: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    container.appendChild(renderer.domElement);

    document.addEventListener("mousemove", onDocumentMouseMove, false);

    //

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

function onWindowResize() {
    windowHalfX = window.innerWidth / 2;
    windowHalfY = window.innerHeight / 2;

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);
}

function onDocumentMouseMove(event) {
    mouseX = (event.clientX - windowHalfX) / 2;
    mouseY = (event.clientY - windowHalfY) / 2;
}

//

function animate() {
    requestAnimationFrame(animate);
    render();
}

function render() {
    camera.position.x += (mouseX - camera.position.x) * 0.05;
    camera.position.y += (-mouseY - camera.position.y) * 0.05;

    camera.lookAt(scene.position);

    renderer.render(scene, camera);
}
</script>

I'm looking for a material like here: https://threejs.org/examples/#webgl_materials_envmaps_exr

So I would try it this way:

* {
margin: 0;
padding: 0;
}

.object {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
pointer-events: none;
background-color: rgb(200, 200, 200);
}
<script type="module">
import * as THREE from "https://threejs.org/build/three.module.js";

import { OBJLoader } from "https://threejs.org/examples/jsm/loaders/OBJLoader.js";

var container;

var camera, scene, renderer;

var mouseX = 0,
    mouseY = 0;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

var object;

init();
animate();

function init() {
    container = document.createElement("div");
    container.className = "object";
    document.body.appendChild(container);

    camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        1,
        2000
    );
    camera.position.z = 250;

    // scene

    scene = new THREE.Scene();

    var ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
    scene.add(ambientLight);

    var pointLight = new THREE.PointLight(0xffffff, 2);
    pointLight.position.set(100, 100, 50);

    camera.add(pointLight);
    scene.add(camera);

    // manager

    function loadModel() {
        object.traverse(function (child) {
            //This allow us to check if the children is an instance of the Mesh constructor
            if (child instanceof THREE.Mesh) {
                child.material = new THREE.MeshStandardMaterial({
                    color: "#555",
                    roughness: 0.1,
                    metalness: 0.4
                });
                child.material.flatShading = false;

                //Sometimes there are some vertex normals missing in the .obj files, ThreeJs will compute them
            }
        });
        object.position.y = -90;
        scene.add(object);
    }

    var manager = new THREE.LoadingManager(loadModel);

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

    // model

    function onProgress(xhr) {
        if (xhr.lengthComputable) {
            var percentComplete = (xhr.loaded / xhr.total) * 100;
            console.log("model " + Math.round(percentComplete, 2) + "% downloaded");
        }
    }

    function onError() {}

    var loader = new OBJLoader(manager);

    loader.load(
        "https://threejs.org/examples/models/obj/female02/female02.obj",
        function (obj) {
            object = obj;
        },
        onProgress,
        onError
    );

    //

    renderer = new THREE.WebGLRenderer({ alpha: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    container.appendChild(renderer.domElement);

    document.addEventListener("mousemove", onDocumentMouseMove, false);

    //

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

function onWindowResize() {
    windowHalfX = window.innerWidth / 2;
    windowHalfY = window.innerHeight / 2;

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);
}

function onDocumentMouseMove(event) {
    mouseX = (event.clientX - windowHalfX) / 2;
    mouseY = (event.clientY - windowHalfY) / 2;
}

//

function animate() {
    requestAnimationFrame(animate);
    render();
}

function render() {
    camera.position.x += (mouseX - camera.position.x) * 0.05;
    camera.position.y += (-mouseY - camera.position.y) * 0.05;

    camera.lookAt(scene.position);

    renderer.render(scene, camera);
}
</script>

Unfortunately, it does not work. Why?

I would be very thankful if somebody could help me! :)

Share Improve this question edited Jul 22, 2023 at 4:47 Anna_B asked Jan 30, 2021 at 23:03 Anna_BAnna_B 8901 gold badge7 silver badges30 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 13

The main issue is that newEnvMap is not ready when the object was loaded.

In general, the main steps to add an Environment Map to a scene are:

  1. Import EXRLoader.
  2. Create a "Prefiltered, Mipmapped Radiance Environment Map (PMREM)" with THREE.PMREMGenerator.
  3. Load the EXR (or the JPG image) with new EXRLoader() (or with THREE.TextureLoader().load()).
  4. Once EXR is loaded, objects must be updated with this setting. In the CodePen, this is done with the function loadObjectAndAndEnvMap(). This function loads the model and updates envMap with object.material.envMap = newEnvMap;.
  5. Don't forget to object.material.needsUpdate = true.
  6. Finally, if you want to visualize the background itself, it is needed to set scene.background = background; inside the render function.
  7. (Extra) In case the environment map is still not visible, check for the roughness, metalness and envMapIntensity of your materials. It is a common mistake to set values that don't reflect the environment. Here are a few setting examples:

Demo:

* {
margin: 0;
padding: 0;
}

.object {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
pointer-events: none;
background-color: rgb(200, 200, 200);
}
<script type="module">
import * as THREE from "https://threejs.org/build/three.module.js";
import { OBJLoader } from "https://threejs.org/examples/jsm/loaders/OBJLoader.js";
import { EXRLoader } from "https://threejs.org/examples/jsm/loaders/EXRLoader.js";

var container;
var camera, scene, renderer;
let exrCubeRenderTarget, exrBackground;
let newEnvMap;
let torusMesh, planeMesh;

var mouseX = 0,
    mouseY = 0;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

var object;

init();
animate();

function init() {
    container = document.createElement("div");
    container.className = "object";
    document.body.appendChild(container);

    camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        1,
        2000
    );
    camera.position.z = 250;

    // scene

    scene = new THREE.Scene();

    /*var ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
    scene.add(ambientLight);
    var pointLight = new THREE.PointLight(0xffffff, 2);
    pointLight.position.set(100, 100, 50);
    camera.add(pointLight);*/

    scene.add(camera);

    // manager
    function loadModel() {
        THREE.DefaultLoadingManager.onLoad = function () {
            pmremGenerator.dispose();
        };

        // -----------------

        function loadObjectAndAndEnvMap() {
            object.traverse(function (child) {
                //This allow us to check if the children is an instance of the Mesh constructor
                if (child instanceof THREE.Mesh) {
                    child.material = new THREE.MeshStandardMaterial({
                        color: "#555",
                        roughness: 0.0,
                        metalness: 2.0,
                        envMapIntensity: 5.0
                    });
                    //child.material.flatShading = false;

                    console.log("setting envmap");
                    child.material.envMap = newEnvMap;
                    child.material.needsUpdate = true;

                    //Sometimes there are some vertex normals missing in the .obj files, ThreeJs will compute them
                }
            });
            object.position.y = -90;
            scene.add(object);
        }

        const pmremGenerator = new THREE.PMREMGenerator(renderer);
        pmremGenerator.compileEquirectangularShader();

        new EXRLoader()
            .setDataType(THREE.UnsignedByteType)
            .load(
                "https://threejs.org/examples/textures/piz_compressed.exr",
                function (texture) {
                    exrCubeRenderTarget = pmremGenerator.fromEquirectangular(texture);
                    exrBackground = exrCubeRenderTarget.texture;
                    newEnvMap = exrCubeRenderTarget ? exrCubeRenderTarget.texture : null;

                    loadObjectAndAndEnvMap(); // Add envmap once the texture has been loaded

                    texture.dispose();
                }
            );

        renderer.toneMapping = THREE.ACESFilmicToneMapping;
        renderer.outputEncoding = THREE.sRGBEncoding;
    }

    var manager = new THREE.LoadingManager(loadModel);

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

    // model
    function onProgress(xhr) {
        if (xhr.lengthComputable) {
            var percentComplete = (xhr.loaded / xhr.total) * 100;
            console.log("model " + Math.round(percentComplete, 2) + "% downloaded");
        }
    }
    function onError() {}
    var loader = new OBJLoader(manager);
    loader.load(
        "https://threejs.org/examples/models/obj/female02/female02.obj",
        function (obj) {
            object = obj;
        },
        onProgress,
        onError
    );

    //

    renderer = new THREE.WebGLRenderer({ alpha: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    container.appendChild(renderer.domElement);

    document.addEventListener("mousemove", onDocumentMouseMove, false);

    //

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

function onWindowResize() {
    windowHalfX = window.innerWidth / 2;
    windowHalfY = window.innerHeight / 2;

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);
}

function onDocumentMouseMove(event) {
    mouseX = (event.clientX - windowHalfX) / 2;
    mouseY = (event.clientY - windowHalfY) / 2;
}

//

function animate() {
    requestAnimationFrame(animate);
    render();
}

function render() {
    camera.position.x += (mouseX - camera.position.x) * 0.05;
    camera.position.y += (-mouseY - camera.position.y) * 0.05;

    camera.lookAt(scene.position);

    scene.background = exrBackground;
    renderer.toneMappingExposure = 1.0;
    renderer.render(scene, camera);
}
</script>

In case you don't like SO snippets, here is the CodePen version you can vote/fork/share.

You can now use scene.environment as the environment map for all physical materials in the scene. However, it's not possible to overwrite an existing texture assigned to MeshStandardMaterial.envMap. Doc

发布评论

评论列表(0)

  1. 暂无评论