本篇博文总共会实现两种混色旋转的3D圆锥:


上一篇博文讲解了绘制圆柱体,这一篇讲解绘制一个彩色旋转的圆锥
在绘制圆柱体时提到过,关键点是先将圆柱进行拆解,便于创建出顶点坐标数组
同样,绘制圆锥也先进行拆解
圆锥的拆解很简单,有两种方式可以理解:
也就是把圆锥拆成:一个2D圆 + 扇形锥面
讲到这里顺带提一句:
在OpenGL的世界里,不论多么复杂图形,最终都会被拆解成使用最基础的单位图元:三角形来完成绘制
为什么OpenGL渲染的基础单位图元是三角形呢?
因为一个点只是点,两个点组成线,三个点能确定一个面。
三角形是形成一个面最基础的图形单元,所以也是OpenGL的基础图元。
这次顶点颜色数组的定义和赋值与立方体绘制类似,在Render类中使用代码动态完成
- //MVP矩阵
- private float[] mMVPMatrix = new float[16];
-
- //着色器程序/渲染器
- private int shaderProgram;
-
- //mvp变换矩阵属性
- private int mvpMatrixLoc;
- //位置属性
- private int aPositionLocation;
- //颜色属性
- private int aColorLocation;
-
- //surface宽高比率
- private float ratio;
- //圆锥锥顶 顶点
- private float vertexData[];
- //圆锥底部圆 顶点
- private float vertexData1[];
- //圆锥锥顶 顶点颜色
- private float colorData[];
- //圆锥底部圆 顶点颜色
- private float colorData1[];
-
- //对应的坐标和颜色缓冲
- private FloatBuffer vertexBuffer;
- private FloatBuffer vertexBuffer1;
- private FloatBuffer colorBuffer;
- private FloatBuffer colorBuffer1;
- //MVP矩阵
- private float[] mMVPMatrix = new float[16];
这几个部分的代码实现2D图形绘制基本一致
可参考以前2D绘制的相关博文,里面都有详细的代码实现
不再重复展示代码
需要传入两个参数:
createPositions(0.6f, 60);
函数实现:
- private void createPositions(float radius, int n) {
- ArrayList
red = new ArrayList<>(); - ArrayList
blue = new ArrayList<>(); - ArrayList
magenta = new ArrayList<>(); - ArrayList
totalColor1 = new ArrayList<>(); - ArrayList
totalColor2 = new ArrayList<>(); - //红
- red.add(1.0f);
- red.add(0.0f);
- red.add(0.0f);
- red.add(0.0f);
- //蓝
- blue.add(0.0f);
- blue.add(0.0f);
- blue.add(1.0f);
- blue.add(0.0f);
- //粉 Magenta
- magenta.add(1.0f);
- magenta.add(0.2f);
- magenta.add(1.0f);
- magenta.add(0.0f);
-
- ArrayList
data = new ArrayList<>(); - //设置圆心的顶点坐标
- data.add(0.0f);
- data.add(0.0f);
- data.add(1.0f);
- //设置底部圆的顶点坐标
- float angDegSpan = 360f / n;
- for (float i = 0; i < 360 + angDegSpan; i += angDegSpan) {
- data.add((float) (radius * Math.sin(i * Math.PI / 180f)));
- data.add((float) (radius * Math.cos(i * Math.PI / 180f)));
- //底部圆的顶点Z坐标设置为-0.5f
- data.add(-0.5f);
- }
- //所有顶点坐标
- float[] f = new float[data.size()];
- for (int i = 0; i < f.length; i++) {
- f[i] = data.get(i);
- }
- vertexData = f;
-
- //设置圆心和底部圆顶点对应的颜色数据
- colorData = new float[f.length * 4 / 3];
- for (int i = 0; i < f.length / 3; i++) {
- if (i == 0) {
- totalColor1.addAll(red);
- } else {
- totalColor1.addAll(blue);
- }
- }
-
- for (int i = 0; i < totalColor1.size(); i++) {
- colorData[i] = totalColor1.get(i);
- }
-
- //底部圆
- vertexData1 = new float[vertexData.length];
- for (int i = 0; i < vertexData.length; i++) {
- if (i == 2) {
- vertexData1[i] = -0.5f;
- } else {
- vertexData1[i] = vertexData[i];
- }
- }
-
- colorData1 = new float[f.length * 4 / 3];
- for (int i = 0; i < f.length / 3; i++) {
- totalColor2.addAll(magenta);
- }
- for (int i = 0; i < totalColor2.size(); i++) {
- colorData1[i] = totalColor2.get(i);
- }
- }
- //MVP矩阵赋值
- mMVPMatrix = TransformUtils.getConeMVPMatrix(ratio);
- //将变换矩阵传入顶点渲染器
- glUniformMatrix4fv(mvpMatrixLoc, 1, false, mMVPMatrix, 0);
getConeMVPMatrix():
采用的是透视投影方式
- public static float[] getConeMVPMatrix(float ratio) {
- float[] modelMatrix = getIdentityMatrix(16, 0); //模型变换矩阵
- float[] viewMatrix = getIdentityMatrix(16, 0); //观测变换矩阵/相机矩阵
- float[] projectionMatrix = getIdentityMatrix(16, 0); //投影变换矩阵
-
- mConeRotateAgree = (mConeRotateAgree + 1) % 360;
- //旋转方向xyz三个轴是相对于相机观察方向的,可以写一篇博客
- Matrix.rotateM(modelMatrix, 0, mConeRotateAgree, 1, 0, 1); //获取模型旋转变换矩阵
- //设置相机位置
- Matrix.setLookAtM(viewMatrix, 0, 5, 0.0f, -3.0f, 0f, 0f, 0f, 0f, 0.0f, 1.0f);
- //设置透视投影
- Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1, 1, 3, 10);
- //计算变换矩阵
- float[] tmpMatrix = new float[16];
- Matrix.multiplyMM(tmpMatrix, 0, viewMatrix, 0, modelMatrix, 0);
- float[] mvpMatrix = new float[16];
- Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, tmpMatrix, 0);
-
- return mvpMatrix;
- }
- drawCenterAndSide();
- drawBottomCircle();
(1).drawCenterAndSide()
- //准备顶点坐标和颜色数据
- glVertexAttribPointer(aPositionLocation, 3, GL_FLOAT, false, 0, vertexBuffer);
- glVertexAttribPointer(aColorLocation, 4, GL_FLOAT, false, 0, colorBuffer);
-
- //绘制
- glDrawArrays(GL_TRIANGLE_FAN, 0, vertexData.length / 3);
(2).drawBottomCircle()
- //准备顶点坐标和颜色数据
- glVertexAttribPointer(aPositionLocation, 3, GL_FLOAT, false, 0, vertexBuffer1);
- //底部圆颜色(粉色)缓冲
- glVertexAttribPointer(aColorLocation, 4, GL_FLOAT, false, 0, colorBuffer1);
-
- //绘制
- glDrawArrays(GL_TRIANGLE_FAN, 0, vertexData1.length / 3);
(1).cone_vertex_shader.glsl
- #version 300 es
-
- layout (location = 0) in vec4 vPosition;
- layout (location = 1) in vec4 aColor;
-
- uniform mat4 u_Matrix;
-
- out vec4 vColor;
-
- void main() {
- gl_Position = u_Matrix*vPosition;
- vColor = aColor;
- }
(2).cone_fragtment_shader.glsl
- #version 300 es
- #extension GL_OES_EGL_image_external_essl3 : require
- precision mediump float;
-
- in vec4 vColor;
-
- out vec4 outColor;
-
- void main(){
- outColor = vColor;
- }
最终实现出来的是锥面红蓝渐变、锥底粉色的圆锥

个人这个效果并不太好,底部和锥面的颜色变化没有渐变,过于突兀
只要在绘制底部圆的函数中更改一下,就可以得到底部圆心对应锥顶颜色,圆周对应锥面底部颜色的圆锥
注释掉底部圆的颜色缓冲代码
- //准备顶点坐标和颜色数据
- glVertexAttribPointer(aPositionLocation, 3, GL_FLOAT, false, 0, vertexBuffer1);
- //注释掉这句,底部圆的圆心颜色就会和圆锥锥顶颜色一样,底部圆的圆周颜色和圆锥锥面底部颜色一样
- //glVertexAttribPointer(aColorLocation, 4, GL_FLOAT, false, 0, colorBuffer1);
-
- //绘制
- glDrawArrays(GL_TRIANGLE_FAN, 0, vertexData1.length / 3);
效果如下:

两种混色旋转的3D圆锥绘制过程到此讲解结束
下一篇博文讲解混色旋转的3D球体绘制