你可以以顶点1234的顺序画,坐标就是如下:
private final float[] sPos={
-1.0f,1.0f, //左上角
-1.0f,-1.0f, //左下角
1.0f,-1.0f , //右下角
1.0f,1.0f //右上角
};
你也可以以1243的顺序画,坐标就设置如下:
private final float[] sPos={
-1.0f,1.0f, //左上角
-1.0f,-1.0f, //左下角
1.0f,1.0f, //右上角
1.0f,-1.0f //右下角
};
代码如下:(顶点以1234的顺序)
public class Square implements GLSurfaceView.Renderer {
String vertexShaderCode = "attribute vec4 vPosition;\n" +
"uniform mat4 vMatrix;\n" +
"void main() {\n" +
" gl_Position = vMatrix*vPosition;\n" +
"}" ;
String fragmentShaderCode = "precision mediump float;\n" +
" uniform vec4 vColor;\n" +
" void main() {\n" +
" gl_FragColor = vColor;\n" +
" }";
int mProgram;
private FloatBuffer vertexBuffer;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static float squareCoords[] = {
-0.5f, 0.5f, 0.0f, // top left
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f, // bottom right
0.5f, 0.5f, 0.0f }; // top right
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; //顶点统一白色
public Square() {
ByteBuffer bb = ByteBuffer.allocateDirect(
squareCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
//创建一个空的OpenGLES程序
mProgram = GLES20.glCreateProgram();
//将顶点着色器加入到程序
GLES20.glAttachShader(mProgram, vertexShader);
//将片元着色器加入到程序中
GLES20.glAttachShader(mProgram, fragmentShader);
//连接到着色器程序
GLES20.glLinkProgram(mProgram);
}
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
//计算宽高比
float ratio=(float)width/height;
//设置透视投影
Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
//设置相机位置
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 7.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
//计算变换矩阵
Matrix.multiplyMM(mMVPMatrix,0,mProjectMatrix,0,mViewMatrix,0);
}
int mMatrixHandler;
int mPositionHandle;
int vColorHandle;
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glUseProgram(mProgram);
mMatrixHandler= GLES20.glGetUniformLocation(mProgram,"vMatrix");
GLES20.glUniformMatrix4fv(mMatrixHandler,1,false,mMVPMatrix,0);
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
12, vertexBuffer);
vColorHandle = GLES20.glGetUniformLocation(mProgram , "vColor");
GLES20.glUniform4fv(vColorHandle , 1 , color , 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP , 0, 4);
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
//编译着色器
public static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
上面是以1234的顺序画的,效果如下:
很奇怪,我们传入顶点1234的坐标,为什么没有出现正方形的效果?我们来分析其中的一句代码.。
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP , 0, 4);
第二个参数表示从第0个顶点开始绘制,第三个参数表示总共4个顶点需要绘制。4个顶点在之前已经传入。
其中的第一个参数可以设置的值如下:(核心)
我们使用的是 GL_TRIANGLE_STRIP ,又传入了4个点按顺序1234绘制。所以会绘制2个三角形是123和234,所以自然没有绘制出正方形。
绘制正方形,只需绘制按顺序1243绘制,就可以绘制出2个三角形是124和243,这两个三角形正好组成了一个正方形。
可以想一想,圆形的绘制上面第一个参数该用什么?
GLES20.GL_TRIANGLE_FAN
假如我们传入坐标012341,0为中心,所以绘制出012 , 023 , 034 , 041 这4个图形,正好环绕一圈得到:
这里我们只绘制了4个,假如我们绘制很多个环绕的小三角形,是不是就可以得到圆呢?
接下来上代码测试一下:
Activity 和 GLSurfaceView的代码就不给出了,很简单。直接看Render的代码。
public class Circle implements GLSurfaceView.Renderer {
String vertexShaderCode = "attribute vec4 vPosition;\n" +
"uniform mat4 vMatrix;\n" +
"void main() {\n" +
" gl_Position = vMatrix*vPosition;\n" +
"}" ;
String fragmentShaderCode = "precision mediump float;\n" +
" uniform vec4 vColor;\n" +
" void main() {\n" +
" gl_FragColor = vColor;\n" +
" }";
int mProgram;
private FloatBuffer vertexBuffer;
private float[] circlrCoods;
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; //顶点统一白色
public Circle() {
//设置所有坐标
circlrCoods = createPositions();
//float[] → FloatBuffer
ByteBuffer bb = ByteBuffer.allocateDirect(circlrCoods.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(circlrCoods);
vertexBuffer.position(0);
}
private float[] createPositions(){
ArrayList data=new ArrayList<>();
data.add(0.0f); //设置圆心坐标
data.add(0.0f);
data.add(0.0f);
//分成100条边,绘制出来应该很像圆了
float radius = 0.5f; //半径1
float angDegSpan=360f/100; //依次递加的角度
for(float i=0;i<360+angDegSpan;i+=angDegSpan){
data.add((float)(radius*Math.cos(i*Math.PI/180f))); //x
data.add((float) (radius*Math.sin(i*Math.PI/180f))); //y
data.add(0.0f); //z
}
float[] f=new float[data.size()];
for (int i=0;i
代码中主要的内容就是计算顶点的坐标,其余的代码跟之前类似。
不过要注意的是:在获得顶点坐标数组 float[] 后转换为 FloatBuffer 时,一定是用下面:
ByteBuffer bb = ByteBuffer.allocateDirect(circlrCoods.length * 4);
而不是
ByteBuffer bb = ByteBuffer.allocate(circlrCoods.length * 4);
之前没发现,一直闪退!!!