three.js单击单个粒子

时间:2015-10-23 17:21:33

标签: javascript three.js

在此example 你可以看到2个可点击的粒子,但它们都受到点击的影响。此外,我只想检测粒子上的点击而不将其过滤掉。喜欢这里

if (intersects.length>0){
    if(intersects[0].object.type == "Points"){
        intersects[0].object.material.color.setHex( Math.random() * 0xffffff );
    }
}

对我来说使用粒子非常重要,因为它们可以与相机保持相同的尺寸,而且我不需要使用第二个正交相机。最后,我希望从Star Citizen获得类似ARK Starmap的东西。系统总是保持相同的大小并且可以点击。

$(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 个答案:

答案 0 :(得分:1)

你误认为两者的颜色变化都是在点击中检测到的......你没有着色颗粒,你正在为材料上色。并且材料在粒子之间共享。

我已经设法修复你的小提琴,花了很多功夫(但在这个过程中学到了一点)。

http://jsfiddle.net/agqq96bq/5/

一些关键点:

  • 我将three.js切换为非缩小版本,因为这样可以更轻松地进行故障排除。
  • raycaster支持Points对象,我已经使用了它。为了获得最佳结果,需要设置一个阈值(它定义了多大程度,以确定点击在粒子上注册的距离)。
  • 您需要为每个粒子赋予自己独特的颜色,并将其设置为使用THREE.VertexColor s。代码现在就这样做了。
  • 我使用Raycaster
  • 整理了代码
  • 你会在那里找到代码也添加了Sprite ...最初我认为你无法匹配Points对象中的粒子,但是三个.js源代码证明我错了,问题已在那里得到解决,精灵不再需要了。无论如何我都离开了精灵,容易摆脱。
  • 我添加了代码以利用userData属性(在three.js对象中的官方位置来存储您自己的数据),当您真正想要执行某些操作时,您会发现这非常宝贵点击的项目。