在介绍OpenGl开发之前,首先我们得明白OpenGL—坐标变换的一些基本概念:

坐标:

物体坐标:

设置的顶点坐标即为物体本身的坐标,即每个物体内部都有一个自己的坐标系,管理自己的位置。

  1. glBegin(GL_TRIANGLE_FAN);  
  2.     glVertex3f(1, 0, 0);  
  3.     glVertex3f(0, 1, 0);  
  4.     glVertex3f(0, 0, 1);  
  5. glEnd(); 

 

全局坐标:

全局坐标 = 模型矩阵 * 三角形每个顶点坐标;
全局坐标即物体相对整个空间的坐标。比如人这个实体,心脏是坐标中心,头就在心脏的上方,脚在心脏下方,这是相对物体的坐标来说的,也就是刚才的描述是在物体坐标下描述。而全局坐标即你这个人相对地球(假如整个地球就是我们要描述的空间)来说在哪个经纬度,这个就是全局坐标。

视觉坐标:

视觉坐标 = 模型视图矩阵 * 顶点坐标 = 视图矩阵 * 模型矩阵 * 顶点坐标;
视觉坐标就是将当前全局的坐标转换到了相对眼睛看到的坐标。因为整个世界太大了,如果只想看某一部分,所以就引入了视觉坐标。视觉坐标就是定义了一个摄像机,看到场景中的哪些实体就将这些实体渲染出来,不在摄像机范围内的就不显示。视觉坐标就是将以摄像机的坐标为坐标原点,其他的物体都是相对摄像机的坐标来确定的。比如摄像机中的一个三角形,现在这个三角形在摄像机中的上面,还是下面,距离摄像机多远等,此时都是在视觉坐标下来计算的。

裁剪坐标:

裁剪坐标 =  投影矩阵 * 模型视图矩阵 * 顶点坐标;

裁剪坐标就是经过投影矩阵裁剪后的坐标,比如上述定义的摄像机,这个摄像机看到的范围是有限的,有一个夹角和一个近距离和远距离。夹角外的看不到,设置一个近距离裁剪,就是太近的也当做看不见,太远的也看不见。也就是将上述的视觉坐标定义了一个裁剪体,在这个范围内的才渲染。同时将这个视觉坐标这些3d的顶点投影都这个视景体中,也就是差不多是最后2D的画面了。

标准设备坐标:

设备坐标 = 裁剪坐标 / w;
此时设备坐标的x,y,z 范围是[-1, 1]之间

显示坐标:

即最后的显示在显示器上的坐标,也就是将[-1, 1] 与窗口的实际宽高对应

正常的设置投影矩阵的opengl函数为glFrustum 或者 gluPerspective,通过设置视口的宽高,近裁剪与远裁剪等方式来形成一个投影矩阵,通过将投影矩阵与视图坐标相乘形成裁剪坐标。具体投影矩阵算法推倒可参照网上资料。

 

在android中使用OpenGL ES需要三个步骤:

 

1. 创建GLSurfaceView组件,使用Activity来显示GLSurfaceView组建。

2. 为GLSurfaceView组建创建GLSurfaceView.Renderer实例,实现GLSurfaceView.Renderer类时需要实现该接口里的三个方法:

  • abstract void onDrawFrame(GL10 gl):Called to draw the current frame.

  • abstract void onSurfaceChanged(GL10 gl, int width, int height):Called when the surface changed size.

  • abstract void onSurfaceCreated(GL10 gl, EGLConfig config):Called when the surface is created or recreated.

3. 调用GLSurfaceView组建的setRenderer (GLSurfaceView.Renderer renderer) 方法指定Renderer对象,该对象将会完成GLSurfaceView里3D图形的绘制。

 

最近学习 opengl,看了一些简单的教程。发现一般都是到实现金字塔或者立方体就结束了。

纹理方面,对三维物体的多个面未做处理。参看了这些例子,做一个android上的多纹理的立方体。

效果图:

 

一、Activity

先上简单的代码,实现onKeyUp(int keyCode, KeyEvent event)、onTrackballEvent(MotionEvent e)、onTouchEvent(MotionEvent e)三个方法,实现3D 图片随touch事件旋转功能。

package com.ant.opengl_cube;

import android.app.Activity;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;

public class MainActivity extends Activity {
    GLRender render = new GLRender();
    private float mPreviousX;
    private float mPreviousY;
    private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
    private final float TRACKBALL_SCALE_FACTOR = 36.0f;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        GLImage.load(this.getResources());
        GLSurfaceView glView = new GLSurfaceView(this);

        glView.setRenderer(render);
        setContentView(glView);

    }

    public boolean onKeyUp(int keyCode, KeyEvent event) {
        render.onKeyUp(keyCode, event);
        return false;
    }

    public boolean onTrackballEvent(MotionEvent e) {
        render.xrot += e.getX() * TRACKBALL_SCALE_FACTOR;
        render.yrot += e.getY() * TRACKBALL_SCALE_FACTOR;
        return true;
    }

    public boolean onTouchEvent(MotionEvent e) {
        float x = e.getX();
        float y = e.getY();
        switch (e.getAction()) {
        case MotionEvent.ACTION_MOVE:
            float dx = x - mPreviousX;
            float dy = y - mPreviousY;
            render.xrot += dx * TOUCH_SCALE_FACTOR;
            render.yrot += dy * TOUCH_SCALE_FACTOR;
        }
        mPreviousX = x;
        mPreviousY = y;
        return true;
    }
}

class GLImage {
    public static Bitmap mBitmap1;
    public static Bitmap mBitmap2;
    public static Bitmap mBitmap3;
    public static Bitmap mBitmap4;
    public static Bitmap mBitmap5;
    public static Bitmap mBitmap6;

    public static void load(Resources resources) {
        mBitmap1 = BitmapFactory.decodeResource(resources, R.drawable.icon1);
        mBitmap2 = BitmapFactory.decodeResource(resources, R.drawable.icon2);
        mBitmap3 = BitmapFactory.decodeResource(resources, R.drawable.icon3);
        mBitmap4 = BitmapFactory.decodeResource(resources, R.drawable.icon4);
        mBitmap5 = BitmapFactory.decodeResource(resources, R.drawable.icon5);
        mBitmap6 = BitmapFactory.decodeResource(resources, R.drawable.icon6);

    }
}

 二、Renderer核心代码

1、glDrawElements()

OpenGL基本的绘图函数例如glVertex、glNormal等在调试模式下运行时,如果模型的顶点数或者三角面数过大(比如超过一万时),则程序运行速度会非常慢,根本就无法进行正常的调试。为此查阅了相关资料,找到glArrayElement、glDrawElements这两个个函数。这两个函数都能通过少数几条语句的调用实现大量数据的绘制,从而节省了函数调用的资源占用。

 
glArrayElement函数用法简单直接,只要把所有的顶点、法向量等数据,按照三角形的顺序准备好,就可以直接渲染,但缺点是不支持顶点索引,所以内存占用比较大。举例来说,如果一个网格有100个顶点,一般大约会有200个三角面,如果使用glArrayElement就需要存储200×3=600个顶点的数据,相比原有的数据多了5倍。如果是已经条带化的数据,这种冗余数据多的可能就不只5倍了。权衡之下还是决定使用glDrawElements函数。
 
glDrawElements函数支持顶点数据列表,更为方便的是它还支持顶点索引,所以就成为了快速渲染的首选。可是我在具体使用过程中,却总是没有任何顶点数据被绘制出来,查了相关资料,既不是数据错误,也不是硬件不支持,只好暂时搁置一边了。一个偶然的机会,我看到某段示例代码,发现glDrawElements中索引数据类型的参数是GL_UNSIGNED_INT,而我之前用的参数都是GL_INT(因为算法的需要,有时需要存储负数索引,以表示正反方向的不同)。抱着试试看的想法,我把参数改成了GL_UNSIGNED_INT,结果竟然绘制出图像来了。赶紧查阅了MSDN,对glDrawElements的说明如下:
void glDrawElements(
  GLenum
 mode,
  GLsizei count,
  GLenum type,
  const GLvoid *indices
);

Parameters

mode
The kind of primitives to render. It can assume one of the following symbolic values: GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_QUAD_STRIP, GL_QUADS, and GL_POLYGON.
count
The number of elements to be rendered.
type
The type of the values in indices. Must be one of GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT.
indices
A pointer to the location where the indices are stored.
注意其中对type参数的说明,索引数据的类型必须是GL_UNSIGNED_BYTE、GL_UNSIGNED_SHORT、GL_UNSIGNED_INT之一。这一来就解释了为什么glDrawElements没有绘制出任何元素的问题所在了。可气的是OpenGL竟然没有对这个问题给出任何的提示,不知到是不是微软有意如此淡化OpenGL的作用,如果改天有机会可以用linux系统下的编译器作作测试。
 
最后,附上我在渲染时调用的部分代码。
 
//顶点
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, (float*)m_vDataCoord[0]);
 
// 法向量
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, (float*)m_vDataNormal[0]);
 
//顶点颜色
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3, GL_FLOAT, 0, (float*)m_vDataColor[0]);
 
//纹理坐标
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, (float*)m_vDataUv[0]);
glDrawElements(GL_TRIANGLES, (GLsizei)m_vIndexCoord.size()*3, GL_UNSIGNED_INT, (GLvoid*)m_vIndexCoord[0]);
 
2、纹理映射坐标glTexCoordPointer用法

glTexCoordPointer(int size, int type, int stride, Buffer pointer);  设置顶点数组为纹理坐标缓存

其中: size:纹理顶点坐标的分量个数;  //size: number of coordinates per vertex;   

          type:纹理坐标的数据类型;short, int, float, double都可以;

          stride:位图的宽度,可以理解为相邻的两个纹理之间跨多少个字节,一般为0,因为一般不会在纹理中再添加其他的信  息。//stride: offset between 2 consecutive vertices;

              pointer:存放纹理坐标的数组,指明将绘制的第i个点(i<count)分别对应着贴图的哪一个角,四个角分别用(0,1)(左上角)、(1,1)(右上角)、(1,0)(右下角)、(0,0)(左下角)表示。如
                                              

 IntBuffer texCoords = IntBuffer.wrap(new int[]{
                                                   0,1,1,1,1,0,0,0,               
                                                 });
 gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, texCoords);

 

注意:pointer是以顶点数组为参照的,而不是以绘制索引为参照!如
 

 gl.glVertexPointer(3, GL10.GL_FIXED, 0, vertices);
  gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, texCoords);
  gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 4,  GL10.GL_UNSIGNED_BYTE, indices);

 


poInter以vertices中顶点的顺序为参照,而不是indices所指定的顺序

 

下面是Renderer类,其中,代码中都有注释了,应该简单易懂

package com.ant.cube3d;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import java.nio.IntBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLUtils;
import android.view.KeyEvent;

public class GLRender implements Renderer {
    public GLRender() {
        // 注意构造函数中那些Buffer的创建方式。在这个地方,
        // 不能直接使用FloatBuffer/IntBuffer 的wrap() method。
        // 直接用这个method创建出来的buffer会导致JE:
        vertices = bufferUtil(verticesdata);
        texCoords = bufferUtil(texCoordsdata);
        normals = bufferUtil(normalsdata);
        lightAmbient = bufferUtil(light1);
        lightDiffuse = bufferUtil(light2);
        lightPosition = bufferUtil(light3);
    }

    // 通过事件分发,提供方法给View层,动态onDrawFram(),就是3D物体跟着转
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        key = !key;
        return false;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        gl.glDisable(GL10.GL_DITHER);

        // 告诉系统对透视进行修正
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
        // 黑色背景
        gl.glClearColor(0, 0, 0, 0);

        gl.glEnable(GL10.GL_CULL_FACE);
        // 启用阴影平滑
        gl.glShadeModel(GL10.GL_SMOOTH);
        // 启用深度测试
        gl.glEnable(GL10.GL_DEPTH_TEST);

        // 设置光线,,1.0f为全光线,a=50%
        gl.glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
        // 基于源象素alpha通道值的半透明混合函数
        gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);

        // 纹理相关
        GLTextureUtil(gl);

        // 深度测试相关
        gl.glClearDepthf(1.0f);
        gl.glDepthFunc(GL10.GL_LEQUAL);
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
        gl.glEnable(GL10.GL_TEXTURE_2D);

        // 设置环境光
        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, lightAmbient);

        // 设置漫射光
        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_DIFFUSE, lightDiffuse);

        // 设置光源位置
        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_POSITION, lightPosition);

        // 开启一号光源
        gl.glEnable(GL10.GL_LIGHT1);

        // 开启混合
        gl.glEnable(GL10.GL_BLEND);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        float ratio = (float) width / height;
        // 设置OpenGL场景的大小
        gl.glViewport(0, 0, width, height);
        // 设置投影矩阵
        gl.glMatrixMode(GL10.GL_PROJECTION);
        // 重置投影矩阵
        gl.glLoadIdentity();
        // 设置视口的大小
        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
        // 选择模型观察矩阵
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        // 重置模型观察矩阵
        gl.glLoadIdentity();
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        // 清除屏幕和深度缓存
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

        gl.glMatrixMode(GL10.GL_MODELVIEW);
        // 重置当前的模型观察矩阵
        gl.glLoadIdentity();

        gl.glEnable(GL10.GL_LIGHTING);

        gl.glTranslatef(0.0f, 0.0f, z);

        // 设置旋转
        gl.glRotatef(xrot, 0.0f, 1.0f, 0.0f);
        gl.glRotatef(yrot, 1.0f, 0.0f, 0.0f);
        // 设置法线
        gl.glNormalPointer(GL10.GL_FIXED, 0, normals);
        // size:指定了每个顶点对应的坐标个数,只能是2,3,4中的一个,默认值是4
        // type:指定了数组中每个顶点坐标的数据类型,可取常量:GL_BYTE, GL_SHORT,GL_FIXED,GL_FLOAT;
        // stride:指定了连续顶点间的字节排列方式,如果为0,数组中的顶点就会被认为是按照紧凑方式排列的,默认值为0
        // pointer:制订了数组中第一个顶点的首地址,默认值为0,对于我们的android,大家可以不用去管什么地址的,一般给一个int就可以了
        gl.glVertexPointer(3, GL10.GL_FIXED, 0, vertices);
        // 设置顶点数组为纹理坐标缓存
        gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, texCoords);

        // glEnableClientState - glDisableClientState这对。
        // 它们的区别是通知的具体对象在概念上不一样——分别是服务端和客户端。
        // 事实上我也无法很清楚地解释清楚,反正电脑上的具体程序,包括它用到
        // 的内存等等看作客户端,把你电脑里面的——显卡里的OpenGL“模块”,乃
        // 至整张拥有OpenGL流水线、硬件实现OpenGL功能的显卡,作为服务端。
        // 它们各自维护一些“状态”,glEnable 等是直接维护流水线处理相关的状态的,
        // glEnableClientState 维护的则是进入流水线前的状态
        gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

        // 绘制四边形

        BindElementsWithTexture(gl);
        // 修改旋转角度
        // xrot+=0.3f;
        // yrot+=0.2f;

        // 混合开关
        if (key) {
            gl.glEnable(GL10.GL_BLEND); // 打开混合
            gl.glDisable(GL10.GL_DEPTH_TEST); // 关闭深度测试
        } else {
            gl.glDisable(GL10.GL_BLEND); // 关闭混合
            gl.glEnable(GL10.GL_DEPTH_TEST); // 打开深度测试
        }
    }

    // 绘制四边形和Texture元素绑定
    public void BindElementsWithTexture(GL10 gl) {
        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[0]);
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 4, GL10.GL_UNSIGNED_BYTE,
                indices1);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[1]);
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 8, GL10.GL_UNSIGNED_BYTE,
                indices2);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[2]);
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 12, GL10.GL_UNSIGNED_BYTE,
                indices3);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[3]);
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 16, GL10.GL_UNSIGNED_BYTE,
                indices4);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[4]);
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 20, GL10.GL_UNSIGNED_BYTE,
                indices5);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[5]);
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 24, GL10.GL_UNSIGNED_BYTE,
                indices6);

        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
    }

    
    public FloatBuffer bufferUtil(float[] arr) {
        FloatBuffer buffer;

        ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 6);
        qbb.order(ByteOrder.nativeOrder());

        buffer = qbb.asFloatBuffer();
        buffer.put(arr);
        buffer.position(0);

        return buffer;
    }

    public IntBuffer bufferUtil(int[] arr) {
        IntBuffer buffer;

        ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 6);
        qbb.order(ByteOrder.nativeOrder());

        buffer = qbb.asIntBuffer();
        buffer.put(arr);
        buffer.position(0);

        return buffer;
    }

    // Texture纹理初始化
    public void GLTextureUtil(GL10 gl) {

        IntBuffer textureBuffer = IntBuffer.allocate(6);
        gl.glGenTextures(6, textureBuffer);
        texture = textureBuffer.array();

        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[0]);
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GLImage.mBitmap1, 0);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
                GL10.GL_NEAREST);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
                GL10.GL_NEAREST);

        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[1]);
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GLImage.mBitmap2, 0);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
                GL10.GL_NEAREST);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
                GL10.GL_NEAREST);

        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[2]);
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GLImage.mBitmap3, 0);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
                GL10.GL_NEAREST);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
                GL10.GL_NEAREST);

        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[3]);
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GLImage.mBitmap4, 0);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
                GL10.GL_NEAREST);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
                GL10.GL_NEAREST);

        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[4]);
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GLImage.mBitmap5, 0);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
                GL10.GL_NEAREST);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
                GL10.GL_NEAREST);

        gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[5]);
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GLImage.mBitmap6, 0);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
                GL10.GL_NEAREST);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
                GL10.GL_NEAREST);
    }

    boolean key = true;
    float xrot = 0.0f;
    float yrot = 0.0f;
    float xspeed, yspeed;
    float z = -5.0f;
    int one = 0x10000;//void glVertexPointer(GLint size,
//GLenum type,
//GLsizei stride,
//const GLvoid * pointer)这里不同的数据类型含义不同,如果选择GL_FIXED,那么0x10000表示单位长度,如果选择GL_FLOAT那么1.0f表示单位度。)
// 光线参数 FloatBuffer lightAmbient; FloatBuffer lightDiffuse; FloatBuffer lightPosition; float[] light1 = new float[] { 0.5f, 0.5f, 0.5f, 1.0f }; float[] light2 = new float[] { 1.0f, 1.0f, 1.0f, 1.0f }; float[] light3 = new float[] { 0.0f, 0.0f, 2.0f, 1.0f }; int[] texture; IntBuffer vertices; IntBuffer normals; IntBuffer texCoords; int[] verticesdata = new int[] { -one,-one,one, one,-one,one, one,one,one, -one,one,one, -one,-one,-one, -one,one,-one, one,one,-one, one,-one,-one, -one,one,-one, -one,one,one, one,one,one, one,one,-one, -one,-one,-one, one,-one,-one, one,-one,one, -one,-one,one, one,-one,-one, one,one,-one, one,one,one, one,-one,one, -one,-one,-one, -one,-one,one, -one,one,one, -one,one,-one, }; int[] normalsdata = new int[] { 0,0,one, 0,0,one, 0,0,one, 0,0,one, 0,0,one, 0,0,one, 0,0,one, 0,0,one, 0,one,0, 0,one,0, 0,one,0, 0,one,0, 0,-one,0, 0,-one,0, 0,-one,0, 0,-one,0, one,0,0, one,0,0, one,0,0, one,0,0, -one,0,0, -one,0,0, -one,0,0, -one,0,0, }; int[] texCoordsdata = new int[] { one,0,0,0,0,one,one,one, 0,0,0,one,one,one,one,0, one,one,one,0,0,0,0,one, 0,one,one,one,one,0,0,0, 0,0,0,one,one,one,one,0, one,0,0,0,0,one,one,one, }; ByteBuffer indices1 = ByteBuffer.wrap(new byte[] { 0,1,3,2, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, }); ByteBuffer indices2 = ByteBuffer.wrap(new byte[] { 0,0,0,0, 4,5,7,6, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, }); ByteBuffer indices3 = ByteBuffer.wrap(new byte[] { 0,0,0,0, 0,0,0,0, 8,9,11,10, 0,0,0,0, 0,0,0,0, 0,0,0,0, }); ByteBuffer indices4 = ByteBuffer.wrap(new byte[] { 0,0,0,0, 0,0,0,0, 0,0,0,0, 12,13,15,14, 0,0,0,0, 0,0,0,0, }); ByteBuffer indices5 = ByteBuffer.wrap(new byte[] { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 16,17,19,18, 0,0,0,0, }); ByteBuffer indices6 = ByteBuffer.wrap(new byte[] { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 20,21,23,22, }); }

 

posted on 2016-04-27 22:09  梁安  阅读(2133)  评论(0编辑  收藏  举报