我在这里尝试做的是当用户点击对象模型的特定部分时,该部分的线框被暴露以显示哪个部分正在发生变化。用户可以从调色板中为相同的部件选择颜色。在颜色选择上,我希望模型的那一部分改变颜色。这里 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>
答案 0 :(得分:1)
只是一堆想法:
selectedColor是正确的十六进制吗?
使用设置代替 setHex 对其他颜色进行硬编码,以确保所有对象都变色。
在换色后调用 requestAnimationFrame(render); ,它会反映您可能已做的所有更改,否则可能需要一些时间才能刷新场景。
修改强>
这里出现了红色药丸...也许这是一个痛苦的解决方案,但无论如何在图形世界中是最好的做法...... 你应该分享材料。这意味着,事先创建所有需要的材料,并在整个应用程序中重复使用相同的定义材料。这可以在创建删除材料时节省应用程序内存或开销。然后,创建两个材质,例如:ObjectMaterial和SelectedObjectMaterial。每当您的对象被选中时,将其材质更改为SelectedObjectMaterial,只要它不再被选中,就将其重新分配给ObjectMaterial。
共享方法也适用于网格和几何,节省这意味着更优化的应用程序,更好的性能和更清晰的代码。