2023年11月29日发(作者:)
AndroidOpenGLES2.0绘图:绘制纹理
1. public class MyGLSurfaceView extends GLSurfaceView {
2.
3. public MyGLSurfaceView(Context context) {
4. super(context);
5. setFocusableInTouchMode(true);
6. // Tell the surface view we want to create an OpenGL ES 2.0-compatible
7. // context, and set an OpenGL ES 2.0-compatible renderer.
8. this.setEGLContextClientVersion(2);
9. this.setRenderer(new MyRenderer());
10. }
11. }
并没有什么特别之处,android view的渲染操作需要实现⼀个render接⼝,GLSurfaceView的渲染接⼝为
er。我们需要实现接⼝的⽅法。
java代码
1. public class MyRenderer implements Renderer {
2.
3. public void onDrawFrame(GL10 gl) {}
4. public void onSurfaceChanged(GL10 gl, int width, int height) {}
5. public void onSurfaceCreated(GL10 gl, EGLConfig config) {}
6. }
接⼝实现3个⽅法,对应绘制,绘制区域变化,区域创建。需要说明的是参数GL10 gl是OpenGL ES1.x版本的对象。这⾥我们不会使⽤
到。还有⼀点就是,onDrawFrame⽅法的调⽤是有系统调⽤的,不需要⼿动调⽤。系统会以⼀定的频率不断的回调。
接下来我们进⼊ES2.0的使⽤,上代码先:
java代码
1. public void onSurfaceCreated(GL10 gl, EGLConfig config) {
2.
3. le(_TEXTURE_2D);
4. // Active the texture unit 0
5. veTexture(_TEXTURE0);
6. loadVertex();
7. initShader();
8. loadTexture();
9. }
1、启⽤2D纹理
绘制区域创建的时候,我们设置了启⽤2D的纹理,并且激活了纹理单元unit0。什么意思呢,说起来话长,以后慢慢说。简单说⼀下,记
住OpenGL 是基于状态的,就是很多状态的设置和切换,这⾥启⽤GL_TEXTURE_2D就是⼀个状态的开启,表明OpenGL可以使⽤2D纹
理。
什么是激活纹理单元?这个和硬件有点关系,OpenGL要显卡会划分存储纹理的存储区域不⽌⼀个区域。这⾥是使⽤区域 unit 0,多重纹
理绘制可以开启多个,这个以后说。接下来,调⽤了三个函数,载⼊顶点,初始化着⾊器,载⼊纹理。
2、加载顶点
OpenGL绘制图形是根据顶点以后链接起来的。为什么要这样,其实这样很强⼤是⼀种设计吧。顶点可以暂时简单理解为含有位置信息
的坐标点。
java代码
1. private void loadVertex() {
2.
3. // float size = 4
4. this.vertex = teDirect( * 4)
5. .order(Order())
6. .asFloatBuffer();
7. this.(quadVertex).position(0);
8. // short size = 2
9. this.index = teDirect( * 2)
10. .order(Order())
11. .asShortBuffer();
12. this.(quadIndex).position(0);
13. }
14. private FloatBuffer vertex;
15. private ShortBuffer index;
16. private float[] quadVertex = new float[] {
17. -0.5f, 0.5f, 0.0f, // Position 0
18. 0, 1.0f, // TexCoord 0
19. -0.5f, -0.5f, 0.0f, // Position 1
20. 0, 0, // TexCoord 1
21. 0.5f , -0.5f, 0.0f, // Position 2
22. 1.0f, 0, // TexCoord 2
23. 0.5f, 0.5f, 0.0f, // Position 3
24. 1.0f, 1.0f, // TexCoord 3
25. };
26. private short[] quadIndex = new short[] {
27. (short)(0), // Position 0
28. (short)(1), // Position 1
29. (short)(2), // Position 2
30. (short)(2), // Position 2
31. (short)(3), // Position 3
32. (short)(0), // Position 0
33. };
FloatBuffer,ShortBuffer是封装了本地数据结构的封装对象。是 的,这个2个对象⾥⾯的数据不被java虚拟机管理,相当于C语⾔的存储
⽅式。quadVertex的数据就是⼀个矩形的坐标,和纹理坐标。⼀两句话很难 解释清楚,这⾥涉及到openGL的⼏个经典的坐标系,下次说。
概括的说,openGL的坐标是单位化的,都是0.0-1.0的浮点型,屏幕的中⼼点是 (0,0)。⽽纹理的坐标左下⾓是(0,0)。 这⾥的quadVertex是在
屏幕中⼤概花了⼀个矩形贴了⼀个图⽚, position0 是左上点,以后左下,右下,右上的顺序,纹理坐标同理。
quadIndx是这刚才的这些顶点索引排列。这⾥⼀个矩形也就4个顶点,每个顶点3个位置坐标,2个纹理坐标。也就是说⼀个顶点有5个
float数据。⾄于为什么顶点为什么这么排列下次说,是2个三⾓形合成了⼀个矩形,⼏句话很难解释清楚。
所以说,这段代码就是把矩形的位置和纹理坐标,存储到本地数据,准备后⾯使⽤⽽已。
3、初始化着⾊器
这个着⾊器就是ES2.0的特⾊,⼜叫可编程着⾊器,也是区别于ES1.x的本质。这⾥只做简单的介绍。可编程着⾊器是⼀种脚本,语法类
似C语⾔,脚本分为顶点着⾊器和⽚段着⾊器,分别对应了openGL不同的渲染流程。
顶点着⾊器:
java代码
1. uniform mat4 u_MVPMatrix;
2.
3. attribute vec4 a_position;
4. attribute vec2 a_texCoord;
5. varying vec2 v_texCoord;
6. void main()
7. {
8. gl_Position = a_position;
9. v_texCoord = a_texCoord;
10. }
⽚段着⾊器:
java代码
1. precision lowp float;
2.
3. varying vec2 v_texCoord;
4. uniform sampler2D u_samplerTexture;
5. void main()
6. {
7. gl_FragColor = texture2D(u_samplerTexture, v_texCoord);
8. }
这⾥记住⼀句话,顶点着⾊器,会在顶点上执⾏;⽚段着⾊器会在像素点上执⾏。刚才的矩形就有4个顶点,每个顶点都会应⽤这个脚
本。也就是说,顶点是位置相关信息,⽚段是⾊彩纹理相关信息。
这个2段脚本都是⽂本,需要编译,链接,等等⼀些操作才能被ES2.0所使⽤。过程就像C语⾔的编译运⾏过程。openGL 提供了相关函
数去做这些事情。
java代码
1. private void initShader() {
2.
3. String vertexSource = omAssets("");
4. String fragmentSource = omAssets("");
5. // Load the shaders and get a linked program
6. program = ogram(vertexSource, fragmentSource);
7. // Get the attribute locations
8. attribPosition = ttribLocation(program, "a_position");
9. attribTexCoord = ttribLocation(program, "a_texCoord");
10. uniformTexture = niformLocation(program,
11. "u_samplerTexture");
12. rogram(program);
13. leVertexAttribArray(attribPosition);
14. leVertexAttribArray(attribTexCoord);
15. // Set the sampler to texture unit 0
16. orm1i(uniformTexture, 0);
17. }
可以看到,顶点和⽚段⼀起构成⼀个program,它可以被openGL所使⽤,是⼀个 编译好的脚本程序,存储在显存。
ttribLocation 和 niformLocation 这句话是神马作⽤呢。简单说就是,java程序和着⾊器脚本数据通信的。把
就像参数的传递⼀样,这样脚本就能根据外界的参数变化,实时的改变openGL 流⽔线渲染的处理流程。
封装的加载着⾊器的辅助⽅法:
java代码
1. public static int loadProgram(String vertexSource, String
2. fragmentSource) {
3.
4. // Load the vertex shaders
5. int vertexShader = ader(_VERTEX_SHADE
6. vertexSource);
7. // Load the fragment shaders
8. int fragmentShader = ader(_FRAGMENT_S
9. fragmentSource);
10. // Create the program object
11. int program = teProgram();
12. if (program == 0) {
13. throw new RuntimeException("Error create program.");
14. }
15. chShader(program, vertexShader);
16. chShader(program, fragmentShader);
17. // Link the program
18. Program(program);
19. int[] linked = new int[1];
20. // Check the link status
21. rogramiv(program, _LINK_STATUS, linked, 0
22. if (linked[0] == 0) {
23. teProgram(program);
24. throw new RuntimeException("Error linking program: " +
25. rogramInfoLog(program));
26. }
27. // Free up no longer needed shader resources
28. teShader(vertexShader);
29. teShader(fragmentShader);
30. return program;
31. }
R,
HADER,
);
java代码
1. public static int loadShader(int shaderType, String source) {
2.
3. // Create the shader object
4. int shader = teShader(shaderType);
5. if (shader == 0) {
6. throw new RuntimeException("Error create shader.");
7. }
8. int[] compiled = new int[1];
9. // Load the shader source
10. erSource(shader, source);
11. // Compile the shader
12. ileShader(shader);
13. // Check the compile status
14. haderiv(shader, _COMPILE_STATUS, compi
15. if (compiled[0] == 0) {
16. teShader(shader);
17. throw new RuntimeException("Error compile shader: " +
18. haderInfoLog(shader));
19. }
20. return shader;
21. }
led, 0);
为什么openGL的很多操作⽬标都是int类型的?因为openGL只会在显存⽣成或绑定地址,返回id,以后⽤id相当于句柄去改变它的内部状
态。
4、加载纹理
就是把图⽚的数据上传到显存,以后再使⽤它。请注意纹理图⽚的长和宽最好是2的N次⽅,不然不⼀定能绘制出来。
java代码
1. static int[] loadTexture(String path) {
2.
3. int[] textureId = new int[1];
4. // Generate a texture object
5. extures(1, textureId, 0);
6. int[] result = null;
7. if (textureId[0] != 0) {
8. InputStream is = omAsserts(path);
9. Bitmap bitmap;
10. try {
11. bitmap = Stream(is);
12. } finally {
13. try {
14. ();
15. } catch (IOException e) {
16. throw new RuntimeException("Error loading Bitmap.");
17. }
18. }
19. result = new int[3];
20. result[TEXTURE_ID] = textureId[0]; // TEXTURE_ID
21. result[TEXTURE_WIDTH] = th(); // TEXTURE_WIDTH
22. result[TEXTURE_HEIGHT] = ght(); // TEXTURE_HEIGHT
23. // Bind to the texture in OpenGL
24. Texture(_TEXTURE_2D, textureId[0]);
25. // Set filtering
26. arameteri(_TEXTURE_2D, _TE
27. _LINEAR);
28. arameteri(_TEXTURE_2D, _TE
29. _NEAREST);
30. arameteri(_TEXTURE_2D, _TE
31. _CLAMP_TO_EDGE);
32. arameteri(_TEXTURE_2D, _TE
33. _CLAMP_TO_EDGE);
34. // Load the bitmap into the bound texture.
35. ge2D(_TEXTURE_2D, 0, bitmap, 0);
36. // Recycle the bitmap, since its data has been loaded into OpenGL.
37. e();
38. } else {
39. throw new RuntimeException("Error loading texture.");
40. }
41. return result;
42. }
XTURE_MIN_FILTER,
XTURE_MAG_FILTER,
XTURE_WRAP_S,
XTURE_WRAP_T,
这⾥使⽤了android的⼯具类吧bitmap直接转换成openGL纹理需要的格式了。过程是,先⽣成⼀个纹理的id在显卡上的,以后根据id上
传纹理数据,以后保存这个id就
可以操作这个纹理了。⾄于纹理的⼀些过滤特性设置,将来再说。
现在貌似就剩下绘制了,准备好了顶点信息,顶点对应的纹理坐标。初始化了着⾊器,上传了纹理图⽚。接下来就已把他们合起来绘制
了。
java代码
1. public void onDrawFrame(GL10 gl) {
2.
3. // clear screen to black
4. rColor(0.0f, 0.0f, 0.0f, 0.0f);
5. r(_COLOR_BUFFER_BIT);
6. Texture(_TEXTURE_2D, textureId);
7. on(0);
8. // load the position
9. // 3(x , y , z)
10. // (2 + 3 )* 4 (float size) = 20
11. exAttribPointer(attribPosition,
12. 3, _FLOAT,
13. false, 20, vertex);
14. on(3);
15. // load the texture coordinate
16. exAttribPointer(attribTexCoord,
17. 2, _FLOAT,
18. false, 20, vertex);
19. Elements(_TRIANGLES, 6, _UN
SIGNED_SHORT,
20. index);
21. }
为了保持了代码的简单,OpenGL的基于状态体现,bind这个函数⽆处不在,这⾥ bindTexture就是通知openGL使⽤那个id的纹理图
⽚。接下来的操作就是针对bind的图⽚的。绘制就需要让openGL知道绘制神马。所 以这⾥需要⽤到vertex这个本地数据容器,⾥⾯装在的
是顶点和纹理坐标信息。exAttribPointer就是把顶点数据,按照openGL喜欢的格式上传到显卡存储。draw⽅法的调⽤,是在
前⾯应 ⽤了纹理id的情况下,所以绘制纹理坐标的时候,会使⽤上传的纹理图⽚。
每次都需要把数据上传到OpenGL,毕竟显存和内存不是同⼀个地⽅,OpenGL采⽤了CS模式。当然使⽤VBO等技术可以把数据缓存在
显存,以提⾼运⾏性能。
1. public class MyGLSurfaceView extends GLSurfaceView {
2.
3. public MyGLSurfaceView(Context context) {
4. super(context);
5. setFocusableInTouchMode(true);
6. // Tell the surface view we want to create an OpenGL ES 2.0-compatible
7. // context, and set an OpenGL ES 2.0-compatible renderer.
8. this.setEGLContextClientVersion(2);
9. this.setRenderer(new MyRenderer());
10. }
11. }
并没有什么特别之处,android view的渲染操作需要实现⼀个render接⼝,GLSurfaceView的渲染接⼝为
er。我们需要实现接⼝的⽅法。
java代码
1. public class MyRenderer implements Renderer {
2.
3. public void onDrawFrame(GL10 gl) {}
4. public void onSurfaceChanged(GL10 gl, int width, int height) {}
5. public void onSurfaceCreated(GL10 gl, EGLConfig config) {}
6. }
接⼝实现3个⽅法,对应绘制,绘制区域变化,区域创建。需要说明的是参数GL10 gl是OpenGL ES1.x版本的对象。这⾥我们不会使⽤
到。还有⼀点就是,onDrawFrame⽅法的调⽤是有系统调⽤的,不需要⼿动调⽤。系统会以⼀定的频率不断的回调。
接下来我们进⼊ES2.0的使⽤,上代码先:
java代码
1. public void onSurfaceCreated(GL10 gl, EGLConfig config) {
2.
3. le(_TEXTURE_2D);
4. // Active the texture unit 0
5. veTexture(_TEXTURE0);
6. loadVertex();
7. initShader();
8. loadTexture();
9. }
1、启⽤2D纹理
绘制区域创建的时候,我们设置了启⽤2D的纹理,并且激活了纹理单元unit0。什么意思呢,说起来话长,以后慢慢说。简单说⼀下,记
住OpenGL 是基于状态的,就是很多状态的设置和切换,这⾥启⽤GL_TEXTURE_2D就是⼀个状态的开启,表明OpenGL可以使⽤2D纹
理。
什么是激活纹理单元?这个和硬件有点关系,OpenGL要显卡会划分存储纹理的存储区域不⽌⼀个区域。这⾥是使⽤区域 unit 0,多重纹
理绘制可以开启多个,这个以后说。接下来,调⽤了三个函数,载⼊顶点,初始化着⾊器,载⼊纹理。
2、加载顶点
OpenGL绘制图形是根据顶点以后链接起来的。为什么要这样,其实这样很强⼤是⼀种设计吧。顶点可以暂时简单理解为含有位置信息
的坐标点。
java代码
1. private void loadVertex() {
2.
3. // float size = 4
4. this.vertex = teDirect( * 4)
5. .order(Order())
6. .asFloatBuffer();
7. this.(quadVertex).position(0);
8. // short size = 2
9. this.index = teDirect( * 2)
10. .order(Order())
11. .asShortBuffer();
12. this.(quadIndex).position(0);
13. }
14. private FloatBuffer vertex;
15. private ShortBuffer index;
16. private float[] quadVertex = new float[] {
17. -0.5f, 0.5f, 0.0f, // Position 0
18. 0, 1.0f, // TexCoord 0
19. -0.5f, -0.5f, 0.0f, // Position 1
20. 0, 0, // TexCoord 1
21. 0.5f , -0.5f, 0.0f, // Position 2
22. 1.0f, 0, // TexCoord 2
23. 0.5f, 0.5f, 0.0f, // Position 3
24. 1.0f, 1.0f, // TexCoord 3
25. };
26. private short[] quadIndex = new short[] {
27. (short)(0), // Position 0
28. (short)(1), // Position 1
29. (short)(2), // Position 2
30. (short)(2), // Position 2
31. (short)(3), // Position 3
32. (short)(0), // Position 0
33. };
FloatBuffer,ShortBuffer是封装了本地数据结构的封装对象。是 的,这个2个对象⾥⾯的数据不被java虚拟机管理,相当于C语⾔的存储
⽅式。quadVertex的数据就是⼀个矩形的坐标,和纹理坐标。⼀两句话很难 解释清楚,这⾥涉及到openGL的⼏个经典的坐标系,下次说。
概括的说,openGL的坐标是单位化的,都是0.0-1.0的浮点型,屏幕的中⼼点是 (0,0)。⽽纹理的坐标左下⾓是(0,0)。 这⾥的quadVertex是在
屏幕中⼤概花了⼀个矩形贴了⼀个图⽚, position0 是左上点,以后左下,右下,右上的顺序,纹理坐标同理。
quadIndx是这刚才的这些顶点索引排列。这⾥⼀个矩形也就4个顶点,每个顶点3个位置坐标,2个纹理坐标。也就是说⼀个顶点有5个
float数据。⾄于为什么顶点为什么这么排列下次说,是2个三⾓形合成了⼀个矩形,⼏句话很难解释清楚。
所以说,这段代码就是把矩形的位置和纹理坐标,存储到本地数据,准备后⾯使⽤⽽已。
3、初始化着⾊器
这个着⾊器就是ES2.0的特⾊,⼜叫可编程着⾊器,也是区别于ES1.x的本质。这⾥只做简单的介绍。可编程着⾊器是⼀种脚本,语法类
似C语⾔,脚本分为顶点着⾊器和⽚段着⾊器,分别对应了openGL不同的渲染流程。
顶点着⾊器:
java代码
1. uniform mat4 u_MVPMatrix;
2.
3. attribute vec4 a_position;
4. attribute vec2 a_texCoord;
5. varying vec2 v_texCoord;
6. void main()
7. {
8. gl_Position = a_position;
9. v_texCoord = a_texCoord;
10. }
⽚段着⾊器:
java代码
1. precision lowp float;
2.
3. varying vec2 v_texCoord;
4. uniform sampler2D u_samplerTexture;
5. void main()
6. {
7. gl_FragColor = texture2D(u_samplerTexture, v_texCoord);
8. }
这⾥记住⼀句话,顶点着⾊器,会在顶点上执⾏;⽚段着⾊器会在像素点上执⾏。刚才的矩形就有4个顶点,每个顶点都会应⽤这个脚
本。也就是说,顶点是位置相关信息,⽚段是⾊彩纹理相关信息。
这个2段脚本都是⽂本,需要编译,链接,等等⼀些操作才能被ES2.0所使⽤。过程就像C语⾔的编译运⾏过程。openGL 提供了相关函
数去做这些事情。
java代码
1. private void initShader() {
2.
3. String vertexSource = omAssets("");
4. String fragmentSource = omAssets("");
5. // Load the shaders and get a linked program
6. program = ogram(vertexSource, fragmentSource);
7. // Get the attribute locations
8. attribPosition = ttribLocation(program, "a_position");
9. attribTexCoord = ttribLocation(program, "a_texCoord");
10. uniformTexture = niformLocation(program,
11. "u_samplerTexture");
12. rogram(program);
13. leVertexAttribArray(attribPosition);
14. leVertexAttribArray(attribTexCoord);
15. // Set the sampler to texture unit 0
16. orm1i(uniformTexture, 0);
17. }
可以看到,顶点和⽚段⼀起构成⼀个program,它可以被openGL所使⽤,是⼀个 编译好的脚本程序,存储在显存。
ttribLocation 和 niformLocation 这句话是神马作⽤呢。简单说就是,java程序和着⾊器脚本数据通信的。把
就像参数的传递⼀样,这样脚本就能根据外界的参数变化,实时的改变openGL 流⽔线渲染的处理流程。
封装的加载着⾊器的辅助⽅法:
java代码
1. public static int loadProgram(String vertexSource, String
2. fragmentSource) {
3.
4. // Load the vertex shaders
5. int vertexShader = ader(_VERTEX_SHADE
6. vertexSource);
7. // Load the fragment shaders
8. int fragmentShader = ader(_FRAGMENT_S
9. fragmentSource);
10. // Create the program object
11. int program = teProgram();
12. if (program == 0) {
13. throw new RuntimeException("Error create program.");
14. }
15. chShader(program, vertexShader);
16. chShader(program, fragmentShader);
17. // Link the program
18. Program(program);
19. int[] linked = new int[1];
20. // Check the link status
21. rogramiv(program, _LINK_STATUS, linked, 0
22. if (linked[0] == 0) {
23. teProgram(program);
24. throw new RuntimeException("Error linking program: " +
25. rogramInfoLog(program));
26. }
27. // Free up no longer needed shader resources
28. teShader(vertexShader);
29. teShader(fragmentShader);
30. return program;
31. }
R,
HADER,
);
java代码
1. public static int loadShader(int shaderType, String source) {
2.
3. // Create the shader object
4. int shader = teShader(shaderType);
5. if (shader == 0) {
6. throw new RuntimeException("Error create shader.");
7. }
8. int[] compiled = new int[1];
9. // Load the shader source
10. erSource(shader, source);
11. // Compile the shader
12. ileShader(shader);
13. // Check the compile status
14. haderiv(shader, _COMPILE_STATUS, compi
15. if (compiled[0] == 0) {
16. teShader(shader);
17. throw new RuntimeException("Error compile shader: " +
18. haderInfoLog(shader));
19. }
20. return shader;
21. }
led, 0);
为什么openGL的很多操作⽬标都是int类型的?因为openGL只会在显存⽣成或绑定地址,返回id,以后⽤id相当于句柄去改变它的内部状
态。
4、加载纹理
就是把图⽚的数据上传到显存,以后再使⽤它。请注意纹理图⽚的长和宽最好是2的N次⽅,不然不⼀定能绘制出来。
java代码
1. static int[] loadTexture(String path) {
2.
3. int[] textureId = new int[1];
4. // Generate a texture object
5. extures(1, textureId, 0);
6. int[] result = null;
7. if (textureId[0] != 0) {
8. InputStream is = omAsserts(path);
9. Bitmap bitmap;
10. try {
11. bitmap = Stream(is);
12. } finally {
13. try {
14. ();
15. } catch (IOException e) {
16. throw new RuntimeException("Error loading Bitmap.");
17. }
18. }
19. result = new int[3];
20. result[TEXTURE_ID] = textureId[0]; // TEXTURE_ID
21. result[TEXTURE_WIDTH] = th(); // TEXTURE_WIDTH
22. result[TEXTURE_HEIGHT] = ght(); // TEXTURE_HEIGHT
23. // Bind to the texture in OpenGL
24. Texture(_TEXTURE_2D, textureId[0]);
25. // Set filtering
26. arameteri(_TEXTURE_2D, _TE
27. _LINEAR);
28. arameteri(_TEXTURE_2D, _TE
29. _NEAREST);
30. arameteri(_TEXTURE_2D, _TE
31. _CLAMP_TO_EDGE);
32. arameteri(_TEXTURE_2D, _TE
33. _CLAMP_TO_EDGE);
34. // Load the bitmap into the bound texture.
35. ge2D(_TEXTURE_2D, 0, bitmap, 0);
36. // Recycle the bitmap, since its data has been loaded into OpenGL.
37. e();
38. } else {
39. throw new RuntimeException("Error loading texture.");
40. }
41. return result;
42. }
XTURE_MIN_FILTER,
XTURE_MAG_FILTER,
XTURE_WRAP_S,
XTURE_WRAP_T,
这⾥使⽤了android的⼯具类吧bitmap直接转换成openGL纹理需要的格式了。过程是,先⽣成⼀个纹理的id在显卡上的,以后根据id上
传纹理数据,以后保存这个id就
可以操作这个纹理了。⾄于纹理的⼀些过滤特性设置,将来再说。
现在貌似就剩下绘制了,准备好了顶点信息,顶点对应的纹理坐标。初始化了着⾊器,上传了纹理图⽚。接下来就已把他们合起来绘制
了。
java代码
1. public void onDrawFrame(GL10 gl) {
2.
3. // clear screen to black
4. rColor(0.0f, 0.0f, 0.0f, 0.0f);
5. r(_COLOR_BUFFER_BIT);
6. Texture(_TEXTURE_2D, textureId);
7. on(0);
8. // load the position
9. // 3(x , y , z)
10. // (2 + 3 )* 4 (float size) = 20
11. exAttribPointer(attribPosition,
12. 3, _FLOAT,
13. false, 20, vertex);
14. on(3);
15. // load the texture coordinate
16. exAttribPointer(attribTexCoord,
17. 2, _FLOAT,
18. false, 20, vertex);
19. Elements(_TRIANGLES, 6, _UN
SIGNED_SHORT,
20. index);
21. }
为了保持了代码的简单,OpenGL的基于状态体现,bind这个函数⽆处不在,这⾥ bindTexture就是通知openGL使⽤那个id的纹理图
⽚。接下来的操作就是针对bind的图⽚的。绘制就需要让openGL知道绘制神马。所 以这⾥需要⽤到vertex这个本地数据容器,⾥⾯装在的
是顶点和纹理坐标信息。exAttribPointer就是把顶点数据,按照openGL喜欢的格式上传到显卡存储。draw⽅法的调⽤,是在
前⾯应 ⽤了纹理id的情况下,所以绘制纹理坐标的时候,会使⽤上传的纹理图⽚。
每次都需要把数据上传到OpenGL,毕竟显存和内存不是同⼀个地⽅,OpenGL采⽤了CS模式。当然使⽤VBO等技术可以把数据缓存在
显存,以提⾼运⾏性能。


发布评论