微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ThreeJs:无法在顶部和底部加载不同的图像

如何解决ThreeJs:无法在顶部和底部加载不同的图像

我试图在 Threejs 中使用纹理在顶部和底部放置不同的图像。 但我在底部和顶部得到相同的图像。 下面是我正在使用的代码。我的需求是在 ThreeJs 中使用纹理在两侧显示不同的图像。

注意: 1. 在我的代码中,我使用了 ThreeJs 版本(r125),这是必要的我不能使用旧版本。

<html lang="en">

    <head>
        <title>three.js webgl - geometry - shapes</title>
        <Meta charset="utf-8">
        <Meta name="viewport" content="width=device-width,user-scalable=no,minimum-scale=1.0,maximum-scale=1.0">
        <link type="text/css" rel="stylesheet" href="main.css">
        <style>
            body {
                background-color: #f0f0f0;
                color: #444;
            }
        </style>
    </head>

    <body>

        <div id="info">texture on shapes</div>

        <script type="module">
            import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r125/build/three.module.js';
            import { OrbitControls } from "https://threejsfundamentals.org/threejs/resources/threejs/r125/examples/jsm/controls/OrbitControls.js";

            let container;
            let camera,scene,renderer;
            let group;
            let windowHalfX = window.innerWidth / 2;

            init();
            animate();

            function init() {

                container = document.createElement('div');
                document.body.appendChild(container);

                scene = new THREE.Scene();
                scene.background = new THREE.Color(0xbbbbbb);

                camera = new THREE.PerspectiveCamera(50,window.innerWidth / window.innerHeight,1,1000);
                camera.position.set(0,-150,-300);
                scene.add(camera);

                const light = new THREE.PointLight(0xffffff,0.8);
                camera.add(light);

                group = new THREE.Group();
                group.rotation.y = Math.PI;
                scene.add(group);

                const helper = new THREE.GridHelper(500,10);
                helper.rotation.x = Math.PI / 2;
                group.add(helper);

                const rectWidth = 120;
                const rectHeight = 200;

                const rectangleShape = new THREE.Shape()
                    .moveto(0,0)
                    .lineto(0,rectHeight)
                    .lineto(rectWidth,0);

                const extrudeSettings = { depth: 10,bevelEnabled: true,bevelSegments: 2,steps: 1,bevelSize: 1,bevelThickness: 1 };

                const geometry = new THREE.ExtrudeGeometry(rectangleShape,extrudeSettings);

                var textureLoader1 = new THREE.TextureLoader();
                var topTexture = textureLoader1.load("https://threejsfundamentals.org/threejs/resources/images/tree-01.png"); // Top side Image
                topTexture.repeat.set(1 / rectWidth,1 / rectHeight);

                var textureLoader2 = new THREE.TextureLoader();
                var bottomTexture = textureLoader2.load("https://threejsfundamentals.org/threejs/resources/images/tree-02.png"); // Bottom side Image
                bottomTexture.repeat.set(1 / rectWidth,1 / rectHeight);

                var frontMaterial = new THREE.MeshphongMaterial({ map: topTexture,side: THREE.FrontSide });
                var backMaterial = new THREE.MeshphongMaterial({ map: bottomTexture,side: THREE.BackSide });
                var sideMaterial = new THREE.MeshphongMaterial({ color: 0xD9D934 });

                var materials = [frontMaterial,sideMaterial,backMaterial];
                var material = new THREE.MeshFaceMaterial(materials);

                let mesh = new THREE.Mesh(geometry,material);
                mesh.position.set(-60,-100,0);
                // Edited but faces not found
                for (var face in mesh.geometry.faces) {
                    if (mesh.geometry.faces[face].normal.z < -0.9) {
                        mesh.geometry.faces[face].materialIndex = 5;
                    }
                }
                group.add(mesh);
            
                renderer = new THREE.Webglrenderer({ antialias: true });
                renderer.setPixelRatio(window.devicePixelRatio);
                renderer.setSize(window.innerWidth,window.innerHeight);
                container.appendChild(renderer.domElement);

                const controls = new OrbitControls(camera,renderer.domElement);
                controls.target.set(0,0);
                controls.update();

                window.addEventListener('resize',onWindowResize);

            }

            function onWindowResize() {

                windowHalfX = window.innerWidth / 2;

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

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

            }

            function animate() {

                requestAnimationFrame(animate);

                render();

            }

            function render() {
                renderer.render(scene,camera);
            }

        </script>

    </body>
</html>

解决方法

ExtrudeGeometry 上的材料无法按照您期望的方式工作。引用 documentation for ExtrudeGeometry

在使用此几何体创建网格时,如果您希望将单独的材料用于其面和挤出的侧面,您可以使用一系列材料。第一种材料将应用于面部;第二种材料将应用于两侧。

如果需要,您可以添加第三种材质,然后通过手动更改该面的材质索引将其设置在其中一个面上。但据我所知,没有办法通过构造函数自动执行此操作。

编辑:更正我自己,我相信您不能再这样做(更改单个面的材质索引),因为 ExtrudeGeometry 的实现方式发生了变化。相反,我相信您现在必须使用单个纹理并创建 UV 贴图。

您的代码已更新为使用 UV 贴图,该贴图使用一张图像的上半部分作为 ExtrudeGeometry 顶面的纹理,将下半部分用作底面。这是通过定义自定义 UV 生成器并将其添加到传递给 ExtrudeGeometry 的配置来完成的。 UV 生成器提供两种方法:generateTopUV() 和 generateSideWallUV()。后者与 THREE 提供的默认值相同。另一种是对几何体的顶部和底部进行 UV 映射。

请注意,这是一个非常不可移植的 kludge,针对这个特定问题的几何进行了硬编码。

<html lang="en">

<head>
    <title>three.js webgl - geometry - shapes</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,user-scalable=no,minimum-scale=1.0,maximum-scale=1.0">
    <link type="text/css" rel="stylesheet" href="main.css">
    <style>
        body {
            background-color: #f0f0f0;
            color: #444;
        }
    </style>
</head>

<body>

    <div id="info">texture on shapes</div>

    <script type="module">
        import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r125/build/three.module.js';
        import { OrbitControls } from "https://threejsfundamentals.org/threejs/resources/threejs/r125/examples/jsm/controls/OrbitControls.js";

        let container;
        let camera,scene,renderer;
        let group;
        let windowHalfX = window.innerWidth / 2;

        init();
        animate();

        function init() {

            container = document.createElement('div');
            document.body.appendChild(container);

            scene = new THREE.Scene();
            scene.background = new THREE.Color(0xbbbbbb);

            camera = new THREE.PerspectiveCamera(50,window.innerWidth / window.innerHeight,1,1000);
            camera.position.set(0,-150,-300);
            scene.add(camera);
            const light = new THREE.PointLight(0xffffff,0.8);
            camera.add(light);

            group = new THREE.Group();
            group.rotation.y = Math.PI;
            scene.add(group);

            const helper = new THREE.GridHelper(500,10);
            helper.rotation.x = Math.PI / 2;
            group.add(helper);

            const rectWidth = 120;
            const rectHeight = 200;

            const rectangleShape = new THREE.Shape()
                .moveTo(0,0)
                .lineTo(0,rectHeight)
                .lineTo(rectWidth,0);

            const uvGenerator = {
                    generateTopUV:  function(geometry,vertices,indexA,indexB,indexC) {
                            const ax = vertices[indexA * 3];
                            const ay = vertices[indexA * 3 + 1];
                            const az = vertices[indexA * 3 + 2];
                            const bx = vertices[indexB * 3];
                            const by = vertices[indexB * 3 + 1];
                            const bz = vertices[indexB * 3 + 2];
                            const cx = vertices[indexC * 3];
                            const cy = vertices[indexC * 3 + 1];
                            const cz = vertices[indexC * 3 + 2];
                            if(indexA > 3) {
                                    return([
                                            new THREE.Vector2(ax,ay / 2),new THREE.Vector2(bx,by / 2),new THREE.Vector2(cx,cy / 2),]);
                            } else {
                                    return([
                                            new THREE.Vector2(ax,(ay / 2) + rectHeight / 2),(by / 2) + rectHeight / 2),(cy / 2) + rectHeight / 2),]);
                            }
                    },generateSideWallUV: function(geometry,indexC,indexD) {
                            const ax = vertices[indexA * 3];
                            const ay = vertices[indexA * 3 + 1];
                            const az = vertices[indexA * 3 + 2];
                            const bx = vertices[indexB * 3];
                            const by = vertices[indexB * 3 + 1];
                            const bz = vertices[indexB * 3 + 2];
                            const cx = vertices[indexC * 3];
                            const cy = vertices[indexC * 3 + 1];
                            const cz = vertices[indexC * 3 + 2];
                            const dx = vertices[indexD * 3];
                            const dy = vertices[indexD * 3 + 1];
                            const dz = vertices[indexD * 3 + 2];
                            if(Math.abs(ay - by) < 0.01) {
                                    return([
                                            new THREE.Vector2(ax,1 - az),1 - bz),1 - cz),new THREE.Vector2(dx,1 - dz),]);
                            } else {
                                    return([
                                            new THREE.Vector2(ay,new THREE.Vector2(by,new THREE.Vector2(cy,new THREE.Vector2(dy,};

            const extrudeSettings = { depth: 10,bevelEnabled: true,bevelSegments: 2,steps: 1,bevelSize: 1,bevelThickness: 1,UVGenerator: uvGenerator };

            const geometry = new THREE.ExtrudeGeometry(rectangleShape,extrudeSettings);

            var textureLoader1 = new THREE.TextureLoader();
            var topTexture = textureLoader1.load("https://threejsfundamentals.org/threejs/resources/images/tree-01.png"); // Top side Image
            topTexture.repeat.set(1 / rectWidth,1 / rectHeight);

            var frontMaterial = new THREE.MeshPhongMaterial({ map: topTexture,side: THREE.FrontSide });
            var sideMaterial = new THREE.MeshPhongMaterial({ color: 0xD9D934 });

            var materials = [frontMaterial,sideMaterial];
            var material = new THREE.MeshFaceMaterial(materials);

            let mesh = new THREE.Mesh(geometry,material);
            mesh.position.set(-60,-100,0);
            group.add(mesh);
        
            renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.setSize(window.innerWidth,window.innerHeight);
            container.appendChild(renderer.domElement);

            const controls = new OrbitControls(camera,renderer.domElement);
            controls.target.set(0,0);
            controls.update();
            window.addEventListener('resize',onWindowResize);

        }

        function onWindowResize() {

            windowHalfX = window.innerWidth / 2;

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

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

        }

        function animate() {

            requestAnimationFrame(animate);

            render();

        }
        function render() {
            renderer.render(scene,camera);
        }

    </script>

</body>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。