28.使用法向贴图创建更精细的凹凸和皱纹

此博客演示了如何使用Three.js库创建3D场景,包括设置法线贴图以增加物体表面的凹凸感,并调整normalScale属性来控制凹凸程度。示例中展示了两个带纹理的立方体,一个应用了法线贴图,一个没有,以及一个木质地板纹理。此外,还讨论了光源的配置,如环境光、点光源和方向光,以及使用dat.GUI进行交互式参数调整。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

	通过设置normalMap属性设置为一个法向纹理,还可以指定凹凸的程度,方法是设置normalScale属性。
<!DOCTYPE html>

<html>

<head>
    <title>Example 10.03 - Normal maps</title>
    <script type="text/javascript" src="../libs/three.js"></script>

    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>

    <div id="Stats-output">
    </div>
    <!-- Div which will hold the Output -->
    <div id="WebGL-output">
    </div>

    <!-- Javascript code that runs our Three.js examples -->
    <script type="text/javascript">
        // once everything is loaded, we run our Three.js stuff.
        function init() {

            var stats = initStats();

            // create a scene, that will hold all our elements such as objects, cameras and lights.
            var scene = new THREE.Scene();

            // create a camera, which defines where we're looking at.
            var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

            // create a render and set the size
            var webGLRenderer = new THREE.WebGLRenderer();
            webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
            webGLRenderer.setSize(window.innerWidth, window.innerHeight);
            webGLRenderer.shadowMapEnabled = true;

            var sphere1 = createMesh(new THREE.BoxGeometry(15, 15, 15), "plaster.jpg");
            sphere1.rotation.y = -0.5;
            sphere1.position.x = 12;
            scene.add(sphere1);

            var sphere2 = createMesh(new THREE.BoxGeometry(15, 15, 15), "plaster.jpg", "plaster-normal.jpg");
            sphere2.rotation.y = 0.5;
            sphere2.position.x = -12;
            scene.add(sphere2);
            console.log(sphere2.geometry.faceVertexUvs);

            var floorTex = THREE.ImageUtils.loadTexture("../assets/textures/general/floor-wood.jpg");
            var plane = new THREE.Mesh(new THREE.BoxGeometry(200, 100, 0.1, 30), new THREE.MeshPhongMaterial({
                color: 0x3c3c3c,
                map: floorTex
            }));
            plane.position.y = -7.5;
            plane.rotation.x = -0.5 * Math.PI;
            scene.add(plane);

            // position and point the camera to the center of the scene
            camera.position.x = 00;
            camera.position.y = 12;
            camera.position.z = 38;
            camera.lookAt(new THREE.Vector3(0, 0, 0));

            var ambiLight = new THREE.AmbientLight(0x242424);
            scene.add(ambiLight);

            var light = new THREE.SpotLight();
            light.position.set(0, 30, 30);
            light.intensity = 1.2;
            scene.add(light);


            //        var pointColor = "#ff5808";
            var pointColor = "#ff5808";
            var directionalLight = new THREE.PointLight(pointColor);


            //        directionalLight.distance = 0;
            //        directionalLight.intensity = 0.5;


            scene.add(directionalLight);


            // add a small sphere simulating the pointlight
            var sphereLight = new THREE.SphereGeometry(0.2);
            var sphereLightMaterial = new THREE.MeshBasicMaterial({
                color: 0xac6c25
            });
            var sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);
            sphereLightMesh.castShadow = true;

            sphereLightMesh.position = new THREE.Vector3(3, 3, 3);
            scene.add(sphereLightMesh);

            // add the output of the renderer to the html element
            document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

            // call the render function
            var step = 0;

            //        var polyhedron = createMesh(new THREE.PolyhedronGeometry(vertices, faces, controls.radius, controls.detail));

            // setup the control gui
            var controls = new function() {
                this.normalScale = 1;
                this.changeTexture = "plaster";
                this.rotate = false;

                this.changeTexture = function(e) {
                    var texture = THREE.ImageUtils.loadTexture("../assets/textures/general/" + e + ".jpg");
                    sphere2.material.map = texture;
                    sphere1.material.map = texture;

                    var bump = THREE.ImageUtils.loadTexture("../assets/textures/general/" + e + "-normal.jpg");
                    sphere2.material.normalMap = bump;
                };

                this.updateBump = function(e) {
                    sphere2.material.normalScale.set(e, e);
                }
            };


            var gui = new dat.GUI();
            gui.add(controls, "normalScale", -2, 2).onChange(controls.updateBump);
            gui.add(controls, "changeTexture", ['plaster', 'bathroom', 'metal-floor']).onChange(controls.changeTexture);
            gui.add(controls, "rotate");


            render();

            function createMesh(geom, imageFile, normal) {

                if (normal) {
                    var t = THREE.ImageUtils.loadTexture("../assets/textures/general/" + imageFile);
                    var m = THREE.ImageUtils.loadTexture("../assets/textures/general/" + normal);
                    var mat2 = new THREE.MeshPhongMaterial();
                    mat2.map = t;
                    mat2.normalMap = m;

                    var mesh = new THREE.Mesh(geom, mat2);
                    return mesh;
                } else {
                    var t = THREE.ImageUtils.loadTexture("../assets/textures/general/" + imageFile);
                    var mat1 = new THREE.MeshPhongMaterial({
                        map: t
                    });
                    var mesh = new THREE.Mesh(geom, mat1);
                    return mesh;
                }

                return mesh;
            }

            function createNormalmapShaderMaterial(diffuseMap, normalMap) {
                var shader = THREE.ShaderLib["normalmap"];
                var uniforms = THREE.UniformsUtils.clone(shader.uniforms);

                var dT = THREE.ImageUtils.loadTexture(diffuseMap);
                var nT = THREE.ImageUtils.loadTexture(normalMap);

                uniforms["uShininess"].value = 50;
                uniforms["enableDiffuse"].value = true;
                uniforms["uDiffuseColor"].value.setHex(0xffffff);
                uniforms["tDiffuse"].value = dT;
                uniforms["tNormal"].value = nT;

                uniforms["uNormalScale"].value.set(1, 1);
                uniforms["uSpecularColor"].value.setHex(0xffffff);
                uniforms["enableSpecular"].value = true;

                return new THREE.ShaderMaterial({
                    fragmentShader: shader.fragmentShader,
                    vertexShader: shader.vertexShader,
                    uniforms: uniforms,
                    lights: true
                });
            }

            var invert = 1;
            var phase = 0;

            function render() {
                stats.update();
                step += 0.1;

                if (controls.rotate) {
                    sphere1.rotation.y -= 0.01;
                    sphere2.rotation.y += 0.01;
                }


                if (phase > 2 * Math.PI) {
                    invert = invert * -1;
                    phase -= 2 * Math.PI;
                } else {
                    phase += 0.03;
                }

                sphereLightMesh.position.z = +(21 * (Math.sin(phase)));
                sphereLightMesh.position.x = -14 + (14 * (Math.cos(phase)));

                if (invert < 0) {
                    var pivot = 0;
                    sphereLightMesh.position.x = (invert * (sphereLightMesh.position.x - pivot)) + pivot;
                }

                directionalLight.position.copy(sphereLightMesh.position);

                // render using requestAnimationFrame
                requestAnimationFrame(render);
                webGLRenderer.render(scene, camera);
            }


            function initStats() {

                var stats = new Stats();
                stats.setMode(0); // 0: fps, 1: ms

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

                document.getElementById("Stats-output").appendChild(stats.domElement);

                return stats;
            }
        };

        window.onload = init;
    </script>
</body>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值