【问题标题】:Three.js: How to add envMap correctly?Three.js:如何正确添加envMap?
【发布时间】:2021-05-04 12:37:49
【问题描述】:

现在我想要这样的材料: https://threejs.org/examples/#webgl_materials_envmaps_exr

所以我会添加以下内容:

* {
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>

不幸的是,它不起作用。为什么?

如果有人可以帮助我,我将非常感激! :)

【问题讨论】:

    标签: javascript three.js


    【解决方案1】:

    主要问题是加载对象时newEnvMap 还没有准备好。

    一般来说,将环境贴图添加到场景的主要步骤是:

    1. 导入EXRLoader
    2. 使用THREE.PMREMGenerator 创建一个“预过滤、Mipmapped Radiance Environment Map (PMREM)”。
    3. 使用new EXRLoader()(或THREE.TextureLoader().load())加载EXR(或JPG图像)。
    4. 加载 EXR 后,必须使用此设置更新对象。在我所做的 CodePen 中,这是通过函数 loadObjectAndAndEnvMap() 完成的。此函数加载模型并将envMap 更新为object.material.envMap = newEnvMap;
    5. 别忘了object.material.needsUpdate = true
    6. 最后如果你想可视化背景本身,需要scene.background = background;render函数里面。
    7. (额外)如果环境贴图仍然不可见,请检查材料的roughnessmetalnessenvMapIntensity。设置不反映环境的值是一个常见的错误。以下是一些设置示例:

    演示:

    * {
    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>

    如果您不喜欢 SO sn-ps,here 是您可以投票/分叉/分享的 CodePen 版本。

    【讨论】:

      【解决方案2】:

      您现在可以使用scene.environment 作为场景中所有物理材质的环境贴图。但是,无法覆盖分配给 MeshStandardMaterial.envMap 的现有纹理。 Doc

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-14
        • 2017-04-19
        • 2020-01-29
        • 2013-06-10
        • 2020-07-23
        • 1970-01-01
        相关资源
        最近更新 更多