诛仙加点模拟器:Android Opengl - Colored 3D Cube

来源:百度文库 编辑:九乡新闻网 时间:2024/04/29 07:15:19
[转]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: 
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.

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: 
    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...  
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 
            };

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) 
 

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, 
            };

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! 

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 
        };

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 
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; 
}

I hope you succeeded and understood this tutorial. 

Please vote and/or leave a comment  .

 原文地址 http://www.anddev.org/colored_3d_cube-t4.html