Раздел собственных объектов на ощупь в OpenGL - PullRequest
1 голос
/ 20 декабря 2011

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

У меня есть собственный класс для всех моих сеток, поэтому SimplePlane расширяет сетку.Здесь вы можете увидеть метод 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 моего рендерера:

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    

    }

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

1 Ответ

1 голос
/ 20 декабря 2011

Сначала получите точку, где пользователь коснулся экрана, используя 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 = ближняя плоскость), где пользователь коснулся.Вы можете создать луч, используя его и точку «глаза» камеры, а затем определить, какие объекты в вашем трехмерном мире пересек луч, чтобы определить, какие объекты выбрал пользователь *:

    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% работает, но реальное решение будет выглядеть примерно так

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

...