点击更改对象模型的颜色 ​​- Three.js

时间:2016-09-07 07:16:27

标签: 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>

1 个答案:

答案 0 :(得分:1)

只是一堆想法:

selectedColor是正确的十六进制吗?

使用设置代替 setHex 对其他颜色进行硬编码,以确保所有对象都变色。

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

修改

这里出现了红色药丸...也许这是一个痛苦的解决方案,但无论如何在图形世界中是最好的做法...... 你应该分享材料。这意味着,事先创建所有需要的材料,并在整个应用程序中重复使用相同的定义材料。这可以在创建删除材料时节省应用程序内存或开销。然后,创建两个材质,例如:ObjectMaterial和SelectedObjectMaterial。每当您的对象被选中时,将其材质更改为SelectedObjectMaterial,只要它不再被选中,就将其重新分配给ObjectMaterial。

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