THREE.js Определить щелчок по одной геометрии (объединенная геометрия) - PullRequest
1 голос
/ 22 мая 2019

Я хочу изменить цвет только для одной геометрии при клике. Я создаю геометрии путем клонирования и объединения их в одну буферную геометрию. Итак, есть одна большая сетка с множеством атрибутов буферной геометрии. Теперь, нажав на сетку, я могу изменить цвет для всей сетки, но возможно ли изменить цвет только для одного элемента (блока)?

Вот мой код:

// set up threejs
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 50, window.innerWidth/window.innerHeight, 0.01, 1000 );

var renderer = new THREE.WebGLRenderer(); 
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
camera.position.z = 5;


// add merged geometries
var allGeometries = new THREE.Geometry();
var geometry = new THREE.BoxGeometry( 0.5, 0.5, 0.5 );
var geoVerticeAmm = geometry.vertices.length;
var amm = 50;

for(var i=0; i<amm; i++){
  var x = (0.5-Math.random())*3;
  var y = (0.5-Math.random())*3;
  var z = (0.5-Math.random())*3;
  
  var newGeo = geometry.clone();
  newGeo.translate(x, y, z);
  allGeometries.merge( newGeo );
}

var material = new THREE.MeshBasicMaterial( { 
  color: 0x005E99,
  vertexColors: THREE.VertexColors,
  transparent: true,
} );
var buffGeometry = new THREE.BufferGeometry().fromGeometry(allGeometries);
var mesh = new THREE.Mesh( buffGeometry, material );

var allGeoVerticeAmm = mesh.geometry.attributes.position.count;
var colorsArray = new Float32Array(allGeoVerticeAmm * 3);
mesh.geometry.addAttribute('color', new THREE.BufferAttribute(colorsArray, 3));

for(var i=0; i<allGeoVerticeAmm; i++){
  var col = i/allGeoVerticeAmm;
  mesh.geometry.attributes.color.array[ i * 3 ] = col;
  mesh.geometry.attributes.color.array[ i * 3 + 1 ] = col;
  mesh.geometry.attributes.color.array[ i * 3 + 2 ] = col;
} 
mesh.geometry.colorsNeedUpdate = true;

mesh.callback = function() { 
  // change color only for one box
  var r = Math.round( Math.random()*255 );
  var g = Math.round( Math.random()*255 );
  var b = Math.round( Math.random()*255 );
  
  this.material.color = new THREE.Color("rgb(" + r + ", " + g + ", " + b + ")");
}

scene.add(mesh);


// raycaster
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();


function onDocumentMouseDown( event ) {
  event.preventDefault();
  mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
  mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;

  raycaster.setFromCamera( mouse, camera );

  var intersects = raycaster.intersectObjects( scene.children ); 

  if ( intersects.length > 0 ) {
      intersects[0].object.callback();
  }
}

document.addEventListener('mousedown', onDocumentMouseDown, false);

// render
var render = function () {
  requestAnimationFrame( render );
  renderer.render(scene, camera);
};
render();
Click on box
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.min.js"></script>

1 Ответ

2 голосов
/ 22 мая 2019

У вас есть 2 варианта:

  1. При выполнении лучевого вещания возвращаемый объект имеет свойства face и faceIndex.Вы можете использовать эту информацию, чтобы пройтись по color BufferAttribute сетки, которую вы создали, и сделать сравнение: если вершины являются частью геометрии, связанной с этой гранью, измените их значения цвета.

  2. Вы можете сохранять геометрию независимой как отдельные сетки.Это намного проще, потому что после выполнения лучевого вещания вы можете просто установить:
    intersects[0].object.material.color = '0xff9900'; без необходимости циклически проходить через отдельные вершины.

...