绘制流程跟2维图形绘制一致,只是坐标需要自己去计算。
圆柱体、圆锥、球型,其实就是绘制一个一个的圆形,将他们无限分割就是一个一个的圆
//立方体
public class Cube extends Shape {
private FloatBuffer vertexBuffer;
private FloatBuffer colorBuffer;
private ShortBuffer indexBuffer;
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"varying vec4 vColor;" +
"attribute vec4 aColor;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition;" +
"vColor = aColor;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"varying vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
final float cubePositions[] = {
-1.0f, 1.0f, 1.0f, //正面左上0
-1.0f, -1.0f, 1.0f, //正面左下1
1.0f, -1.0f, 1.0f, //正面右下2
1.0f, 1.0f, 1.0f, //正面右上3
-1.0f, 1.0f, -1.0f, //反面左上4
-1.0f, -1.0f, -1.0f, //反面左下5
1.0f, -1.0f, -1.0f, //反面右下6
1.0f, 1.0f, -1.0f, //反面右上7
};
final short index[] = {
6, 7, 4, 6, 4, 5, //后面
6, 3, 7, 6, 2, 3, //右面
6, 5, 1, 6, 1, 2, //下面
0, 3, 2, 0, 2, 1, //正面
0, 1, 5, 0, 5, 4, //左面
0, 7, 3, 0, 4, 7, //上面
};
float color[] = {
0f, 1f, 0f, 1f,
0f, 1f, 0f, 1f,
0f, 1f, 0f, 1f,
0f, 1f, 0f, 1f,
1f, 0f, 0f, 1f,
1f, 0f, 0f, 1f,
1f, 0f, 0f, 1f,
1f, 0f, 0f, 1f,
};
static final int COORDS_PER_VERTEX = 3;
static final int BYTES_PER_FLOAT = 4;
int vertexStride = COORDS_PER_VERTEX * BYTES_PER_FLOAT;
private int program;
private int vPMatrixHandle;
private int positionHandle;
private int colorHandle;
public Cube() {
ByteBuffer bb = ByteBuffer.allocateDirect(cubePositions.length * BYTES_PER_FLOAT);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(cubePositions);
vertexBuffer.position(0);
ByteBuffer colBuffer = ByteBuffer.allocateDirect(color.length * BYTES_PER_FLOAT);
colBuffer.order(ByteOrder.nativeOrder());
colorBuffer = colBuffer.asFloatBuffer();
colorBuffer.put(color);
colorBuffer.position(0);
ByteBuffer dexBuffer = ByteBuffer.allocateDirect(index.length * 2);
dexBuffer.order(ByteOrder.nativeOrder());
indexBuffer = dexBuffer.asShortBuffer();
indexBuffer.put(index);
indexBuffer.position(0);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
program = GLES20.glCreateProgram();
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program);
}
public void draw(float[] vPMatrix) {
GLES20.glUseProgram(program);
vPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, vPMatrix, 0);
positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
colorHandle = GLES20.glGetAttribLocation(program, "aColor");
GLES20.glEnableVertexAttribArray(colorHandle);
GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false, 0, colorBuffer);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, index.length, GLES20.GL_UNSIGNED_SHORT, indexBuffer);
GLES20.glDisableVertexAttribArray(positionHandle);
}
}
public class Cone extends Shape {
//圆锥就是把圆心的z坐标改成设置的height 从x,y轴看去是三角形,从z轴方向看是圆形
private FloatBuffer vertexBuffer;
static final int COORDS_PER_VERTEX = 3;
static final int BYTES_PER_FLOAT = 4;
int vertexStride = COORDS_PER_VERTEX * BYTES_PER_FLOAT;
private float radius;
private float height;
//将圆形切割成40个三角形
private final int count = 40;
float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 1.0f};
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private int program;
private int vPMatrixHandle;
private int positionHandle;
private int colorHandle;
public Cone(float radius, float height) {
this.radius = radius;
this.height = height;
float[] coords = circleCoords(radius);
ByteBuffer bb = ByteBuffer.allocateDirect(coords.length * BYTES_PER_FLOAT);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(coords);
vertexBuffer.position(0);
program = GLES20.glCreateProgram();
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program);
}
private float[] circleCoords(float radius) {
float[] coords = new float[(count + 2) * COORDS_PER_VERTEX];
int offset = 0;
coords[offset++] = 0;
coords[offset++] = 0;
coords[offset++] = height;
for (int i = 0; i < count + 1; i++) {
float angleInRadians = ((float) i / (float) count)
* ((float) Math.PI * 2f);
coords[offset++] = (float) Math.sin(angleInRadians) * radius;
coords[offset++] = (float) (Math.cos(angleInRadians) * radius);
coords[offset++] = 0;
}
return coords;
}
public void draw(float[] vPMatrix) {
GLES20.glUseProgram(program);
vPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, vPMatrix, 0);
positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
colorHandle = GLES20.glGetUniformLocation(program, "vColor");
GLES20.glUniform4fv(colorHandle, 1, color, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, (count + 2));
GLES20.glDisableVertexAttribArray(positionHandle);
}
}
public class Ball extends Shape {
private FloatBuffer vertexBuffer;
static final int COORDS_PER_VERTEX = 3;
//将圆形切割成40个三角形
private final int count = 40;
private float radius;
float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 1.0f};
static final int BYTES_PER_FLOAT = 4;
int vertexStride = COORDS_PER_VERTEX * BYTES_PER_FLOAT;
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private int program;
private int vPMatrixHandle;
private int positionHandle;
private int colorHandle;
private int vertexCount;
private static final String TAG = Ball.class.getSimpleName();
public Ball(float radius, int count) {
float[] coords = initBallCoords(radius, count);
Log.i(TAG, "coords = : " + Arrays.toString(coords));
ByteBuffer bb = ByteBuffer.allocateDirect(coords.length * BYTES_PER_FLOAT);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(coords);
vertexBuffer.position(0);
vertexCount = coords.length / COORDS_PER_VERTEX;
program = GLES20.glCreateProgram();
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program);
}
//赤道处圆心 0,0,0 半径为R 一个圆形 40份需要41个点
//0-90°圆锥
//0-> -90°圆锥
private float[] initBallCoords(float radius, int count) {
float[] coords = new float[((count + 1) * 181 + 1) * COORDS_PER_VERTEX];
int offset = 0;
// coords[offset++] = 0;
// coords[offset++] = 0;
// coords[offset++] = 0;
//赤道
// offset = getCircleCoords(coords, radius, count, 0, offset);
//上半球,下半球
for (int i = 1; i <= 90; i++) {
float miniRadius = (float) (radius * Math.cos(i * 180 / Math.PI));
//坐标Z
float z = (float) (radius * Math.sin(i * 180 / Math.PI));
offset = getCircleCoords(coords, miniRadius, count, z, offset);
}
for (int i = 1; i <= 90; i++) {
float miniRadius = (float) (radius * Math.cos(i * 180 / Math.PI));
//坐标Z
float z = (float) (-radius * Math.sin(i * 180 / Math.PI));
offset = getCircleCoords(coords, miniRadius, count, z, offset);
}
return coords;
}
private int getCircleCoords(float[] coords, float radius, int count, float z, int offset) {
for (int i = 0; i < count + 1; i++) {
float angleInRadians = ((float) i / (float) count)
* ((float) Math.PI * 2f);
coords[offset++] = (float) Math.sin(angleInRadians) * radius;
coords[offset++] = (float) (Math.cos(angleInRadians) * radius);
coords[offset++] = z;
}
return offset;
}
public void draw(float[] vPMatrix) {
GLES20.glUseProgram(program);
vPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, vPMatrix, 0);
positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
colorHandle = GLES20.glGetUniformLocation(program, "vColor");
GLES20.glUniform4fv(colorHandle, 1, color, 0);
GLES20.glDrawArrays(GLES20.GL_LINES, 0, vertexCount);
GLES20.glDisableVertexAttribArray(positionHandle);
}
}
为了看起来方便可以顺便加一个动画
public class GLRender_Matrix_4 implements GLSurfaceView.Renderer {
private float[] vPMatrix = new float[16];
private float[] projectMatrix = new float[16];
private float[] viewMatrix = new float[16];
private float[] rotationMatrix = new float[16];
private Ball ball;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0, 0, 0, 1);
Matrix.setLookAtM(viewMatrix, 0, 6, 6, -6, 0, 0, 0, 1, 1, 1);
ball = new Ball(0.5f, 40);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratial = (float) width / height;
Matrix.frustumM(projectMatrix, 0, -ratial, ratial, -1, 1, 3, 200);
}
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
Matrix.multiplyMM(vPMatrix, 0, projectMatrix, 0, viewMatrix, 0);
float[] scrach = new float[16];
long time = SystemClock.uptimeMillis() % 4000L;
float angle = 0.090f * ((int) time);
//可以设置旋转的方向 X轴、Y轴、Z轴
Matrix.setRotateM(rotationMatrix, 0, angle, 0, 1, 0f);
Matrix.multiplyMM(scrach, 0, vPMatrix, 0, rotationMatrix, 0);
ball.draw(scrach);
}
}
矩阵可以叠加,球型实在看不出来是球,所以换成GL_LINES 了,为了验证坐标计算的正确性
绘制模式: