简体   繁体   English

如何在OpenGL 2.0,Android中指示3D可旋转立方体的每个面

[英]How to indicate each face of a 3D rotatable Cube in OpenGL 2.0, Android

I created a 3D rotatable cube using OpenGL2.0. 我使用OpenGL2.0创建了3D可旋转立方体。 Now I want it to show the name of each face if we touch a particular face. 现在,我希望它显示每张面孔的名称(如果我们触摸特定的面孔)。 For example, we rotate the cube and show the bottom face as the front. 例如,我们旋转立方体并将底面显示为正面。 Then we touch or click this face, a prompt will appear and tell us that it is the "bottom face". 然后,我们触摸或单击此面孔,将出现提示,告诉我们这是“底部面孔”。

Anybody has an idea of how to do this? 有人知道如何执行此操作吗? Since I just need this simple feature, if the solution is easy, that would be better. 因为我只需要这个简单的功能,所以如果解决方案很简单,那会更好。 Thank you so much! 非常感谢!

public class MyCube {
private FloatBuffer vertexBuffer;
private ShortBuffer drawListBuffer;
private ShortBuffer[] ArrayDrawListBuffer;
private FloatBuffer colorBuffer;

private int mProgram;

//For Projection and Camera Transformations
private final String vertexShaderCode =
        // This matrix member variable provides a hook to manipulate
        // the coordinates of the objects that use this vertex shader
        "uniform mat4 uMVPMatrix;" +
                "attribute vec4 vPosition;" +
                //"attribute vec4 vColor;" +
                //"varying vec4 vColorVarying;" +
                "void main() {" +
                // the matrix must be included as a modifier of gl_Position
                // Note that the uMVPMatrix factor *must be first* in order
                // for the matrix multiplication product to be correct.
                "  gl_Position = uMVPMatrix * vPosition;" +
                //"vColorVarying = vColor;"+
                "}";

// Use to access and set the view transformation
private int mMVPMatrixHandle;

private final String fragmentShaderCode =
        "precision mediump float;" +
                "uniform vec4 vColor;" +
                //"varying vec4 vColorVarying;"+
                "void main() {" +
                //"  gl_FragColor = vColorVarying;" +
                "  gl_FragColor = vColor;" +
                "}";

// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
float cubeCoords[] = {
        -0.5f, 0.5f, 0.5f,   // front top left 0
        -0.5f, -0.5f, 0.5f,   // front bottom left 1
        0.5f, -0.5f, 0.5f,   // front bottom right 2
        0.5f, 0.5f, 0.5f,  // front top right 3
        -0.5f, 0.5f, -0.5f,   // back top left 4
        0.5f, 0.5f, -0.5f,   // back top right 5
        -0.5f, -0.5f, -0.5f,   // back bottom left 6
        0.5f, -0.5f, -0.5f,  // back bottom right 7
        };


// Set color with red, green, blue and alpha (opacity) values
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
float red[] = { 1.0f, 0.0f, 0.0f, 1.0f };
float blue[] = { 0.0f, 0.0f, 1.0f, 1.0f };

private short drawOrder[][] = {
                                {0, 1, 2, 0, 2, 3},//front
                                {0, 4, 5, 0, 5, 3}, //Top
                                {0, 1, 6, 0, 6, 4}, //left
                                {3, 2, 7, 3, 7 ,5}, //right
                                {1, 2, 7, 1, 7, 6}, //bottom
                                {4, 6, 7, 4, 7, 5} //back
                                }; //(order to draw vertices)


final float cubeColor3[][] =
        {
                // Front face (red)
                {1.0f, 0.0f, 0.0f, 1.0f,
                1.0f, 0.0f, 0.0f, 1.0f,
                1.0f, 0.0f, 0.0f, 1.0f,
                1.0f, 0.0f, 0.0f, 1.0f,
                1.0f, 0.0f, 0.0f, 1.0f,
                1.0f, 0.0f, 0.0f, 1.0f},

                // Top face (green)
                {0.0f, 1.0f, 0.0f, 1.0f,
                0.0f, 1.0f, 0.0f, 1.0f,
                0.0f, 1.0f, 0.0f, 1.0f,
                0.0f, 1.0f, 0.0f, 1.0f,
                0.0f, 1.0f, 0.0f, 1.0f,
                0.0f, 1.0f, 0.0f, 1.0f},

                // Left face (blue)
                {0.0f, 0.0f, 1.0f, 1.0f,
                0.0f, 0.0f, 1.0f, 1.0f,
                0.0f, 0.0f, 1.0f, 1.0f,
                0.0f, 0.0f, 1.0f, 1.0f,
                0.0f, 0.0f, 1.0f, 1.0f,
                0.0f, 0.0f, 1.0f, 1.0f},

                // Right face (yellow)
                {1.0f, 1.0f, 0.0f, 1.0f,
                1.0f, 1.0f, 0.0f, 1.0f,
                1.0f, 1.0f, 0.0f, 1.0f,
                1.0f, 1.0f, 0.0f, 1.0f,
                1.0f, 1.0f, 0.0f, 1.0f,
                1.0f, 1.0f, 0.0f, 1.0f},

                // Bottom face (cyan)
                {0.0f, 1.0f, 1.0f, 1.0f,
                0.0f, 1.0f, 1.0f, 1.0f,
                0.0f, 1.0f, 1.0f, 1.0f,
                0.0f, 1.0f, 1.0f, 1.0f,
                0.0f, 1.0f, 1.0f, 1.0f,
                0.0f, 1.0f, 1.0f, 1.0f},

                // Back face (magenta)
                {1.0f, 0.0f, 1.0f, 1.0f,
                1.0f, 0.0f, 1.0f, 1.0f,
                1.0f, 0.0f, 1.0f, 1.0f,
                1.0f, 0.0f, 1.0f, 1.0f,
                1.0f, 0.0f, 1.0f, 1.0f,
                1.0f, 0.0f, 1.0f, 1.0f}
        };



public MyCube() {
    // initialize vertex byte buffer for shape coordinates
    ByteBuffer bb = ByteBuffer.allocateDirect(
            // (# of coordinate values * 4 bytes per float)
           cubeCoords.length * 4);
    bb.order(ByteOrder.nativeOrder());
    vertexBuffer = bb.asFloatBuffer();
    vertexBuffer.put(cubeCoords);
    vertexBuffer.position(0);


    int vertexShader = MyRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
            vertexShaderCode);
    int fragmentShader = MyRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
            fragmentShaderCode);

    // create empty OpenGL ES Program
    mProgram = GLES20.glCreateProgram();

    // add the vertex shader to program
    GLES20.glAttachShader(mProgram, vertexShader);

    // add the fragment shader to program
    GLES20.glAttachShader(mProgram, fragmentShader);

    // creates OpenGL ES program executables
    GLES20.glLinkProgram(mProgram);
}

private int mPositionHandle;
private int mColorHandle;

private final int vertexCount = cubeCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

public void draw(float[] mvpMatrix) { // pass in the calculated transformation matrix


    // Draw the cube
    for (int face = 0; face < 6; face++) {

        // Add program to OpenGL ES environment
        GLES20.glUseProgram(mProgram);

        // get handle to vertex shader's vPosition member
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        // get handle to fragment shader's vColor member

        //mColorHandle = GLES20.glGetAttribLocation(mProgram, "vColor");
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

        // Enable a handle to the cube vertices
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        // Prepare the cube coordinate data
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                vertexStride, vertexBuffer);
        // initialize byte buffer for the draw list
        ByteBuffer dlb = ByteBuffer.allocateDirect(
                // (# of coordinate values * 2 bytes per short)
                drawOrder[face].length * 2);
        dlb.order(ByteOrder.nativeOrder());
        drawListBuffer = dlb.asShortBuffer();
        drawListBuffer.put(drawOrder[face]);
        drawListBuffer.position(0);

        GLES20.glUniform4fv(mColorHandle, 1, cubeColor3[face], 0);

        // get handle to shape's transformation matrix
        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");

        // Pass the projection and view transformation to the shader
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder[face].length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
    }


    // Disable vertex array
    GLES20.glDisableVertexAttribArray(mMVPMatrixHandle);
  }
}

Renderer: 渲染器:

public class MyRenderer implements GLSurfaceView.Renderer{

private MyCube mCube;

// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
//create another transformation matrix (a rotation matrix)
private float[] mRotationMatrix = new float[16];

/** Store the accumulated rotation. */
private final float[] mAccumulatedRotation = new float[16];
/** Store the current rotation. */
private final float[] mCurrentRotation = new float[16];
/** Create a temporary matrix. */
private final float[] mTemporaryMatrix = new float[16];



public void onSurfaceCreated(GL10 unused, EGLConfig config) {
    // Set the background frame color
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    GLES20.glEnable(GLES20.GL_DEPTH_TEST);

    // initialize a square
    mCube = new MyCube();

    // Initialize the accumulated rotation matrix
    Matrix.setIdentityM(mAccumulatedRotation, 0);
}

public void onDrawFrame(GL10 unused) {
    // Redraw background color
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

    float[] scratch = new float[16];
    // Create a rotation transformation for the square
    Matrix.setIdentityM(mRotationMatrix, 0);
    Matrix.setIdentityM(mCurrentRotation, 0);
    Matrix.rotateM(mCurrentRotation, 0, mDeltaX, 0.0f, 1.0f, 0.0f);
    Matrix.rotateM(mCurrentRotation, 0, mDeltaY, 1.0f, 0.0f, 0.0f);
    mDeltaX = 0.0f;
    mDeltaY = 0.0f;

    // Multiply the current rotation by the accumulated rotation, and then set the accumulated
    // rotation to the result.
    Matrix.multiplyMM(mTemporaryMatrix, 0, mCurrentRotation, 0, mAccumulatedRotation, 0);
    System.arraycopy(mTemporaryMatrix, 0, mAccumulatedRotation, 0, 16);

    // Rotate the cube taking the overall rotation into account.
    Matrix.multiplyMM(mTemporaryMatrix, 0, mRotationMatrix, 0, mAccumulatedRotation, 0);
    System.arraycopy(mTemporaryMatrix, 0, mRotationMatrix, 0, 16);



    // Set the camera position (View matrix)
    Matrix.setLookAtM(mViewMatrix, 0, -2, 2, 5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

    //Calculate the projection and view transformation
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);

    // Combine the rotation matrix with the projection and camera view
    // Note that the mMVPMatrix factor *must be first* in order
    // for the matrix multiplication product to be correct.
    Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);

    // Draw shape
    mCube.draw(scratch);
}


@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
    GLES20.glViewport(0, 0, width, height);

    float ratio = (float) width / height;

    // this projection matrix is applied to object coordinates
    // in the onDrawFrame() method
    Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}

public static int loadShader(int type, String shaderCode){

    // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
    // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
    int shader = GLES20.glCreateShader(type);

    // add the source code to the shader and compile it
    GLES20.glShaderSource(shader, shaderCode);
    GLES20.glCompileShader(shader);

    return shader;
}

public volatile float mDeltaX;
public volatile float mDeltaY;
}
}

MyActivity.java MyActivity.java

public class MyActivity extends Activity {
private MyGLSurfaceView mGLView;

public void showToast(final String toast) {
    runOnUiThread(new Runnable() {
        public void run() {
            Toast.makeText(MyActivity.this, toast, Toast.LENGTH_SHORT).show();
        }
    });
}



@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Create a GLSurfaceView instance and set it
    // as the ContentView for this Activity.
    mGLView = new MyGLSurfaceView(this);
    setContentView(mGLView);

    //LinearLayout ll = new LinearLayout(this);
    Button b = new Button(this);
    b.setText("hello world");
    //ll.addView(b);
    //ll.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
    this.addContentView(b,
            new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
}

MyGLSurfaceView.java MyGLSurfaceView.java

public class MyGLSurfaceView extends GLSurfaceView {

private final MyRenderer mRenderer;

private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
private float mPreviousX;
private float mPreviousY;


float touchedX = 0;
float touchedY = 0;


@Override
public boolean onTouchEvent(MotionEvent event) {
    // MotionEvent reports input details from the touch screen
    // and other input controls. In this case, you are only
    // interested in events where the touch position changed.

    if (event != null) {
        float x = event.getX();
        float y = event.getY();

        if (event.getAction() == MotionEvent.ACTION_MOVE) {

            if (mRenderer != null) {
                float deltaX = (x - mPreviousX) / 2f;
                float deltaY = (y - mPreviousY) / 2f;

                mRenderer.mDeltaX += deltaX;
                mRenderer.mDeltaY += deltaY;
                mRenderer.mTotalDeltaX += mRenderer.mDeltaX;
                mRenderer.mTotalDeltaY += mRenderer.mDeltaY;
                mRenderer.mTotalDeltaX = mRenderer.mTotalDeltaX % 360;
                mRenderer.mTotalDeltaY = mRenderer.mTotalDeltaY % 360;

            }
            requestRender();
        }
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (event.getX() < 950f && event.getX() > 150f && event.getX() < 1300f && event.getX() > 400f) {
                Log.d("DEBUG", Float.toString(mRenderer.mTotalDeltaX) + " " + Float.toString(mRenderer.mTotalDeltaY));
                Log.d("DEBUG", Float.toString(event.getX()) + " " + Float.toString(event.getY()));
//***Here is where I want to add toast*** Thank you so much!///

            } else {

            }
        }


        mPreviousX = x;
        mPreviousY = y;

        return true;
    } else {
        return super.onTouchEvent(event);
    }
}






public MyGLSurfaceView(Context context){
    super(context);

    // Create an OpenGL ES 2.0 context
    setEGLContextClientVersion(2);

    mRenderer = new MyRenderer();

    // Set the Renderer for drawing on the GLSurfaceView
    setRenderer(mRenderer);

    // Render the view only when there is a change in the drawing data.
    // To allow the Square to rotate automatically, this line is commented out:
    //setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}

} }

So it appears in your code that you have, 所以它在您的代码中显示出来,

mDeltaX;
mDeltaY;

which act as temporary variables for rotating the cube (you reset them to 0.0 each frame). 用作旋转多维数据集的临时变量(您将它们重置为每帧0.0)。 In addition to these variables, create two variables, 除了这些变量,还创建两个变量,

mTotalDeltaX;
mTotalDeltaY;

and instead of resetting them to 0.0, let them accumulate the entire change in X and change in Y. 而不是将它们重置为0.0,而是让它们累积X和Y的全部变化。

With these variables, you now know how much you have rotated totally relative to the X-axis and Y-axis. 使用这些变量,您现在知道相对于X轴和Y轴完全旋转了多少。 Now, you just need to use several if-statements based on these two variables to determine which face is currently in view. 现在,您只需要使用基于这两个变量的多个if语句来确定当前在看哪张脸。

For example, if 例如,如果

mTotalDeltaX = 0.0;
mTotalDeltaY = 0.0;

you know that you are looking at the 1st face of the cube, since it hasn't been rotated at all. 您知道您正在看立方体的第一个面,因为它根本没有旋转。

If you are unable to determine what values of mTotalDeltaX and mTotalDeltaY would give you the correct face, I suggest that you use logcat to help you as you figure out what values of mTotalDeltaX and mTotalDeltaY show which faces. 如果您无法确定mTotalDeltaX和mTotalDeltaY的值将为您提供正确的面孔,建议您使用logcat来帮助您确定mTotalDeltaX和mTotalDeltaY的值显示哪些面孔。 Put this line in onDrawFrame(): 将此行放在onDrawFrame()中:

Log.d("DEBUG", Float.toString(mTotalDeltaX) + " " + Float.toString(mTotalDeltaY));

As you rotate your cube, look at your logcat and see what mTotalDeltaX and mTotalDeltaY are. 旋转多维数据集时,请查看logcat并查看mTotalDeltaX和mTotalDeltaY。 Record these numbers down, and create a series of if statements accordingly. 记下这些数字,并相应地创建一系列if语句。

Important note: Use the modulus operator to prevent mTotalDeltaX and mTotalDeltaY from being negative or over 360 degrees. 重要说明:使用模数运算符可防止mTotalDeltaX和mTotalDeltaY为负或超过360度。 This will allow to use if statements within that range. 这将允许使用该范围内的if语句。 For example, after you have updated mTotalDeltaX and mTotalDeltaY, 例如,更新mTotalDeltaX和mTotalDeltaY之后,

mTotalDeltaX += mDeltaX;
mTotalDeltaY += mDeltaY;

apply the modulus operator, 应用模运算符,

mTotalDeltaX = mTotalDeltaX % 360;
mTotalDeltaY = mTotalDeltaY % 360;

EDIT: In response to your new question below, to make a Toast in when ACTION_DOWN is detected: 编辑:响应下面您的新问题,在检测到ACTION_DOWN时举杯:

At the bottom of your MyGLSurfaceView.java, you have the context being passed as a parameter. 在MyGLSurfaceView.java的底部,您将上下文作为参数传递。 Save that context, into another context variable, 将该上下文保存到另一个上下文变量中,

Context myContext;

public MyGLSurfaceView(Context context){
super(context);
myContext = context;

// Create an OpenGL ES 2.0 context
setEGLContextClientVersion(2);

mRenderer = new MyRenderer();

// Set the Renderer for drawing on the GLSurfaceView
setRenderer(mRenderer);

// Render the view only when there is a change in the drawing data.
// To allow the Square to rotate automatically, this line is commented out:
//setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}

Now, in your ACTION_DOWN, where you have commented that you want your toast, 现在,在您的ACTION_DOWN中,您已评论要烤面包,

Toast.makeText(myContext, "text", Toast.LENGTH_SHORT).show();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM