javascript - 单击时更改对象模型的颜色 ​​- Three.js

标签 javascript three.js

我在这里想做的是,当用户单击对象模型的特定部分时,该部分的线框就会暴露出来,以显示哪个部分正在发生更改。用户可以从调色板中为同一部分选择颜色。在颜色选择时,我希望模型的那部分改变颜色。这里 child.material.color.set(selectedColor) 由于某种原因不起作用。我错过了什么吗?请原谅冗长的代码库。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Tacchhi.com Demo</title>
    <link rel="stylesheet" href="css/main.css">
</head>
<body>

    <div class="palette">
        <span></span>
        <span></span>
        <span></span>
    </div>

    <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
    <script src="js/Three-r80.js"></script>
    <script src="js/OrbitControls.js"></script>
    <script src="js/OBJLoader.js"></script>
    <script src="js/MTLLoader.js"></script>
    <script src="js/Projector.js"></script>
    <script>
        //GLOBAL VARIABLES
        var renderCanvas, scene, camera, renderer, cameraControl, objModel, raycaster, vector, clickInfo, marker, modelHasLoaded;

        //VIEWPORT DIMENSIONS
        var viewportWidth = window.innerWidth;
        var viewportHeight = window.innerHeight;

        function init(){
            //SCENE
            window.scene = new THREE.Scene();

            //CAMERA
            camera = new THREE.PerspectiveCamera(75, viewportWidth/viewportHeight, 1, 1000);
            camera.position.set(0, 20, 160);
            camera.lookAt(scene.position);

            //RENDERER
            renderer = new THREE.WebGLRenderer();
            renderer.setSize(viewportWidth, viewportHeight);
            renderer.setClearColor('#ccc');

            //LIGHTING
            var ambientLight = new THREE.AmbientLight('#000');
            scene.add(ambientLight);
            var pointLight = new THREE.PointLight('#fff', 1, 2000);
            pointLight.position.set(-window.innerWidth, 0, 0);
            var pointLight2 = new THREE.PointLight('#fff', 1, 2000);
            pointLight2.position.set(window.innerWidth, 0, 0);
            var pointLight3 = new THREE.PointLight('#fff', 1, 2000);
            pointLight3.position.set(0, viewportHeight/2, -100);
            var pointLight4 = new THREE.PointLight('#fff', 1, 2000);
            pointLight4.position.set(0, 0, 100);
            scene.add(pointLight);
            scene.add(pointLight2);
            scene.add(pointLight3);
            scene.add(pointLight4);

            //OBJECT MODEL WITHOUT MATERIALS
            var objLoader = new THREE.OBJLoader();
            objLoader.setPath('obj/')
            objLoader.load('deadpool.obj', function(object){
                objModel = object;
                objModel.position.set(0, -90, 0);
                objModel.rotation.y = 300;
                objModel.name = 'ObjectModel3D';
                modelHasLoaded = true;
                scene.add(objModel);
            });

            //ORBIT CONTROLS
            cameraControl = new THREE.OrbitControls(camera);

            //RENDER AFTER OBJECT HAS LOADED
            function renderCheck(){
                if(modelHasLoaded){
                    render();
                    clearInterval(renderCheckInterval);

                    //set mouse cursor for drag/dragend
                    renderCanvas = document.getElementsByTagName("canvas")[0];
                    renderCanvas.style.cursor = "url('images/grab-icon.png'), auto";
                    renderCanvas.addEventListener('mousedown', function(){
                        renderCanvas.style.cursor = "url('images/grabbing-icon.png'), auto";
                    }, false);
                    renderCanvas.addEventListener('mouseup', function(){
                        renderCanvas.style.cursor = "url('images/grab-icon.png'), auto";
                    }, false);
                } else {    
                    console.log('model not loaded');
                }
            }
            var renderCheckInterval = setInterval(renderCheck, 500);

            //RAYCASTING
            raycaster = new THREE.Raycaster();
            vector = new THREE.Vector3();
            clickInfo = {
                x: 0,
                y: 0,
                userHasClicked: false
            };
            window.addEventListener('click', function(event){
                clickInfo.userHasClicked = true;
                clickInfo.x = event.clientX;
                clickInfo.y = event.clientY;
            }, false);

            //MARKER FOR RAYCASTING
            marker = new THREE.Mesh(new THREE.SphereGeometry(1), new THREE.MeshBasicMaterial({color: 'red'}));

            //APPEND CANVAS
            document.body.appendChild(renderer.domElement);
        }

        function render(){
            //check for user clicks
            if(clickInfo.userHasClicked){
                clickInfo.userHasClicked = false;
                var x = (clickInfo.x / innerWidth) * 2 - 1;
                var y = -(clickInfo.y / innerHeight) * 2 + 1;
                vector.set(x, y, 0.5); 
                vector.unproject(camera);
                raycaster.set(camera.position, vector.sub(camera.position).normalize());
                var intersects = raycaster.intersectObjects(scene.children, true);
                if(intersects.length){
                  var target = intersects[0];

                  //place marker on click location
                  marker.position.set(target.point.x, target.point.y, target.point.z);
                  scene.add(marker);
                  applyWireframe();

                  //display color palette
                  TweenLite.to($('.palette'), 0.75, {left: '0', ease: Power4.easeOut});
                } else {
                    removeWireframe();

                    //hide color palette
                    TweenLite.to($('.palette'), 0.75, {left: '-100px', ease: Power4.easeOut});
                }
            }
            requestAnimationFrame(render);
            cameraControl.update();
            renderer.render(scene, camera);
        }

        //APPLY WIREFRAME FOR THE SELECTED PART
        function applyWireframe(){
            var wireframeObject = scene.getObjectByName('ObjectModel3D', true);
            wireframeObject.traverse(function(child){
                if(child instanceof THREE.Mesh){
                    child.material.wireframe = true;
                    child.material.linewidth = 1;
                    child.material.color.set('#333');
                }   
            });
        }

        //REMOVE WIREFRAME FOR THE SELECTED PART
        function removeWireframe(){
            scene.remove(marker);
            var wireframeObject = scene.getObjectByName('ObjectModel3D', true);
            wireframeObject.traverse(function(child){
                if(child instanceof THREE.Mesh){
                    child.material.wireframe = false;
                    child.material.color.set('#fff');
                }   
            });
        }

        //SET COLOR OF OBJECT MODEL
        $('.palette span').click(function(){
            $color = new THREE.Color($(this).css('backgroundColor'));
            var selectedColor = '#' + $color.getHexString();
            var item = scene.getObjectByName('ObjectModel3D', true);
            item.traverse(function(child){
                if(child instanceof THREE.Mesh){
                    child.material.color.set(selectedColor);
                    console.log('material color set to - ' + selectedColor);
                }
            });
        });

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

最佳答案

只是一堆想法:

selectedColor 是正确的十六进制吗?

使用set而不是setHex硬编码另一种颜色,只是为了确保所有对象都着色。

在颜色更改后调用 requestAnimationFrame(render);,它将反射(reflect)您可能所做的所有更改,否则可能需要一些时间才能刷新场景。

编辑:

红色药丸来了...也许这是一个痛苦的解决方案,但无论如何这是图形世界中的最佳实践...您应该共享 Material 。这意味着,预先创建所有类型所需的 Material ,并在整个应用程序中重复使用相同的定义 Material 。这可以节省您的应用程序内存或创建/删除 Material 时的开销。然后,创建两种 Material ,例如:ObjectMaterial 和 SelectedObjectMaterial。每当您的对象被选中时,将其 Material 更改为 SelectedObjectMaterial,一旦不再被选中,就重新为其分配 ObjectMaterial。

共享方法也适用于网格和几何体,这意味着更优化的应用程序、更好的性能和更清晰的代码。

关于javascript - 单击时更改对象模型的颜色 ​​- Three.js,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39363514/

相关文章:

javascript - 客户端和服务器端编程有什么区别?

javascript - 自透明对象仅从一侧看起来正确

javascript - Three.js - 使用 scale.set() 缩放模型或增加模型大小?

javascript - 单击 div 未打开模式

javascript - Math.floor(Math.random() * 5 + 1)的概念,真实范围是多少,为什么?

javascript - 尝试使用 Three.js 重置整个场景时性能下降

Three.js pbr解决方案

android - 如何将 ThreeJS 与 PhoneGap 一起使用?

javascript - 需要来自 TFS/Sharepoint 的 Ping 请求

javascript - 处理 Origin http ://localhost is not allowed by Access-Control-Allow-Origin Without CORS header