我不知道如何添加触摸或长按来操作 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/