kostenloser Webspace werbefrei: lima-city


Three.js object picking

lima-cityForumDie eigene HomepageHTML, CSS & Javascript

  1. Autor dieses Themas

    m****r

    Hallo,

    ich versuche gerade mit der Three bibliothek einen 3-dimensionalen Körper in meinen Browser einzubinden, der mit der Maus drehbar und anklickbar ist. Hierzu muss ich natürlich wissen, ob der User mit einem Mausklick den Körper getroffen hat. Daran scheitere ich allerdings leider. Ich selber habe von JS wenig Ahnung und von der Three-Bibliothek eh noch weniger.

    Zur Erklärung: Ich hatte bevor ich das ganze hier angefangen habe, nichtmal eine Ahnung was three.js ist, von daher verzeiht mir bitte unsauberen Code. Ich habe mittlerweile rausgefunden, dass ich 3 Dinge benötige, um festzustellen, ob der User mit seinem Mausklick den Körper getroffen hat. Hierzu benötige ich erstens die Korrdinaten des Mausklicks x,y, die dann in einen 3D Vektor umgerechnet werden, der die Richtung angibt. Anschließend benötige ich die Position der Kamera, die die ganze Szene aufnimmt und caste einen Ray, der von der Position der Kamera ausgeht und in Richtung des Richtungsvektors geht. Drittens überprüfe ich dann, ob dieser Ray / Strahl den Körper schneidet. Wenn ja, hat der User mit seinem Mausklick den Körper getroffen, wenn nein eben nicht.

    Code:

    <!DOCTYPE html>
    <html lang="en">
    	<head>
    		<title>3D Body</title>
              <script src="three.js"></script>  
              <script src="OBJLoader.js"></script>  
    		<script src="TrackballControls.js"></script>    
              <style type="text/css">
                   body {
                        width:100%;
                        height:100%;
                        padding:0;
                        margin:0;
                   }
                   #container {
                        width:100%;
                        height:100%;                         
                   }
              </style> 
    	</head>                            
    
    	<body>
    		<div id="container"></div>  
    
    		<script>       
                   // Basic vars
    			var container, camera, controls, scene, renderer;
                   var model, texture;
                   var width, height;
                   
                   // Listeners
                   window.addEventListener('click',checkClick,false);
    
    			init(); 
    			animate();
    
    			function init() {
                        // Renderer  
                        container = document.getElementById('container');
                        width = window.innerWidth;
                        height = window.innerHeight;
    				renderer = new THREE.CanvasRenderer();
    				renderer.setSize(width,height);   
    				
    				container.appendChild(renderer.domElement);  
                        
                        // Camera, controls
    				camera = new THREE.PerspectiveCamera(60,width/height,1,500);
    				camera.position.z = 400;   
    				controls = new THREE.TrackballControls(camera,renderer.domElement);  
    				controls.rotateSpeed = 1.0;
    				controls.zoomSpeed = 1.2;
    				controls.panSpeed = 0.8;  
    				controls.noZoom = false;
    				controls.noPan = false;  
    				controls.staticMoving = true;
    				controls.dynamicDampingFactor = 0.3;   
                        controls.keys = [65];  
    				controls.addEventListener('change',render);
                        
    				// Scene
    				scene = new THREE.Scene();                        
                        
                        // Texture                        
                        texture = new THREE.Texture();   
    				var loader = new THREE.ImageLoader();
    				loader.addEventListener( 'load', function ( event ) {
    
    					texture.image = event.content;
    					texture.needsUpdate = true;
    
    				} );
    				loader.load( 'texture.jpg' );
                        
                        // Model                              
                        var loader = new THREE.OBJLoader();
    				loader.addEventListener('load',function(event) {  
    					model = event.content;      
    					model.traverse( function ( child ) {   
    						if ( child instanceof THREE.Mesh ) { 
    							child.material.map = texture;  
    						}                               
    					} );   
    					model.position.y = - 80;
    					scene.add(model); 
    				});
    				loader.load( 'body.obj' );
    			}
    
    			function animate() {
                        // Animate
    				requestAnimationFrame(animate);
    				controls.update();   
    			}
    
    			function render() {
                        // Render complete scene
    				renderer.render(scene,camera);  
    			} 
                   function checkClick() {
                        // On every click, check for body hit
                        console.log(event);
                        
                        // -- Versuch 1 --
                        /*var mouseX = event.offsetX || event.clientX,
                             mouseY = event.offsetY || event.clientY,
                             projector = new THREE.Projector();
    
                        var vector = new THREE.Vector3((mouseX / width) * 2 - 1,-(mouseY / height) * 2 + 1,0.5);
                        console.log(vector);
    
                        projector.unprojectVector(vector, camera);
     
                        var ray = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize()),
                        intersects = ray.intersectObjects(scene.children);
                        console.log(ray);*/
                        
                        /*
                        // -- Versuch 2
                        var x = ( event.clientX / width ) * 2 - 1;
                        var y = -( event.clientY / height ) * 2 + 1;
                        
                        var projector = new THREE.Projector();
                        var vector = new THREE.Vector3( x,y, 0.5 );    
                        
                        
                        console.log(vector);
                        // Line
                        var material = new THREE.LineBasicMaterial({
                             color: 0x0000ff
                        });  
                        var geometry = new THREE.Geometry();
                        geometry.vertices.push(camera.position);
                        geometry.vertices.push(vector);
                        
                        var line = new THREE.Line(geometry, material);
                        scene.add(line);  
                        
                        
    	               projector.unprojectVector( vector, camera );
                        console.log(vector);
    	               var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
                        console.log(ray);
    
    	               var intersects = ray.intersectObject(scene.children);
                        console.log(intersects); */
                        
    
                        // -- Versuch 3
                        var x = ( event.clientX / window.innerWidth ) * 2 - 1;
                        var y = -( event.clientY / window.innerHeight ) * 2 + 1;
                        var Vector = new THREE.Vector3(x,y,0.5);
                        var projector = new THREE.Projector();
                        
                        console.log(Vector);
                        var raycaster = projector.pickingRay(Vector.clone(),camera);
                        var intersects = raycaster.intersectObjects(scene.children);
                        
                        if (intersects.length) {
                             console.log("found something");
                        }
                        else {
                             console.log("found nothing");
                        }
                        console.log("---");
                   }
    		</script>
    
    	</body>
    </html>


    Die ganzen console.log() sind zu Debug Zwecken da. Im Moment bin ich soweit, dass die X und Y Mauskoordinaten richtig übergeben werden, am Ende kommt trotzdem immer ein Found nothing, obwohl ich auf den Körper geklickt habe. Was mache ich falsch?

    Screenshot: http://tinypic.com/view.php?pic=2eol37r&s=5

    Achja, die 3 Versuche in der CheckClick() Function sind darauf zurückzuführen, dass ich eine ganze Menge zu dem Thema gegoogelt habe und verschiedene Beispiele gefunden habe, die ich einfach stumpf kopiert habe. Kein einziges funktioniert. Die 3 Versuche machen eigentlich genau das gleiche, benutzen aber unterschiedliche Funktionen, da sie wohl zu unterschiedlichen Zeiten entstanden sind - hab ich auch lange gebraucht um das rauszufinden. Die Three.js Bibliothek entwickelt sich ja immer weiter und das in dem Code derzeit nicht auskommentierte 3te Beispiel müsste der Code sein, der laut der neusten Version von Three.js funktionieren müsste. Tut er aber nicht.

    Was mache ich falsch? Vielen Dank für jegliche Hilfe.

    EDIT: Wer es selber ausporbieren möchte, hier ist das 3D Modell: http://www.file-upload.net/download-7709937/body.obj.html

    Beitrag zuletzt geändert: 13.6.2013 17:48:48 von midwar
  2. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

  3. g****e

    Ich habe dir mal ein Beispiel rausgesucht:
    https://github.com/mrdoob/three.js/blob/master/examples/webgl_interactive_cubes.html
    Daraus wird deutlich (in der Render funktion), dass du hier die Maus natürlich verarbeiten musst. OnMouseMove werden die Daten für dieses Event zwischengespeichert (die Koordinaten werden dabei auf den Bildschirm umgerechnet, dass der Bildschirm einem normierten Koordinatensystem entspricht). Dann kannst du mittels raycaster ein intersect ausführen, und dieses Rückgabearray dann analysieren.

    In dem Beispiel auf Github, also dem Link oben, kannst du den Code gut nachvollziehen und siehst, dass du diese Projektionen usw garnicht mehr selbst machen musst. ThreeJS bringt für dich die RayCaster usw alles mit.
    Bei deinem console.log(ray) wäre zu sagen, dass die Rückgabe, also dein intersects die Objekte enthält, welche durchstoßen werden. Also müssstest du console.log(intersects) schreiben.

    Liebe Grüße
  4. Autor dieses Themas

    m****r

    Hallo,

    erstmal danke für die Antwort, jedoch hilft sie mir leider nicht weiter.

    Ich weiß sehr wohl, dass ich die Projektion gar nicht mehr selber machen muss. Ich habe ja lange gebraucht um zu verstehen, dass in den neueren Versionen von threejs das alles automatisch gemacht wird. Ich benötige dann nur noch:

    var projector = new THREE.Projector();
                        var raycaster = projector.pickingRay(Vector.clone(),camera);
                        var intersects = raycaster.intersectObjects(scene.children);


    Aber genau das habe ich doch jetzt ewig lange versucht und es funktioniert nicht. Dabei möchte ich einfach nur einen 3D Körper, der
    - mit der Maus drehbar ist
    - bestimmte Bereiche anklickbar sind

    Was mache ich falsch (Denn deine Ratschläge setze ich doch eigentlich schon um..)?
  5. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

Dir gefällt dieses Thema?

Über lima-city

Login zum Webhosting ohne Werbung!