上回分解-_-!,Android OpenGL射线拾取&手势旋转(一)。
3
)Renderer
:RayPickRenderer.java
OpenGL渲染器,比较多的东西都在这里面了。
- public class RayPickRenderer implements Renderer {
-
- private Context mContext;
- private Cube cube;
-
- int texture = -1;
-
- public float mfAngleX = 0.0f;
- public float mfAngleY = 0.0f;
-
- public float gesDistance = 0.0f;
-
-
- private Vector3f mvEye = new Vector3f(0, 0, 7f), mvCenter = new Vector3f(0,
- 0, 0), mvUp = new Vector3f(0, 1, 0);
-
- private OnSurfacePickedListener onSurfacePickedListener;
-
- public RayPickRenderer(Context context) {
- mContext = context;
- cube = new Cube();
- }
-
-
-
-
- @Override
- public void onDrawFrame(GL10 gl) {
-
- gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
- gl.glLoadIdentity();
-
-
- setUpCamera(gl);
-
- gl.glPushMatrix();
- {
-
- drawModel(gl);
- }
- gl.glPopMatrix();
-
-
-
-
-
-
-
-
- gl.glPushMatrix();
- {
-
- drawPickedTriangle(gl);
- }
- gl.glPopMatrix();
-
- updatePick();
- }
-
-
-
-
-
-
- private void setUpCamera(GL10 gl) {
-
- gl.glMatrixMode(GL10.GL_MODELVIEW);
- gl.glLoadIdentity();
-
-
- Matrix4f.gluLookAt(mvEye, mvCenter, mvUp, AppConfig.gMatView);
- gl.glLoadMatrixf(AppConfig.gMatView.asFloatBuffer());
- }
-
-
-
-
- private Matrix4f matRot = new Matrix4f();
- private Vector3f point;
-
-
-
-
- private void drawModel(GL10 gl) {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- matRot.setIdentity();
-
-
- point = new Vector3f(mfAngleX, mfAngleY, 0);
-
- try {
-
- matInvertModel.set(AppConfig.gMatModel);
- matInvertModel.invert();
- matInvertModel.transform(point, point);
-
- float d = Vector3f.distance(new Vector3f(), point);
-
-
- if (Math.abs(d - gesDistance) <= 1E-4) {
-
-
- matRot.glRotatef((float) (gesDistance * Math.PI / 180), point.x
- / d, point.y / d, point.z / d);
-
-
- if (0 != gesDistance) {
- AppConfig.gMatModel.mul(matRot);
- }
- }
- } catch (Exception e) {
-
- }
- gesDistance = 0;
-
- gl.glMultMatrixf(AppConfig.gMatModel.asFloatBuffer());
-
-
- gl.glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
-
- gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
-
- gl.glEnable(GL10.GL_TEXTURE_2D);
- gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
- gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
-
- gl.glVertexPointer(3, GL10.GL_FLOAT, 0,
- cube.getCoordinate(Cube.VERTEX_BUFFER));
- gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0,
- cube.getCoordinate(Cube.TEXTURE_BUFFER));
- gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 24, GL10.GL_UNSIGNED_BYTE,
- cube.getIndices());
-
- gl.glDisable(GL10.GL_TEXTURE_2D);
- gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
- gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
-
-
- drawCoordinateSystem(gl);
- }
-
- private Vector3f transformedSphereCenter = new Vector3f();
- private Ray transformedRay = new Ray();
- private Matrix4f matInvertModel = new Matrix4f();
- private Vector3f[] mpTriangle = { new Vector3f(), new Vector3f(),
- new Vector3f() };
- private FloatBuffer mBufPickedTriangle = IBufferFactory
- .newFloatBuffer(3 * 3);
-
-
-
-
- private void updatePick() {
- if (!AppConfig.gbNeedPick) {
- return;
- }
- AppConfig.gbNeedPick = false;
-
- PickFactory.update(AppConfig.gScreenX, AppConfig.gScreenY);
-
- Ray ray = PickFactory.getPickRay();
-
-
- AppConfig.gMatModel.transform(cube.getSphereCenter(),
- transformedSphereCenter);
-
-
- cube.surface = -1;
-
-
-
- if (ray.intersectSphere(transformedSphereCenter, cube.getSphereRadius())) {
-
-
-
-
-
- matInvertModel.set(AppConfig.gMatModel);
- matInvertModel.invert();
-
- ray.transform(matInvertModel, transformedRay);
-
- if (cube.intersect(transformedRay, mpTriangle)) {
-
- AppConfig.gbTrianglePicked = true;
-
- Log.i("触碰的立方体面", "=标记=" + cube.surface);
-
- if (null != onSurfacePickedListener) {
- onSurfacePickedListener.onSurfacePicked(cube.surface);
- }
-
- mBufPickedTriangle.clear();
- for (int i = 0; i < 3; i++) {
- IBufferFactory
- .fillBuffer(mBufPickedTriangle, mpTriangle[i]);
-
-
- }
- mBufPickedTriangle.position(0);
- }
- } else {
- AppConfig.gbTrianglePicked = false;
- }
- }
-
-
-
-
- private void drawPickedTriangle(GL10 gl) {
- if (!AppConfig.gbTrianglePicked) {
- return;
- }
-
-
-
- gl.glMultMatrixf(AppConfig.gMatModel.asFloatBuffer());
-
- gl.glColor4f(1.0f, 0.0f, 0.0f, 0.7f);
-
- gl.glEnable(GL10.GL_BLEND);
- gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
-
- gl.glDisable(GL10.GL_DEPTH_TEST);
- gl.glDisable(GL10.GL_TEXTURE_2D);
-
- gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
-
- gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mBufPickedTriangle);
-
- gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
-
- gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
- gl.glEnable(GL10.GL_DEPTH_TEST);
- gl.glDisable(GL10.GL_BLEND);
- }
-
-
-
-
- private void drawCoordinateSystem(GL10 gl) {
-
- gl.glDisable(GL10.GL_DEPTH_TEST);
-
- gl.glLineWidth(2.0f);
-
- gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
-
- FloatBuffer fb = IBufferFactory.newFloatBuffer(3 * 2);
- fb.put(new float[] { 0, 0, 0, 1.4f, 0, 0 });
- fb.position(0);
-
-
- gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
- gl.glVertexPointer(3, GL10.GL_FLOAT, 0, fb);
-
- gl.glDrawArrays(GL10.GL_LINES, 0, 2);
-
- fb.clear();
- fb.put(new float[] { 0, 0, 0, 0, 1.4f, 0 });
- fb.position(0);
-
- gl.glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
- gl.glVertexPointer(3, GL10.GL_FLOAT, 0, fb);
-
- gl.glDrawArrays(GL10.GL_LINES, 0, 2);
-
- fb.clear();
- fb.put(new float[] { 0, 0, 0, 0, 0, 1.4f });
- fb.position(0);
-
- gl.glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
- gl.glVertexPointer(3, GL10.GL_FLOAT, 0, fb);
-
- gl.glDrawArrays(GL10.GL_LINES, 0, 2);
-
-
- gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
- gl.glLineWidth(1.0f);
- gl.glEnable(GL10.GL_DEPTH_TEST);
- }
-
-
-
-
- @Override
- public void onSurfaceCreated(GL10 gl, EGLConfig config) {
-
- gl.glEnable(GL10.GL_DITHER);
-
- gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
-
-
- gl.glClearColor(0.5f, 0.5f, 0.5f, 1);
-
- gl.glShadeModel(GL10.GL_SMOOTH);
-
-
- gl.glEnable(GL10.GL_CULL_FACE);
- gl.glCullFace(GL10.GL_BACK);
-
- gl.glEnable(GL10.GL_DEPTH_TEST);
-
- gl.glDisable(GL10.GL_LIGHTING);
- gl.glDisable(GL10.GL_BLEND);
-
- loadTexture(gl);
-
- AppConfig.gMatModel.setIdentity();
- }
-
-
-
-
- @Override
- public void onSurfaceChanged(GL10 gl, int width, int height) {
-
- gl.glViewport(0, 0, width, height);
- AppConfig.gpViewport[0] = 0;
- AppConfig.gpViewport[1] = 0;
- AppConfig.gpViewport[2] = width;
- AppConfig.gpViewport[3] = height;
-
-
- float ratio = (float) width / height;
- gl.glMatrixMode(GL10.GL_PROJECTION);
- gl.glLoadIdentity();
-
- Matrix4f.gluPersective(45.0f, ratio, 1, 10, AppConfig.gMatProject);
- gl.glLoadMatrixf(AppConfig.gMatProject.asFloatBuffer());
- AppConfig.gMatProject.fillFloatArray(AppConfig.gpMatrixProjectArray);
-
- gl.glMatrixMode(GL10.GL_MODELVIEW);
- }
-
- private void loadTexture(GL10 gl) {
-
-
- gl.glClearDepthf(1.0f);
-
- gl.glEnable(GL10.GL_TEXTURE_2D);
-
- try {
- IntBuffer intBuffer = IntBuffer.allocate(1);
-
- gl.glGenTextures(1, intBuffer);
- texture = intBuffer.get();
-
- gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
-
-
- InputStream is = mContext.getResources().openRawResource(
- R.drawable.snow_leopard);
- Bitmap mBitmap = BitmapFactory.decodeStream(is);
-
-
-
- GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0);
-
-
- gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
- GL10.GL_LINEAR);
- gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
- GL10.GL_LINEAR);
-
- is.close();
- } catch (IOException e) {
-
- e.printStackTrace();
- }
- }
-
- public void setOnSurfacePickedListener(
- OnSurfacePickedListener onSurfacePickedListener) {
- this.onSurfacePickedListener = onSurfacePickedListener;
- }
-
- }
4
)主Activity
:RayPickActivity
继承各面点击的监听接口,提示了个Toast就OK了。很简单,当时都没注释。
- public class RayPickActivity extends Activity implements
- OnSurfacePickedListener {
-
- private GLSurfaceView mGLSurfaceView;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- mGLSurfaceView = new MyGLSurfaceView(this, this);
- mGLSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
- setContentView(mGLSurfaceView);
- mGLSurfaceView.requestFocus();
- mGLSurfaceView.setFocusableInTouchMode(true);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- mGLSurfaceView.onResume();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- mGLSurfaceView.onPause();
- }
-
- private Handler myHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- Toast.makeText(RayPickActivity.this, "选中了" + msg.what + "面",
- Toast.LENGTH_SHORT).show();
- }
- };
-
- @Override
- public void onSurfacePicked(int which) {
- myHandler.sendEmptyMessage(which);
- }
-
- }
5
)Matrix4f
内的glRotatef(…)
方法
公式如下图,其中其中C为cosθ,S为sinθ,A为单位化的旋转轴。
![rotate.jpg]()
但这是左手坐标系下的公式,之前有改过右手坐标系的但不能实现效果。其他几个绕X、Y、Z轴的也是这样。
这应该是因为OpenGL坐标系原点在左下角,而窗口坐标系的原点为右上角,程序在Y轴上做了修正的关系导致的。这次可以高抬左手,大拇指向右、食指向下、弯曲中指90°,是不是各正轴都对应上了呢^^。
-
-
-
- public final void glRotatef(float angle, float x, float y, float z) {
- float sinAngle, cosAngle;
-
- sinAngle = (float) Math.sin((double) angle);
- cosAngle = (float) Math.cos((double) angle);
-
- this.m00 = cosAngle + (1 - cosAngle) * x * x;
- this.m01 = (1 - cosAngle) * x * y - sinAngle * z;
- this.m02 = (1 - cosAngle) * x * z + sinAngle * y;
- this.m03 = 0;
-
- this.m10 = (1 - cosAngle) * x * y + sinAngle * z;
- this.m11 = cosAngle + (1 - cosAngle) * y * y;
- this.m12 = (1 - cosAngle) * y * z - sinAngle * x;
- this.m13 = 0;
-
- this.m20 = (1 - cosAngle) * x * z - sinAngle * y;
- this.m21 = (1 - cosAngle) * y * z + sinAngle * x;
- this.m22 = cosAngle + (1 - cosAngle) * z * z;
- this.m23 = 0;
-
- this.m30 = 0;
- this.m31 = 0;
- this.m32 = 0;
- this.m33 = 1;
- }
三、后记
小弟那时做这个,貌似是为了做个3D魔方啊。然后无聊可以在那转啊转啊的,不过愿望很美好……总之,我没做下去,忘记当时又忙活啥去了T^T。
现在也没这个激情继续做这个呢,希望这篇文档能给那些有同样想法的人给予一定的帮助吧,加油^^。