• 转 Android中3D技术基础详解 制作一个可旋转的立方体


    一:

    先介绍下3D中一些专业术语:

    1.视区:viewport.假如你从窗户往外看,若将窗户更换为高质量的照片,只要你部移动,看到的景象就是一样的。这个“窗户”就被称为视区。

    2.视野:根据眼睛和窗户之间的距离和窗户的大小,可以看到的外面世界多少事不同的,这称为视野。

    在3D计算机图形领域,计算机屏幕作为视区。你的工作就是让用户将其窗口想象成玻璃后面的另一个世界。OpenGL图形库就是用于完成此任务的API。

    类一:主类

    layout中的main可删掉,因为要自定义View

    代码如下:

    package org.example.opengl;

    import android.app.Activity;
    import android.os.Bundle;

    public class OpenGL extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new GLView(this));
    }
    }

    类二:GLView

    这个类是视图类,实现主类中的布局。其中定义了一个线程,所有功能都在线程里面来完成。

    package org.example.opengl;

    import android.content.Context;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;

    class GLView extends SurfaceView implements SurfaceHolder.Callback {

    private GLThread glThread;

    GLView(Context context) {
    super(context);
    getHolder().addCallback(this);
    getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    glThread = new GLThread(this);
    glThread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
    int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    glThread.requestExitAndWait();
    glThread = null;
    }
    }

    三:GLCube类。这个类中定义OpenGl句柄方面的东西。代码如下:

    package org.example.opengl;

    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    import java.nio.IntBuffer;

    import javax.microedition.khronos.opengles.GL10;

    class GLCube {
    private final IntBuffer mVertexBuffer;
    public GLCube(){
    int one = 65536;
    int half = one / 2;
    int vertices[] = {
    //前
    -half,-half,half,half,-half,half,
    -half,half,half,half,half,half,
    //后
    -half,-half,-half,-half,half,-half,
    half,-half,-half,half,half,-half,
    //左
    -half,-half,half,-half,half,half,
    -half,-half,-half,-half,half,-half,
    //右
    half,-half,-half,half,half,-half,
    half,-half,half,half,half,half,
    //上
    -half,half,half,half,half,half,
    -half,half,-half,half,half,-half,
    //下
    -half,-half,half,-half,-half,-half,
    -half,half,-half,half,half,-half,
    };
    ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
    vbb.order(ByteOrder.nativeOrder());
    mVertexBuffer = vbb.asIntBuffer();
    mVertexBuffer.put(vertices);
    mVertexBuffer.position(0);
    }
    public void draw(GL10 gl){
    gl.glVertexPointer(3,GL10.GL_FIXED,0,mVertexBuffer);
    gl.glColor4f(1,1,1,1);
    gl.glNormal3f(0, 0, 1);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4);
    gl.glNormal3f(0, 0, -1);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,4,4);

    gl.glColor4f(1,1,1,1);
    gl.glNormal3f(-1,0, 0);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,8,4);
    gl.glNormal3f(1,0, 0);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,12,4);

    gl.glColor4f(1,1,1,1);
    gl.glNormal3f(0,1,0);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,16,4);
    gl.glNormal3f(0,-1,0);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,20,4);
    }
    }

    四:GLThread线程类。类中drawFrame方法中绘制图像。

    package org.example.opengl;

    import javax.microedition.khronos.egl.EGL10;
    import javax.microedition.khronos.egl.EGL11;
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.egl.EGLContext;
    import javax.microedition.khronos.egl.EGLDisplay;
    import javax.microedition.khronos.egl.EGLSurface;
    import javax.microedition.khronos.opengles.GL10;

    import android.app.Activity;
    import android.content.Context;
    import android.opengl.GLU;

    class GLThread extends Thread {
    private final GLView view;
    private boolean done = false;
    private final GLCube cube = new GLCube();
    private long startTime;
    GLThread(GLView view) {
    this.view = view;
    }
    @Override
    public void run() {
    EGL10 egl = (EGL10)EGLContext.getEGL();
    EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

    int[] version = new int[2];
    egl.eglInitialize(display, version);

    int[] configSpec = {
    EGL10.EGL_RED_SIZE,5,EGL10.EGL_GREEN_SIZE,6,EGL10.EGL_BLUE_SIZE,5,EGL10.EGL_DEPTH_SIZE,16,EGL10.EGL_NONE
    };
    EGLConfig[] configs = new EGLConfig[1];
    int[] numConfig = new int[1];
    egl.eglChooseConfig(display, configSpec, configs, 1, numConfig);
    EGLConfig config = configs[0];

    EGLContext glc = egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,null);
    EGLSurface surface = egl.eglCreateWindowSurface(display, config, view.getHolder(),null);
    egl.eglMakeCurrent(display, surface, surface, glc);

    GL10 gl = (GL10) (glc.getGL()); //返回实际的OpenGL接口
    init(gl);

    while(!done){
    drawFrame(gl);
    egl.eglSwapBuffers(display, surface);

    if(egl.eglGetError() == EGL11.EGL_CONTEXT_LOST){
    Context c = view.getContext();
    if(c instanceof Activity){
    ((Activity)c).finish();
    }
    }
    }
    //释放openGL资源
    egl.eglMakeCurrent(display, EGL10.EGL_NO_SURFACE,EGL10.EGL_NO_SURFACE,EGL10.EGL_NO_CONTEXT);
    egl.eglDestroySurface(display, surface);
    egl.eglDestroyContext(display, glc);
    egl.eglTerminate(display);
    }
    public void requestExitAndWait(){
    done = true;
    try {
    join();
    } catch (InterruptedException e) {

    }
    }
    private void init(GL10 gl){
    gl.glViewport(0, 0, view.getWidth(),view.getHeight());
    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glLoadIdentity();
    float ratio = (float)view.getWidth() / view.getHeight();
    GLU.gluPerspective(gl, 45.0f,ratio,1,100f);
    gl.glEnable(GL10.GL_DEPTH_TEST);
    gl.glDepthFunc(GL10.GL_LEQUAL);
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

    //定义光源
    float lightAmbient[] = new float[]{0.2f,0.2f,0.2f,1};
    float lightDiffuse[] = new float[]{1,1,1,1};
    float[] lightPos = new float[]{1,1,1,1};

    gl.glEnable(GL10.GL_LIGHTING);
    gl.glEnable(GL10.GL_LIGHT0);
    gl.glLightfv(GL10.GL_LIGHT0,GL10.GL_AMBIENT,lightAmbient,0);
    gl.glLightfv(GL10.GL_LIGHT0,GL10.GL_DIFFUSE,lightDiffuse,0);
    gl.glLightfv(GL10.GL_LIGHT0,GL10.GL_POSITION,lightPos,0);

    //材料
    float matAmbient[] = new float[]{1,1,1,1};
    float matDiffuse[] = new float[]{1,1,1,1};
    gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,GL10.GL_AMBIENT,matAmbient,0);
    gl.glMaterialfv(GL10.GL_FRONT_AND_BACK,GL10.GL_DIFFUSE,matDiffuse,0);

    startTime = System.currentTimeMillis();
    }
    private void drawFrame(GL10 gl){
    long elapsed = System.currentTimeMillis() - startTime;

    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); //把屏幕清理为黑
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();
    gl.glTranslatef(0, 0,-3.0f);
    gl.glRotatef(elapsed * (30f/1000), 0,1,0);
    gl.glRotatef(elapsed * (15f/1000), 1,0,0);
    cube.draw(gl);

    }
    }

    这是个最简单的OpenGL的例子。

    提示两点:

    1.用Android是实现了OpenGL ES接口。其中有很多是OpenGL中的函数,可能让大家感觉比较陌生,这个其实不难,可以找OpenGL方面的书来看看。

    2.在这个例子中用的是绘图模式是:三角形条带(一种常见的OpenGL绘图模式),在这个模式中,制定两个起点,然后每个后续的点与前两个起点一起定义一个三角形

  • 相关阅读:
    什么?Spring Boot CommandLineRunner 有坑!?
    关于 websocket 跨域的一个奇怪问题…
    电商金额计算的 4 个坑,千万注意了!
    微服务模块划分原则和接口定义原则
    tcp的三次握手(连接)与四次挥手(断开)
    二叉树遍历及算法实现
    elasticsearch搜索 倒排索引
    kubernetes落地-传统web服务迁移
    Docker核心技术-容器管理
    Docker核心技术-镜像管理
  • 原文地址:https://www.cnblogs.com/mwl523/p/16420260.html
Copyright © 2020-2023  润新知