OpenGLES:绘制一个混色旋转的3D球体

一.概述

前面几篇博文讲解了如何使用OpenGLES实现不同的3D图形

本篇博文讲解怎样实现3D世界的代表图形:一个混色旋转的3D球体

二.球体解析

2.1 极限正多面体

如果有学习过我前几篇3D图形绘制的博文,就知道要想绘制一个3D图形,首先要做的第一步就是将要绘制的3D图形进行拆解,拆解成能够使用单位图元——三角形进行绘制的各种子图形

然而懂点微积分的都知道,球体本身就可以看作是一个被极限分解的正多面体

所以球面本身就可以使用三角形进行绘制,并不需要拆解成其他子图形

那么,现在要做的就是如何求解球体的顶点坐标。

2.2 求解球体顶点坐标

众所周知,地球上任何一个地方都能用经纬度进行标识

以此类推,先给球体设置一个经纬度

根据经纬度就将球体分解成四边形,再将四边形分解成三角形。

那么求解球体的坐标,就只需要求出四边形的坐标即可。

2.3 球体顶点坐标公式

根据上述讲解和图示,很容易就能得出球体顶点坐标公式:

  • x0 = R * cos(a) * sin(b)
  • y0 = R * sin(a))
  • z0 = R * cos(a) * cos(b)

三.Render:变量定义

3.1 常规变量定义

还是常见的几个变量,跟其他3D图形的常规变量并无差别

//MVP矩阵
private float[] mMVPMatrix = new float[16];//着色器程序/渲染器
private int shaderProgram;//返回属性变量的位置
//MVP变换矩阵属性
private int mvpMatrixLoc;
//位置属性
private int aPositionLocation;
//颜色属性
private int aColorLocation;//surface宽高比
private float ratio;

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

前文中已经讲解,对于球体,并不需要拆解出子图形,而且颜色混合我会在着色器代码中实现,并不会在Render代码中动态加载实现,因此只需要定义一个数组和缓冲,就是顶点坐标。

//球体顶点坐标数组
private float vertexData[];
//顶点缓冲
private FloatBuffer vertexBuffer;

3.3 定义MVP矩阵

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

四.Render:着色器、内存分配等

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

4.2 着色器属性获取、赋值

4.3 缓冲内存分配

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

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

不再重复展示代码

五.Render:动态创建顶点

创建顶点时需要传入半径:0.85f

createBallPositions(0.85f);

球体渲染的关键函数: 

createBallPositions(float r):

private void createBallPositions(float r) {// 存放顶点坐标的ArrayListArrayList<Float> alVertix = new ArrayList<Float>();// 将球进行单位切分的角度final int angleSpan = 5;// 纬度angleSpan度一份for (int wAngle = -90; wAngle < 90; wAngle = wAngle + angleSpan) {// 经度angleSpan度一份for (int jAngle = 0; jAngle <= 360; jAngle = jAngle + angleSpan) {// 纵向横向各到一个角度后计算对应的此点在球面上的坐标float x0 = (float) (r * Math.cos(Math.toRadians(wAngle)) * Math.sin(Math.toRadians(jAngle)));float y0 = (float) (r * Math.sin(Math.toRadians(wAngle)));float z0 = (float) (r * Math.cos(Math.toRadians(wAngle)) * Math.cos(Math.toRadians(jAngle)));float x1 = (float) (r * Math.cos(Math.toRadians(wAngle)) * Math.sin(Math.toRadians(jAngle + angleSpan)));float y1 = (float) (r * Math.sin(Math.toRadians(wAngle)));float z1 = (float) (r * Math.cos(Math.toRadians(wAngle)) * Math.cos(Math.toRadians(jAngle + angleSpan)));float x2 = (float) (r * Math.cos(Math.toRadians(wAngle + angleSpan)) * Math.sin(Math.toRadians(jAngle + angleSpan)));float y2 = (float) (r * Math.sin(Math.toRadians(wAngle + angleSpan)));float z2 = (float) (r * Math.cos(Math.toRadians(wAngle + angleSpan)) * Math.cos(Math.toRadians(jAngle + angleSpan)));float x3 = (float) (r * Math.cos(Math.toRadians(wAngle + angleSpan)) * Math.sin(Math.toRadians(jAngle)));float y3 = (float) (r * Math.sin(Math.toRadians(wAngle + angleSpan)));float z3 = (float) (r * Math.cos(Math.toRadians(wAngle + angleSpan)) * Math.cos(Math.toRadians(jAngle)));// 将计算出来的XYZ坐标加入存放顶点坐标的ArrayListalVertix.add(x1);alVertix.add(y1);alVertix.add(z1);alVertix.add(x0);alVertix.add(y0);alVertix.add(z0);alVertix.add(x2);alVertix.add(y2);alVertix.add(z2);alVertix.add(x3);alVertix.add(y3);alVertix.add(z3);/*2---------------3|             / ||          /    ||       /       ||    /          || /             |1---------------0*/}}float f[] = new float[alVertix.size()];for (int i = 0; i < f.length; i++) {f[i] = alVertix.get(i);}vertexData = f;
}

六.Render:绘制

6.1 MVP矩阵

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

getBallMVPMatrix(float ratio)

依然采用的是视椎体透视投影:

public static float[] getBallMVPMatrix(float ratio) {float[] modelMatrix = getIdentityMatrix(16, 0); //模型变换矩阵float[] modelMatrix0 = getIdentityMatrix(16, 0); //模型变换矩阵float[] viewMatrix = getIdentityMatrix(16, 0); //观测变换矩阵/相机矩阵float[] projectionMatrix = getIdentityMatrix(16, 0); //投影变换矩阵mBallRotateAgree = (mBallRotateAgree + 1.0f) % 360;Matrix.setRotateM(modelMatrix, 0, mBallRotateAgree, 1, 0, 1);Matrix.translateM(modelMatrix0,0,0.0f,0.3f,0.3f);Matrix.multiplyMM(modelMatrix, 0, modelMatrix, 0, modelMatrix0, 0);Matrix.setLookAtM(viewMatrix, 0, 0, 0, 3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1, 1, 1, 10);float[] tmpMatrix = new float[16];float[] mvpMatrix = new float[16];Matrix.multiplyMM(tmpMatrix, 0, viewMatrix, 0, modelMatrix, 0);Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, tmpMatrix, 0);return mvpMatrix;
}

6.2 绘制球体

//准备顶点坐标内存
glVertexAttribPointer(aPositionLocation, 3, GL_FLOAT, false, 0, vertexBuffer);
//绘制
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexData.length / 3);

七.着色器代码

(1).ball_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;float x = vPosition.x;float y = vPosition.y;float z = vPosition.z;//效果较真实vColor = vec4(x, y, z, 0.0);
}
(2).ball_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;
}

八.效果展示

混色旋转的球体:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/124286.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MYSQL的CRUD语句(含c++代码)

一.MySQl表的创建与删除 创建语句与删除语句 注意&#xff1a; 主键的数据类型&#xff0c;不可以是变长度类型需要()限制长度&#xff0c;表名字需要使用符号来包围。 二.MySQl数据插入 三.MySQl数据删除 四.MySQl数据更新 使用语句 SET SQL_SAFE_UPDATES 0; show variabl…

MySQL优化、锁、总结常见问题

慢 SQL 如何定位呢&#xff1f; 慢 SQL 的监控主要通过两个途径&#xff1a; 慢查询日志&#xff1a;开启 MySQL 的慢查询日志&#xff0c;再通过一些工具比如 mysqldumpslow 去分析对应的慢查询日志&#xff0c;当然现在一般的云厂商都提供了可视化的平台。服务监控&#xf…

Python数据透视表

Python数据透视表 1、Excel数据透视表2、Python数据透视表 1、Excel数据透视表 数据透视表&#xff08;Pivot Table&#xff09;是一种交互式的表&#xff0c;可以进行某些计算&#xff0c;如求和与计数等。所进行的计算与数据跟数据透视表中的排列有关 之所以称为数据透视表…

知识图谱-Neo4j使用详解

neo4j应用场景 知识图谱欺诈检测实时推荐引擎反洗钱主数据管理供应链管理增强网络和IT运营管理能力数据谱系身份和访问管理材料清单 图数据库neo4j简介 关系查询&#xff1a;mysql和neo4j性能对比 neo4j的特性和优点&#xff1a; Neo4j-CQL简介 neo4j的Cypher语言是为处理图…

智能合约漏洞,Dyna 事件分析

智能合约漏洞&#xff0c;Dyna 事件分析 1. 漏洞简介 https://twitter.com/BlockSecTeam/status/1628319536117153794 https://twitter.com/BeosinAlert/status/1628301635834486784 2. 相关地址或交易 攻击交易 1&#xff1a; https://bscscan.com/tx/0x7fa89d869fd1b89e…

Hadoop启动后jps发现没有DateNode解决办法

多次使用 Hadoop namenode -format 格式化节点后DateNode丢失 找到hadoop配置文件core-site.xml查找tmp路径 进入该路径&#xff0c;使用rm -rf data删除data文件 再次使用Hadoop namenode -format 格式化后jps后出现DateNode节点

【Java 进阶篇】MySQL启动与关闭、目录结构以及 SQL 相关概念

MySQL 服务启动与关闭 MySQL是一个常用的关系型数据库管理系统&#xff0c;通过启动和关闭MySQL服务&#xff0c;可以控制数据库的运行状态。本节将介绍如何在Windows和Linux系统上启动和关闭MySQL服务。 在Windows上启动和关闭MySQL服务 启动MySQL服务 在Windows上&#x…

java使用数据库连接池

我的jar包名字 这些包都可以去搜索,有很多小伙伴会用网盘给我们.导入jar包就是复制然后粘贴就好了

论文笔记(整理):轨迹相似度顶会论文中使用的数据集

0 汇总 数据类型数据名称数据处理出租车数据波尔图 原始数据&#xff1a;2013年7月到2014年6月&#xff0c;170万条数据 ICDE 2023 Contrastive Trajectory Similarity Learning with Dual-Feature Attention 过滤位于城市&#xff08;或国家&#xff09;区域之外的轨迹 过…

Transformer学习-self-attention

这里写自定义目录标题 Self-attentionMulti-head self-attention用self-attention解决其他问题 Self-attention 用Wq、Wk、Wv分别乘输入向量得到q、k、v向量 用每个q向量乘所有的k向量得到对应项的attention&#xff0c;即用每项的query向量去匹配所有的key向量&#xff0c;得…

python模拟表格任意输入位置

在表格里输入数值&#xff0c;要任意位置&#xff0c;我找到了好方法&#xff1a; input输入 1. 行 2. 列输入&#xff1a;1 excel每行输入文字input输入位置 3.2 表示输入位置在&#xff1a;3行个列是要实现一个类似于 Excel 表格的输入功能&#xff0c;并且希望能够指定输入…

基于Java的水果生鲜购物网站设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…