问题描述
我有一个问题,不知道如何添加触摸或长按来操作 OpenGL 平移和缩放参数?
I have a problem on dunno how to add touch or long click to manipulate the OpenGL translate and scale parameter?
目前我的编码是在手机屏幕中间显示一个纹理,我想用手指拖动和缩放纹理,那么如何操作OpenGL的平移和缩放参数?
Currently my coding is displaying a texture in the middle of the mobile screen, and I want to drag and scale the texture with finger, So how do I manipulate the OpenGL translate and scale parameter?
这是我的主要课程:
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 类)应该是获取触摸事件的类.所以你应该添加这个方法:
Your GLSurfaceView (Stage class) should be the class that gets touch events. So you should add this method to it:
@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 之前添加它):
And remember that you have scaled the virtual dimensions of your GLSurfaceView, so you should probably do the same with x and y (add this just before you start using x and y):
x = x * w / screenWidth;
y = y * h / screenHeight;
有关 MotionEvent 的更多信息(如何处理触摸向下/向上等),请参阅 此类的 Android 文档.
For more information regarding the MotionEvent (how to handle touch down/up etc) please refer to the Android documentation for this class.
更新:
对于翻译,你需要有四个成员变量:
For translation, you need to have four member variables:
- 为触摸保存 x 和 y.
- 保存了精灵的 X 和 Y.
最初将它们全部设置为无效值,例如 -1.当您收到 ACTION_DOWN 事件时,将事件 x 和 y 以及精灵 X 和 Y 保存在变量中.
Initially set all of them to an invalid value such as -1. When you get the ACTION_DOWN event, save the event x and y and sprite X and Y in the variables.
在 ACTION_MOVE 上,检查其中一个是否为 -1.如果不是,则表示您正在拖动.所以你得到新的 x 和 y 与保存的差异,并将其添加到保存的 X 和 Y.这将是你的精灵的新位置.
On ACTION_MOVE, you check one of them if it is -1. If it is not, it means you are dragging. So you get the difference of the new x and y with the saved one, and add it to saved X and Y. This will be the new position of your sprite.
在 ACTION_UP 上,只需将保存的值设置回 -1(或至少设置您在 ACTION_MOVE 上检查的值).
On ACTION_UP, simply set saved values back to -1 (or at least set the one you are checking on ACTION_MOVE).
缩放有点复杂.您需要查找指针索引 > 0 的 ACTION_POINTER_DOWN.一旦找到,您也可以保存第二个指针的值,就像翻译一样.您还需要保存精灵的原始缩放因子.然后,每当您获得 ACTION_MOVE 或 ACTION_POINTER_MOVE 时,您都会查看两个指针是否都存在(-1 的技巧),如果存在,则获取它们的区别.但这一次,差异将构成您的比例因子,而不是位置.
Scaling is a little bit more complicated. You need to look for ACTION_POINTER_DOWN with a pointer index > 0. Once you have that, you save the values of the second pointer, too, just like the translation. You also need to save the original scaling factor of the sprite. Then whenever you get ACTION_MOVE or ACTION_POINTER_MOVE, you look to see if both pointers are present (the trick with -1), and if so, get their difference. But this time the difference will constitute to your scaling factor, not the position.
这篇关于如何在 Android OpenGL ES 中应用拖放和缩放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!