1

What I'm trying to do here is when user clicks on a particular part of object model the wireframe of that part is exposed to show which part is undergoing changes. The user can pick a color for the same part from the palette. On color selection I want that part of model to change color. Here child.material.color.set(selectedColor) is not working for some reason. Am I missing something? Pardon the lengthy code base.

<!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 Answer 1

1

Just a bunch of ideas:

Is selectedColor a correct hexadecimal?

Hardcode another color using set instead of setHex, just to be sure all the object is getting colored.

Call requestAnimationFrame(render); after your color change, it will reflect all changes you may have done, otherwise it can take some time until the scene gets refreshed.

EDIT:

Here it comes the red pill... maybe this is a painful solution, but is the best practice anyway in the graphics world... you should share materials. This means, creating beforehand all kind of needed materials and re-using the very same defined material through the whole application. This saves your application memory or overhead when creating-deleting materials. Then, create two materials for example: ObjectMaterial and SelectedObjectMaterial. Whenever your object gets selected, change its material to SelectedObjectMaterial, as soon as it is not selected anymore, re-assign to it the ObjectMaterial.

The sharing methodology applies as well to meshes and geometries, saving in this means more optimal application, better performance and clearer code.

Sign up to request clarification or add additional context in comments.

5 Comments

selectedColor is correct. set() instead of setHex() not working either. The only thing that is happening is the removal of wireframe from the scene. The object model's first color still persists.
Edited answer with a different approach to get you to the solution you want to get (even through a different path)
Thanks for the suggestion. I'll try that way also.
When I set the color of object model inside load function, the color changes. But the same code is not working on color selection. Any ideas?
I found what the problem was. I was setting the material color inside removeWireframe function. That was why I couldn't set the object model's color inside color selection function. Now it works fine. Thanks for the input anyhow.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.