下面程序的opengl的图形是根据Opengl1.0版本API进行的.
<a> : 首先绘制点:
<1> : 新建一个android studio工程,这个工程参考前一篇坐标系的.工程名:PumpKinBasicGL10,主类如下:
package org.durian.pumpkinbasicgl10; import android.app.Activity; import android.opengl.GLSurfaceView; import android.os.Bundle; import org.durian.pumpkinbasicgl10.draw2d.PumpKinRenderer; import org.durian.pumpkinbasicgl10.draw2d.dot.PumpkinDotRenderer; import org.durian.pumpkinbasicgl10.draw2d.line.PumpKinLineRenderer; import org.durian.pumpkinbasicgl10.draw2d.triangle.PumpKinTriangleRenderer; import org.durian.pumpkinbasicgl10.draw3d.cube.PumpKinCubeRenderer; import org.durian.pumpkinbasicgl10.draw3d.shapes.PumpKinPyramidRenderer; public class MainActivity extends Activity { private GLSurfaceView mSurfaceView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mSurfaceView=new GLSurfaceView(this); mSurfaceView.setRenderer(/*new PumpKinRenderer()*/new PumpkinDotRenderer()/*new PumpKinLineRenderer(this)*//*new PumpKinTriangleRenderer()*//*new PumpKinPyramidRenderer()*//*new PumpKinCubeRenderer()*/); setContentView(mSurfaceView/*R.layout.activity_main*/); } @Override protected void onResume() { super.onResume(); mSurfaceView.onResume(); } @Override protected void onPause() { super.onPause(); mSurfaceView.onPause(); } }
<2> : 画点类程序如下:
package org.durian.pumpkinbasicgl10.draw2d.dot; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; /** * Created by Administrator on 2016/4/26. */ public class PumpKinDot { private FloatBuffer vertexsBuffer; private FloatBuffer colorsBuffer; //x,y,z private float[] vertexs=new float[]{ 1.0f,0.0f,0.0f, 0.0f,1.0f,0.0f, -1.0f,0.0f,0.0f, 0.0f,-1.0f,0.0f, 0.5f,0.0f,0.0f, 0.0f,0.5f,0.0f, -0.5f,0.0f,0.0f, 0.0f,-0.5f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,1.0f, 0.0f,0.0f,-1.0f, 0.0f,0.0f,0.5f, 0.0f,0.0f,-0.5f, 0.0f,0.0f,0.0f }; //r,g,b,a private float[] colors={ 0.0f,1.0f,0.0f,1.0f, 1.0f,0.0f,0.0f,1.0f, 0.0f,1.0f,0.0f,1.0f, 1.0f,0.0f,0.0f,1.0f, 0.0f,1.0f,0.0f,1.0f, 1.0f,1.0f,0.0f,1.0f, 0.0f,1.0f,0.0f,1.0f, 1.0f,0.0f,0.0f,1.0f, 1.0f,1.0f,1.0f,1.0f, 1.0f,1.0f,1.0f,1.0f, 1.0f,1.0f,1.0f,1.0f, 1.0f,1.0f,1.0f,1.0f, 1.0f,1.0f,1.0f,1.0f, 1.0f,1.0f,1.0f,1.0f, }; public PumpKinDot(){ ByteBuffer vbb=ByteBuffer.allocateDirect(vertexs.length*4); vbb.order(ByteOrder.nativeOrder()); vertexsBuffer=vbb.asFloatBuffer(); vertexsBuffer.put(vertexs); vertexsBuffer.position(0); ByteBuffer cbb=ByteBuffer.allocateDirect(colors.length*4); cbb.order(ByteOrder.nativeOrder()); colorsBuffer=cbb.asFloatBuffer(); colorsBuffer.put(colors); colorsBuffer.position(0); } public void draw(GL10 gl){ gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertexsBuffer); gl.glEnableClientState(GL10.GL_COLOR_ARRAY); gl.glColorPointer(4,GL10.GL_FLOAT,0,colorsBuffer); gl.glDrawArrays(GL10.GL_POINTS,0,vertexs.length/3); gl.glDisableClientState(GL10.GL_COLOR_ARRAY); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } }上面程序主要是注意
gl.glDrawArrays(GL10.GL_POINTS,0,vertexs.length/3);
第一个参数为设置绘制图形类型.第一篇博客已有说明.
程序在x,y,z轴上面绘制画出多个点.
渲染的类:
package org.durian.pumpkinbasicgl10.draw2d.dot; import android.opengl.GLSurfaceView; import android.opengl.GLU; import org.durian.pumpkinbasicgl10.draw2d.PumpKin; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; /** * Created by Administrator on 2016/4/26. */ public class PumpkinDotRenderer implements GLSurfaceView.Renderer { private PumpKinDot pumpKinDot; private PumpKin pumpKin; public PumpkinDotRenderer() { pumpKinDot = new PumpKinDot(); pumpKin=new PumpKin(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); gl.glClearDepthf(1.0f); gl.glEnable(GL10.GL_DEPTH_TEST); gl.glDepthFunc(GL10.GL_LEQUAL); gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); gl.glShadeModel(GL10.GL_SMOOTH); gl.glDisable(GL10.GL_DITHER); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { if (height == 0) { height = 1; } float aspect = (float) width / height; gl.glViewport(0, 0, width, height); gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); GLU.gluPerspective(gl, 45, aspect, 0.1f, 100.0f); 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.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, -6.0f); gl.glRotatef(45,1.0f,1.0f,1.0f); //pumpKin.draw(gl); pumpKinDot.draw(gl); } }
上面对于的坐标线:
//pumpKin.draw(gl);
被注释了,这个绘制的坐标线不是必须的,只是让人可以更好定位三维空间位置,能够看得见.
运行结果:
上面的在程序中,做了坐标变换:对坐标做了旋转变换.
gl.glRotatef(45,1.0f,1.0f,1.0f);
坐标线条程序和前一篇一模一样:
package org.durian.pumpkinbasicgl10.draw2d; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; /** * Created by Administrator on 2016/4/28. */ public class PumpKin { private FloatBuffer vertexsBuffer; private FloatBuffer colorsBuffer; private ByteBuffer indicesBuffer; private float vertexs[]={ -3.0f,0.0f,0.0f, 3.0f,0.0f,0.0f, 0.0f,-3.0f,0.0f, 0.0f,3.0f,0.0f, 0.0f,0.0f,-3.0f, 0.0f,0.0f,3.0f }; private float colors[]={ 1.0f,0.0f,0.0f,1.0f, 1.0f,0.0f,0.0f,1.0f, 0.0f,1.0f,0.0f,1.0f, 0.0f,1.0f,0.0f,1.0f, 0.0f,0.0f,1.0f,1.0f, 0.0f,0.0f,1.0f,1.0f }; private byte indices[]={0,1,2}; public PumpKin(){ ByteBuffer vbb=ByteBuffer.allocateDirect(vertexs.length*4); vbb.order(ByteOrder.nativeOrder()); vertexsBuffer=vbb.asFloatBuffer(); vertexsBuffer.put(vertexs); vertexsBuffer.position(0); ByteBuffer cbb=ByteBuffer.allocateDirect(colors.length*4); cbb.order(ByteOrder.nativeOrder()); colorsBuffer=cbb.asFloatBuffer(); colorsBuffer.put(colors); colorsBuffer.position(0); } public void draw(GL10 gl){ gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_COLOR_ARRAY); gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertexsBuffer); gl.glColorPointer(4,GL10.GL_FLOAT,0,colorsBuffer); gl.glDrawArrays(GL10.GL_LINES,0,vertexs.length/3); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } }
package org.durian.pumpkinbasicgl10.draw2d; import android.opengl.GLSurfaceView; import android.opengl.GLU; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; /** * Created by Administrator on 2016/4/28. */ public class PumpKinRenderer implements GLSurfaceView.Renderer { private PumpKin pumpKin; public PumpKinRenderer(){ pumpKin=new PumpKin(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClearDepthf(1.0f); gl.glEnable(GL10.GL_DEPTH_TEST); gl.glDepthFunc(GL10.GL_LEQUAL); gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_NICEST); gl.glShadeModel(GL10.GL_SMOOTH); gl.glDisable(GL10.GL_DITHER); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { if(height==0){ height=1; } float aspect=(float)width/height; gl.glViewport(0,0,width,height); gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); GLU.gluPerspective(gl, 45, aspect, 0.1f, 100.0f); 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.glLoadIdentity(); gl.glTranslatef(0.0f,0.0f,-2f); gl.glRotatef(45,1.0f,1.0f,1.0f); pumpKin.draw(gl); } }
<b> : 下面介绍绘制直线,其实绘制直线前面已经有了,比如绘制坐标直线.只需要在上面工程添加绘制line的类和渲染类
package org.durian.pumpkinbasicgl10.draw2d.line; import android.util.Log; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; /** * Created by Administrator on 2016/4/26. */ public class PumpKinLine { private FloatBuffer vertexsBuffer; private FloatBuffer colorsBuffer; private ByteBuffer indicesBuffer; private float[] vertexss={ -1.0f,-1.0f,0.0f, 1.0f,-1.0f,0.0f, -1.0f,1.0f,0.0f, 1.0f,1.0f,0.0f }; //x,y,z private float[] vertexs={ 0.0f,0.0f,0.0f, 1.0f,0.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f }; //r,g,b,a private float[] colors={ 1.0f,0.0f,0.0f,1.0f, 0.0f,1.0f,0.0f,1.0f, 1.0f,0.0f,0.0f,1.0f, 0.0f,1.0f,0.0f,1.0f }; private byte[] indices={ 0,1,2 }; public PumpKinLine(){ ByteBuffer vbb=ByteBuffer.allocateDirect(vertexs.length*4); vbb.order(ByteOrder.nativeOrder()); vertexsBuffer=vbb.asFloatBuffer(); vertexsBuffer.put(vertexs); vertexsBuffer.position(0); ByteBuffer cbb=ByteBuffer.allocateDirect(colors.length*4); cbb.order(ByteOrder.nativeOrder()); colorsBuffer=cbb.asFloatBuffer(); colorsBuffer.put(colors); colorsBuffer.position(0); indicesBuffer=ByteBuffer.allocateDirect(indices.length); indicesBuffer.put(indices); indicesBuffer.position(0); } public void draw(GL10 gl){ gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_COLOR_ARRAY); gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertexsBuffer); gl.glColorPointer(4,GL10.GL_FLOAT,0,colorsBuffer); gl.glColor4f(1.0f,0.0f,0.0f,1.0f); gl.glDrawArrays(GL10.GL_LINES,0,vertexs.length/3); //gl.glDrawElements(GL10.GL_TRIANGLES,indices.length,GL10.GL_UNSIGNED_BYTE,indicesBuffer); gl.glDisableClientState(GL10.GL_COLOR_ARRAY); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } }
绘制也可以通过:
gl.glDrawElements(GL10.GL_TRIANGLES,indices.length,GL10.GL_UNSIGNED_BYTE,indicesBuffer);
进行,只是这个方法需要提供绘制序列点indices数组.
绘制的直线的:
0.0f,0.0f,0.0f, 1.0f,0.0f,0.0f,
这两点连接的线
以及:
0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f
这两天链接的线.
即两条线分别沿x,y正方向.
对应的渲染类如下:
package org.durian.pumpkinbasicgl10.draw2d.line; import android.content.Context; import android.opengl.GLSurfaceView; import android.opengl.GLU; import org.durian.pumpkinbasicgl10.draw2d.PumpKin; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; /** * Created by Administrator on 2016/4/26. */ public class PumpKinLineRenderer implements GLSurfaceView.Renderer { private PumpKinLine pumpKinLine; private PumpKin pumpKin; public PumpKinLineRenderer(){ pumpKinLine=new PumpKinLine(); pumpKin=new PumpKin(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClearDepthf(1.0f); gl.glEnable(GL10.GL_DEPTH_TEST); gl.glDepthFunc(GL10.GL_LEQUAL); gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_NICEST); gl.glShadeModel(GL10.GL_SMOOTH); gl.glDisable(GL10.GL_DITHER); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { if(height==0){ height=1; } float aspect=(float)width/height; gl.glViewport(0,0,width,height); gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); GLU.gluPerspective(gl, 45, aspect, 0.1f, 100.0f); 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.glLoadIdentity(); //gl.glTranslatef(0.0f,0.0f,0.0f); gl.glTranslatef(0.0f,0.0f,-0.1f); //gl.glTranslatef(-3.0f,0.0f,-6.0f); //gl.glTranslatef(3.0f,0.0f,1.0f); // pumpKin.draw(gl); pumpKinLine.draw(gl); } }
如果想显示当前的坐标线,可以将
// pumpKin.draw(gl);
去掉注释.
<c> : 绘制多边形:代码如下
package org.durian.pumpkinbasicgl10.draw2d.triangle; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; /** * Created by Administrator on 2016/4/27. */ public class PumpKinTriangle { private FloatBuffer vertexsBuffer; private FloatBuffer vertexsaBuffer; private FloatBuffer colorsBuffer; private FloatBuffer colorsaBuffer; private ByteBuffer indicesBuffer; private ByteBuffer indicesaBuffer; //x,y,z private float[] vertexs={ 1.0f,0.0f,0.0f, 0.0f,1.0f,0.0f, 0.0f,0.0f,1.0f }; private float[] vertexsa={ 1.0f,0.0f,0.0f, 0.0f,1.0f,0.0f, 0.0f,0.0f,1.0f, 1.0f,0.0f,1.0f, 0.5f,1.0f,0.0f, 0.5f,1.0f,1.0f }; //r,g,b,a private float[] colors={ 1.0f,0.0f,0.0f,1.0f, 0.0f,1.0f,0.0f,1.0f, 0.0f,0.0f,1.0f,1.0f }; private float[] colorsa={ 1.0f,0.0f,0.0f,1.0f, 0.0f,1.0f,0.0f,1.0f, 0.0f,0.0f,1.0f,1.0f, 1.0f,0.0f,0.0f,1.0f, 0.0f,1.0f,0.0f,1.0f, 0.0f,0.0f,1.0f,1.0f }; private byte[] indices={0,1,2}; private byte[] indicesa={0,1,2,3,4,5}; public PumpKinTriangle(){ ByteBuffer vbb=ByteBuffer.allocateDirect(vertexs.length*4); vbb.order(ByteOrder.nativeOrder()); vertexsBuffer=vbb.asFloatBuffer(); vertexsBuffer.put(vertexs); vertexsBuffer.position(0); ByteBuffer vbba=ByteBuffer.allocateDirect(vertexsa.length*4); vbba.order(ByteOrder.nativeOrder()); vertexsaBuffer=vbba.asFloatBuffer(); vertexsaBuffer.put(vertexsa); vertexsaBuffer.position(0); ByteBuffer cbb=ByteBuffer.allocateDirect(colors.length*4); cbb.order(ByteOrder.nativeOrder()); colorsBuffer=cbb.asFloatBuffer(); colorsBuffer.put(colors); colorsBuffer.position(0); ByteBuffer cbba=ByteBuffer.allocateDirect(colorsa.length*4); cbba.order(ByteOrder.nativeOrder()); colorsaBuffer=cbba.asFloatBuffer(); colorsaBuffer.put(colorsa); colorsaBuffer.position(0); indicesBuffer=ByteBuffer.allocateDirect(indices.length); indicesBuffer.order(ByteOrder.nativeOrder()); indicesBuffer.put(indices); indicesBuffer.position(0); indicesaBuffer=ByteBuffer.allocateDirect(indicesa.length); indicesaBuffer.order(ByteOrder.nativeOrder()); indicesaBuffer.put(indicesa); indicesaBuffer.position(0); } // type :GL10.GL_TRIANGLES public void draw(GL10 gl){ gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_COLOR_ARRAY); gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertexsBuffer); gl.glColorPointer(4,GL10.GL_FLOAT,0,colorsBuffer); gl.glDrawArrays(GL10.GL_TRIANGLES,0,vertexs.length/3); gl.glDisableClientState(GL10.GL_COLOR_ARRAY); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } public void drawE(GL10 gl){ gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_COLOR_ARRAY); gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertexsBuffer); gl.glColorPointer(4,GL10.GL_FLOAT,0,colorsBuffer); gl.glDrawElements(GL10.GL_TRIANGLES,indices.length,GL10.GL_UNSIGNED_BYTE,indicesBuffer); gl.glDisableClientState(GL10.GL_COLOR_ARRAY); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } public void drawNc(GL10 gl){ gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glColor4f(0.0f,1.0f,0.0f,1.0f); gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertexsBuffer); gl.glDrawArrays(GL10.GL_TRIANGLES,0,vertexs.length/3); } //type : GL10.GL_TRIANGLE_STRIP public void draw1(GL10 gl){ gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_COLOR_ARRAY); gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertexsaBuffer); gl.glColorPointer(4,GL10.GL_FLOAT,0,colorsaBuffer); gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,vertexsa.length/3); gl.glDisableClientState(GL10.GL_COLOR_ARRAY); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } //type : GL10.GL_TRIANGLE_FAN public void draw1E(GL10 gl){ gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_COLOR_ARRAY); gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertexsaBuffer); gl.glColorPointer(4,GL10.GL_FLOAT,0,colorsaBuffer); gl.glDrawElements(GL10.GL_TRIANGLE_FAN,indicesa.length,GL10.GL_UNSIGNED_BYTE,indicesaBuffer); gl.glDisableClientState(GL10.GL_COLOR_ARRAY); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } }
程序采用了两种绘制图像的方法:
gl.glDrawArrays
和:
gl.glDrawElements
这两种绘制在前面大致说过了.
这里主要介绍这两个方法的第一个参数:分别是GL_TRIANGLES、GL_TRIANGLE_STRIP和GL_TRIANGLE_FAN
图片出处:http://blog.csdn.net/xiajun07061225/article/details/7455283,参考具体说明:
GL_TRIANGLES是以每三个顶点绘制一个三角形。第一个三角形使用顶点v0,v1,v2,第二个使用v3,v4,v5,以此类推。如果顶点的个数n不是3的倍数,那么最后的1个或者2个顶点会被忽略。 GL_TRIANGLE_STRIP则稍微有点复杂。 其规律是: 构建当前三角形的顶点的连接顺序依赖于要和前面已经出现过的2个顶点组成三角形的当前顶点的序号的奇偶性(如果从0开始): 如果当前顶点是奇数: 组成三角形的顶点排列顺序:T = [n-1 n-2 n]. 如果当前顶点是偶数: 组成三角形的顶点排列顺序:T = [n-2 n-21 n]. 以上图为例,第一个三角形,顶点v2序号是2,是偶数,则顶点排列顺序是v0,v1,v2。第二个三角形,顶点v3序号是3,是奇数,则顶点排列顺序是v2,v1,v3,第三个三角形,顶点v4序号是4,是偶数,则顶点排列顺序是v2,v3,v4,以此类推。 这个顺序是为了保证所有的三角形都是按照相同的方向绘制的,使这个三角形串能够正确形成表面的一部分。对于某些操作,维持方向是很重要的,比如剔除。 注意:顶点个数n至少要大于3,否则不能绘制任何三角形。 GL_TRIANGLE_FAN与GL_TRIANGLE_STRIP类似,不过它的三角形的顶点排列顺序是T = [n-1 n-2 n].各三角形形成一个扇形序列
对应渲染类:
package org.durian.pumpkinbasicgl10.draw2d.triangle; import android.opengl.GLSurfaceView; import android.opengl.GLU; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; /** * Created by Administrator on 2016/4/27. */ public class PumpKinTriangleRenderer implements GLSurfaceView.Renderer { private PumpKinTriangle pumpKinTriangle; public PumpKinTriangleRenderer(){ pumpKinTriangle=new PumpKinTriangle(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClearDepthf(1.0f); gl.glEnable(GL10.GL_DEPTH_TEST); gl.glDepthFunc(GL10.GL_LEQUAL); gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_NICEST); gl.glShadeModel(GL10.GL_SMOOTH); gl.glDisable(GL10.GL_DITHER); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { if(height==0){ height=1; } float aspect=(float)width/height; gl.glViewport(0,0,width,height); gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); GLU.gluPerspective(gl, 45, aspect, 0.1f, 100.0f); 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.glLoadIdentity(); gl.glTranslatef(0.0f,0.0f,-6.0f); pumpKinTriangle.draw1(gl); } }
如果调用draw1方法,运行结果如下:
如果将渲染类中程序修改:
// pumpKinTriangle.draw1(gl); pumpKinTriangle.draw1E(gl);
运行结果:
上面大致介绍了基本二维图形的绘制.
下面介绍三维图形,三维图形其实和二维在程序上面没什么区别,只是需要注意z轴了,坐标方式差不多.三维图形基本也是由基本二维图形构成的.
<d> : 绘制金字塔模型:
package org.durian.pumpkinbasicgl10.draw3d.shapes; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; /** * Created by Administrator on 2016/4/28. */ public class PumpKinPyramid { private FloatBuffer vertexsBuffer; private FloatBuffer colorsBuffer; private ByteBuffer indicesBuffer; // 5 vertices of the pyramid in (x,y,z) private float[] vertexs={ -1.0f, -1.0f, -1.0f, // 0. left-bottom-back 1.0f, -1.0f, -1.0f, // 1. right-bottom-back 1.0f, -1.0f, 1.0f, // 2. right-bottom-front -1.0f, -1.0f, 1.0f, // 3. left-bottom-front 0.0f, 1.0f, 0.0f // 4. top }; // Colors of the 5 vertices in RGBA private float[] colors={ 0.0f, 0.0f, 1.0f, 1.0f, // 0. blue 0.0f, 1.0f, 0.0f, 1.0f, // 1. green 0.0f, 0.0f, 1.0f, 1.0f, // 2. blue 0.0f, 1.0f, 0.0f, 1.0f, // 3. green 1.0f, 0.0f, 0.0f, 1.0f // 4. red }; private byte indices[]={ 2, 4, 3, // front face (CCW) 1, 4, 2, // right face 0, 4, 1, // back face 4, 0, 3 // left face }; public PumpKinPyramid(){ ByteBuffer vbb=ByteBuffer.allocateDirect(vertexs.length*4); vbb.order(ByteOrder.nativeOrder()); vertexsBuffer=vbb.asFloatBuffer(); vertexsBuffer.put(vertexs); vertexsBuffer.position(0); ByteBuffer cbb=ByteBuffer.allocateDirect(colors.length*4); cbb.order(ByteOrder.nativeOrder()); colorsBuffer=cbb.asFloatBuffer(); colorsBuffer.put(colors); colorsBuffer.position(0); indicesBuffer=ByteBuffer.allocateDirect(indices.length); indicesBuffer.order(ByteOrder.nativeOrder()); indicesBuffer.put(indices); indicesBuffer.position(0); } public void draw(GL10 gl){ gl.glFrontFace(GL10.GL_CCW); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_COLOR_ARRAY); gl.glColorPointer(4,GL10.GL_FLOAT,0,colorsBuffer); gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertexsBuffer); gl.glDrawElements(GL10.GL_TRIANGLE_STRIP,indices.length,GL10.GL_UNSIGNED_BYTE,indicesBuffer); gl.glDisableClientState(GL10.GL_COLOR_ARRAY); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } }
其中:
gl.glFrontFace(GL10.GL_CCW);
改程序设置:设置逆时针方向为正面.
上面的程序了vertexs顶点数组,可以很难搞清,等下在渲染器中添加坐标,然后再来对应上面的坐标点就了解了.
下面给出对应的渲染类:
package org.durian.pumpkinbasicgl10.draw3d.shapes; import android.opengl.GLSurfaceView; import android.opengl.GLU; import org.durian.pumpkinbasicgl10.draw2d.PumpKin; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; /** * Created by Administrator on 2016/4/28. */ public class PumpKinPyramidRenderer implements GLSurfaceView.Renderer { private PumpKinPyramid pumpKinPyramid; private PumpKin pumpKin; public PumpKinPyramidRenderer(){ pumpKinPyramid=new PumpKinPyramid(); pumpKin=new PumpKin(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClearDepthf(1.0f); gl.glEnable(GL10.GL_DEPTH_TEST); gl.glDepthFunc(GL10.GL_LEQUAL); gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_NICEST); gl.glShadeModel(GL10.GL_SMOOTH); gl.glDisable(GL10.GL_DITHER); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { if(height==0){ height=1; } float aspect=(float)width/height; gl.glViewport(0,0,width,height); gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); GLU.gluPerspective(gl, 45, aspect, 0.1f, 100.0f); 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.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, -8.0f); gl.glRotatef(45,1.0f,1.0f,1.0f); pumpKinPyramid.draw(gl); pumpKin.draw(gl); } }
运行结果:
一个金字塔形的立体需要4个面,一共需要5个顶点,主要是要定好坐标原点,比如上面坐标原点在金字塔中心位置.比如上面对着我们的绿色角,对应的顶点坐标(-1.0f, -1.0f, 1.0f),红色顶点在y轴(红线是x轴,绿色y轴,蓝色z轴)位置(0.0f, 1.0f, 0.0f),刚好绿线(y轴)结果顶点,其他的一次类推.
<e> : 下面介绍立方体,基本上都是类似做法,立方体有八个坐标,同上,原点(0,0,0)设置在立方体中心位置,程序如下:
package org.durian.pumpkinbasicgl10.draw3d.cube; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; /** * Created by Administrator on 2016/4/29. */ public class PumpKinCube { private FloatBuffer vertexsBuffer; private FloatBuffer lvertexsBuffer; private FloatBuffer lcolorsBuffer; /* * eight vertex as following : * V0 : -1.0f, -1.0f, 1.0f * V1 : 1.0f, -1.0f, 1.0f * V2 : -1.0f, 1.0f, 1.0f * V3 : -1.0f, -1.0f, -1.0f * V4 : -1.0f, -1.0f, -1.0f * V5 : -1.0f, 1.0f, -1.0f * V6 : 1.0f, -1.0f, -1.0f * V7 : 1.0f, 1.0f, -1.0f * 三维坐标系原点在这个立方体中心 * */ private float[] vertices = { // Vertices of the 6 faces // FRONT -1.0f, -1.0f, 1.0f, // 0. left-bottom-front 1.0f, -1.0f, 1.0f, // 1. right-bottom-front -1.0f, 1.0f, 1.0f, // 2. left-top-front 1.0f, 1.0f, 1.0f, // 3. right-top-front // BACK 1.0f, -1.0f, -1.0f, // 6. right-bottom-back -1.0f, -1.0f, -1.0f, // 4. left-bottom-back 1.0f, 1.0f, -1.0f, // 7. right-top-back -1.0f, 1.0f, -1.0f, // 5. left-top-back // LEFT -1.0f, -1.0f, -1.0f, // 4. left-bottom-back -1.0f, -1.0f, 1.0f, // 0. left-bottom-front -1.0f, 1.0f, -1.0f, // 5. left-top-back -1.0f, 1.0f, 1.0f, // 2. left-top-front // RIGHT 1.0f, -1.0f, 1.0f, // 1. right-bottom-front 1.0f, -1.0f, -1.0f, // 6. right-bottom-back 1.0f, 1.0f, 1.0f, // 3. right-top-front 1.0f, 1.0f, -1.0f, // 7. right-top-back // TOP -1.0f, 1.0f, 1.0f, // 2. left-top-front 1.0f, 1.0f, 1.0f, // 3. right-top-front -1.0f, 1.0f, -1.0f, // 5. left-top-back 1.0f, 1.0f, -1.0f, // 7. right-top-back // BOTTOM -1.0f, -1.0f, -1.0f, // 4. left-bottom-back 1.0f, -1.0f, -1.0f, // 6. right-bottom-back -1.0f, -1.0f, 1.0f, // 0. left-bottom-front 1.0f, -1.0f, 1.0f // 1. right-bottom-front }; private float[][] colors = { // Colors of the 6 faces {1.0f, 0.5f, 0.0f, 1.0f}, // 0. orange {1.0f, 0.0f, 1.0f, 1.0f}, // 1. violet {0.0f, 1.0f, 0.0f, 1.0f}, // 2. green {0.0f, 0.0f, 1.0f, 1.0f}, // 3. blue {1.0f, 0.0f, 0.0f, 1.0f}, // 4. red {1.0f, 1.0f, 0.0f, 1.0f} // 5. yellow }; public PumpKinCube(){ ByteBuffer vbb=ByteBuffer.allocateDirect(vertices.length*4); vbb.order(ByteOrder.nativeOrder()); vertexsBuffer=vbb.asFloatBuffer(); vertexsBuffer.put(vertices); vertexsBuffer.position(0); } public void draw(GL10 gl){ gl.glFrontFace(GL10.GL_CCW); gl.glEnable(GL10.GL_CULL_FACE); gl.glCullFace(GL10.GL_BACK); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertexsBuffer); for(int i=0;i<6;i++){ gl.glColor4f(colors[i][0],colors[i][1],colors[i][2],colors[i][3]); gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,i*4,4); } gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl.glDisable(GL10.GL_CULL_FACE); } }
特别说一下:
gl.glFrontFace(GL10.GL_CCW); gl.glEnable(GL10.GL_CULL_FACE); gl.glCullFace(GL10.GL_BACK);
gl.glEnable(GL10.GL_CULL_FACE);设置openggl有剔除效果,就是看不到的面就不画,当然可以增加效率
gl.glCullFace(GL10.GL_BACK);设置背面被剔除,不画.
gl.glFrontFace(GL10.GL_CCW);设置逆时针方向为正面
对应渲染器类:
package org.durian.pumpkinbasicgl10.draw3d.cube; import android.opengl.GLSurfaceView; import android.opengl.GLU; import org.durian.pumpkinbasicgl10.draw2d.PumpKin; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; /** * Created by Administrator on 2016/4/29. */ public class PumpKinCubeRenderer implements GLSurfaceView.Renderer { private PumpKinCube pumpKinCube; private PumpKin pumpKin; private int cubeAngle=0; private int cubeSpeech=1; public PumpKinCubeRenderer(){ pumpKinCube=new PumpKinCube(); pumpKin=new PumpKin(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { gl.glClearColor(0.0f,0.0f,0.0f,1.0f); gl.glClearDepthf(1.0f); gl.glEnable(GL10.GL_DEPTH_TEST); gl.glDepthFunc(GL10.GL_LEQUAL); gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_NICEST); gl.glShadeModel(GL10.GL_SMOOTH); gl.glDisable(GL10.GL_DITHER); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { if(height==0){ height=1; } float aspect=(float)width/height; gl.glViewport(0,0,width,height); gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); GLU.gluPerspective(gl, 45, aspect, 0.1f, 100.0f); 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.glLoadIdentity(); gl.glTranslatef(0.0f,0.0f,-6.0f); gl.glRotatef(cubeAngle,1.0f,1.0f,1.0f); gl.glScalef(0.8f,0.8f,0.8f); pumpKinCube.draw(gl); pumpKin.draw(gl); cubeAngle+=cubeSpeech; } }
运行如下:
至于纹理部分将在后面单独给出来简述.