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

2023-10-05 02:36

本文主要是介绍OpenGLES:绘制一个混色旋转的3D圆锥,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

效果展示:

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

一.圆锥解析

1.1 对圆锥的拆解

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

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

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

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

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

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

1.2 单位图元:三角形

讲到这里顺带提一句:

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

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

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

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

二.GLRender:变量定义

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

2.1 常规变量定义

//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 定义顶点坐标数组和缓冲

//圆锥锥顶 顶点
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矩阵

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

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

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

3.2 着色器属性获取、赋值

3.3 缓冲内存分配

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

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

不再重复展示代码

四.GLRender:动态创建顶点

需要传入两个参数:

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

函数实现:

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);//粉 Magentamagenta.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.5fdata.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矩阵

//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;
}

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

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 eslayout (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球体绘制

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



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

相关文章

无人叉车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 则负责绘制动画。

MiniGPT-3D, 首个高效的3D点云大语言模型,仅需一张RTX3090显卡,训练一天时间,已开源

项目主页:https://tangyuan96.github.io/minigpt_3d_project_page/ 代码:https://github.com/TangYuan96/MiniGPT-3D 论文:https://arxiv.org/pdf/2405.01413 MiniGPT-3D在多个任务上取得了SoTA,被ACM MM2024接收,只拥有47.8M的可训练参数,在一张RTX

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

利用matlab bar函数绘制较为复杂的柱状图,并在图中进行适当标注

示例代码和结果如下:小疑问:如何自动选择合适的坐标位置对柱状图的数值大小进行标注?😂 clear; close all;x = 1:3;aa=[28.6321521955954 26.2453660695847 21.69102348512086.93747104431360 6.25442246899816 3.342835958564245.51365061796319 4.87

SAM2POINT:以zero-shot且快速的方式将任何 3D 视频分割为视频

摘要 我们介绍 SAM2POINT,这是一种采用 Segment Anything Model 2 (SAM 2) 进行零样本和快速 3D 分割的初步探索。 SAM2POINT 将任何 3D 数据解释为一系列多向视频,并利用 SAM 2 进行 3D 空间分割,无需进一步训练或 2D-3D 投影。 我们的框架支持各种提示类型,包括 3D 点、框和掩模,并且可以泛化到不同的场景,例如 3D 对象、室

YOLOv8/v10+DeepSORT多目标车辆跟踪(车辆检测/跟踪/车辆计数/测速/禁停区域/绘制进出线/绘制禁停区域/车道车辆统计)

01:YOLOv8 + DeepSort 车辆跟踪 该项目利用YOLOv8作为目标检测模型,DeepSort用于多目标跟踪。YOLOv8负责从视频帧中检测出车辆的位置,而DeepSort则负责关联这些检测结果,从而实现车辆的持续跟踪。这种组合使得系统能够在视频流中准确地识别并跟随特定车辆。 02:YOLOv8 + DeepSort 车辆跟踪 + 任意绘制进出线 在此基础上增加了用户

二维旋转公式

二维旋转公式 ros的tf工具包可以很方便的实现任意坐标系之间的坐标转换。但是,如果只是想简单的测试想法,而又不想编写过于庞杂的代码,考虑自己写二维旋转的函数。而与二维旋转问题对偶的另一个问题便是二维坐标系旋转变换。这两个问题的形式基本一样,只是旋转的角度相差一个负号。就是这个容易搞混,所以做个笔记,以备查用。 1. 二维旋转公式(算法) 而(此文只针对二维)旋转则是表示某一坐标点 ( x