three.js创建简单的法向贴图

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37338983/article/details/82804197

在上一节,我们用了three.js创建了简单的凹凸贴图效果:点击查看凹凸贴图,凹凸贴图可以呈现出比普通贴图更多细节,也更具层次感,如果我们对场景要求更为细致,我们可以使用法向贴图对材质进行贴图,本文以THREE.MeshPhongMaterial为例,演示一个法向贴图的示例,法向贴图主要是利用材质的normalMap来贴图,利用normalScale来控制其纹理的凹凸程度,代码如下:

function createTextureMesh(geometry, image, otherImage) {
        let map = new THREE.TextureLoader().load(image);
        let normalMap = new THREE.TextureLoader().load(otherImage);

        let material = new THREE.MeshPhongMaterial();
            material.map = map;//打底贴图
            material.normalMap = normalMap;//法向贴图
            material.normalScale = new THREE.Vector2(0.3, 0.3);//凹凸程度

        return new THREE.Mesh(geometry, material);
    }

其中image和otherImage都是图片所在的路径;为了贴图看起来更加细致和逼真,这里用了普通贴图和法向贴图相叠加。接下来实现一个法向贴图的场景(PS:一般用于法向贴图的图片文件名字都会含有normal字眼,用于凹凸贴图的会含有bump字眼,例如:XX-normal.jpg、XX-bump.jpg等等,所以在贴图时,读者可以根据需求再去找相应的文件),这里笔者实现了一个交互菜单栏,用于实现法向贴图凹凸程度的调节,效果如下:

 

demo代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>法向贴图</title>
    <script type="text/javascript" src="build/three.js"></script>
    <script type="text/javascript" src="js/controls/OrbitControls.js"></script>
    <script type="text/javascript" src="js/libs/stats.js"></script>
    <script type="text/javascript" src="js/libs/dat.gui.min.js"></script>
    <style>
        body {
            margin: 0px;
            overflow: hidden;
        }
    </style>
</head>
<body>
<script type="text/javascript" >
    let container1 = document.createElement('div');
    document.body.appendChild(container1);

    let container2 = document.createElement('div');
    document.body.appendChild(container2);

    let scene = undefined;
    let renderer = undefined;
    let camera = undefined;
    let pointLight = ambientLight = undefined;
    let controls = undefined;
    let stats = undefined;
    let sphere = undefined, cube = undefined;

    let guiFields = {
        "normalScale": 0.3
    };

    main();
    render();

    function main() {
        initScene();
        initRenderer(container1);
        initCamera();
        initLight();
        initControls();
        normalMapMesh();
        initGUI();
        initStats(container2);
        window.addEventListener('resize', onWindowResize, false);
    }

    function initScene() {
        scene = new THREE.Scene();
    }

    function initCamera() {
        camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(0, 5, 35);
        camera.lookAt(scene.position);
    }

    function initRenderer(container1) {
        renderer = new THREE.WebGLRenderer({antialias:true});
        renderer.setClearColor(0xeeeeee, 1.0);
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;
        container1.appendChild(renderer.domElement);
    }

    function initLight() {
        ambientLight = new THREE.AmbientLight(0xffffff, 0.35);
        scene.add(ambientLight);

        pointLight= new THREE.PointLight(0xff5808);
        pointLight.position.set(10, 10, 10);
        scene.add(pointLight);
    }

    function initControls() {
        controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.autoRotate = false;
        controls.enableKeys = true;
    }

    function initGUI() {
        let gui = new dat.GUI();
        gui.add(guiFields, 'normalScale', -2, 2).onChange(function (e) {
            sphere.material.normalScale.set(e, e);
            cube.material.normalScale.set(e, e);
        });
    }

    function normalMapMesh() {
        let image1 = "textures/general/plaster.jpg";
        let otherImage1 = "textures/general/plaster-normal.jpg";

        let image2 = "textures/general/metal-floor.jpg";
        let otherImage2 = "textures/general/metal-floor-normal.jpg";

        sphere = createTextureMesh(new THREE.SphereGeometry(8, 20, 20), image1, otherImage1);
        sphere.position.set(-10, 0, 0);
        scene.add(sphere);

        cube = createTextureMesh(new THREE.BoxGeometry(10, 10, 10, 20, 20, 20), image2, otherImage2);
        cube.position.set(10, 0, 0);
        scene.add(cube);
    }

    function createTextureMesh(geometry, image, otherImage) {
        let map = new THREE.TextureLoader().load(image);
        let normalMap = new THREE.TextureLoader().load(otherImage);

        let material = new THREE.MeshPhongMaterial();
            material.map = map;
            material.normalMap = normalMap;
            material.normalScale = new THREE.Vector2(0.3, 0.3);

        return new THREE.Mesh(geometry, material);
    }

    function initStats(container2) {
        stats = new Stats();
        stats.setMode(0);

        stats.domElement.style.position = 'absolute';
        stats.domElement.style.left = '0px';
        stats.domElement.style.top = '0px';

        container2.appendChild(stats.domElement);
    }

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

    function render() {
        controls.update();
        stats.update();
        requestAnimationFrame(render);
        renderer.render(scene, camera);
    }
</script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/qq_37338983/article/details/82804197