2012-11-16 6 views
5

Ich versuche, eine einfache Anwendung zu erstellen, die Ihnen erlaubt, 3D-Modell von .obj zu laden und zu vergrößern/zu drehen, indem Sie den Bildschirm berühren.libgdx wie man 3D-Modell auf Berührung zoomt und dreht

Ich habe es geschafft, Code zu schreiben, der 3D-Modell aus Datei lädt und Gesten erkennt, aber jetzt bin ich mir nicht sicher, was ich tun soll, um Zoom-/Drehfunktionen durch Berühren des Bildschirms zu aktivieren.

Hier ist mein Code für jetzt:

public class RenderObjApp implements ApplicationListener, GestureDetector.GestureListener { 
    public static int SCREEN_WIDTH = 800; 
    public static int SCREEN_HEIGHT = 600; 

    private static final String TAG = RenderObjApp.class.getSimpleName(); 

    private Mesh model; 
    private PerspectiveCamera camera; 

    private float scale = 1f; 

    @Override 
    public void create() { 
     model = ObjLoader.loadObj(Gdx.files.internal("data/cessna.obj").read(), true); 
     Gdx.gl.glEnable(GL10.GL_DEPTH_TEST); 
     Gdx.input.setInputProcessor(new GestureDetector(this)); 
    } 

    @Override 
    public void dispose() { 
    } 

    @Override 
    public void pause() { 
    } 


    @Override 
    public void render() { 
     Gdx.gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 
     Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 
     camera.update(); 
     camera.apply(Gdx.gl10); 
     model.render(GL10.GL_TRIANGLES); 
    } 

    @Override 
    public void resize(int arg0, int arg1) { 
     float aspectRatio = (float) arg0/(float) arg1; 
     camera = new PerspectiveCamera(75, 2f * aspectRatio, 2f); 
     camera.near = 0.1f; 
     camera.translate(0, 0, 0); 
    } 

    @Override 
    public void resume() { 
    } 

    @Override 
    public boolean touchDown(float x, float y, int pointer) { 
     Gdx.app.log(TAG, "touchDown: "); 
     return false; 
    } 

    @Override 
    public boolean tap(float x, float y, int count, int pointer, int button) { 
     Gdx.app.log(TAG, "tap: "); 
     return false; 
    } 

    @Override 
    public boolean longPress(float x, float y) { 
     Gdx.app.log(TAG, "zoom: "); 
     return false; 
    } 

    @Override 
    public boolean fling(float velocityX, float velocityY, int pointer, int button) { 
     Gdx.app.log(TAG, "fling: "); 
     return false; 
    } 

    @Override 
    public boolean pan(float x, float y, float deltaX, float deltaY) { 
     Gdx.app.log(TAG, "pan: "); 
     return false; 
    } 

    @Override 
    public boolean zoom(float initialDistance, float distance) { 
     Gdx.app.log(TAG, "zoom: initialDistance=" + initialDistance + ", distance=" + distance); 
     return false; 
    } 

    @Override 
    public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) { 
     Gdx.app.log(TAG, "pinch: "); 
     return false; 
    } 
} 

So wie ich suche die PerspectiveCamera und Netz sich zu drehen.

Antwort

0

Sie müssen entweder die Kamera drehen oder das Modell drehen.

Ich glaube, die libGDX Camera.rotateAround Methode tut, was Sie brauchen. Belassen Sie den "Punkt" als Mittelpunkt Ihres Modells und legen Sie den Parameter "Achse" fest, je nachdem, auf welche Weise der Benutzer schleudert/schwenkt. Der "Winkel" kann entweder ein fester Wert oder relativ zur Intensität des Schleuderns sein.

2

Ich habe an einer "Blender-style" -Kamera gearbeitet, die Pinch-to-Zoom-Fähigkeit sowie (auf dem Desktop) die meisten Funktionen hat, die Sie mit Blenders Kamera erhalten. Es ist ein work in progress - es imitiert das Verhalten von Blenders Kamera (noch) nicht perfekt. Ich denke, das wird dich in die richtige Richtung weisen. Einige Dinge, die Sie wissen sollten:

  1. Möglicherweise müssen Sie Ihr Modell so übersetzen, dass es auf dem Ursprung sitzt. Die Kamera bleibt auf den Ursprung ausgerichtet, es sei denn, Sie übersetzen sie. (Sie können nur auf dem Desktop und nicht auf Android bisher übersetzen);

  2. Ich habe die meisten Pinch-to-Zoom-Handling-Code hier: https://code.google.com/p/libgdx-users/wiki/PinchToZoom.

  3. Sorry für die magischen Zahlen. Ich werde diese Konstanten in der Zukunft machen.

  4. Wenn Sie oder jemand anderes diesen Code verbessert, würde ich mich freuen, wenn Sie eine Kopie mit mir teilen würden.

Die abstrakte Klasse:

/* Author: Christopher Grabowski, yourchristopher6334 gmail.com */ 

package ...; 

import com.badlogic.gdx.InputProcessor; 
import com.badlogic.gdx.graphics.PerspectiveCamera; 
import com.badlogic.gdx.input.GestureDetector.GestureListener; 
import com.badlogic.gdx.math.Vector2; 

abstract public class ControllableCamera extends PerspectiveCamera implements InputProcessor{ 

    abstract public void resize(int width, int height); 
    abstract public void render(); 

    public ControllableCamera(int fieldOfView, int width, int height) { 
     super(fieldOfView, width, height); 
    } 

    @Override 
    public boolean keyDown(int keyCode) { 
     return false; 
    } 

    @Override 
    public boolean keyTyped(char arg0) { 
     return false; 
    } 

    @Override 
    public boolean keyUp(int arg0) { 
     return false; 
    } 

    @Override 
    public boolean touchDown(int x, int y, int pointer, int button) { 
     return false; 
    } 

    @Override 
    public boolean touchDragged(int screenX, int screenY, int pointer) { 
     return false; 
    } 

    @Override 
    public boolean touchUp(int x, int y, int pointer, int button) { 
     return false; 
    } 

    @Override 
    public boolean mouseMoved(int arg0, int arg1) { 
     return false; 
    } 

    @Override 
    public boolean scrolled(int direction) { 
     return false; 
    } 
} 

Die konkrete Klasse:

/* Author: Christopher Grabowski, yourchristopher6334 gmail.com */ 

package ...; 

import com.badlogic.gdx.Gdx; 
import com.badlogic.gdx.Input.Keys; 
import com.badlogic.gdx.math.Vector3; 

/* 
* the pause, resize, and render methods must be called within their corresponding 
* methods in the ApplicationListener 
*/ 

public class BlenderStyleCamera extends ControllableCamera { 
    public static final Vector3 ORIGIN = new Vector3(0, 0, 0); 

    private static boolean shiftIsPressed = false, controlIsPressed = false, 
      isScrollingUp = false, isScrollingDown = false, 
      isSingleTouched = false, justSingleTouched = false; 

    private float aspectRatio; 
    private int x = -1, y = -1; 
    private float dx = 0.0f, dy = 0.0f; 
    private final Vector3 tmp = new Vector3(); 

    // fields related to pinch-to-zoom 
    private int numberOfFingers = 0; 
    private int fingerOnePointer; 
    private int fingerTwoPointer; 
    private float lastDistance = 0; 
    private final Vector3 fingerOne = new Vector3(); 
    private final Vector3 fingerTwo = new Vector3(); 

    public BlenderStyleCamera(int fieldOfView, int width, int height) { 
     super(fieldOfView, width, height); 
     aspectRatio = viewportHeight/viewportWidth; 
     Gdx.input.setInputProcessor(this); 
     up.set(0.0f, 1.0f, 0.0f); 
     position.set(0.0f, 0.0f, 30.0f); 
     far = 300.0f; 
     lookAt(0, 0, 0); 
     translate(0.0f, 0.0f, 2.1f); 
     lookAt(0, 0, 0); 
     update(); 
    } 

    public void pause() { 
     numberOfFingers = 0; 
    } 

    @Override 
    public void resize(int width, int height) { 
     viewportWidth = width; 
     viewportHeight = height; 
     aspectRatio = viewportHeight/viewportWidth; 
     update(); 
    } 

    @Override 
    public void render() { 
     if (isSingleTouched) { 

      // This gets the change in touch position and 
      // compensates for the aspect ratio. 
      if (x == -1 || y == -1 || justSingleTouched) { 
       x = Gdx.input.getX(); 
       y = Gdx.input.getY(); 
      } else { 
       dx = (x - Gdx.input.getX()); 
       dy = (y - Gdx.input.getY())/aspectRatio; 
      } 

      // This zooms when control is pressed. 
      if (controlIsPressed && dy > 0) { 
       scrollIn(); 
      } else if (controlIsPressed && dy < 0) { 
       scrollOut(); 
      } 

      // This translates the camera blender-style 
      // if shift is pressed. 
      // Note that this will look weird with a 
      // perspective camera. 
      else if (shiftIsPressed) { 
       translateTangentially(); 
      } 

      // Default is to rotate the object 
      // (actually rotate the camera about a sphere 
      // that surrounds the object). 
      else { 
       travelAround(); 
      } 

      x = Gdx.input.getX(); 
      y = Gdx.input.getY(); 

      justSingleTouched = false; 
     } 

     // this zooms when the mouse wheel is rotated 
     if (isScrollingUp) { 
      scrollIn(); 
      isScrollingUp = false; 
     } else if (isScrollingDown) { 
      scrollOut(); 
      isScrollingDown = false; 
     } 

     // Some key controls 
     if (Gdx.input.isKeyPressed(Keys.LEFT) || Gdx.input.isKeyPressed(Keys.A)) { 
      translateTangentially(1, 0); 
     } else if (Gdx.input.isKeyPressed(Keys.RIGHT) 
       || Gdx.input.isKeyPressed(Keys.D)) { 
      translateTangentially(-1, 0); 
     } 

     if (Gdx.input.isKeyPressed(Keys.UP) || Gdx.input.isKeyPressed(Keys.W)) { 
      translateTangentially(0, 1); 
     } else if (Gdx.input.isKeyPressed(Keys.DOWN) 
       || Gdx.input.isKeyPressed(Keys.S)) { 
      translateTangentially(0, -1); 
     } 

     update(); 
    } 

    // These methods create the pinch zoom 
    // and set some flags for logic in render method. 
    @Override 
    public boolean touchDown(int x, int y, int pointer, int button) { 
     // for pinch-to-zoom 
     numberOfFingers++; 
     if (numberOfFingers == 1) { 
      isSingleTouched = true; 
      justSingleTouched = true; 
      fingerOnePointer = pointer; 
      fingerOne.set(x, y, 0); 
     } else if (numberOfFingers == 2) { 
      isSingleTouched = false; 
      fingerTwoPointer = pointer; 
      fingerTwo.set(x, y, 0); 

      float distance = fingerOne.dst(fingerTwo); 
      lastDistance = distance; 
     } 
     return true; 
    } 

    @Override 
    public boolean touchDragged(int x, int y, int pointer) { 
     if (numberOfFingers > 1) { 
      if (pointer == fingerOnePointer) { 
       fingerOne.set(x, y, 0); 
      } 
      if (pointer == fingerTwoPointer) { 
       fingerTwo.set(x, y, 0); 
      } 

      float distance = fingerOne.dst(fingerTwo); 

      if (lastDistance > distance) { 
       scrollOut(); 
      } else if (lastDistance < distance) { 
       scrollIn(); 
      } 

      lastDistance = distance; 
      update(); 
     } 
     return true; 
    } 

    @Override 
    public boolean touchUp(int x, int y, int pointer, int button) { 
     isSingleTouched = false; 
     if (numberOfFingers == 1) { 
      Vector3 touchPoint = new Vector3(x, y, 0); 
      unproject(touchPoint); 
     } 
     numberOfFingers--; 

     // just some error prevention... clamping number of fingers (ouch! :-) 
     if (numberOfFingers < 0) { 
      numberOfFingers = 0; 
     } 

     lastDistance = 0; 
     return false; 
    } 

    // These methods set flags for logic in render method. 
    @Override 
    public boolean keyDown(int keycode) { 

     switch (keycode) { 
     case (Keys.SHIFT_LEFT): 
     case (Keys.SHIFT_RIGHT): 
      shiftIsPressed = true; 
      break; 
     case (Keys.CONTROL_LEFT): 
     case (Keys.CONTROL_RIGHT): 
      controlIsPressed = true; 
      break; 
     case (Keys.O): 
      this.up.set(0.0f, 1.0f, 0.0f); 
      this.position.set(0.0f, 0.0f, 30.0f); 
      this.lookAt(0, 0, 0); 
      this.update(); 
     } 
     return true; 
    } 

    @Override 
    public boolean keyUp(int arg0) { 
     shiftIsPressed = controlIsPressed = false; 
     return true; 
    } 

    @Override 
    public boolean scrolled(int direction) { 
     if (direction == -1) { 
      isScrollingUp = true; 
     } else if (direction == 1) { 
      isScrollingDown = true; 
     } 
     return true; 
    } 

    // The rest of the methods translate the camera. 
    public void scrollIn() { 
     float magnitude = 1.0f; 
     scrollIn(magnitude); 
    } 

    public void scrollIn(float magnitude) { 
     if (position.dst2(ORIGIN) > 2.0f) { 
      tmp.set(position); 
      tmp.nor(); 
      this.translate(-tmp.x * magnitude, -tmp.y * magnitude, -tmp.z 
        * magnitude); 
      update(); 
     } 
    } 

    public void scrollOut() { 
     float magnitude = 1.0f; 
     scrollOut(magnitude); 
    } 

    public void scrollOut(float magnitude) { 
     tmp.set(position); 
     tmp.nor(); 
     this.translate(tmp.x * magnitude, tmp.y * magnitude, tmp.z * magnitude); 
     update(); 
    } 

    private void travelAround() { 
     tmp.set(up); 
     rotateAround(ORIGIN, tmp, dx); 
     tmp.crs(position).nor(); 
     rotateAround(ORIGIN, tmp, dy); 
    } 

    private void translateTangentially() { 
     translateTangentially(dx, dy); 
    } 

    private void translateTangentially(float dx, float dy) { 
     tmp.set(up); 
     tmp.crs(position); 
     if (dx > 0) { 
      translate(tmp.x/15.0f, tmp.y/15.0f, tmp.z/15.0f); 
     } else if (dx < 0) { 
      translate(-tmp.x/15.0f, -tmp.y/15.0f, -tmp.z/15.0f); 
     } 

     if (dy > 0) { 
      translate(-up.x, -up.y, -up.z); 
     } else if (dy < 0) { 
      translate(up); 
     } 
    } 

}