android - 如何在 Android OpenGL ES 中应用拖放和缩放

标签 android opengl-es

我不知道如何添加触摸或长按来操作 OpenGL 平移和缩放参数?

目前我的代码是在手机屏幕中间显示一个纹理,我想用手指拖动和缩放纹理,那么如何操作OpenGL平移和缩放参数?

这是我的主课:

import android.app.Activity;
import android.os.Bundle;
import android.view.WindowManager;

public class MainActivity extends Activity {

private Stage stage;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    //screen setting
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

    setContentView(R.layout.main_layout);
    stage = (Stage)findViewById(R.id.my_stage);
}

@Override
protected void onPause() {
    super.onPause();
    stage.onPause();
}

@Override
protected void onResume() {
    super.onResume();
    stage.onResume();
}
}

这是我的第二个子类:

import android.content.Context;
import android.opengl.GLES10;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class Stage extends GLSurfaceView{

/* Stage width and height */
private float w, h;

/* Screen width and height */
private int screenWidth, screenHeight;

/* Our native vertex buffer */
private FloatBuffer vertexBuffer;

private Texture tex;

public Stage(Context context, AttributeSet attrs) {
    super(context, attrs);
    setEGLConfigChooser(8, 8, 8, 8, 0, 0);
    setRenderer(new MyRenderer());
    setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

    float vertices[] = {
            -0.5f, -0.5f,  0.0f,  // 0. left-bottom
            0.5f, -0.5f,  0.0f,  // 1. right-bottom
            -0.5f,  0.5f,  0.0f,  // 2. left-top
            0.5f,  0.5f,  0.0f   // 3. right-top
    };

    ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
    vbb.order(ByteOrder.nativeOrder());
    vertexBuffer = vbb.asFloatBuffer();
    vertexBuffer.put(vertices);
    vertexBuffer.position(0);

    tex = new Texture(R.drawable.kdk);

}

private final class MyRenderer implements GLSurfaceView.Renderer {

    public final void onDrawFrame(GL10 gl) {

        gl.glClear(GLES10.GL_COLOR_BUFFER_BIT);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
        tex.prepare(gl, GL10.GL_CLAMP_TO_EDGE);
        tex.draw(gl, (w / 2), (h / 2), tex.getWidth(), tex.getHeight(), 0);

    }

    public final void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glClearColor(0, 0, 0, 1.0f);

        if(width > height) {
            h = 600;
            w = width * h / height;
        } else {
            w = 600;
            h = height * w / width;
        }
        screenWidth = width;
        screenHeight = height;

        gl.glViewport(0, 0, screenWidth, screenHeight);
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glOrthof(0, w, h, 0, -1, 1);
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    public final void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // Set up alpha blending
        gl.glEnable(GL10.GL_ALPHA_TEST);
        gl.glEnable(GL10.GL_BLEND);
        gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);

        // We are in 2D. Why needs depth?
        gl.glDisable(GL10.GL_DEPTH_TEST);

        // Enable vertex arrays (we'll use them to draw primitives).
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

        // Enable texture coordination arrays.
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

        tex.load(getContext());
    }



}

}

这是我的第三个子类:

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES10;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;

public class Texture {

/**
 * The OpenGL ES texture name associated with this texture.
 */
protected int textureId;

/**
 * The horizontal and vertical dimensions of the image.
 */
protected int width, height;

/**
 * The resource identifier for the image we want to load.
 */
int resourceId;

/**
 * Whether or not we should generate mip maps.
 */
boolean mipmaps;

/**
 * The buffer containing texture mappings.
 */
private FloatBuffer tempTextureBuffer = null;

Texture(int resourceId, boolean mipmaps) {
    this.resourceId = resourceId;
    this.textureId = -1;
    this.mipmaps = mipmaps;
}

Texture(int resourceId) {
    this(resourceId, false);
}

/**
 * Generates a new OpenGL ES texture name (identifier).
 * @return The newly generated texture name.
 */
private static final int newTextureID() {
    int[] temp = new int[1];
    GLES10.glGenTextures(1, temp, 0);
    return temp[0];
}

public final int getWidth() {
    return width;
}

public final int getHeight() {
    return height;
}

public final void load(Context context) {
    // Load the bitmap from resources.
    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inScaled = false;
    Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), resourceId, opts);

    // Update this texture instance's width and height.
    width = bmp.getWidth();
    height = bmp.getHeight();

    // Create and bind a new texture name.
    textureId = newTextureID();
    GLES10.glBindTexture(GL10.GL_TEXTURE_2D, textureId);

    // Load the texture into our texture name.
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);

    // Set magnification filter to bilinear interpolation.
    GLES10.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

    if(mipmaps) {
        // If mipmaps are requested, generate mipmaps and set minification filter to trilinear filtering.
        GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
        GLES10.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_LINEAR);
    }
    else GLES10.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);

    // Recycle the bitmap.
    bmp.recycle();

    // If texture mapping buffer has not been initialized yet, do it now.
    if(tempTextureBuffer == null)
        buildTextureMapping();
}

/**
 * Builds the texture mapping buffer.
 */
private void buildTextureMapping() {
    // The array of texture mapping coordinates.
    final float texture[] = {
            0, 0, // The first vertex
            1, 0, // The second vertex
            0, 1, // The third vertex
            1, 1, // The fourth vertex
    };

    // Create a native buffer out of the above array.
    final ByteBuffer ibb = ByteBuffer.allocateDirect(texture.length * 4);
    ibb.order(ByteOrder.nativeOrder());
    tempTextureBuffer = ibb.asFloatBuffer();
    tempTextureBuffer.put(texture);
    tempTextureBuffer.position(0);
}

/**
 * Deletes the texture name and marks this instance as unloaded.
 */
public final void destroy() {
    GLES10.glDeleteTextures(1, new int[] {textureId}, 0);

    // Setting this value to -1 indicates that it is unloaded.
    textureId = -1;
}

public final boolean isLoaded() {
    return textureId >= 0;
}

public final void prepare(GL10 gl, int wrap) {
    // Enable 2D texture
    gl.glEnable(GL10.GL_TEXTURE_2D);

    // Bind our texture name
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId);

    // Set texture wrap methods
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, wrap);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, wrap);

    // Enable texture coordinate arrays and load (activate) ours
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, tempTextureBuffer);
}

public final void draw(GL10 gl, float x, float y, float w, float h, float rot) {
    gl.glPushMatrix();
    gl.glTranslatef(x, y, 0);
    gl.glRotatef(rot, 0, 0, 1);
    gl.glScalef(w, h, 0); // Scaling will be performed first.
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
    gl.glPopMatrix();
}

}

最佳答案

您的 GLSurfaceView(Stage 类)应该是获取触摸事件的类。所以你应该给它添加这个方法:

@Override
public boolean onTouchEvent(MotionEvent event) {
    final int action = event.getAction() & MotionEvent.ACTION_MASK;
    float x, y;
    int pointerIndex;

    if (action == MotionEvent.ACTION_DOWN) {
        pointerId = event.getPointerId(0);
        x = event.getX();
        y = event.getY();
        pointerIndex = 0;
    } else {
        pointerIndex = event.getActionIndex();
        pointerId = event.getPointerId(pointerIndex);
        x = event.getX(pointerIndex);
        y = event.getY(pointerIndex);
    }

    // Now you have your x and y, your action (up, down, etc), and pointer index.   
}

请记住,您已经缩放了 GLSurfaceView 的虚拟尺寸,因此您可能应该对 x 和 y 执行相同的操作(在开始使用 x 和 y 之前添加它):

x = x * w / screenWidth;
y = y * h / screenHeight;

有关 MotionEvent 的更多信息(如何处理向下/向上触摸等),请参阅 Android documentation for this class .

更新:

为了翻译,你需要有四个成员变量:

  • 为触摸保存了 x 和 y。
  • 保存 Sprite 的 X 和 Y。

最初将它们全部设置为无效值,例如 -1。当你得到 ACTION_DOWN 事件时,将事件 x 和 y 以及 Sprite X 和 Y 保存在变量中。

在 ACTION_MOVE 上,您检查其中一个是否为 -1。如果不是,则表示您正在拖动。所以你得到新的 x 和 y 与保存的 x 和 y 的差异,并将其添加到保存的 X 和 Y。这将是你的 Sprite 的新位置。

在 ACTION_UP 上,只需将保存的值设置回 -1(或至少在 ACTION_MOVE 上设置您正在检查的值)。

缩放有点复杂。您需要查找指针索引 > 0 的 ACTION_POINTER_DOWN。一旦找到,您也可以保存第二个指针的值,就像翻译一样。您还需要保存 Sprite 的原始比例因子。然后,每当您获得 ACTION_MOVE 或 ACTION_POINTER_MOVE 时,您都会查看两个指针是否都存在(-1 的技巧),如果存在,则获取它们的差异。但这次差异将构成您的比例因子,而不是位置。

关于android - 如何在 Android OpenGL ES 中应用拖放和缩放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32556914/

相关文章:

android - Google Translate API 有时需要很长时间来初始化

android - 错误 OpenGL渲染器 : GL error: Out of memory

android - 在 Activity 之间传递 View

Android - 使用带有通知的未决 Intent

android - 绘制带有空白区域的位图

opengl-es - LibGDX - Sprite 到像素图

java - 如何在android上更新顶点缓冲区?

android - RxJava2 找不到 Func0

android - Android NDK OpenGL 应用程序的 float 或定点数?

html - 如何在 WebGL/OpenGL 中有效地旋转大量的 gl.LINES?