三.js点击单粒子 [英] three.js click single particle

查看:22
本文介绍了三.js点击单粒子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这个示例您可以看到 2 个可点击的粒子,但它们都受到点击的影响.另外我只想检测粒子上的点击而不将它们从场景中过滤掉.喜欢这里

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 );
    }
}

使用粒子对我来说很重要,因为它们可以始终与相机保持相同的大小,而且我不需要使用第二个正交相机.最后,我想实现类似于 Star Citizen 的 ARK Starmap 之类的东西.系统始终保持相同大小且可点击.

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();
   });

推荐答案

您误以为在单击时检测到两者的颜色变化...您不是在为粒子着色,而是在为材料着色.并且材料在粒子之间共享.

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/

一些关键点:

  • 我将three.js 切换到非缩小版本,因为这样可以更轻松地进行故障排除.
  • raycaster 确实支持 Points 对象,我已经利用了它.为了获得最佳效果,需要设置一个阈值(它的大小定义了点击在粒子上注册的距离).
  • 您需要为每个粒子赋予其独特的颜色,并将其设置为使用 THREE.VertexColors.代码现在执行此操作.
  • 我使用 Raycaster 整理了代码.
  • 你会在那里找到代码,它也添加了 Sprites ...最初我认为你无法匹配 Points 对象中的粒子,但是three.js源证明我错了,问题已经在那里解决了,不再需要精灵了.无论如何,我已经留下了精灵,很容易摆脱.
  • 我已经添加了代码来利用 userData 属性(在three.js 对象中的官方位置来存储您自己的数据),当您真正想要时,您会发现这非常宝贵对被点击的项目做一些事情.
  • 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.VertexColors. The code does this now.
  • I tidied the code using the Raycaster.
  • You'll find code in there which also adds Sprites ... initially I thought you'd not be able to match against particles in a Points 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.

这篇关于三.js点击单粒子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆