OpenglES2.0 for Android:来画个立方体吧

前言:

前面一直在说OpenglES2.0二维图形的绘制,接下来我们步入三维的世界 ,三维世界远比二维要有趣的多,与此同时复杂性也要高得多,在unity3D中我们可以很容易的就创建

一个立方体,而在OpenglES2.0中这个过程要复杂得多,但是更加有趣 。先来看下我们的整个流程:

 

\


摄像机的设置:

想想你的摄像头,它的位置不同,朝向不同,对同一个事物拍摄得到的画面肯定是不同的,Opengl中的摄像头和我们日常生活中的摄像头是一样的道理

 

\

(图一)

 

 

在Opengl中摄像头包含三部分的信息:

1. 摄像头的位置 ,在三维空间中用 x y z 表示

2. 摄像头的镜头的指向,这里即观察的物体的坐标,一般选取物体的center坐标(通过摄像头的位置与观察的物体的坐标可以确定一个向量,这个向量就可以决定观察的方向)

3. 摄像头的UP方向,摄像机顶端的指向

 

下面的人眼观察物体的图示更容易帮助我们理解:

 

\

(图二 )

 

可以看出摄像机的位置,朝向,UP方向有很多不同的组合,对于不同的组合观察同一物体会得到不同的结果

为了更好地理解,这里给出国外大牛做的一个demo :

 

\

 

我们先做只需要看gluLookAt , eye 就是我们所说的摄像机的位置,center即摄像头的镜头的指向

我们可以改变这些值,来观察一下右上方的图像的变化。

 

下载地址:https://download.csdn.net/detail/cassiepython/9541794

 

透视投影

我们观察物体,会有近大远小的效果,透视投影即为了产生这种效果,和美术中 的透视是一个概念

\

(图三)

 

其中,视点指摄像机的位置,近平面指距离视点较近的垂直于观察方向的平面,视景体又叫做视锥体为椎台形区域。

透视投影的投影线互不平行,相较于视点,因此,对于同样尺寸的物体,在近处投影出来大,在远处投影出来小,由此产生近大远小的效果。

 

 

\

(图四)

 

大家可以继续结合上面的小软件修改参数试下来了解透视投影。

 

立方体顶点坐标

OK,现在让我们开始着手具体的编程,首先来定义立方体的顶点坐标,此时我们肯定不能只是X ,Y了 ,还要加入一个新的参数 Z ,Z和X, Y的范围是一样的,

也是从 -1 到 1 ,我们看向自己的手机屏幕,想象我们的视线穿过两个平面,前面的为 1 后面的为 -1 。

 

我们接着上一节的工程来做,在shape包下新建一个类 ——Cube.java ,然后创建顶点数据 ,此时 Cube.java 代码如下:

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

package com.cumt.shape;

 

import java.nio.ByteBuffer;

import java.nio.ByteOrder;

import java.nio.FloatBuffer;

import android.content.Context;

 

public class Cube {

     

    private FloatBuffer vertexBuffer;

    private Context context;

    //float类型的字节数

    private static final int BYTES_PER_FLOAT = 4;

 

    static float vertices[] = {

        //前面

        0,0,1.0f,

        1.0f,1.0f,1.0f,

        -1.0f,1.0f,1.0f,

        0,0,1.0f,

        -1.0f,1.0f,1.0f,

        -1.0f,-1.0f,1.0f,

        0,0,1.0f,

        -1.0f,-1.0f,1.0f,

        1.0f,-1.0f,1.0f,

        0,0,1.0f,

        1.0f,-1.0f,1.0f,

        1.0f,1.0f,1.0f,

        //后面

        0,0,-1.0f,         

        1.0f,1.0f,-1.0f,

        1.0f,-1.0f,-1.0f,

        0,0,-1.0f,

        1.0f,-1.0f,-1.0f,

        -1.0f,-1.0f,-1.0f,

        0,0,-1.0f,

        -1.0f,-1.0f,-1.0f,

        -1.0f,1.0f,-1.0f,

        0,0,-1.0f,

        -1.0f,1.0f,-1.0f,

        1.0f,1.0f,-1.0f,

        //左面

        -1.0f,0,0,         

        -1.0f,1.0f,1.0f,

        -1.0f,1.0f,-1.0f,

        -1.0f,0,0,  

        -1.0f,1.0f,-1.0f,

        -1.0f,-1.0f,-1.0f,

        -1.0f,0,0,  

        -1.0f,-1.0f,-1.0f,

        -1.0f,-1.0f,1.0f,

        -1.0f,0,0,  

        -1.0f,-1.0f,1.0f,

        -1.0f,1.0f,1.0f,

        //右面

        1.0f,0,0,  

        1.0f,1.0f,1.0f,

        1.0f,-1.0f,1.0f,

        1.0f,0,0,  

        1.0f,-1.0f,1.0f,

        1.0f,-1.0f,-1.0f,

        1.0f,0,0,  

        1.0f,-1.0f,-1.0f,

        1.0f,1.0f,-1.0f,

        1.0f,0,0

        1.0f,1.0f,-1.0f,

        1.0f,1.0f,1.0f,

        //上面

        0,1.0f,0,     

        1.0f,1.0f,1.0f,

        1.0f,1.0f,-1.0f,

        0,1.0f,0,          

        1.0f,1.0f,-1.0f,

        -1.0f,1.0f,-1.0f,

        0,1.0f,0,      

        -1.0f,1.0f,-1.0f,

        -1.0f,1.0f,1.0f,   

        0,1.0f,0,     

        -1.0f,1.0f,1.0f,

        1.0f,1.0f,1.0f,    

        //下面

        0,-1.0f,0,         

        1.0f,-1.0f,1.0f,

        -1.0f,-1.0f,1.0f,

        0,-1.0f,0

        -1.0f,-1.0f,1.0f,

        -1.0f,-1.0f,-1.0f,

        0,-1.0f,0,  

        -1.0f,-1.0f,-1.0f,

        1.0f,-1.0f,-1.0f,

        0,-1.0f,0,   

        1.0f,-1.0f,-1.0f,

        1.0f,-1.0f,1.0f

    };

     

    public Cube(Context context){

        this.context = context;

         

        vertexBuffer = ByteBuffer

                .allocateDirect(vertices.length * BYTES_PER_FLOAT)

                .order(ByteOrder.nativeOrder())

                .asFloatBuffer();

        // 把坐标们加入FloatBuffer中

        vertexBuffer.put(vertices);

        // 设置buffer,从第一个坐标开始读

        vertexBuffer.position(0);

    }

}

 

我们每个面定义了12个顶点:

 

\

每一个面分为4个三角形,每个三角形包含3个点,共12个点(我们打算使用GL_TRIANGLES方式绘制 )

 

接下来看下我们的着色器代码,顶点着色器我们使用仍然使用上一节的vertex_shader.glsl :

 

 

?

1

2

3

4

5

6

7

uniform mat4 u_Matrix;

attribute vec4 a_Position; 

  

void main()                   

{                             

    gl_Position = u_Matrix * a_Position;

}

 

u_Matrix用于我们传入最终的变幻矩阵 (投影矩阵 and 摄像机矩阵)。

 

 

然后我们编译链接着色器 此时Cube类代码 (Cube.java ):

 

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

package com.cumt.shape;

 

import java.nio.ByteBuffer;

import java.nio.ByteOrder;

import java.nio.FloatBuffer;

import com.cumt.openglestwo_test_one.R;

import com.cumt.utils.ShaderHelper;

import com.cumt.utils.TextResourceReader;

import android.content.Context;

import android.opengl.GLES20;

 

public class Cube {

     

    private FloatBuffer vertexBuffer;

    private Context context;

    //float类型的字节数

    private static final int BYTES_PER_FLOAT = 4;

    //共有72个顶点坐标,每个面包含12个顶点坐标

    private static final int POSITION_COMPONENT_COUNT = 12*6;

    // 数组中每个顶点的坐标数

    private static final int COORDS_PER_VERTEX = 3;

     

    private static final String A_POSITION = "a_Position";

    private static final String U_COLOR = "u_Color";

    private static final String U_MATRIX = "u_Matrix";

    private int uMatrixLocation;

    private int uColorLocation;

    private int aPositionLocation;

    private int program;

 

    static float vertices[] = {

        //前面

        0,0,1.0f,

        1.0f,1.0f,1.0f,

        -1.0f,1.0f,1.0f,

        0,0,1.0f,

        -1.0f,1.0f,1.0f,

        -1.0f,-1.0f,1.0f,

        0,0,1.0f,

        -1.0f,-1.0f,1.0f,

        1.0f,-1.0f,1.0f,

        0,0,1.0f,

        1.0f,-1.0f,1.0f,

        1.0f,1.0f,1.0f,

        //后面

        0,0,-1.0f,         

        1.0f,1.0f,-1.0f,

        1.0f,-1.0f,-1.0f,

        0,0,-1.0f,

        1.0f,-1.0f,-1.0f,

        -1.0f,-1.0f,-1.0f,

        0,0,-1.0f,

        -1.0f,-1.0f,-1.0f,

        -1.0f,1.0f,-1.0f,

        0,0,-1.0f,

        -1.0f,1.0f,-1.0f,

        1.0f,1.0f,-1.0f,

        //左面

        -1.0f,0,0,         

        -1.0f,1.0f,1.0f,

        -1.0f,1.0f,-1.0f,

        -1.0f,0,0,  

        -1.0f,1.0f,-1.0f,

        -1.0f,-1.0f,-1.0f,

        -1.0f,0,0,  

        -1.0f,-1.0f,-1.0f,

        -1.0f,-1.0f,1.0f,

        -1.0f,0,0,  

        -1.0f,-1.0f,1.0f,

        -1.0f,1.0f,1.0f,

        //右面

        1.0f,0,0,  

        1.0f,1.0f,1.0f,

        1.0f,-1.0f,1.0f,

        1.0f,0,0,  

        1.0f,-1.0f,1.0f,

        1.0f,-1.0f,-1.0f,

        1.0f,0,0,  

        1.0f,-1.0f,-1.0f,

        1.0f,1.0f,-1.0f,

        1.0f,0,0

        1.0f,1.0f,-1.0f,

        1.0f,1.0f,1.0f,

        //上面

        0,1.0f,0,     

        1.0f,1.0f,1.0f,

        1.0f,1.0f,-1.0f,

        0,1.0f,0,          

        1.0f,1.0f,-1.0f,

        -1.0f,1.0f,-1.0f,

        0,1.0f,0,      

        -1.0f,1.0f,-1.0f,

        -1.0f,1.0f,1.0f,   

        0,1.0f,0,     

        -1.0f,1.0f,1.0f,

        1.0f,1.0f,1.0f,    

        //下面

        0,-1.0f,0,         

        1.0f,-1.0f,1.0f,

        -1.0f,-1.0f,1.0f,

        0,-1.0f,0

        -1.0f,-1.0f,1.0f,

        -1.0f,-1.0f,-1.0f,

        0,-1.0f,0,  

        -1.0f,-1.0f,-1.0f,

        1.0f,-1.0f,-1.0f,

        0,-1.0f,0,   

        1.0f,-1.0f,-1.0f,

        1.0f,-1.0f,1.0f

    };

     

    public Cube(Context context){

        this.context = context;

         

        vertexBuffer = ByteBuffer

                .allocateDirect(vertices.length * BYTES_PER_FLOAT)

                .order(ByteOrder.nativeOrder())

                .asFloatBuffer();

        // 把坐标们加入FloatBuffer中

        vertexBuffer.put(vertices);

        // 设置buffer,从第一个坐标开始读

        vertexBuffer.position(0);

         

        getProgram();

         

        uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR);

        aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);

        uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);

         

        //---------传入顶点数据数据

        GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,

                GLES20.GL_FLOAT, false, 0, vertexBuffer);

        GLES20.glEnableVertexAttribArray(aPositionLocation);

    }

     

    //获取program

    private void getProgram(){

        //获取顶点着色器文本

        String vertexShaderSource = TextResourceReader

                .readTextFileFromResource(context, R.raw.vertex_shader);

        //获取片段着色器文本

        String fragmentShaderSource = TextResourceReader

                .readTextFileFromResource(context, R.raw.simple_fragment_shader);

        //获取program的id

        program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);

        GLES20.glUseProgram(program);

    }

}


接下来我们应该定义实现draw方法,在此之前先让我们解决投影矩阵的问题

 


设置相机和投影

我们来定义一个工具类来获得最终的变幻矩阵 ,我们需要使用两个函数 :

 

\

 

\

这两个函数的参数的含义与上面我们讲解相机和投影时的那些参数是对应的,大家可以回到前面再看下,这里不再重复。

 

我们在utils包中定义工具类——MatrixState 然后看我的工具类的代码 (MatrixState.java):

 

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

package com.cumt.utils;

 

import android.opengl.Matrix;

 

//存储系统矩阵状态的类

public class MatrixState {

    private static float[] mProjMatrix = new float[16];// 4x4矩阵 存储投影矩阵

    private static float[] mVMatrix = new float[16];// 摄像机位置朝向9参数矩阵

 

    // 设置摄像机

    public static void setCamera(float cx, // 摄像机位置x

            float cy, // 摄像机位置y

            float cz, // 摄像机位置z

            float tx, // 摄像机目标点x

            float ty, // 摄像机目标点y

            float tz, // 摄像机目标点z

            float upx, // 摄像机UP向量X分量

            float upy, // 摄像机UP向量Y分量

            float upz // 摄像机UP向量Z分量

    ) {

        Matrix.setLookAtM(mVMatrix, 0, cx, cy, cz, tx, ty, tz, upx, upy, upz);

    }

 

    // 设置透视投影参数

    public static void setProjectFrustum(float left, // near面的left

            float right, // near面的right

            float bottom, // near面的bottom

            float top, // near面的top

            float near, // near面距离

            float far // far面距离

    ) {

        Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);

    }

 

    // 获取具体物体的总变换矩阵

    static float[] mMVPMatrix = new float[16];

 

    public static float[] getFinalMatrix() {

        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);

        return mMVPMatrix;

    }

}


这个工具类中有三个方法,我们在渲染类 (MyRender.java)中的 onSurfaceChanged中调用前两个方法设置摄像机和投影矩阵,在Cube的draw方法中就可以通过第三个方法

 

getFinalMatrix 来获取最终的变换矩阵 然后传入着色器程序。 (我们注意multiplyMM函数,这个函数工作是将我们的投影矩阵和摄像机矩阵进行矩阵的乘法运算,存储在

mMVPMatrix中,这个mMVPMatrix即为我们最终的变换矩阵,即我们需要传入着色器程序的矩阵。

 

OK,看下完整的 Cube.java 类 和 MyRender.java :

 

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

package com.cumt.shape;

 

import java.nio.ByteBuffer;

import java.nio.ByteOrder;

import java.nio.FloatBuffer;

import com.cumt.openglestwo_test_one.R;

import com.cumt.utils.MatrixState;

import com.cumt.utils.ShaderHelper;

import com.cumt.utils.TextResourceReader;

import android.content.Context;

import android.opengl.GLES20;

 

public class Cube {

     

    private FloatBuffer vertexBuffer;

    private Context context;

    //float类型的字节数

    private static final int BYTES_PER_FLOAT = 4;

    //共有72个顶点坐标,每个面包含12个顶点坐标

    private static final int POSITION_COMPONENT_COUNT = 12*6;

    // 数组中每个顶点的坐标数

    private static final int COORDS_PER_VERTEX = 3;

     

    private static final String A_POSITION = "a_Position";

    private static final String U_COLOR = "u_Color";

    private static final String U_MATRIX = "u_Matrix";

    private int uMatrixLocation;

    private int uColorLocation;

    private int aPositionLocation;

    private int program;

 

    static float vertices[] = {

        //前面

        0,0,1.0f,

        1.0f,1.0f,1.0f,

        -1.0f,1.0f,1.0f,

        0,0,1.0f,

        -1.0f,1.0f,1.0f,

        -1.0f,-1.0f,1.0f,

        0,0,1.0f,

        -1.0f,-1.0f,1.0f,

        1.0f,-1.0f,1.0f,

        0,0,1.0f,

        1.0f,-1.0f,1.0f,

        1.0f,1.0f,1.0f,

        //后面

        0,0,-1.0f,         

        1.0f,1.0f,-1.0f,

        1.0f,-1.0f,-1.0f,

        0,0,-1.0f,

        1.0f,-1.0f,-1.0f,

        -1.0f,-1.0f,-1.0f,

        0,0,-1.0f,

        -1.0f,-1.0f,-1.0f,

        -1.0f,1.0f,-1.0f,

        0,0,-1.0f,

        -1.0f,1.0f,-1.0f,

        1.0f,1.0f,-1.0f,

        //左面

        -1.0f,0,0,         

        -1.0f,1.0f,1.0f,

        -1.0f,1.0f,-1.0f,

        -1.0f,0,0,  

        -1.0f,1.0f,-1.0f,

        -1.0f,-1.0f,-1.0f,

        -1.0f,0,0,  

        -1.0f,-1.0f,-1.0f,

        -1.0f,-1.0f,1.0f,

        -1.0f,0,0,  

        -1.0f,-1.0f,1.0f,

        -1.0f,1.0f,1.0f,

        //右面

        1.0f,0,0,  

        1.0f,1.0f,1.0f,

        1.0f,-1.0f,1.0f,

        1.0f,0,0,  

        1.0f,-1.0f,1.0f,

        1.0f,-1.0f,-1.0f,

        1.0f,0,0,  

        1.0f,-1.0f,-1.0f,

        1.0f,1.0f,-1.0f,

        1.0f,0,0

        1.0f,1.0f,-1.0f,

        1.0f,1.0f,1.0f,

        //上面

        0,1.0f,0,     

        1.0f,1.0f,1.0f,

        1.0f,1.0f,-1.0f,

        0,1.0f,0,          

        1.0f,1.0f,-1.0f,

        -1.0f,1.0f,-1.0f,

        0,1.0f,0,      

        -1.0f,1.0f,-1.0f,

        -1.0f,1.0f,1.0f,   

        0,1.0f,0,     

        -1.0f,1.0f,1.0f,

        1.0f,1.0f,1.0f,    

        //下面

        0,-1.0f,0,         

        1.0f,-1.0f,1.0f,

        -1.0f,-1.0f,1.0f,

        0,-1.0f,0

        -1.0f,-1.0f,1.0f,

        -1.0f,-1.0f,-1.0f,

        0,-1.0f,0,  

        -1.0f,-1.0f,-1.0f,

        1.0f,-1.0f,-1.0f,

        0,-1.0f,0,   

        1.0f,-1.0f,-1.0f,

        1.0f,-1.0f,1.0f

    };

     

    public Cube(Context context){

        this.context = context;

         

        vertexBuffer = ByteBuffer

                .allocateDirect(vertices.length * BYTES_PER_FLOAT)

                .order(ByteOrder.nativeOrder())

                .asFloatBuffer();

        // 把坐标们加入FloatBuffer中

        vertexBuffer.put(vertices);

        // 设置buffer,从第一个坐标开始读

        vertexBuffer.position(0);

         

        getProgram();

         

        uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR);

        aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);

        uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);

         

        //---------传入顶点数据数据

        GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,

                GLES20.GL_FLOAT, false, 0, vertexBuffer);

        GLES20.glEnableVertexAttribArray(aPositionLocation);

    }

     

    //获取program

    private void getProgram(){

        //获取顶点着色器文本

        String vertexShaderSource = TextResourceReader

                .readTextFileFromResource(context, R.raw.vertex_shader);

        //获取片段着色器文本

        String fragmentShaderSource = TextResourceReader

                .readTextFileFromResource(context, R.raw.simple_fragment_shader);

        //获取program的id

        program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);

        GLES20.glUseProgram(program);

    }

     

    public void draw(){

        GLES20.glUniform4f(uColorLocation, 1.0f, 0.0f, 0.0f, 0.0f);    

        GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, MatrixState.getFinalMatrix(),0);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, POSITION_COMPONENT_COUNT);

    }

}

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

package com.cumt.render;

 

import javax.microedition.khronos.egl.EGLConfig;

import javax.microedition.khronos.opengles.GL10;

import com.cumt.utils.MatrixState;

import com.cumt.shape.Cube;

import android.content.Context;

import android.opengl.GLES20;

import android.opengl.GLSurfaceView.Renderer;

import android.util.Log;

import static android.opengl.GLES20.glClear;

import static android.opengl.GLES20.glClearColor;

import static android.opengl.GLES20.glViewport;

 

public class MyRender implements Renderer {

     

    private Context context;

     

    public MyRender(Context context){

        this.context = context;

    }

     

//  Circle circle;

    Cube cube;

     

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {

        Log.w("MyRender","onSurfaceCreated");

        //设置屏幕背景色RGBA

        glClearColor(0.5f,0.5f,0.5f, 1.0f); 

//      //打开深度检测

        GLES20.glEnable(GLES20.GL_DEPTH_TEST);

//        //打开背面剪裁  

        GLES20.glEnable(GLES20.GL_CULL_FACE);

//      circle = new Circle(context);

        cube = new Cube(context);

    }

 

    public void onSurfaceChanged(GL10 gl, int width, int height) {

        glViewport(0,0,width,height);

        float ratio = (float) width / height;

        //设置投影矩阵

//      circle.projectionMatrix(width, height);

        // 调用此方法计算产生透视投影矩阵

        MatrixState.setProjectFrustum(-ratio,ratio, -1, 1, 20, 100);

        // 调用此方法产生摄像机9参数位置矩阵

        MatrixState.setCamera(-16f, 8f, 45, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

    }

 

    public void onDrawFrame(GL10 gl) {

//      glClear(GL_COLOR_BUFFER_BIT);

        //清除深度缓冲与颜色缓冲

        glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

//      circle.draw();

        cube.draw();

    }

}

 

然后我们回到MainActivity 设置屏幕显示方式为竖屏,全屏 ,此时MainActivity代码如下 (MainActivity.java):

 

 

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

package com.cumt.openglestwo_test_one;

 

import com.cumt.render.MyRender;

import android.app.Activity;

import android.content.pm.ActivityInfo;

import android.opengl.GLSurfaceView;

import android.os.Bundle;

import android.view.Window;

import android.view.WindowManager;

 

public class MainActivity extends Activity {

 

    private GLSurfaceView glSurfaceView;

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        // 设置为全屏

        requestWindowFeature(Window.FEATURE_NO_TITLE);

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,

                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        // 设置为横屏模式

        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        glSurfaceView = new GLSurfaceView(this);

        //OpenGL ES 2.0

        glSurfaceView.setEGLContextClientVersion(2);

        glSurfaceView.setRenderer(new MyRender(this));

        // 设置渲染模式为主动渲染

        glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);

        setContentView(glSurfaceView);

    }

 

    @Override

    protected void onPause() {

        // TODO Auto-generated method stub

        super.onPause();

        glSurfaceView.onPause();

    }

 

    @Override

    protected void onResume() {

        // TODO Auto-generated method stub

        super.onResume();

        glSurfaceView.onResume();

    }

}


快来运行一下 :

 

 

\

 


一个全红的立方体诞生了~~(大家还可以尝试用线段的绘制方式来绘制一个 " 空心 " 的立方体),可是这样看起来根本看不出来它的一些边 ,我们来想办法给它美化一下,在这节先不考虑纹理贴图,我们把每个面设置成不同的颜色。

 

OK,先来看下我们接下来的过程 :

 

\

 

在Cube类中定义顶点坐标,并转化为FloatBuffer类型 ,此时代码如下 (Cube.java ) :

 

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

package com.cumt.shape;

 

import java.nio.ByteBuffer;

import java.nio.ByteOrder;

import java.nio.FloatBuffer;

import com.cumt.openglestwo_test_one.R;

import com.cumt.utils.MatrixState;

import com.cumt.utils.ShaderHelper;

import com.cumt.utils.TextResourceReader;

import android.content.Context;

import android.opengl.GLES20;

 

public class Cube {

     

    //顶点坐标

    private FloatBuffer vertexBuffer;

    //颜色坐标

    private FloatBuffer colorBuffer;

    private Context context;

    //float类型的字节数

    private static final int BYTES_PER_FLOAT = 4;

    //共有72个顶点坐标,每个面包含12个顶点坐标

    private static final int POSITION_COMPONENT_COUNT = 12*6;

    // 数组中每个顶点的坐标数

    private static final int COORDS_PER_VERTEX = 3;

     

    private static final String A_POSITION = "a_Position";

    private static final String U_COLOR = "u_Color";

    private static final String U_MATRIX = "u_Matrix";

    private int uMatrixLocation;

    private int uColorLocation;

    private int aPositionLocation;

    private int program;

 

    static float vertices[] = {

        //前面

        0,0,1.0f,

        1.0f,1.0f,1.0f,

        -1.0f,1.0f,1.0f,

        0,0,1.0f,

        -1.0f,1.0f,1.0f,

        -1.0f,-1.0f,1.0f,

        0,0,1.0f,

        -1.0f,-1.0f,1.0f,

        1.0f,-1.0f,1.0f,

        0,0,1.0f,

        1.0f,-1.0f,1.0f,

        1.0f,1.0f,1.0f,

        //后面

        0,0,-1.0f,         

        1.0f,1.0f,-1.0f,

        1.0f,-1.0f,-1.0f,

        0,0,-1.0f,

        1.0f,-1.0f,-1.0f,

        -1.0f,-1.0f,-1.0f,

        0,0,-1.0f,

        -1.0f,-1.0f,-1.0f,

        -1.0f,1.0f,-1.0f,

        0,0,-1.0f,

        -1.0f,1.0f,-1.0f,

        1.0f,1.0f,-1.0f,

        //左面

        -1.0f,0,0,         

        -1.0f,1.0f,1.0f,

        -1.0f,1.0f,-1.0f,

        -1.0f,0,0,  

        -1.0f,1.0f,-1.0f,

        -1.0f,-1.0f,-1.0f,

        -1.0f,0,0,  

        -1.0f,-1.0f,-1.0f,

        -1.0f,-1.0f,1.0f,

        -1.0f,0,0,  

        -1.0f,-1.0f,1.0f,

        -1.0f,1.0f,1.0f,

        //右面

        1.0f,0,0,  

        1.0f,1.0f,1.0f,

        1.0f,-1.0f,1.0f,

        1.0f,0,0,  

        1.0f,-1.0f,1.0f,

        1.0f,-1.0f,-1.0f,

        1.0f,0,0,  

        1.0f,-1.0f,-1.0f,

        1.0f,1.0f,-1.0f,

        1.0f,0,0

        1.0f,1.0f,-1.0f,

        1.0f,1.0f,1.0f,

        //上面

        0,1.0f,0,     

        1.0f,1.0f,1.0f,

        1.0f,1.0f,-1.0f,

        0,1.0f,0,          

        1.0f,1.0f,-1.0f,

        -1.0f,1.0f,-1.0f,

        0,1.0f,0,      

        -1.0f,1.0f,-1.0f,

        -1.0f,1.0f,1.0f,   

        0,1.0f,0,     

        -1.0f,1.0f,1.0f,

        1.0f,1.0f,1.0f,    

        //下面

        0,-1.0f,0,         

        1.0f,-1.0f,1.0f,

        -1.0f,-1.0f,1.0f,

        0,-1.0f,0

        -1.0f,-1.0f,1.0f,

        -1.0f,-1.0f,-1.0f,

        0,-1.0f,0,  

        -1.0f,-1.0f,-1.0f,

        1.0f,-1.0f,-1.0f,

        0,-1.0f,0,   

        1.0f,-1.0f,-1.0f,

        1.0f,-1.0f,1.0f

    };

     

    //顶点颜色值数组,每个顶点4个色彩值RGBA

    static float colors[]=new float[]{

            //前面       

            1,1,1,0,//中间为白色

            1,0,0,0,

            1,0,0,0,

            1,1,1,0,//中间为白色

            1,0,0,0,

            1,0,0,0,

            1,1,1,0,//中间为白色

            1,0,0,0,

            1,0,0,0,

            1,1,1,0,//中间为白色

            1,0,0,0,

            1,0,0,0,

            //后面

            1,1,1,0,//中间为白色

            0,0,1,0,

            0,0,1,0,

            1,1,1,0,//中间为白色

            0,0,1,0,

            0,0,1,0,

            1,1,1,0,//中间为白色

            0,0,1,0,

            0,0,1,0,

            1,1,1,0,//中间为白色

            0,0,1,0,

            0,0,1,0,

            //左面

            1,1,1,0,//中间为白色

            1,0,1,0,

            1,0,1,0,

            1,1,1,0,//中间为白色

            1,0,1,0,

            1,0,1,0,

            1,1,1,0,//中间为白色

            1,0,1,0,

            1,0,1,0,

            1,1,1,0,//中间为白色

            1,0,1,0,

            1,0,1,0,

            //右面

            1,1,1,0,//中间为白色

            1,1,0,0,

            1,1,0,0,

            1,1,1,0,//中间为白色

            1,1,0,0,

            1,1,0,0,

            1,1,1,0,//中间为白色

            1,1,0,0,

            1,1,0,0,

            1,1,1,0,//中间为白色

            1,1,0,0,

            1,1,0,0,

            //上面

            1,1,1,0,//中间为白色

            0,1,0,0,

            0,1,0,0,

            1,1,1,0,//中间为白色

            0,1,0,0,

            0,1,0,0,

            1,1,1,0,//中间为白色

            0,1,0,0,

            0,1,0,0,

            1,1,1,0,//中间为白色

            0,1,0,0,

            0,1,0,0,               

            //下面

            1,1,1,0,//中间为白色

            0,1,1,0,

            0,1,1,0,

            1,1,1,0,//中间为白色

            0,1,1,0,

            0,1,1,0,

            1,1,1,0,//中间为白色

            0,1,1,0,

            0,1,1,0,

            1,1,1,0,//中间为白色

            0,1,1,0,

            0,1,1,0,

    };

     

    public Cube(Context context){

        this.context = context;

         

        vertexBuffer = ByteBuffer

                .allocateDirect(vertices.length * BYTES_PER_FLOAT)

                .order(ByteOrder.nativeOrder())

                .asFloatBuffer();

        // 把坐标们加入FloatBuffer中

        vertexBuffer.put(vertices);

        // 设置buffer,从第一个坐标开始读

        vertexBuffer.position(0);

         

        //颜色buffer

        colorBuffer = ByteBuffer

                .allocateDirect(colors.length * BYTES_PER_FLOAT)

                .order(ByteOrder.nativeOrder())

                .asFloatBuffer();

        colorBuffer.put(colors);

        colorBuffer.position(0);

         

        getProgram();

         

        uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR);

        aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);

        uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);

         

        //---------传入顶点数据数据

        GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,

                GLES20.GL_FLOAT, false, 0, vertexBuffer);

        GLES20.glEnableVertexAttribArray(aPositionLocation);

    }

     

    //获取program

    private void getProgram(){

        //获取顶点着色器文本

        String vertexShaderSource = TextResourceReader

                .readTextFileFromResource(context, R.raw.vertex_shader);

        //获取片段着色器文本

        String fragmentShaderSource = TextResourceReader

                .readTextFileFromResource(context, R.raw.simple_fragment_shader);

        //获取program的id

        program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);

        GLES20.glUseProgram(program);

    }

     

    public void draw(){

        GLES20.glUniform4f(uColorLocation, 1.0f, 0.0f, 0.0f, 0.0f);    

        GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, MatrixState.getFinalMatrix(),0);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, POSITION_COMPONENT_COUNT);

    }

}


创建新的顶点着色器和片段着色器程序 (vertex_shader_cube.glsl 和fragment_shader_cube.glsl ):

 

 

 

?

1

2

3

4

5

6

7

8

9

10

11

//vertex_shader_cube.glsl

uniform mat4 u_Matrix;

attribute vec4 a_Position; 

attribute vec4 a_Color;    //顶点颜色

varying  vec4 v_Color;  //用于传递给片元着色器的变量

  

void main()                   

{                             

    gl_Position = u_Matrix * a_Position;

    v_Color = a_Color;//将接收的颜色传递给片元着色器

}

 

?

1

2

3

4

5

6

7

8

//fragment_shader_cube.glsl

precision mediump float;               

varying vec4 v_Color; //接收从顶点着色器过来的参数                          

   

void main()                        

{                              

    gl_FragColor = v_Color;                                        

}

 

 

去点原来的引入颜色的相关代码,加入当前要传递的颜色相关的代码,此时Cube类如下 (Cube.java ) :

 

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

package com.cumt.shape;

 

import java.nio.ByteBuffer;

import java.nio.ByteOrder;

import java.nio.FloatBuffer;

import com.cumt.openglestwo_test_one.R;

import com.cumt.utils.MatrixState;

import com.cumt.utils.ShaderHelper;

import com.cumt.utils.TextResourceReader;

import android.content.Context;

import android.opengl.GLES20;

 

public class Cube {

 

    //顶点坐标

    private FloatBuffer vertexBuffer;

    //颜色坐标

    private FloatBuffer colorBuffer;

    private Context context;

    //float类型的字节数

    private static final int BYTES_PER_FLOAT = 4;

    //共有72个顶点坐标,每个面包含12个顶点坐标

    private static final int POSITION_COMPONENT_COUNT = 12*6;

    // 数组中每个顶点的坐标数

    private static final int COORDS_PER_VERTEX = 3;

    // 颜色数组中每个颜色的值数

    private static final int COORDS_PER_COLOR = 4;

     

    private static final String A_POSITION = "a_Position";

    private static final String A_COLOR = "a_Color";

    private static final String U_MATRIX = "u_Matrix";

    private int uMatrixLocation;

    private int aColorLocation;

    private int aPositionLocation;

    private int program;

 

    static float vertices[] = {

        //前面

        0,0,1.0f,

        1.0f,1.0f,1.0f,

        -1.0f,1.0f,1.0f,

        0,0,1.0f,

        -1.0f,1.0f,1.0f,

        -1.0f,-1.0f,1.0f,

        0,0,1.0f,

        -1.0f,-1.0f,1.0f,

        1.0f,-1.0f,1.0f,

        0,0,1.0f,

        1.0f,-1.0f,1.0f,

        1.0f,1.0f,1.0f,

        //后面

        0,0,-1.0f,         

        1.0f,1.0f,-1.0f,

        1.0f,-1.0f,-1.0f,

        0,0,-1.0f,

        1.0f,-1.0f,-1.0f,

        -1.0f,-1.0f,-1.0f,

        0,0,-1.0f,

        -1.0f,-1.0f,-1.0f,

        -1.0f,1.0f,-1.0f,

        0,0,-1.0f,

        -1.0f,1.0f,-1.0f,

        1.0f,1.0f,-1.0f,

        //左面

        -1.0f,0,0,         

        -1.0f,1.0f,1.0f,

        -1.0f,1.0f,-1.0f,

        -1.0f,0,0,  

        -1.0f,1.0f,-1.0f,

        -1.0f,-1.0f,-1.0f,

        -1.0f,0,0,  

        -1.0f,-1.0f,-1.0f,

        -1.0f,-1.0f,1.0f,

        -1.0f,0,0,  

        -1.0f,-1.0f,1.0f,

        -1.0f,1.0f,1.0f,

        //右面

        1.0f,0,0,  

        1.0f,1.0f,1.0f,

        1.0f,-1.0f,1.0f,

        1.0f,0,0,  

        1.0f,-1.0f,1.0f,

        1.0f,-1.0f,-1.0f,

        1.0f,0,0,  

        1.0f,-1.0f,-1.0f,

        1.0f,1.0f,-1.0f,

        1.0f,0,0

        1.0f,1.0f,-1.0f,

        1.0f,1.0f,1.0f,

        //上面

        0,1.0f,0,     

        1.0f,1.0f,1.0f,

        1.0f,1.0f,-1.0f,

        0,1.0f,0,          

        1.0f,1.0f,-1.0f,

        -1.0f,1.0f,-1.0f,

        0,1.0f,0,      

        -1.0f,1.0f,-1.0f,

        -1.0f,1.0f,1.0f,   

        0,1.0f,0,     

        -1.0f,1.0f,1.0f,

        1.0f,1.0f,1.0f,    

        //下面

        0,-1.0f,0,         

        1.0f,-1.0f,1.0f,

        -1.0f,-1.0f,1.0f,

        0,-1.0f,0

        -1.0f,-1.0f,1.0f,

        -1.0f,-1.0f,-1.0f,

        0,-1.0f,0,  

        -1.0f,-1.0f,-1.0f,

        1.0f,-1.0f,-1.0f,

        0,-1.0f,0,   

        1.0f,-1.0f,-1.0f,

        1.0f,-1.0f,1.0f

    };

     

    //顶点颜色值数组,每个顶点4个色彩值RGBA

    static float colors[]=new float[]{

            //前面       

            1,1,1,0,//中间为白色

            1,0,0,0,

            1,0,0,0,

            1,1,1,0,//中间为白色

            1,0,0,0,

            1,0,0,0,

            1,1,1,0,//中间为白色

            1,0,0,0,

            1,0,0,0,

            1,1,1,0,//中间为白色

            1,0,0,0,

            1,0,0,0,

            //后面

            1,1,1,0,//中间为白色

            0,0,1,0,

            0,0,1,0,

            1,1,1,0,//中间为白色

            0,0,1,0,

            0,0,1,0,

            1,1,1,0,//中间为白色

            0,0,1,0,

            0,0,1,0,

            1,1,1,0,//中间为白色

            0,0,1,0,

            0,0,1,0,

            //左面

            1,1,1,0,//中间为白色

            1,0,1,0,

            1,0,1,0,

            1,1,1,0,//中间为白色

            1,0,1,0,

            1,0,1,0,

            1,1,1,0,//中间为白色

            1,0,1,0,

            1,0,1,0,

            1,1,1,0,//中间为白色

            1,0,1,0,

            1,0,1,0,

            //右面

            1,1,1,0,//中间为白色

            1,1,0,0,

            1,1,0,0,

            1,1,1,0,//中间为白色

            1,1,0,0,

            1,1,0,0,

            1,1,1,0,//中间为白色

            1,1,0,0,

            1,1,0,0,

            1,1,1,0,//中间为白色

            1,1,0,0,

            1,1,0,0,

            //上面

            1,1,1,0,//中间为白色

            0,1,0,0,

            0,1,0,0,

            1,1,1,0,//中间为白色

            0,1,0,0,

            0,1,0,0,

            1,1,1,0,//中间为白色

            0,1,0,0,

            0,1,0,0,

            1,1,1,0,//中间为白色

            0,1,0,0,

            0,1,0,0,               

            //下面

            1,1,1,0,//中间为白色

            0,1,1,0,

            0,1,1,0,

            1,1,1,0,//中间为白色

            0,1,1,0,

            0,1,1,0,

            1,1,1,0,//中间为白色

            0,1,1,0,

            0,1,1,0,

            1,1,1,0,//中间为白色

            0,1,1,0,

            0,1,1,0,

    };

     

    public Cube(Context context){

        this.context = context;

         

        vertexBuffer = ByteBuffer

                .allocateDirect(vertices.length * BYTES_PER_FLOAT)

                .order(ByteOrder.nativeOrder())

                .asFloatBuffer();

        // 把坐标们加入FloatBuffer中

        vertexBuffer.put(vertices);

        // 设置buffer,从第一个坐标开始读

        vertexBuffer.position(0);

         

        //颜色buffer

        colorBuffer = ByteBuffer

                .allocateDirect(colors.length * BYTES_PER_FLOAT)

                .order(ByteOrder.nativeOrder())

                .asFloatBuffer();

        colorBuffer.put(colors);

        colorBuffer.position(0);

         

        getProgram();

         

        aColorLocation = GLES20.glGetAttribLocation(program, A_COLOR);

        aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);

        uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);

         

        //---------传入顶点数据数据

        GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,

                GLES20.GL_FLOAT, false, 0, vertexBuffer);

        GLES20.glEnableVertexAttribArray(aPositionLocation);

        //---------传入颜色数据

        GLES20.glVertexAttribPointer(aColorLocation, COORDS_PER_COLOR,

                GLES20.GL_FLOAT, false, 0, colorBuffer);

        GLES20.glEnableVertexAttribArray(aColorLocation);

    }

     

    //获取program

    private void getProgram(){

        //获取顶点着色器文本

        String vertexShaderSource = TextResourceReader

                .readTextFileFromResource(context, R.raw.vertex_shader_cube);

        //获取片段着色器文本

        String fragmentShaderSource = TextResourceReader

                .readTextFileFromResource(context, R.raw.fragment_shader_cube);

        //获取program的id

        program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);

        GLES20.glUseProgram(program);

    }

     

    public void draw(){

        GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, MatrixState.getFinalMatrix(),0);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, POSITION_COMPONENT_COUNT);

    }

}

 

 

运行一下看看结果 :

 

\

 

 

哈 现在我们的立方体就完成了 ,是不是很漂亮 。 关于颜色设置,这里用到了OpenglEs 的平滑着色 ,如果有不明白的

可以去按照 “opengl es 平滑着色 ” 这个关键字搜索一下 。这里不再讲解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值