Раздел собственных объектов на ощупь в OpenGL

1

У меня есть несколько самолетов на моем 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    

    }

Но теперь я не знаю, как я могу начать ощущать прикосновение своего самолета. Я много читаю о выборе цвета или наборе лучей, но я не знаю, где я должен начать в своем коде для его реализации.

Теги:
opengl-es
touch
interaction

1 ответ

1

Сначала найдите точку, где пользователь коснулся экрана, используя 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% определенных работ, но реальное решение будет выглядеть примерно так.

Изменение: обновлен последний фрагмент кода

  • 0
    Хорошо, теперь я получил должность. Но на данный момент я не уверен, что это правильная позиция. Я думаю, что это выглядит хорошо .. Но как мне проверить, находится ли pickPosition внутри моей плоскости?
  • 0
    Измените x и y в gluUnproject, чтобы они были 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) . Если вы видите линии просто как точки или ничего, пока не начнете вращаться, то вы смотрите прямо вдоль линии, и сборка работает
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню