[转]Android(安卓)Opengl - Colored 3D Cube
What is this: This tutorial shows how to create colored 3D Objects using the OpenGL® ES cross-platform API.
What you learn: You will learn how easy it is, to create a Colored 3D Cube, using OpenGL® ES.
Problems/Questions: post here
Difficulty: 1.5 of 5
What it will look like:
Introduction:
Lets quote wikipedia first:
- 1. Setup the view and create a cube
(1.1. Start/Stop the animation if we are (not) viewing it)
2. Do some trigonometry (rotation)
3. Make the Cube paint itself
Most interesting:
What the heck do those values in the Cube-Constructor mean...
I hope you succeeded and understood this tutorial.
Please vote and/or leave a comment .
原文地址 http://www.anddev.org/colored_3d_cube-t4.html
Quote: |
OpenGL ES (OpenGL for Embedded Systems) is a subset of the OpenGL 3D graphics API designed for embedded devices such as mobile phones, PDAs, and video game consoles. It is defined and promoted by the Khronos Group, a graphics hardware and software industry consortium interested in open APIs for graphics and multimedia. |
Java: |
int one = 0x10000; /* Every vertex got 3 values, for * x / y / z position in the kartesian space. */ int vertices [ ] = { -one, -one, -one, // Vertex Zero one, -one, -one, // Vertex Two one, one, -one, // Vertex ... -one, one, -one, -one, -one, one, one, -one, one, one, one, one, -one, one, one, // Vertex Seven }; |
Java: |
/* Every vertex has got its own color, described by 4 values * R(ed) * G(green) * B(blue) * A(lpha) <-- Opticacy */ int colors [ ] = { 0, 0, 0, one, one, 0, 0, one, one, one, 0, one, 0, one, 0, one, 0, 0, one, one, one, 0, one, one, one, one, one, one, 0, one, one, one, }; |
Java: |
/* The last thing is that we need to describe some Triangles(三角形). * A triangle got 3 vertices. * The confusing thing is, that it is important in which order * the vertices of each triangle are described. * So describing a triangle through the vertices: "0, 4, 5" * will not result in the same triangle as: "0, 5, 4" * You probably ask: Why the hell isn't that the same ??? * The reason for that is the call of: "gl.glFrontFace(gl.GL_CW);" * which means, that we have to describe the "visible" side of the * triangles by naming its vertices in a ClockWise order! * From the other side, the triangle will be 100% lookthru! * You can create a kind of magic mirror with that . */ byte indices [ ] = { 0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2, 2, 6, 7, 2, 7, 3, 3, 7, 4, 3, 4, 0, 4, 7, 6, 4, 6, 5, 3, 0, 1, 3, 1, 2 }; |
Java: |
/* * Copyright (C) 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com. google. android. samples. graphics; import android. app. Activity; import android. content. Context; import android. graphics. Canvas; import android. graphics. OpenGLContext; import android. os. Bundle; import android. os. Handler; import android. os. Message; import android. os. SystemClock; import android. view. View; import java. nio. ByteBuffer; import java. nio. ByteOrder; import java. nio. IntBuffer; import javax. microedition. khronos. opengles. GL10; /** * Example of how to use OpenGL|ES in a custom view * */ public class GLView1 extends Activity { @Override protected void onCreate (Bundle icicle ) { super. onCreate (icicle ); setContentView ( new GLView ( getApplication ( ) ) ); } @Override protected void onResume ( ) { super. onResume ( ); //android.os.Debug.startMethodTracing("/tmp/trace/GLView1.dmtrace", // 8 * 1024 * 1024); } @Override protected void onStop ( ) { super. onStop ( ); //android.os.Debug.stopMethodTracing(); } } class GLView extends View { /** * The View constructor is a good place to allocate our OpenGL context */ public GLView ( Context context ) { super (context ); /* * Create an OpenGL|ES context. This must be done only once, an * OpenGL contex is a somewhat heavy object. */ mGLContext = new OpenGLContext ( 0 ); mCube = new Cube ( ); mAnimate = false; } /* * Start the animation only once we're attached to a window * @see android.view.View#onAttachedToWindow() */ @Override protected void onAttachedToWindow ( ) { mAnimate = true; Message msg = mHandler. obtainMessage (INVALIDATE ); mNextTime = SystemClock. uptimeMillis ( ); mHandler. sendMessageAtTime (msg, mNextTime ); super. onAttachedToWindow ( ); } /* * Make sure to stop the animation when we're no longer on screen, * failing to do so will cause most of the view hierarchy to be * leaked until the current process dies. * @see android.view.View#onDetachedFromWindow() */ @Override protected void onDetachedFromWindow ( ) { mAnimate = false; super. onDetachedFromWindow ( ); } /** * Draw the view content * * @see android.view.View#onDraw(android.graphics.Canvas) */ @Override protected void onDraw ( Canvas canvas ) { if ( true ) { /* * First, we need to get to the appropriate GL interface. * This is simply done by casting the GL context to either * GL10 or GL11. */ GL10 gl = (GL10 ) (mGLContext. getGL ( ) ); /* * Before we can issue GL commands, we need to make sure all * native drawing commands are completed. Simply call * waitNative() to accomplish this. Once this is done, no native * calls should be issued. */ mGLContext. waitNative (canvas, this ); int w = getWidth ( ); int h = getHeight ( ); /* * Set the viewport. This doesn't have to be done each time * draw() is called. Typically this is called when the view * is resized. */ gl. glViewport ( 0, 0, w, h ); /* * Set our projection matrix. This doesn't have to be done * each time we draw, but usualy a new projection needs to be set * when the viewport is resized. */ float ratio = ( float )w / h; gl. glMatrixMode (gl. GL_PROJECTION ); gl. glLoadIdentity ( ); gl. glFrustumf (-ratio, ratio, -1, 1, 2, 12 ); /* * dithering is enabled by default in OpenGL, unfortunattely * it has a significant impact on performace in software * implementation. Often, it's better to just turn it off. */ gl. glDisable (gl. GL_DITHER ); /* * Usually, the first thing one might want to do is to clear * the screen. The most efficient way of doing this is to use * glClear(). However we must make sure to set the scissor * correctly first. The scissor is always specified in window * coordinates: */ gl. glClearColor ( 1, 1, 1, 1 ); gl. glEnable (gl. GL_SCISSOR_TEST ); gl. glScissor ( 0, 0, w, h ); gl. glClear (gl. GL_COLOR_BUFFER_BIT ); /* * Now we're ready to draw some 3D object */ gl. glMatrixMode (gl. GL_MODELVIEW ); gl. glLoadIdentity ( ); gl. glTranslatef ( 0, 0, -3.0f ); gl. glScalef ( 0.5f, 0.5f, 0.5f ); gl. glRotatef (mAngle, 0, 1, 0 ); gl. glRotatef (mAngle* 0.25f, 1, 0, 0 ); gl. glColor4f ( 0.7f, 0.7f, 0.7f, 1.0f ); gl. glEnableClientState (gl. GL_VERTEX_ARRAY ); gl. glEnableClientState (gl. GL_COLOR_ARRAY ); gl. glEnable (gl. GL_CULL_FACE ); mCube. draw (gl ); mAngle += 1.2f; /* * Once we're done with GL, we need to flush all GL commands and * make sure they complete before we can issue more native * drawing commands. This is done by calling waitGL(). */ mGLContext. waitGL ( ); } } // ------------------------------------------------------------------------ private static final int INVALIDATE = 1; private final Handler mHandler = new Handler ( ) { @Override public void handleMessage (Message msg ) { if (mAnimate && msg. what == INVALIDATE ) { invalidate ( ); msg = obtainMessage (INVALIDATE ); long current = SystemClock. uptimeMillis ( ); if (mNextTime < current ) { mNextTime = current + 20; } sendMessageAtTime (msg, mNextTime ); mNextTime += 20; } } }; private OpenGLContext mGLContext; private Cube mCube; private float mAngle; private long mNextTime; private boolean mAnimate; } class Cube { public Cube ( ) { int one = 0x10000; /* Every vertex got 3 values, for * x / y / z position in the kartesian space. */ int vertices [ ] = { -one, -one, -one, one, -one, -one, one, one, -one, -one, one, -one, -one, -one, one, one, -one, one, one, one, one, -one, one, one, }; /* Every vertex has got its own color, described by 4 values * R(ed) * G(green) * B(blue) * A(lpha) <-- Opticacy */ int colors [ ] = { 0, 0, 0, one, one, 0, 0, one, one, one, 0, one, 0, one, 0, one, 0, 0, one, one, one, 0, one, one, one, one, one, one, 0, one, one, one, }; /* The last thing is that we need to describe some Triangles. * A triangle got 3 vertices. * The confusing thing is, that it is important in which order * the vertices of each triangle are described. * So describing a triangle through the vertices: "0, 4, 5" * will not result in the same triangle as: "0, 5, 4" * You probably ask: Why the hell isn't that the same ??? * The reason for that is the call of: "gl.glFrontFace(gl.GL_CW);" * which means, that we have to describe the "visible" side of the * triangles by naming its vertices in a ClockWise order! * From the other side, the triangle will be 100% lookthru! * You can create a kind of magic mirror with that . */ byte indices [ ] = { 0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2, 2, 6, 7, 2, 7, 3, 3, 7, 4, 3, 4, 0, 4, 7, 6, 4, 6, 5, 3, 0, 1, 3, 1, 2 }; // Buffers to be passed to gl*Pointer() functions // must be direct, i.e., they must be placed on the // native heap where the garbage collector cannot // move them. // // Buffers with multi-byte datatypes (e.g., short, int, float) // must have their byte order set to native order ByteBuffer vbb = ByteBuffer. allocateDirect (vertices. length* 4 ); vbb. order (ByteOrder. nativeOrder ( ) ); mVertexBuffer = vbb. asIntBuffer ( ); mVertexBuffer. put (vertices ); mVertexBuffer. position ( 0 ); ByteBuffer cbb = ByteBuffer. allocateDirect (colors. length* 4 ); cbb. order (ByteOrder. nativeOrder ( ) ); mColorBuffer = cbb. asIntBuffer ( ); mColorBuffer. put (colors ); mColorBuffer. position ( 0 ); mIndexBuffer = ByteBuffer. allocateDirect (indices. length ); mIndexBuffer. put (indices ); mIndexBuffer. position ( 0 ); } public void draw (GL10 gl ) { gl. glFrontFace (gl. GL_CW ); gl. glVertexPointer ( 3, gl. GL_FIXED, 0, mVertexBuffer ); gl. glColorPointer ( 4, gl. GL_FIXED, 0, mColorBuffer ); gl. glDrawElements (gl. GL_TRIANGLES, 36, gl. GL_UNSIGNED_BYTE, mIndexBuffer ); } private IntBuffer mVertexBuffer; private IntBuffer mColorBuffer; private ByteBuffer mIndexBuffer; } |
This is the tricky part. I think that I described it good enough in them comment.
Lets take a look at two example triangles:
The Code
Original Source:
code.google.com
Modified by: Nicolas 'plusminus' Gramlich
In this code-block the color of all the 8 vertices are described, as '4' each: R(ed) G(reen) B(lue) A(lpha). (Alpha means Opticacy(透明度))
OpenGL SE will create the color-flows automatically!
That is pretty easy, each row stands for a single vertex, consisting of three values (x,y,z) which simply result in a point in the cartesian space.
So if you think of each codeline as one vertex you get something like this:
(Note: We only created the vertices, not the edges. I just added them, that the cube-structure becomes better visible.)
(Note2: You will see that the blue coordinate-system(坐标系) is located right in the middle of the cube)
Description:
What we will do is, create a custom view and using OpenGL ES in it to draw a colored cube.
The Main steps are(根据要绘制的图形设置图形的定点,如果是屏幕的正方形,需要设置4个顶点(x、y、
z的坐标)如果是立方体,则要设置8个顶点):
更多相关文章
- Android(安卓)贝塞尔曲线,撒花了
- Android图形显示系统——上层显示1:界面绘制大纲
- Android(安卓)getWindow().setFlags方法
- Android(安卓)修改TabLayout设置文字大小一致
- android RecyclerView 设置设置选中的一行的内容
- Android(安卓)getWindow().setFlags方法
- Android连接网络问题
- Android图形显示系统——下层显示4:图层合成上(合成原理与3D合成)
- Android及Robotium学习总结【环境变量,真机调试及根据id模拟按键