2012-11-16 7 views
5

.obj에서 3D 모델을로드하고 화면을 터치하여 줌/회전 할 수있는 간단한 앱을 만들려고합니다.libgdx 터치시 3D 모델 확대 및 회전 방법

파일에서 3D 모델을로드하고 제스처를 감지하는 코드를 작성했지만 이제는 화면을 터치하여 줌/회전 기능을 사용하려면 어떻게해야하는지 잘 모릅니다.

여기 지금 내 코드입니다 :

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

그래서 나는 PerspectiveCamera를 회전하고 자체 메쉬하는 방법을 찾고 있어요.

답변

0

카메라를 돌리거나 모델을 회전해야합니다.

저는 libGDX Camera.rotateAround 메서드가 필요한 것을 수행한다고 생각합니다. "포인트"를 모델의 중심으로두고 사용자가 플링/패닝하는 방식에 따라 "축"매개 변수를 설정하십시오. "각도"는 고정 값이거나 플링/팬의 강도에 상대적입니다.

1

이 부분을 보시려면 Mesh rendering issue libgdx을 참조하십시오.

방법 렌더링에 필요한 코드가 포함되어 있습니다.

2

나는 블렌더의 카메라로 얻는 기능 대부분을 (데스크톱에서) 핀치 - 줌 기능을 가진 "블렌더 스타일"카메라로 작업 해왔다. 진행중인 작업입니다. 블렌더 카메라의 동작을 완벽하게 모방하지는 않습니다 (아직). 나는 이것이 당신을 올바른 방향으로 인도 할 것이라고 생각합니다. 귀하가 알아야 할 몇 가지 사항 :

  1. 모델이 원점에 있도록 번역해야 할 수도 있습니다. 카메라를 번역하지 않으면 카메라가 원점을 향하고 있습니다. (지금까지 데스크톱에서만 번역 할 수 있고 안드로이드에서는 번역 할 수 없습니다.);

  2. 대부분의 핀치 - 줌 처리 코드는 https://code.google.com/p/libgdx-users/wiki/PinchToZoom입니다.

  3. 죄송합니다. 나는 앞으로 이러한 상수를 만들 것이다.

  4. 본인 또는 누구든지이 코드를 개선하면 나와 사본을 공유하면 좋을 것입니다.

추상 클래스 :

/* 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; 
    } 
} 

구체적인 클래스 :

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

}