【问题标题】:Three.js Change Mesh face colour using RaycasterThree.js 使用 Raycaster 更改网格面颜色
【发布时间】:2020-07-16 00:38:17
【问题描述】:

我目前正在开发一个 Web 应用程序,当面部被 Raycaster(鼠标)悬停时,它应该为面部赋予另一种颜色。

我目前有一个可用的 .stl 查看器和轨道控件。

使用已知的工作 .stl 文件 see my github 下载并运行我的代码。你可以很容易地运行它,只需要一个实时服务器(这在 VSCode 中很容易做到,参见readme)。

目前它可以完美地更改整个对象的颜色,但是当我尝试使用 raycaster 的 intersects 更改面部颜色时(与更改对象属性的方式相同),它不起作用。我已经读到您必须将vertexColors: THREE.VertexColors 添加到您的材料属性中。

我可以看到颜色值正在发生变化(在面部的颜色属性上使用 console.log),当我更改 intersects[i].face.color.setHex(0x0f0f0f) 时,它会更改为不同的对应值。但视觉面貌并没有改变。

我认为我遗漏了什么或忽略了什么,但我似乎无法弄清楚。

我当前的代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3d viewer tjalle</title>
    <link rel="stylesheet" type="text/css" href="../style/render.css">
</head>

<body>
    <script src="https://rawcdn.githack.com/mrdoob/three.js/r117/build/three.min.js"></script>
    <script src="https://rawcdn.githack.com/mrdoob/three.js/r117/examples/js/loaders/STLLoader.js"></script>
    <script src="https://rawcdn.githack.com/mrdoob/three.js/r117/examples/js/controls/OrbitControls.js"></script>

    <script>
        function init() {
            var raycaster = new THREE.Raycaster();
            var mouse = new THREE.Vector2();
            document.addEventListener('mousemove', onMouseMove, false);


            function onMouseMove(event) {
                mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
                mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
            }

            // Setup some basic stuff
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0xdddddd);


            // Setup Camera 
            camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 5000);

            // Setup renerer and add to page
            renderer = new THREE.WebGLRenderer({
                antialias: true
            });
            renderer.setSize(window.innerWidth, window.innerHeight);

            document.body.appendChild(renderer.domElement);


            window.addEventListener('resize', onWindowResize, false);

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

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

            }

            // Setup Camera Position
            camera.rotation.y = 45 / 180 * Math.PI;
            camera.position.x = 800;
            camera.position.y = 100;
            camera.position.z = 1000;

            // Add Camera Control through orbit.js
            let controls = new THREE.OrbitControls(camera, renderer.domElement);

            // Add some basic ambient lighting (Does light all parts equally and does not cast shadows)
            hlight = new THREE.AmbientLight(0xffffff, 5.3);
            scene.add(hlight);


            //Add some point lights to simulate real lights
            light = new THREE.PointLight(0xffffff, 1, 10000);
            light.position.set(0, 300, 500);
            scene.add(light);

            controls.update();
            // Animation Script
            function animate() {
                raycaster.setFromCamera(mouse, camera);
                // scene.children[2].material.color.set(0x1313)
                // calculate objects intersecting the picking ray
                var intersects = raycaster.intersectObjects(scene.children);
                
                for (var i = 0; i < intersects.length; i++) {
                    // changes whole object to red
                    // intersects[i].object.material.color.set(0xff0000);
                    intersects[i].face.color.setHex(0x0f0f0f)

                }
                if (intersects.length > 1) {
                    console.log(intersects[1].face.color);
                }


                renderer.render(scene, camera);
                requestAnimationFrame(animate);
            }

            // Setup GLTF Loader and load in car
            let loader = new THREE.STLLoader();
            loader.load('example.stl', function (geometry) {

                // console.log(gltf);
                var material = new THREE.MeshLambertMaterial({
                    color: 0x1313,
                    wireframe: false,
                    transparent: false,
                    vertexColors: THREE.vertexColors
                });
                var mesh = new THREE.Mesh(geometry, material);
                mesh.castShadow = true;
                mesh.receiveShadow = true;
                mesh.position.set(0, 0, 0);
                mesh.name = 'Tjalle\'s Mesh'

                scene.add(mesh);
                renderer.render(scene, camera)
                animate();
                console.log("Scene: ",)
                console.log(mesh)
            });


        }

        // Call method for starting init
        init();
    </script>

</body>

</html>

【问题讨论】:

    标签: javascript three.js


    【解决方案1】:

    交集对象的 face 属性是只读的。这意味着即使您修改它,实际的几何数据也不会更新。

    请记住,您使用的是BufferGeometry,它通过顶点数据表示几何。没有像遗留Geometry 类那样的面部抽象。因此,如果您想修改每个面的颜色,您必须确保几何图形中没有面定义共享顶点。或者换句话说,您只能对 非索引 几何图形执行此操作。幸运的是,STLLoader 只返回非索引几何。

    实际的顶点颜色数据存储在颜色缓冲区属性中。您可以通过const colorAttribute = geometry.getAttribute( 'color' ); 访问它。您必须更新此缓冲区属性中的颜色值才能实现您的预​​期功能。这个模式是:

    const face = intersects[ 0 ].face;
    const color = new THREE.Color( Math.random() * 0xffffff ); // random color
    
    const colorAttribute = geometry.getAttribute( 'color' );
    
    colorAttribute.setXYZ( face.a, color.r, color.g, color.b );
    colorAttribute.setXYZ( face.b, color.r, color.g, color.b );
    colorAttribute.setXYZ( face.c, color.r, color.g, color.b );
    
    colorAttribute.needsUpdate = true;
    

    STLLoader 不一定会生成颜色缓冲区属性,因此如果缺少它,您可能必须创建一个。

    【讨论】:

    • 我在度假,很抱歉我的反应迟了。感谢您的深入回答。 STLLoader 确实不提供颜色缓冲区属性。但我认为我能够用我需要看到的面/顶点“覆盖”网格,以模拟选择。我认为这将是一个比编写我自己的颜色缓冲区更容易的选择,尽管我会研究最后一个选项(也许我什至可以为伟大的 three.js 项目做出一点贡献;)。
    猜你喜欢
    • 1970-01-01
    • 2019-07-16
    • 2014-03-05
    • 2020-09-01
    • 1970-01-01
    • 2021-09-27
    • 1970-01-01
    • 2016-03-04
    • 1970-01-01
    相关资源
    最近更新 更多