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

2023-10-18 21:40

本文主要是介绍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.7fdata.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.7fdata.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.7fdata.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 eslayout (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圆柱绘制过程到此讲解结束

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

这篇关于OpenGLES:绘制一个混色旋转的3D圆柱的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/235301

相关文章

css实现图片旋转功能

《css实现图片旋转功能》:本文主要介绍了四种CSS变换效果:图片旋转90度、水平翻转、垂直翻转,并附带了相应的代码示例,详细内容请阅读本文,希望能对你有所帮助... 一 css实现图片旋转90度.icon{ -moz-transform:rotate(-90deg); -webkit-transfo

使用Python绘制蛇年春节祝福艺术图

《使用Python绘制蛇年春节祝福艺术图》:本文主要介绍如何使用Python的Matplotlib库绘制一幅富有创意的“蛇年有福”艺术图,这幅图结合了数字,蛇形,花朵等装饰,需要的可以参考下... 目录1. 绘图的基本概念2. 准备工作3. 实现代码解析3.1 设置绘图画布3.2 绘制数字“2025”3.3

使用Python绘制可爱的招财猫

《使用Python绘制可爱的招财猫》招财猫,也被称为“幸运猫”,是一种象征财富和好运的吉祥物,经常出现在亚洲文化的商店、餐厅和家庭中,今天,我将带你用Python和matplotlib库从零开始绘制一... 目录1. 为什么选择用 python 绘制?2. 绘图的基本概念3. 实现代码解析3.1 设置绘图画

Python绘制土地利用和土地覆盖类型图示例详解

《Python绘制土地利用和土地覆盖类型图示例详解》本文介绍了如何使用Python绘制土地利用和土地覆盖类型图,并提供了详细的代码示例,通过安装所需的库,准备地理数据,使用geopandas和matp... 目录一、所需库的安装二、数据准备三、绘制土地利用和土地覆盖类型图四、代码解释五、其他可视化形式1.

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math

Qt QWidget实现图片旋转动画

《QtQWidget实现图片旋转动画》这篇文章主要为大家详细介绍了如何使用了Qt和QWidget实现图片旋转动画效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 一、效果展示二、源码分享本例程通过QGraphicsView实现svg格式图片旋转。.hpjavascript

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

【WebGPU Unleashed】1.1 绘制三角形

一部2024新的WebGPU教程,作者Shi Yan。内容很好,翻译过来与大家共享,内容上会有改动,加上自己的理解。更多精彩内容尽在 dt.sim3d.cn ,关注公众号【sky的数孪技术】,技术交流、源码下载请添加微信号:digital_twin123 在 3D 渲染领域,三角形是最基本的绘制元素。在这里,我们将学习如何绘制单个三角形。接下来我们将制作一个简单的着色器来定义三角形内的像素

poj 2187 凸包or旋转qia壳法

题意: 给n(50000)个点,求这些点与点之间距离最大的距离。 解析: 先求凸包然后暴力。 或者旋转卡壳大法。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <s

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。