WebGL 踩坑系列-3

绘制球体

在 WebGL 中绘制物体时需要的顶点是以直角坐标表示的,

当然了,gl_Position 是一个四维的向量,一般将顶点赋值给 gl_Position 时,最后一维会设为 1,

gl_Position = uMVPMatrix * vec4(aVertexPosition, 1.0);

这个时候的 aVertexPosition 三维向量就代表了顶点的直角坐标。

如果我们计算出球面上的顶点,并以直角坐标的形式传入着色器中,用合适的方式绘制,就能画出球面了。

但是,绘制球体需要用到顶点,如果直接用直角坐标,并不好计算,

这时候需要用到球坐标系将球面上的各个顶点表示出来,然后再将球坐标表示成直角坐标。

/**
* 假设球心即为原点,将球面坐标系转换成平面直角坐标系
* @param theta 球心到顶点的连线与 Z 轴正方向的夹角为 theta,范围是 [0, 180]
* @param beta 球心到顶点的连线在 xoy 平面上的投影与 X 轴正方向的夹角为 beta,范围是 [0, 360]
* @param r 球半径
* @return 顶点的坐标,用三维数组表示
*/
function calcVertex(theta, beta, r) {
var st = Math.sin(Math.PI * theta / 180);
var ct = Math.cos(Math.PI * theta / 180);
var sb = Math.sin(Math.PI * beta / 180);
var cb = Math.cos(Math.PI * beta / 180);
var x = r * st * cb;
var y = r * st * sb;
var z = r * ct;
return [x, y, z];
}

这个 calcVertex 函数就够把特定角度和半径的球坐标转换成相应的直角坐标了。

现在只需要从 0 - 180 遍历 theta,0 - 360 遍历 beta 角,就可以得到球面上的所有顶点了。

var n = 48;
var vetices = [];
var r = 1;
for( var j = 0; j < n; j++ ) {
for( var i = 0; i < n: i++ ) {
vertices.push.apply( vertices, calcVertex( i * 180 / n, j * 360 / n, r ) );
// 或者用数组的 concat 方法,效果是一样的,不过据说 concat 方法更高效
// vertices = vertices.concat( calcVertex( i * 180 / n, j * 360 / n, r ) );
}
}

接下来把得到的顶点传入 gl 的缓冲区中,

var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

如果只是利用这些顶点,还不能画出球面,借助索引缓冲区可以实现:

var index = [];
for ( j = 0; j < n; j++ ) {
for ( i = 0; i < n+1; i++ ) {
index.push(
i + j * (n+1), // 0
i+1 + j * (n+1), // 1
i+1 + (j+1) * (n+1) // n+1
);
index.push(
i + j * (n+1), // 0
i+1 + (j+1) * (n+1) // n+1
i + (j+1) * (n+1) // n
);
}
} gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
gl.drawElements(gl.TRIANGLES, index.length, gl.UNSIGNED_SHORT, 0);

最后就能在 canvas 画布上画出球面了,n 越大,球面越精细,画出的球越圆滑。

ThreeJS 绘制球形

由于有导入模型的需求,开始接触 ThreeJS,用这个框架只需要调用 SphereGeometry 的 API 生成一个球,最后把球添加到场景中并进行渲染即可。

sphere = new THREE.Mesh(
new THREE.SphereGeometry(4, 36, 36),
new THREE.MeshPhongMaterial( {
opacity: 0.65,
transparent: true,
color: 0xeeeeee
} )
);
scene.add(sphere);

总结

尽管 ThreeJS 对底层的 WebGL 封装的很好,但是我只需要导入 OBJ 格式的模型就行了,ThreeJS 很强大,用起来也很方便。

而要从 WebGL 写的话,还需要去了解 GLSL 着色器语言,自己编写着色器代码,繁琐很多。

WebGL 踩坑系列-3的更多相关文章

  1. WebGL 踩坑系列-1

    WebGL 中的一些选项WebGL 中开启颜色混合(透明效果) gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALP ...

  2. WebGL 踩坑系列-2

    需求:绘制斑点在球面上走过的路径 思路:要绘制斑点在球面上走过的路径,首先要记录上一时刻和当前时刻该斑点所在球面的位置,并且实时更新当前时刻的斑点位置和上一时刻的斑点位置. 为了方便,上一时刻斑点所在 ...

  3. jmeter踩坑系列

    1.踩坑系列一: 抓包出来有host的字段,放到jmeter里面一起请求就报错了,去掉就请求正常了 1.踩坑系列二: 从花瓶复制过去 的values 前面有空格,肉眼看起来没有

  4. python踩坑系列之导入包时下划红线及报错“No module named”问题

    python踩坑系列之导入包时下划红线及报错“No module named”问题 使用pycharm编写Python时,自己写了一个包(commontool),在同级另一个路径下(fileshand ...

  5. 踩坑系列の Oracle dbms_job简单使用

    二话不说先上代码 --创建存储过程 create or replace procedure job_truncateState is begin --此处就是要定时执行的sql execute imm ...

  6. Vue踩坑系列

    前言 前端开发对于vue的使用已经越来越多,它的优点就不做介绍了, 本篇是我对vue使用过程中遇到的问题中做的一些总结,帮助大家踩坑.如果喜欢的话可以点波赞,或者关注一下,希望本文可以帮到大家!!! ...

  7. 踩坑系列:MySql only_full_group_by配置,竟导致所有应用报错?

    1. 踩坑经历 一个很平常的下午,大家都在埋头认真写bug呢,突然企业微信群里炸锅了,好多应用都出现大量的Error日志,而且都报同一个错误,就是下面这个: Caused by: com.mysql. ...

  8. 【踩坑系列】使用long类型处理金额,科学计数法导致金额转大写异常

    1. 踩坑经历 上周,一个用户反馈他创建的某个销售单无法打开,但其余销售单都可以正常打开,当时查看了生产环境的ERROR日志,发现抛了这样的异常:java.lang.NumberFormatExcep ...

  9. electron踩坑系列之一

    前言 以electron作为基础框架,已经开发两个项目了.第一个项目,我主要负责用react写页面,第二项目既负责electron部分+UI部分. 做项目,就是踩坑, 一路做项目,一路踩坑,坑多不可怕 ...

随机推荐

  1. jest+vue-test-utils初步实践

    一.起步 1. jest Jest是 Facebook 的一套开源的 JavaScript 测试框架, 它自动集成了断言.JSDom.覆盖率报告等开发者所需要的所有测试工具,配置较少,对vue框架友好 ...

  2. 1、OpenCV Python 图像加载和保存

    __author__ = "WSX" import cv2 as cv # 这里的文件是图片或者视频 def Save_File( image ): cv.imwrite(&quo ...

  3. 数据结构11: 栈(Stack)的概念和应用及C语言实现

    栈,线性表的一种特殊的存储结构.与学习过的线性表的不同之处在于栈只能从表的固定一端对数据进行插入和删除操作,另一端是封死的. 图1 栈结构示意图 由于栈只有一边开口存取数据,称开口的那一端为“栈顶”, ...

  4. Flume启动时报错Caused by: java.lang.InterruptedException: Timed out before HDFS call was made. Your hdfs.callTimeout might be set too low or HDFS calls are taking too long.解决办法(图文详解)

    前期博客 Flume自定义拦截器(Interceptors)或自带拦截器时的一些经验技巧总结(图文详解) 问题详情 -- ::, (agent-shutdown-hook) [INFO - org.a ...

  5. CF986B Petr and Permutations 思维

    每次交换:逆序对的数量+1或者-1: 假设最后逆序对数量为 sum; ①x+y=3n; ②x-y=sum; -> 3n+sum为偶数: 所以 n 和 sum 必须奇偶一样: #include&l ...

  6. php 常见递归实例

    //计算数组{1,1,2,3,5,8.......} 第n位值 function Process1($i){ if ($i == 0) return 0; if ($i == 1) return 1; ...

  7. 记录Leetcode 鸡蛋掉落 的思路

    前言 首先看一下这个题目,是Leetcode的第887题"鸡蛋掉落": 你将获得 `K` 个鸡蛋,并可以使用一栋从 `1` 到 `N` 共有 `N` 层楼的建筑. 每个蛋的功能都是 ...

  8. 表格排序插件datatables

    之前用过表格排序插件tinytables,用到后面,随着需求的更改,发现这个插件真的low到爆了,不适合用于多表格,只有一个表格的页面可以凑合着用,有很多局限性. 之后发现了一款表格排序插件datat ...

  9. Nginx根据目录自动生成二级域名

    前言:     每次创建二级域名如果都修改一次配置文件的话,项目多了会带来很多不必要的工作量,如果能够在一个web目录下创建一个文件夹并且自动生成文件目录的话,那真是极好的,本文就基于Nginx贴出这 ...

  10. pm2 启动后台 node js

    1,安装node js 参看:https://www.cnblogs.com/wf-l5201314/p/9229974.html 2,pm2安装(安装环境linux / os) 命令:npm ins ...