OpenGL glTranslatef和glScalef

时间:2012-11-04 21:09:35

标签: java android opengl-es

我正在尝试将pan和pinch-to-zoom功能实现到我拥有的OpenGL应用程序中。我能够使用简单的glTranslatef相对轻松地实现平移功能,但使用glScalef功能会带来更多困难。我有三个类,一个用于GLSurfaceView,一个用于GLTriangle,第三个用于GLRenderer,这是glScalef和{{1}使用。

glTranslatef上课:

GLRenderer

public class GLRendererEx implements Renderer, OnTouchListener { private GLTriangleEx tri; float ratio; float x = 0, y = 0; float dx = 0, dy = 0; float sx = 0, sy = 0; float tx = 0, ty = 0; float xtwo = 0, ytwo = 0; float sxtwo = 0, sytwo = 0; float screenX, screenY; float xscale = 1, yscale = 1; float xscaletwo = 1; float xscaletotal = 1, yscaletotal = 1; int NONE = 0, DRAG = 1, ZOOM = 2; int mode = NONE; int width, height; boolean touched = true; Display getOrient = getWindowManager().getDefaultDisplay(); int orientation; public GLRendererEx() { tri = new GLTriangleEx(); screenX = ourSurface.getWidth(); screenY = ourSurface.getHeight(); ourSurface.setOnTouchListener(this); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) { gl.glDisable(GL10.GL_DITHER); gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); gl.glClearColor(0f, 0f, 0f, 1f); gl.glClearDepthf(1f); orientation = getOrient.getRotation(); } @Override public void onDrawFrame(GL10 gl) { gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); GLU.gluLookAt(gl, 0, 0, -5, 0, 0, 0, 0, 2, 0); //warning - x is backwards gl.glTranslatef(tx, ty, 0); gl.glScalef(xscaletotal, yscaletotal, 1); tri.draw(gl); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { gl.glViewport(0, 0, width, height); ratio = ((float) width) / height; screenX = width; screenY = height; orientation = getOrient.getRotation(); gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); gl.glFrustumf(-ratio, ratio, -1, 1, 1, 50); } @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { event.getActionIndex(); sx = x = event.getX(0); sy = y = event.getY(0); mode = DRAG; break; } case MotionEvent.ACTION_POINTER_DOWN: { event.getActionIndex(); sxtwo = xtwo = event.getX(1); sytwo = ytwo = event.getY(1); mode = ZOOM; touched = true; break; } case MotionEvent.ACTION_MOVE: { x = event.getX(0); y = event.getY(0); xtwo = event.getX(1); ytwo = event.getY(1); if (mode == ZOOM) midPoint(x, y, xtwo, ytwo); if (mode == DRAG) { dx = x - sx; dy = y - sy; dx *= -8; dy *= -8; if (orientation == Configuration.ORIENTATION_LANDSCAPE) dx *= 2; dx /= screenX; dy /= screenY; tx += dx; ty += dy; sx = x; sy = y; } break; } case MotionEvent.ACTION_POINTER_UP: { mode = DRAG; break; } case MotionEvent.ACTION_UP: { mode = NONE; break; } } return true; } private float midPoint(float x, float y, float xtwo, float ytwo) { x -= xtwo; y -= ytwo; if (touched) { sxtwo = x; sytwo = y; xscaletwo = FloatMath.sqrt(sxtwo * sxtwo + sytwo * sytwo); touched = false; } xscale -= xscaletwo; xscale = FloatMath.sqrt(x * x + y * y); xscaletotal += xscale; yscaletotal = xscaletotal; return xscale; } } 是坐标,x/y是坐标的变化,dx/dy是开始坐标,sx/sy是坐标的总变化(用于平移),tx/ty是用于计算缩放比例的浮点数,xscale/yscale是缩放比例的总变化,没有拖动缩放和模式代表模式。

就目前而言,我可以通过拉开手指来放大,但是捏也可以缩放而不是缩小。此外,变焦太敏感了。

我真的不知道如何从这里解决这个问题。任何帮助都不仅仅是值得赞赏的。

1 个答案:

答案 0 :(得分:1)

看起来你的“midPoint”有一些工作要做..尝试做这样的事情:

float scale = 1.0; //factor used in glScalef
float previousPinchScale; //needed to remember from previous methode call
private float midPoint(float x, float y, float xtwo, float ytwo) {
    float currentPinchScale = FloatMath.sqrt((x-xTwo)*(x-xTwo) + (y-yTwo)*(y-yTwo)); //current distance between both "touches"
    if (touched) { //gesture just began:
        previousPinchScale = currentPinchScale; //Save relative information about touch positions
        touched = false;
    }
    else { //gesture in progress:
        /*
         At this point we have 2 values of "PinchScale" for this and previous "midPoint" method call.
         The factor of relative change in this distance should be applied to current scene scale:
         currentPinchScale/previousPinchScale is the "relative change", for instance if the distance between the 2 touches would be 10% this factor would return 1.1
         Since we have to consider that scene might already be zoomed you need to take previous scale and multiply it with this change..
         */
        scale *= currentPinchScale/previousPinchScale; //scale used in glScalef
        previousPinchScale = currentPinchScale; //remember the new position of "midPoint" call
    }
    return scale;
}