У меня есть несколько самолетов на моем OpenGlSurfaceView. Теперь я хочу определить, коснулся ли самолет. Я нашел несколько тем в stackoverflow и на других форумах, но я не знаю, как с ними бороться. Может, кто-нибудь может мне помочь.
Мои самолеты - все это:
public SimplePlane() {
float textureCoordinates[] = {
0.0f, 1.0f, //
1.0f, 1.0f, //
0.0f, 0.0f, //
1.0f, 0.0f, //
};
short[] indices = new short[] {
0, 1,
2, 1,
3, 2 };
float[] vertices = new float[] {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f };
setIndices(indices);
setVertices(vertices);
setTextureCoordinates(textureCoordinates);
}
У меня есть собственный класс для всех моих Mesh, поэтому SimplePlane расширяет Mesh. Здесь вы можете увидеть метод draw в классе Mesh:
public void draw(GL10 gl) {
gl.glFrontFace(GL10.GL_CCW);
gl.glEnable(GL10.GL_CULL_FACE);
gl.glCullFace(GL10.GL_BACK);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, verticesBuffer);
gl.glColor4f(rgba[0], rgba[1], rgba[2], rgba[3]);
if (colorBuffer != null) {
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
}
if (mShouldLoadTexture) {
loadGLTexture(gl);
mShouldLoadTexture = false;
}
if (mTextureId != -1 && mTextureBuffer != null) {
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer);
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);
}
gl.glRotatef(rx, 1, 0, 0);
gl.glRotatef(ry, 0, 1, 0);
gl.glRotatef(rz, 0, 0, 1);
gl.glTranslatef(x, y, z);
gl.glDrawElements(GL10.GL_TRIANGLES, numOfIndices,
GL10.GL_UNSIGNED_SHORT, indicesBuffer);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
if (mTextureId != -1 && mTextureBuffer != null) {
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
gl.glDisable(GL10.GL_CULL_FACE);
}
И что метод onDrawFrame моего Renderer:
public void onDrawFrame(GL10 gl) {
gl.glClearColor(_red, _green, _blue, 0.0f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
GLU.gluLookAt(gl, 0,0,0, 0,0,0, 0,0,0);
gl.glLoadIdentity();
gl.glRotatef(_ry, 0f, 1f, 0f);
root.draw(gl); // a group of meshes
}
Но теперь я не знаю, как я могу начать ощущать прикосновение своего самолета. Я много читаю о выборе цвета или наборе лучей, но я не знаю, где я должен начать в своем коде для его реализации.
Сначала найдите точку, где пользователь коснулся экрана, используя myGLSurfaceView.setOnTouchListener(new MyOnTouchListener())
(где myOnTouchListener реализует OnTouchListener).
Затем вам нужно получить классы MatrixGrabber, MatrixStack, MatrixTracking из демонстрации API (C:\android-sdk\samples\android-7\ApiDemos\src\com\example\android\apis\graphics\spritetext).
Затем, чтобы использовать MatrixGrabber, сначала прикрепите его как оболочку к вашему GLSurfaceView:
public class GraphicsEngine extends Activity {
protected GLSurfaceView mGLView;
protected GraphicsRenderer graphicsRenderer;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.graphics);
graphicsRenderer = new GraphicsRenderer(this);
mGLView = (GLSurfaceView) findViewById(R.id.graphics_glsurfaceview1);
// ------
// THIS BIT HERE
mGLView.setGLWrapper(new GLSurfaceView.GLWrapper() {
public GL wrap(GL gl) {
return new MatrixTrackingGL(gl);
}});
// ------
mGLView.setEGLConfigChooser(true);
mGLView.setRenderer(graphicsRenderer);
}
Затем вы можете получить матрицы, необходимые для GLU.gluUnProject(). Этот последний метод дает вам трехмерную точку на ближней плоскости (т.е. z = near-plane), где пользователь коснулся. Вы можете создать луч, используя его и точку зрения камеры, а затем определить, какие объекты в вашем мире 3D пересекают луч, чтобы получить, какие объекты выбрал пользователь *:
MatrixGrabber matrixGrabber = new MatrixGrabber();
matrixGrabber.getCurrentModelView(gl);
matrixGrabber.getCurrentProjection(gl);
float[] vector = new float[4];
// x and y come from the x/y you get from the OnTouchListener.
// OpenGL works from the bottom left corner, so flip the y
GLU.gluUnProject(x, mGLView.getHeight()-y, 0.9f, matrixGrabber.mModelView, 0, matrixGrabber.mProjection, 0, new int[]{mGLView.getTop(),mGLView.getLeft(),mGLView.getWidth(),mGLView.getHeight()}, 0, vector, 0);
Vector3f pickPosition = new Vector3f();
if(vector[3]!=0){
pickPosition.x = vector[0] / vector[3];
pickPosition.y = vector[1] / vector[3];
pickPosition.z = vector[2] / vector[3];
}
* Этот последний фрагмент кода. Я не 100% определенных работ, но реальное решение будет выглядеть примерно так.
Изменение: обновлен последний фрагмент кода
x = mGLView.getWidth() / 2
иy = mGLView.getHeight() / 2
т.y = mGLView.getHeight() / 2
середине экрана. Это должно привести к вектору (0,0,1) = перпендикулярно плоскости экрана / ближней плоскости. Установите x там, где пользователь щелкает, но оставьте y в качестве центра экрана, и вы должны получить несколько векторов на плоскости x / z. Также вы можете нарисовать лучи на вашем экране, используяgl.glDrawElements(GL10.GL_LINE_STRIP, etc)
.gl.glDrawElements(GL10.GL_LINE_STRIP, etc)
. Если вы видите линии просто как точки или ничего, пока не начнете вращаться, то вы смотрите прямо вдоль линии, и сборка работает