Android OpenGL ES 在触摸时添加对象
我正在构建一个小型 Android 应用程序,它将在用户触摸时添加一个立方体。 z 深度始终为 -10,屏幕始终处于横向模式。这个问题似乎被问了很多次,但我无法运行它,请原谅我,因为我是 opengl 的新手。 我对与 gluUnproject 一起使用的屏幕坐标/窗口坐标/对象坐标感到非常困惑。据我了解,屏幕是用户触摸时的,我们甚至可以从运动中获得 x 和 y。窗口坐标是加载单位坐标时的坐标,对象坐标是对单位矩阵进行变换得到对象坐标时的坐标。是这样吗?
这是我的代码,矩阵堆叠来自 android api 示例。请指出我做错了什么。
绘图部分:
public void draw(GL10 gl) {
for (GLObject glObject : list) {
if (glObject != null) {
gl.glLoadIdentity();
glObject.draw(gl);
}
}
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
if (isTouching) {
boolean addObject = false;
for (GLObject glObject : list) {
addObject = glObject.checkTouch(gl, x, y);
}
if (!addObject) {
i++;
Log.d("i", i + "");
addGLObject(gl);
}
isTouching = false;
}
}
onDraw的代码
private void getMatrix(GL10 gl, int mode, float[] mat) {
GLView.matrixTrackingGL.glMatrixMode(mode);
GLView.matrixTrackingGL.getMatrix(mat, 0);
}
public void addGLObject(GL10 gl) {
float[] XY = getWorldCoordinate(gl, x, y);
if (XY != null) {
// XY[0] = (float) (x - Main.SCREEN_WIDTH / 2) / 10;
//
// XY[1] = (float) (Main.SCREEN_HEIGHT / 2 - y) / 10;
GLObject glObject = new GLObject(colors, XY[0], XY[1]);
Log.d("Object position", "X: " + XY[0] + " Y: " + XY[1]);
list.add(glObject);
}
}
private float[] getWorldCoordinate(GL10 gl, int x, int y) {
float[] modelMatrix = new float[16];
float[] projMatrix = new float[16];
int[] viewport = {0, 0, Main.SCREEN_WIDTH, Main.SCREEN_HEIGHT};
getMatrix(gl, GL10.GL_MODELVIEW, modelMatrix);
getMatrix(gl, GL10.GL_PROJECTION, projMatrix);
float[] output = new float[4];
GLU.gluUnProject(x, viewport[1] + viewport[3] - y, -10, modelMatrix, 0, projMatrix, 0, viewport, 0, output, 0);
return new float[] {output[0]/output[3], output[1]/output[3]};
}
public class GLObject {
private float[] vertices = { 1.000000f, 1.000000f, -1.000000f, 1.000000f,
-1.000000f, -1.000000f, -1.000000f, -1.000000f, -1.000000f,
-1.000000f, 1.000000f, -1.000000f, 1.000000f, 1.000000f, 1.000000f,
1.000000f, -1.000001f, 1.000000f, -1.000000f, -1.000000f,
1.000000f, -1.000000f, 1.000000f, 1.000000f, };
private short[] faces = { 0, 1, 2, 0, 2, 3, 4, 7, 6, 4, 6, 5, 0, 4, 5, 0,
5, 1, 1, 5, 6, 1, 6, 2, 2, 6, 7, 2, 7, 3, 4, 0, 3, 4, 3, 7 };
private float[] colors;
private float[] rot = { 0.0f, 0.0f, 0.0f };
private Float positionX, positionY;
private int alpha = 0;
// Our vertex buffer.
private FloatBuffer vertexBuffer;
// Our index buffer.
private ShortBuffer faceBuffer;
public GLObject() {
init();
}
public GLObject(float[] colors, float x, float y) {
this.colors = colors.clone();
this.positionX = x;
this.positionY = y;
if (positionX.intValue() % 2 == 0) {
rot[0] = 1.0f;
} else {
if (positionY.intValue() % 2 == 0) {
rot[1] = 1.0f;
} else {
rot[2] = 1.0f;
}
}
init();
}
private void init() {
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
ByteBuffer ibb = ByteBuffer.allocateDirect(faces.length * 2);
ibb.order(ByteOrder.nativeOrder());
faceBuffer = ibb.asShortBuffer();
faceBuffer.put(faces);
faceBuffer.position(0);
}
public boolean checkTouch(GL10 gl, int x, int y) {
boolean isTouched = false;
ByteBuffer pixels = ByteBuffer.allocate(4);
gl.glReadPixels(x, Main.SCREEN_HEIGHT - y, 1, 1, GL10.GL_RGBA,
GL10.GL_UNSIGNED_BYTE, pixels);
Log.d("COLOR",
pixels.get(0) + " " + pixels.get(1) + " " + pixels.get(2) + " "
+ pixels.get(3));
// isTouched always false to test always add object to screen
return isTouched;
}
public void draw(GL10 gl) {
// Counter-clockwise winding.
gl.glFrontFace(GL10.GL_CCW); // OpenGL docs
// Enable face culling.
gl.glEnable(GL10.GL_CULL_FACE); // OpenGL docs
// What faces to remove with the face culling.
gl.glCullFace(GL10.GL_BACK); // OpenGL docs
// Enabled the vertices buffer for writing and to be used during
// rendering.
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// OpenGL docs.
// Enable color
gl.glColor4f(colors[0], colors[1], colors[2], 1.0f);
// Specifies the location and data format of an array of vertex
// coordinates to use when rendering.
gl.glPushMatrix();
gl.glTranslatef(positionX, positionY, -10);
// rotate
alpha += 1;
gl.glRotatef(alpha, rot[0], rot[1], rot[2]);
// draw
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, // OpenGL docs
vertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, faces.length,// OpenGL docs
GL10.GL_UNSIGNED_SHORT, faceBuffer);
gl.glPopMatrix();
// Disable the vertices buffer.
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // OpenGL docs
// Disable face culling.
gl.glDisable(GL10.GL_CULL_FACE); // OpenGL docs
}
下面是添加对象}
:
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
// Clears the screen and depth buffer.
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | // OpenGL docs.
GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_PROJECTION);
// Reset the projection matrix
gl.glLoadIdentity();
GLU.gluPerspective(gl, 90.0f, Main.SCREEN_WIDTH/Main.SCREEN_HEIGHT, 3.0f, 100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, 4.0f, 2.0f, 1.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
// draw object
glObjectManager.draw(gl);
}
I am building a small Android application which will add a cube on user's touch. The z depth is always -10, screen is always in landscape mode. This question seems to be asked many times, but I cannot get it running, forgive me as I am newbie to opengl.
I am quite confused about the screen coordinate/window coordinate/object coordinate to use with the gluUnproject. As I understand, screen is when user touch and we get x and y from motion even. Window coordinate is when we load the identity, and object coordinate is when we transform the identity matrix to get object's coordinate. Is that right?
And here is my code, the matrix stacking is from android api sample. Please point out what I am doing wrong.
The drawing part:
public void draw(GL10 gl) {
for (GLObject glObject : list) {
if (glObject != null) {
gl.glLoadIdentity();
glObject.draw(gl);
}
}
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
if (isTouching) {
boolean addObject = false;
for (GLObject glObject : list) {
addObject = glObject.checkTouch(gl, x, y);
}
if (!addObject) {
i++;
Log.d("i", i + "");
addGLObject(gl);
}
isTouching = false;
}
}
Here is the code for adding object
private void getMatrix(GL10 gl, int mode, float[] mat) {
GLView.matrixTrackingGL.glMatrixMode(mode);
GLView.matrixTrackingGL.getMatrix(mat, 0);
}
public void addGLObject(GL10 gl) {
float[] XY = getWorldCoordinate(gl, x, y);
if (XY != null) {
// XY[0] = (float) (x - Main.SCREEN_WIDTH / 2) / 10;
//
// XY[1] = (float) (Main.SCREEN_HEIGHT / 2 - y) / 10;
GLObject glObject = new GLObject(colors, XY[0], XY[1]);
Log.d("Object position", "X: " + XY[0] + " Y: " + XY[1]);
list.add(glObject);
}
}
private float[] getWorldCoordinate(GL10 gl, int x, int y) {
float[] modelMatrix = new float[16];
float[] projMatrix = new float[16];
int[] viewport = {0, 0, Main.SCREEN_WIDTH, Main.SCREEN_HEIGHT};
getMatrix(gl, GL10.GL_MODELVIEW, modelMatrix);
getMatrix(gl, GL10.GL_PROJECTION, projMatrix);
float[] output = new float[4];
GLU.gluUnProject(x, viewport[1] + viewport[3] - y, -10, modelMatrix, 0, projMatrix, 0, viewport, 0, output, 0);
return new float[] {output[0]/output[3], output[1]/output[3]};
}
public class GLObject {
private float[] vertices = { 1.000000f, 1.000000f, -1.000000f, 1.000000f,
-1.000000f, -1.000000f, -1.000000f, -1.000000f, -1.000000f,
-1.000000f, 1.000000f, -1.000000f, 1.000000f, 1.000000f, 1.000000f,
1.000000f, -1.000001f, 1.000000f, -1.000000f, -1.000000f,
1.000000f, -1.000000f, 1.000000f, 1.000000f, };
private short[] faces = { 0, 1, 2, 0, 2, 3, 4, 7, 6, 4, 6, 5, 0, 4, 5, 0,
5, 1, 1, 5, 6, 1, 6, 2, 2, 6, 7, 2, 7, 3, 4, 0, 3, 4, 3, 7 };
private float[] colors;
private float[] rot = { 0.0f, 0.0f, 0.0f };
private Float positionX, positionY;
private int alpha = 0;
// Our vertex buffer.
private FloatBuffer vertexBuffer;
// Our index buffer.
private ShortBuffer faceBuffer;
public GLObject() {
init();
}
public GLObject(float[] colors, float x, float y) {
this.colors = colors.clone();
this.positionX = x;
this.positionY = y;
if (positionX.intValue() % 2 == 0) {
rot[0] = 1.0f;
} else {
if (positionY.intValue() % 2 == 0) {
rot[1] = 1.0f;
} else {
rot[2] = 1.0f;
}
}
init();
}
private void init() {
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
ByteBuffer ibb = ByteBuffer.allocateDirect(faces.length * 2);
ibb.order(ByteOrder.nativeOrder());
faceBuffer = ibb.asShortBuffer();
faceBuffer.put(faces);
faceBuffer.position(0);
}
public boolean checkTouch(GL10 gl, int x, int y) {
boolean isTouched = false;
ByteBuffer pixels = ByteBuffer.allocate(4);
gl.glReadPixels(x, Main.SCREEN_HEIGHT - y, 1, 1, GL10.GL_RGBA,
GL10.GL_UNSIGNED_BYTE, pixels);
Log.d("COLOR",
pixels.get(0) + " " + pixels.get(1) + " " + pixels.get(2) + " "
+ pixels.get(3));
// isTouched always false to test always add object to screen
return isTouched;
}
public void draw(GL10 gl) {
// Counter-clockwise winding.
gl.glFrontFace(GL10.GL_CCW); // OpenGL docs
// Enable face culling.
gl.glEnable(GL10.GL_CULL_FACE); // OpenGL docs
// What faces to remove with the face culling.
gl.glCullFace(GL10.GL_BACK); // OpenGL docs
// Enabled the vertices buffer for writing and to be used during
// rendering.
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// OpenGL docs.
// Enable color
gl.glColor4f(colors[0], colors[1], colors[2], 1.0f);
// Specifies the location and data format of an array of vertex
// coordinates to use when rendering.
gl.glPushMatrix();
gl.glTranslatef(positionX, positionY, -10);
// rotate
alpha += 1;
gl.glRotatef(alpha, rot[0], rot[1], rot[2]);
// draw
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, // OpenGL docs
vertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, faces.length,// OpenGL docs
GL10.GL_UNSIGNED_SHORT, faceBuffer);
gl.glPopMatrix();
// Disable the vertices buffer.
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // OpenGL docs
// Disable face culling.
gl.glDisable(GL10.GL_CULL_FACE); // OpenGL docs
}
}
onDraw:
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
// Clears the screen and depth buffer.
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | // OpenGL docs.
GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_PROJECTION);
// Reset the projection matrix
gl.glLoadIdentity();
GLU.gluPerspective(gl, 90.0f, Main.SCREEN_WIDTH/Main.SCREEN_HEIGHT, 3.0f, 100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, 4.0f, 2.0f, 1.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
// draw object
glObjectManager.draw(gl);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
它与横向模式无关,问题是您在 z 轴上将立方体平移 -10。尝试将值设置为 -100,所有立方体都将位于中心。然后尝试将 0 作为 z 值 (x, y, 0)。立方体将距离屏幕中心更远,并且更接近您期望的位置。
看看http://tle.tafevc.com.au/toolbox/file/9495cce8-17b5-a8a5-d9b3-47c0c142d88d/1/sketches_and_drawings_lo.zip/3204a_20_reading_drawings/images/brick_perspective.jpg透视投影的一个例子。当立方体位于 z=0 时,这就是图像中的情况。但当 z=-10 时,它更靠近屏幕中心(X)并且更小,因为它沿着蓝线延伸到地平线。
It has nothing to do with landscape mode, the problem is that you are translating your cube by -10 on the z axis. Try putting values of -100 and all the cubes will be at the center. Then try putting 0 for the z value (x, y, 0). The cubes will be much further out from the center of the screen and closer to where you expect them to be.
Look at http://tle.tafevc.com.au/toolbox/file/9495cce8-17b5-a8a5-d9b3-47c0c142d88d/1/sketches_and_drawings_lo.zip/3204a_20_reading_drawings/images/brick_perspective.jpg for an example of perspective projection. When the cube is at z=0, that is what is in the image. But when z=-10, it is closer to the center of the screen (the X) and smaller, because it follows the blue lines out to the horizon.