OpenGL ES初探(四) – 用OpenGL画正四面体,正方体,球
目录
准备工作
添加初始代码
构建包
com.yxf.variousshape3d
将上篇博客的源码1中的MainActivity、CommonUtils还有Point复制到
com.yxf.variousshape3d
包下;将res/raw/
中的着色器代码复制过来.在
com.yxf.variousshape3d
下添加MyRender类
如下
package com.yxf.variousshapes3d;
import android.content.Context;
import android.opengl.GLSurfaceView;
import com.yxf.variousshapes3d.programs.Program;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import static android.opengl.GLES20.GL_BLEND;
import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES20.GL_ONE_MINUS_SRC_ALPHA;
import static android.opengl.GLES20.GL_SRC_ALPHA;
import static android.opengl.GLES20.glBlendFunc;
import static android.opengl.GLES20.glClear;
import static android.opengl.GLES20.glClearColor;
import static android.opengl.GLES20.glEnable;
import static android.opengl.GLES20.glViewport;
public class MyRenderer implements GLSurfaceView.Renderer {
private Context context;
private List<Program> programs = new CopyOnWriteArrayList<Program>();
public MyRenderer(Context context) {
this.context = context;
}
public void addProgram(Program program) {
programs.add(program);
}
public void clearProgram() {
programs.clear();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
glClearColor(1f, 1f, 1f, 0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for (Program program : programs) {
program.onSurfaceCreated(context);
}
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
glViewport(0, 0, width, height);
for (Program program : programs) {
program.onSurfaceChanged(width, height);
}
}
@Override
public void onDrawFrame(GL10 gl) {
glClear(GL_COLOR_BUFFER_BIT);
for (Program program : programs) {
program.onDrawFrame();
}
}
}
- 在
com.yxf.variousshapes3d
包下创建包programs
,然后在programs
包下添加Program
类如下
package com.yxf.variousshapes3d.programs;
import android.content.Context;
import com.yxf.variousshapes3d.CommonUtils;
import static android.opengl.GLES20.GL_BLEND;
import static android.opengl.GLES20.GL_ONE_MINUS_SRC_ALPHA;
import static android.opengl.GLES20.GL_SRC_ALPHA;
import static android.opengl.GLES20.glBlendFunc;
import static android.opengl.GLES20.glEnable;
import static android.opengl.GLES20.glUseProgram;
public abstract class Program {
protected int program;
private int vertexResourceId, fragmentResourceId;
private ShaderCallback shaderCallback;
public Program() {
}
public void onSurfaceCreated(Context context) {
ShaderCallback callback = getShaderCallback();
this.vertexResourceId = callback.getVertexResourceId();
this.fragmentResourceId = callback.getFragmentResourceId();
shaderCallback = callback;
if (callback == null) {
throw new RuntimeException("the shader callback of program can not is null , program : " + getClass().getName());
}
String vertexShaderSource = CommonUtils.readTextFromResource(context, vertexResourceId);
String fragmentShaderSource = CommonUtils.readTextFromResource(context, fragmentResourceId);
int vertexShader = CommonUtils.compileVertexShader(vertexShaderSource);
int fragmentShader = CommonUtils.compileFragmentShader(fragmentShaderSource);
program = CommonUtils.linkProgram(vertexShader, fragmentShader);
shaderCallback.initialize(program);
}
public void onSurfaceChanged(int width, int height) {
}
protected void useProgram() {
glUseProgram(program);
}
public void onDrawFrame() {
useProgram();
shaderCallback.prepareDraw(program);
}
public abstract ShaderCallback getShaderCallback();
interface ShaderCallback {
int getVertexResourceId();
int getFragmentResourceId();
void initialize(int program);
void prepareDraw(int program);
}
}
结构说明
这次结构和上次结构差异还是有点大的
这次我们基于OpenGL的program扩展出来Program类
然后以Program为单位,在MyRenderer中draw出每个program
构建ShapeProgram
构思
为了避免太多的重复工作,我们不需要每个立体图形都构建一个Program类,我们可以先构建ShapeProgram
类和BaseShape
类,ShapeProgram
负责构建场景和处理矩阵,BaseShape
类负责绘制图形,然后将BaseShape
添加进ShapeProgram
中达到解耦和简化的目的.
构建BaseShape
我们在com.yxf.variousshapes3d
包下添加shapes
包,然后在shapes
包下添加BaseShape
类如下
package com.yxf.variousshapes3d.shapes;
import com.yxf.variousshapes3d.Point;
import java.nio.FloatBuffer;
import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.glVertexAttribPointer;
public abstract class BaseShape {
public static final int BYTES_PER_FLOAT = 4;
public static final int POSITION_COMPONENT_COUNT = 3;
public static final int COLOR_COMPONENT_COUNT = 4;
public static final int STRIDE = (POSITION_COMPONENT_COUNT +
COLOR_COMPONENT_COUNT) * BYTES_PER_FLOAT;
protected int aPositionLocation;
protected int aColorLocation;
protected Point center;
protected Object mLock = new Object();
public BaseShape(Point center) {
this.center = center;
}
public void setLocation(int aPositionLocation, int aColorLocation) {
this.aPositionLocation = aPositionLocation;
this.aColorLocation = aColorLocation;
}
public final void draw() {
preDraw();
synchronized (mLock) {
FloatBuffer vertexData = getVertexData();
vertexData.position(0);
glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT,
false, STRIDE, vertexData);
vertexData.position(POSITION_COMPONENT_COUNT);
glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GL_FLOAT,
false, STRIDE, vertexData);
drawArrays();
}
afterDraw();
}
public void initialize() {
synchronized (mLock) {
initWithoutLock();
}
}
public static FloatBuffer encodeVertices(float[] vertices) {
FloatBuffer vertexData = ByteBuffer.allocateDirect(vertices.length * BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
vertexData.put(vertices);
return vertexData;
}
public abstract void initWithoutLock();
protected abstract FloatBuffer getVertexData();
protected abstract void drawArrays();
protected abstract void preDraw();
protected abstract void afterDraw();
}
由于OpenGL在Android中其实是有个渲染线程的,所以在其中数据处理的地方加了锁.
构建ShapeProgram实例
我们再com.yxf.variousshapes3d.programs
包下创建ShapeProgram
类,继承于Program
类如下
package com.yxf.variousshapes3d.programs;
import com.yxf.variousshapes3d.R;
import com.yxf.variousshapes3d.shapes.BaseShape;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import static android.opengl.GLES20.glEnableVertexAttribArray;
import static android.opengl.GLES20.glGetAttribLocation;
import static android.opengl.GLES20.glGetUniformLocation;
import static android.opengl.GLES20.glUniformMatrix4fv;
import