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

效果展示

本篇博文会实现两种混色效果的3D圆柱:

一.圆柱体解析

上一篇博文讲解了怎么绘制一个混色旋转的立方体

这一篇讲解怎么绘制一个混色旋转的圆柱

圆柱的顶点创建主要基于2D圆进行扩展,与立方体没有相似之处

圆柱绘制的关键点就是将圆柱拆解成:两个Z坐标不为0的圆  + 一个长方形的圆柱面

绘制2D圆的过程这里不再复述,不理解的可以参看前面这篇博文:《OpenGLES:绘制一个颜色渐变的圆》

废话不多说,正文开始了。 

二.GLRender:变量定义

2.1 常规变量定义

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

//着色器mvp矩阵属性
private int mvpMatrix;
//位置属性
private int aPositionLocation;

//surface宽高比率
private float ratio;

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

概述中提到过,绘制圆柱的关键思路是将圆柱拆解成:两个Z坐标不为0的圆  + 一个长方形的圆柱面

所以定义三个顶点坐标数组和对应缓冲

//圆柱柱面顶点数组
private float[] vertexData;
//圆柱顶部圆的顶点数组
private float[] vertexData1;
//圆柱底部圆的顶点数组
private float[] vertexData2;

//圆柱柱面顶点缓冲
private FloatBuffer vertexBuffer;
//圆柱顶部圆的顶点缓冲
private FloatBuffer vertexBuffer1;
//圆柱顶部圆的顶点缓冲
private FloatBuffer vertexBuffer2;

需要注意的是,这次我并没有把顶点颜色单独定义成一个数组,而且在Render类中也不会像上一篇绘制立方体时动态加载和填充顶点颜色值

这次我会换一种方式,直接把颜色填充和变换在着色器代码中实现

最终的色彩渐变效果是一样的,殊途同归,丰富对OpenGLES不同实现方式的学习。

2.3 定义MVP矩阵

//MVP矩阵
private float[] mMVPMatrix = new float[16];

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

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

3.2 着色器属性获取、赋值

3.3 缓冲内存分配

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

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

不再重复展示代码

四.GLRender:动态创建顶点

float radio = 0.6f;
int spanIdx = 60;

vertexData = createSidePos(radio, spanIdx);
vertexData1 = createBottomCirclePos(radio, spanIdx, 0.7f);
vertexData2 = createBottomCirclePos(radio, spanIdx, -0.7f);

重点就在于创建圆柱顶点的两个函数:

  • createSidePos()
  • createBottomCirclePos()

4.1 createSidePos()

private float[] createSidePos(float radius, int n) {
	ArrayList<Float> data = new ArrayList<>();

	//设置顶部/底部圆的顶点坐标
	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.7f
		data.add(-0.7f);

		data.add((float) (radius * Math.sin(i * Math.PI / 180f)));
		data.add((float) (radius * Math.cos(i * Math.PI / 180f)));
		//顶部/底部圆的顶点Z坐标设置为-0.7f
		data.add(0.7f);
	}
	//所有顶点坐标
	float[] f = new float[data.size()];
	for (int i = 0; i < data.size(); i++) {
		f[i] = data.get(i);
	}
	return f;
}

4.2 createBottomCirclePos()

private float[] createBottomCirclePos(float radius, int n, float circleCenterZ) {
	ArrayList<Float> data = new ArrayList<>();
	//顶部/底部圆心坐标
	data.add(0.0f);
	data.add(0.0f);
	data.add(circleCenterZ);

	//设置顶部/底部圆的顶点坐标
	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.7f
		data.add(circleCenterZ);
	}
	//所有顶点坐标
	float[] f = new float[data.size()];
	for (int i = 0; i < data.size(); i++) {
		f[i] = data.get(i);
	}
	return f;
}

五.GLRender:绘制

5.1 MVP矩阵

//填充MVP矩阵
mMVPMatrix = TransformUtils.getCylinderMVPMatrix(ratio);
//将变换矩阵传入顶点渲染器
glUniformMatrix4fv(mvpMatrix, 1, false, mMVPMatrix, 0);

getCylinderMVPMatrix():

public static float[] getCylinderMVPMatrix(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 绘制圆柱柱面、顶部圆、底部圆

(1).drawSide()

//准备顶点坐标和颜色数据
glVertexAttribPointer(aPositionLocation, 3, GL_FLOAT, false, 0, vertexBuffer);
//绘制
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexData.length / 3);

(2).drawBottomCircle1()

//准备顶点坐标和颜色数据
glVertexAttribPointer(aPositionLocation, 3, GL_FLOAT, false, 0, vertexBuffer1);
//绘制
glDrawArrays(GL_TRIANGLE_FAN, 0, vertexData1.length / 3);

(3).drawBottomCircle2()

//准备顶点坐标和颜色数据
glVertexAttribPointer(aPositionLocation, 3, GL_FLOAT, false, 0, vertexBuffer2);
//绘制
glDrawArrays(GL_TRIANGLE_FAN, 0, vertexData2.length / 3);

六.着色器代码

6.1 cylinder_vertex_shader.glsl

先实现一个顶部绿色,底部红色,柱面绿红渐变的旋转圆柱

#version 300 es

layout (location = 0) in vec4 vPosition;
layout (location = 1) in vec4 aColor;

uniform mat4 mvpMatrix;

out vec4 vColor;

void main() {
    gl_Position = mvpMatrix * vPosition;

    if (vPosition.z == 0.7) {
        vColor = vec4(0.0, 1.0, 0.0, 0.0);    //绿
    } else if (vPosition.z == -0.7) {
        vColor = vec4(1.0, 0.0, 0.0, 0.0);    //红
    }
}

6.2 cylinder_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;
}

七.两种效果

上一节中讲了,先来一个顶部绿,底部红,柱面绿红渐变的旋转3D圆柱

效果如下:

如何实现混色渐变的旋转圆柱呢?

很简单,只要修改顶点着色器代码

void main() {
    gl_Position = mvpMatrix * vPosition;

    //颜色混合渐变
    vColor = vec4(vPosition.x,vPosition.y, vPosition.z,0.0);
}

效果如下:

八.结束语

两种混色旋转的3D圆柱绘制过程到此讲解结束

下一篇讲解混色旋转的圆锥

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
使用NDK和OpenGL ES 3.0来绘制一个三角形可以分为以下几个步骤: 1. 首先,创建一个安卓项目,并配置NDK环境。 2. 在项目的jni目录下,创建一个C/C++源文件triangle.c。 3. 在triangle.c文件中,引入相关的头文件,包括<jni.h>和<GLES3/gl3.h>。 4. 在triangle.c文件中,实现一个JNI函数,用于绘制三角形。函数的参数为Surface对象。 5. 在JNI函数中,通过EGL和GLES初始化OpenGL环境,并创建一个EGLSurface用于后续的绘制操作。 6. 在JNI函数中,创建一个顶点数组和顶点缓冲,并将顶点数据存入顶点缓冲。 7. 在JNI函数中,编写着色器代码,包括顶点着色器和片段着色器,并编译和链接它们。 8. 在JNI函数中,通过glClearColor()函数设置清空屏幕时的颜色。 9. 在JNI函数中,通过glClear()函数清空屏幕,并启用深度测试。 10. 在JNI函数中,通过glViewport()函数设置视口大小。 11. 在JNI函数中,通过glUseProgram()函数使用着色器程序。 12. 在JNI函数中,通过glVertexAttribPointer()函数设置顶点数据的属性,并启用顶点属性。 13. 在JNI函数中,通过glDrawArrays()函数绘制三角形。 14. 在JNI函数中,通过eglSwapBuffers()函数交换绘制的缓冲区。 15. 在JNI函数中,清理OpenGL环境,并释放资源。 16. 在Java层的MainActivity中,通过JNI调用C/C++函数进行绘制。 以上是绘制一个三角形的大致步骤。具体的细节和代码实现可以参考相关的OpenGL ES 3.0和NDK的文档和示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值