Bewahrer: three.js object picking

Hallo,

da ich es nicht hinbekomme und schon eine Menge gesucht habe, jetzt hier die Frage was genau ich beim Objekt-picking in three.js falsch mache.

Code:

function checkClick() {  
                    // On every click, check for body hit  
                    var projector = new THREE.Projector();  
                    var directionVector = new THREE.Vector3();  
  
                    directionVector.x = ( event.clientX / window.innerWidth ) * 2 - 1;  
                    directionVector.y = -( event.clientY / window.innerHeight ) * 2 + 1;  
                    directionVector.z = 1;  
                    var objects = [];  
                    objects.push(scene.children);  
                    console.log(directionVector);  
                    var raycaster = projector.pickingRay(directionVector.clone(),camera);  
                    var intersects = raycaster.intersectObjects(scene.children);  
                    if (intersects.length) {  
                         alert("found something");  
                    }  
                    else {  
                         alert("found nothing");  
                    }  
               }

Es kommt immer nur ein found nothing. Ich habe ein einziges 3D Model in meine Scene, von dem ich wissen möchte, ob ich es angeklickt habe oder nicht. Da ich mittlerweile rausgefunden habe, dass raycaster.intersectObjects() ein Array als Argument benötigt, habe ich für das alleine 3D Model in meiner Scene objects erstellt und füge objects mit scene.children mein 3D Model hinzu. Trotzdem funktioniert es nicht. Egal ob ich jetzt raycaster.intersectObjects(scene.children) oder raycaster.intersectObjects(objects) benutze. Was kann ich tun?

  1.   
    directionVector.x = ( event.clientX / window.innerWidth ) * 2 - 1;  
    directionVector.y = -( event.clientY / window.innerHeight ) * 2 + 1;  
    
    

    Wie und wo registrierst du den Event-Handler.
    Nimmt dein Canvas wirklich die gesamte Viewport-Höhe/Breite ein?

    1. directionVector.x = ( event.clientX / window.innerWidth ) * 2 - 1;
      directionVector.y = -( event.clientY / window.innerHeight ) * 2 + 1;

      
      >   
      > Wie und wo registrierst du den Event-Handler.  
      > Nimmt dein Canvas wirklich die gesamte Viewport-Höhe/Breite ein?  
        
      Event wird so ausgelöst: window.addEventListener('click',checkClick,false);  
      Das ganze steht außerhalb jeglicher Funktionen im ganz oben im normalen JS-Code Bereich.  
        
      Und ja, mein Canvas hatte tatsächlich nicht den gesamten sichtbaren Bildschirm eingenommen, ich hab jetzt aber folgendes hinzugefügt:  
        
      ~~~css
      body {  
                          width:100%;  
                          height:100%;  
                          padding:0;  
                          margin:0;  
                     }  
                     #container {  
                          width:100%;  
                          height:100%;  
                     }
      

      Wodurch das Canvas den gesamten Bildschirm einnimmt. Trotzdem kommt immer noch nur ein "Nothing found".

      1. Folgender Post dann hier, da ich im neuen Thread nicht mehr antworten durfte. Sorry dafür, werde mich dran halten.

        Kannst du mal genau beschreiben was nicht geht, bzw. wie oder was funktionieren soll. Leider kennen wir den Inhalt der oben eingebundenen Javascript Dateien nicht. Kannst du mal den Link zu den Originaldateien posten?

        Selbstverständlich! Ich wäre für jede Hilfe dankbar!

        Genaugenommen geht es um folgendes: Ich habe einen 3D Körper (menschlicher, Genderneutraler Körper), der in den Browser geladen werden soll, drehbar mit der Maus sein soll (alle Achsen!), der mit der Maus anklickbar sein soll, damit verschiedene Bereiche ausgewählt werden können. Und das ganze bitte ohne Plugins / Addons, sondern pures JS.

        Das ganze mit der Maus drehbar zu machen, habe ich ja schon hinbekommen - obwohl ich von JS praktisch keine Ahnung habe und bei den Beispielen, die ich so finde, immer meist raten muss was das jetzt bedeutet. Nun geht es daran den Körper anklickbar zu machen. Ich muss also wissen, ob der User mit einem Mausklick den Körper getroffen hat oder nicht. Dazu brauche ich, was ich mittlerweile weiß, ein Picking Ray. Ich habe das ganze bisher so verstanden, dass von der Kamera in Richtung des Mausklicks ein Ray gecastet wird und wenn dieser den Körper schneidet, hat der User den Körper getroffen. Nun habe ich eine Menge Beispiele gefunden, die aber leider aus unterschiedlichen Versionen von Three.JS stammen. Daher benutzen sie unterschiedliche Funtionen. Daraus erklären sich auch die 3 unterschiedlichen Versuche in meinem Code. Wann immer ich nun eines der drei Beispiele ausprobiere (und ich hab wirklich meist einfach nur den Code kopiert), kommt immer ein "Nothing Found", also wurden keine intersects gefunden. Egal WO ich klicke, was ja nicht sein kann. Um das ganze zu debuggen, hab ich dann ein paar console.log() eingebaut. Was schonmal stimmt sind die Mausklick-Koordinaten. Anschließend wird der Richtungsvektordaraus berechnet und die Werte befinden sich alle zwischen -1 und 1, was laut den Beispielen ja richtig und Voraussetzung ist. Also müsste alles funktionieren. Tut es aber nicht, da immer nur ein "Nothing Found" kommt, welches ja nur ausgegeben wird, wenn keine intersects vorhanden sind.

        Hier der Link zum hochgeladenen 3D Modell: http://www.file-upload.net/download-7709937/body.obj.html

        Ein JSFiddle hab ich auch mal schnell, erstellt, es wird aber natürlich nichts angezeigt, da ich dort keine Möglichkeit gefunden habe mein 3D Modell hochzuladen.

        Und zur Sicherheit noch ein Screenshot hinterher: http://tinypic.com/view.php?pic=2eol37r&s=5

        1. Und zur Sicherheit noch ein Screenshot hinterher: http://tinypic.com/view.php?pic=2eol37r&s=5

          Dem Screenshot kann ich entnehmen, dass deine NDCs nicht korrekt sind. NDCs müssen im Wertebereich 0-1 liegen.

          1. Dem Screenshot kann ich entnehmen, dass deine NDCs nicht korrekt sind. NDCs müssen im Wertebereich 0-1 liegen.

            Meines Wissen's nach ist das falsch!

            1. Was genau ist ein NDC? Kurzes Googeln gab mir keinen genauen Aufschluss darüber wofür die Abkürzung NDC steht.
            2. Laut http://soledadpenades.com/articles/three-js-tutorials/object-picking/ müssen die Werte zwischen -1 und 1 liegen!

            ("You must get these two first lines right. They convert the mouse coordinates, which go from 0 to containerWidth, and from 0 to containerHeight, to (-1, 1) in both axes.")

            1. Dem Screenshot kann ich entnehmen, dass deine NDCs nicht korrekt sind. NDCs müssen im Wertebereich 0-1 liegen.

              Meines Wissen's nach ist das falsch!

              Ja du hast Recht, NDC = Normalized Device Coordinates und die liegen zwischen [-1,-1]. Werd nach der Arbeit nochmal einen genaueren Blick auf deinen Code werfen.

              1. Ja du hast Recht, NDC = Normalized Device Coordinates und die liegen zwischen [-1,-1]. Werd nach der Arbeit nochmal einen genaueren Blick auf deinen Code werfen.

                Würde mich sehr freuen! Was du aus dem Screenshot ja sehen kannst ist, dass die X und Y Koordinaten der Maus ordnungsgemäß übernommen werden. Das ist also schonmal nicht der Fehler. Das anschließende Umrechnen habe ich stumpf kopiert, da kann auch kein Fehler sein. Der Richtungsvektor müsste also 1zu1 stimmen.

                1. Puh, tut mir leid, ich kann keinen Logikfehler entdecken. Würde es dir was ausmachen ein Online-Beispiel zu erstellen?

                  1. Puh, tut mir leid, ich kann keinen Logikfehler entdecken. Würde es dir was ausmachen ein Online-Beispiel zu erstellen?

                    Hallo,

                    könnte und würde ich jetzt gerne machen, einziges Problem ist, dass ich keinen Freehoster kenne, auf dem ich meine .obj Datei hochladen und anschließend nutzen kann. Ich hab einen Account bei lima-city.de, dort kommt immer nur ein 403 forbidden, wenn ich versuche eine .obj Datei hochzuladen.

                    Wenn du mir einen Hoster nennst auf dem das geht, kann ich dir gerne ein online-Beispiel erstellen. Alternative: Ich schicke dir die ganzen Daten, dann kannst du es selber sehen.

                    So oder so bin ich mit meinem Latein am Ende und bitte nach wie vor um Hilfe. Ich weiß nicht was an dem Code falsch sein soll.

                    Vielen Dank!

                    1. Alternative: Ich schicke dir die ganzen Daten, dann kannst du es selber sehen.

                      So machen wir's, ihre.werbung@gmail.com ist meine öffentliche Mailadresse, daran kannst du es mir gerne schicken.
                      Falls ich den Fehler dann hoffentlich doch noch entdecke, geht's hier im Thread weiter, damit die Nachwelt möglicherweise davon profitieren kann ^^

                      1. Falls ich den Fehler dann hoffentlich doch noch entdecke, geht's hier im Thread weiter, damit die Nachwelt möglicherweise davon profitieren kann ^^

                        Ich habe es dir an deine eMail Adresse geschickt, ich hoffe du findest den Fehler.

                        Danke!

                        1. Falls ich den Fehler dann hoffentlich doch noch entdecke, geht's hier im Thread weiter, damit die Nachwelt möglicherweise davon profitieren kann ^^

                          Problem ist gelöst. Für alle, die es interessiert, oder die ein ähnliches Problem haben:

                          Ich hatte in meiner Szene (scene) ein einziges 3DObjekt (model), ich wollte überprüfen, ob ich mit einem Mausklick dieses Objekt treffe. Dafür ist der Code:

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

                          Verantwortlich. Logisch gesehen habe ich keinen Fehler, das Problem ist, dass intern mein 3DObjekt (model) weitere Children hat - nämlich eines vom Typ THREE.Mesh. Dieses THREE.Mesh verfügt über die Geometriedaten, das 3DObjekt (model) verfügt nicht über sie. Und da die Funktion intersectObjects() nicht rekursiv arbeitet, hat sie für scene.children nur bei Model nach Geometriedaten gesucht - dort wurden natürlich keine intersects gefunden. Fügt man ein true hintendran, arbeitet die Funktion rekursiv und schon findet der Code entsprechend richtig auch intersects.

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

                          Eine Alternative wäre z.B:

                          var intersects = raycaster.intersectObjects(scene.children[0].children);

                          Mit diesem Code, spreche ich das Child-Element von meiner Szene an, nämlich mein 3DObjekt (model) und anschließend dessen einziges Child-Element - das THREE.Mesh. Und dann werden Kollisionen auch richtig erkannt.

                          Ich hoffe das nützt jemandem etwas.

                          1. Ark, so eine Kleinigkeit. Freut mich, dass du den Fehler entdeckt hast, dann spielt es auch keine Rolle mehr, dass du in deiner Mail den Anhang vergessen hast ;)