我使用OpenGL2.0创建了一个3D可旋转立方体。现在我想让它显示每个脸部的名称,如果我们触摸特定的脸部。例如,我们旋转立方体并将底面显示为正面。然后我们触摸或点击这个脸,会出现一个提示,告诉我们它是“底面”。
任何人都知道如何做到这一点?由于我只需要这个简单的功能,如果解决方案很简单,那就更好了。非常感谢!
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);
}
}
渲染器:
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
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
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);
}
}
答案 0 :(得分:0)
所以它出现在你的代码中,
mDeltaX;
mDeltaY;
用作旋转立方体的临时变量(每帧重置为0.0)。 除了这些变量之外,还要创建两个变量
mTotalDeltaX;
mTotalDeltaY;
而不是将它们重置为0.0,让它们累积X中的整个变化并在Y中变化。
使用这些变量,您现在可以知道相对于X轴和Y轴完全旋转了多少。现在,您只需要使用基于这两个变量的多个if语句来确定当前正在查看哪个面。
例如,如果
mTotalDeltaX = 0.0;
mTotalDeltaY = 0.0;
你知道你正在看立方体的第一面,因为它根本没有被旋转过。
如果您无法确定mTotalDeltaX和mTotalDeltaY的哪些值会为您提供正确的面部,我建议您使用logcat来帮助您确定mTotalDeltaX和mTotalDeltaY的哪些值显示哪些面。将此行放在onDrawFrame():
中Log.d("DEBUG", Float.toString(mTotalDeltaX) + " " + Float.toString(mTotalDeltaY));
在旋转多维数据集时,查看logcat并查看mTotalDeltaX和mTotalDeltaY是什么。记下这些数字,并相应地创建一系列if语句。
重要说明:使用模数运算符可防止mTotalDeltaX和mTotalDeltaY为负数或超过360度。这将允许使用该范围内的if语句。例如,在更新了mTotalDeltaX和mTotalDeltaY后,
mTotalDeltaX += mDeltaX;
mTotalDeltaY += mDeltaY;
应用模数运算符
mTotalDeltaX = mTotalDeltaX % 360;
mTotalDeltaY = mTotalDeltaY % 360;
编辑:在回答下面的新问题时,要在检测到ACTION_DOWN时进入Toast:
在MyGLSurfaceView.java的底部,您将上下文作为参数传递。将该上下文保存到另一个上下文变量中
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);
}
现在,在您的ACTION_DOWN中,您已经评论过您想要祝酒,
Toast.makeText(myContext, "text", Toast.LENGTH_SHORT).show();