问题
In this example you can see 2 particles which are clickable but they are both affected by the click. Also i want just to detect clicks on particles without filtering them out of the scene. Like here
if (intersects.length>0){
if(intersects[0].object.type == "Points"){
intersects[0].object.material.color.setHex( Math.random() * 0xffffff );
}
}
It is important for me to use particles because they can stay always the same size to the camera and i dont need to use a second orthographic camera. In the end i want to achieve something like the ARK Starmap from Star Citizen. Where the systems stay always the same size and are clickable.
$(function(){
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var stats;
var camera, controls, scene, renderer;
var group;
var objectControls;
var particleSystem, raycaster;
var mouse = new THREE.Vector2();
var projector = new THREE.Projector();
function init() {
var width = window.innerWidth;
var height = window.innerHeight;
camera = new THREE.PerspectiveCamera( 50, width / height, 1, 10000000 );
camera.position.z = 1500;
camera.position.y = 100;
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
renderer.setClearColor("black");
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.autoClear = false;
var container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.enableZoom = false;
controls.minDistance = 50;
controls.maxDistance = 500000;
var loader = new THREE.TextureLoader();
loader.load( "textures/systempoint.png", function ( texture ) {
particles = new THREE.Geometry(),
pMaterial = new THREE.PointsMaterial({map: texture, size: 32, transparent:true, sizeAttenuation:false});
particle = new THREE.Vector3(400, 300, 300);
particles.vertices.push(particle);
particle = new THREE.Vector3(300, 400, 300);
particles.vertices.push(particle);
// create the particle system
particleSystem = new THREE.Points(particles,pMaterial);
particleSystem.sortParticles = false;
particleSystem.name = "systems";
scene.add(particleSystem);
});
//////////////////////////////////////////////////////////////////////////
// Lights
//////////////////////////////////////////////////////////////////////////
light = new THREE.AmbientLight( 0x666666 );
scene.add( light );
var params = { recursive: true };
objectControls = new ObjectControls( camera, params );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
stats.domElement.style.zIndex = 100;
container.appendChild( stats.domElement );
window.addEventListener( 'resize', onWindowResize, false );
console.log(scene);
}
function onWindowResize() {
var width = window.innerWidth;
var height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
}
var lastTimeMsec= null;
var nowMsec= null;
function animate() {
requestAnimationFrame( animate );
//controls.update(); // required if controls.enableDamping = true, or if controls.autoRotate = true
stats.update();
objectControls.update();
render();
}
function render() {
renderer.render( scene, camera );
}
$(document).mousedown(function(e) {
e.preventDefault();
var mouseVector = new THREE.Vector3(
( e.clientX / window.innerWidth ) * 2 - 1,
- ( e.clientY / window.innerHeight ) * 2 + 1,
1 );
mouseVector.unproject(camera);
var raycaster = new THREE.Raycaster( camera.position, mouseVector.sub( camera.position ).normalize() );
raycaster.params.Points.threshold = 15
var intersects = raycaster.intersectObjects( scene.children );
if (intersects.length>0){
if(intersects[0].object.type == "Points"){
console.log(intersects[0].object.position);
intersects[0].object.material.color.setHex( Math.random() * 0xffffff );
}
}
});
init();
animate();
});
回答1:
You mistook the change of color of both for both being detected in the click ... you're not coloring the particles, you are coloring the material. And the material is shared between the particles.
I've managed to fix your fiddle, took a lot of effort (but learned a bit in the process).
http://jsfiddle.net/agqq96bq/5/
Some key points:
- I switched three.js to a non-minified version as that makes it much easier to troubleshoot.
- The raycaster does support the
Points
object, and I've made use of this. For best result there's a threshold that needs to be set (how large it is defines how far away you can be for the click to register on a particle). - You need to give each particle its own unique color, and set it to use
THREE.VertexColor
s. The code does this now. - I tidied the code using the
Raycaster
. - You'll find code in there which also adds
Sprite
s ... initially I thought you'd not be able to match against particles in aPoints
object, but the three.js source proved me wrong, the problem has been solved there and the sprites aren't need for that anymore. I've left the sprites in anyway, easy to get rid of. - I've added code to make use of the
userData
property (the official place in a three.js object to store your own data), you'll find this invaluable when you actually want to do something with the item that was clicked on.
来源:https://stackoverflow.com/questions/33308105/three-js-click-single-particle