OpenGLES:绘制一个混色旋转的3D圆锥

效果展示:

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

一.圆锥解析

1.1 对圆锥的拆解

上一篇博文讲解了绘制圆柱体,这一篇讲解绘制一个彩色旋转的圆锥

在绘制圆柱体时提到过,关键点 是先将圆柱进行拆解,便于创建出顶点坐标数组

同样,绘制圆锥也先进行拆解

圆锥的拆解很简单,有两种方式可以理解:

  • 2D圆的圆心从圆平面里抽离出来,赋予一个Z值
  • 2D的圆心和圆平面分别赋予不同的Z值

也就是把圆锥拆成:一个2D圆 + 扇形锥面

1.2 单位图元:三角形

讲到这里顺带提一句:

在OpenGL的世界里,不论多么复杂图形,最终都会被拆解成使用最基础的单位图元:三角形来完成绘制

为什么OpenGL渲染的基础单位图元是三角形呢?

因为一个点只是点,两个点组成线,三个点能确定一个面。

三角形是形成一个面最基础的图形单元,所以也是OpenGL的基础图元。

二.GLRender:变量定义

这次顶点颜色数组的定义和赋值与立方体绘制类似,在Render类中使用代码动态完成

2.1 常规变量定义

java 复制代码
//MVP矩阵
private float[] mMVPMatrix = new float[16];

//着色器程序/渲染器
private int shaderProgram;

//mvp变换矩阵属性
private int mvpMatrixLoc;
//位置属性
private int aPositionLocation;
//颜色属性
private int aColorLocation;

//surface宽高比率
private float ratio;

2.2 定义顶点坐标数组和缓冲

java 复制代码
//圆锥锥顶 顶点
private float vertexData[];
//圆锥底部圆 顶点
private float vertexData1[];
//圆锥锥顶 顶点颜色
private float colorData[];
//圆锥底部圆 顶点颜色
private float colorData1[];

//对应的坐标和颜色缓冲
private FloatBuffer vertexBuffer;
private FloatBuffer vertexBuffer1;
private FloatBuffer colorBuffer;
private FloatBuffer colorBuffer1;

2.3 定义MVP矩阵

java 复制代码
//MVP矩阵
private float[] mMVPMatrix = new float[16];

三.GLRender:着色器、内存分配等

3.1 着色器创建、链接、使用

3.2 着色器属性获取、赋值

3.3 缓冲内存分配

这几个部分的代码实现2D图形绘制基本一致

可参考以前2D绘制的相关博文,里面都有详细的代码实现

不再重复展示代码

四.GLRender:动态创建顶点

需要传入两个参数:

  • 圆锥底部圆半径长度
  • 底部圆和圆锥扇面分割份数
java 复制代码
createPositions(0.6f, 60);

函数实现:

java 复制代码
private void createPositions(float radius, int n) {
	ArrayList<Float> red = new ArrayList<>();
	ArrayList<Float> blue = new ArrayList<>();
	ArrayList<Float> magenta = new ArrayList<>();
	ArrayList<Float> totalColor1 = new ArrayList<>();
	ArrayList<Float> 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<Float> 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);
	}
}

五.GLRender:绘制

5.1 MVP矩阵

java 复制代码
//MVP矩阵赋值
mMVPMatrix = TransformUtils.getConeMVPMatrix(ratio);
//将变换矩阵传入顶点渲染器
glUniformMatrix4fv(mvpMatrixLoc, 1, false, mMVPMatrix, 0);

getConeMVPMatrix():

采用的是透视投影方式

java 复制代码
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;
}

5.2 绘制圆锥的锥顶锥面、底部圆

java 复制代码
drawCenterAndSide();
drawBottomCircle();

(1).drawCenterAndSide()

java 复制代码
//准备顶点坐标和颜色数据
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()

java 复制代码
//准备顶点坐标和颜色数据
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

cpp 复制代码
#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

java 复制代码
#version 300 es
#extension GL_OES_EGL_image_external_essl3 : require
precision mediump float;

in vec4 vColor;

out vec4 outColor;

void main(){
    outColor = vColor;
}

七.效果展示

最终实现出来的是锥面红蓝渐变、锥底粉色的圆锥

个人这个效果并不太好,底部和锥面的颜色变化没有渐变,过于突兀

只要在绘制底部圆的函数中更改一下,就可以得到底部圆心对应锥顶颜色,圆周对应锥面底部颜色的圆锥

注释掉底部圆的颜色缓冲代码

java 复制代码
//准备顶点坐标和颜色数据
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球体绘制

相关推荐
qzhqbb几秒前
神经网络 - 卷积神经网络
神经网络·计算机视觉·cnn
不染尘.3 分钟前
2025_11_7_刷题
开发语言·c++·vscode·算法
TDengine (老段)24 分钟前
TDengine 字符串函数 CONCAT_WS 用户手册
android·大数据·数据库·时序数据库·tdengine·涛思数据
美摄科技30 分钟前
什么是3D贴纸SDK?
3d
会跑的兔子1 小时前
Android 16 Kotlin协程 第一部分
android·开发语言·kotlin
来荔枝一大筐1 小时前
力扣 寻找两个正序数组的中位数
算法
算法与编程之美1 小时前
理解Java finalize函数
java·开发语言·jvm·算法
地平线开发者2 小时前
LLM 训练基础概念与流程简介
算法·自动驾驶
点云SLAM2 小时前
弱纹理图像特征匹配算法推荐汇总
人工智能·深度学习·算法·计算机视觉·机器人·slam·弱纹理图像特征匹配
星释2 小时前
Rust 练习册 :Matching Brackets与栈数据结构
数据结构·算法·rust