WebGL 踩坑系列-2
需求:绘制斑点在球面上走过的路径
思路:要绘制斑点在球面上走过的路径,首先要记录上一时刻和当前时刻该斑点所在球面的位置,并且实时更新当前时刻的斑点位置和上一时刻的斑点位置。
为了方便,上一时刻斑点所在位置记为 last_point,当前时刻位置记为 cur_point,统一用球坐标系进行计算。
- last_point = [ltheta, lbeta, ldis];
- cur_point = [theta, beta, dis];
那么接下来就要把这些记录下来的点(转换成直角坐标系后)和对应的索引存放到 buffer 缓冲区中,
- gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
- gl.bufferSubData(gl.ARRAY_BUFFER, offset, new Float32Array(vertices));
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
- gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, offset, new Uint16ArrayBuffer(indices));
vertex_buffer 和 index_buffer 分别是创建的 gl 缓冲区。 offset 根据已经存入的 vertices 和 indices 来计算,
注意:这里的 offset 都应该是字节数。
比如当前已经向缓冲区中存入了 100 个顶点数据(也就是100 * 3 个浮点数),200 个索引数据
那么 vertices 的 offset 应该是 100 * 3 * 4 = 1200,浮点数的字节数是 4,所以这里需要乘上 4。
而 Uint 的字节数是 2,索引的 offset 应该是 200 * 2 = 400。
如果不想计算这里的偏移量,可以将每次记录下来的顶点 push 一个数组里,比如 vertices_array,然后直接将该数组的所有数据更新到 buffer 中:
- vertices_array.push(vertices);
- gl.bindBuffer(gl.ARRAY_BUFFER, vertices_buffer);
- gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Float32Array(vertices_array)
索引缓冲区也是一样的。
这种方式很明显的缺陷在于,vertices_array 会越来越大,而且每次都要把所有记录到的顶点全部传送到缓冲区中。
另外,在创建缓冲区的时候需要指定创建的缓冲区类型是 gl.DYNAMIC_DRAW。用于多次传输数据,多次绘制。
方法1
用 gl 的绘图 API 进行绘制即可,最简单的方法是:
- gl.drawElements(gl.LINES, index.length, gl.UNSIGNED_SHORT, 0);
index.length 就是记录的索引长度。
方法2:
第一种方法绘制的是线条,我之前想到的复杂一点的方式是记录 cur_point 周围的顶点,
然后用这些顶点绘制黎曼矩形,也就是将路径绘制成面。
那么这样就需要计算 cur_point 的周围点。
最开始用的方法是简单的计算 cur_point 周围四个点的坐标,注意到 cur_point 用的是球坐标系,
若用 dt 表示 theta 角的变化,db 表示 beta 角的变化
- var dt = 1 * Math.PI / 180;
- var db = 1 * Math.PI / 180;
- var p1 = [ cur_point[0] - dt, cur_point[1] - db, cur_point[2] ];
- var p2 = [ cur_point[0] - dt, cur_point[1] + db, cur_point[2] ];
- var p3 = [ cur_point[0] + dt, cur_point[1] + db, cur_point[2] ];
- var p4 = [ cur_point[0] + dt, cur_point[1] - db, cur_point[2] ];
这样就得到了周围的四个点,再和 last_point 周围的四个点一起,绘制三角形,就可以形成路径了。
然而这种方法有个非常难受的地方,当 p1[0] = p2[0] 的时候,把球坐标转换成直角坐标的时候,就会发现,p1 和 p2 重合了,路径的宽度在不同的 theta 角处是不一样的。
在极点附近的路径很窄,而赤道处附近的路径很宽。
这样的路径绘制出来看上去就非常难受。
方法3:
后来我想了一种方法,因为路径的宽度会随着当前顶点的 theta 角变化,那么p1,p2,p3,p4 四个点用的 db 就不应该一样。
- var db1 = 1 * Math.PI / 180 / Math.sin(cur_point[0] - dt);
- var db2 = 1 * Math.PI / 180 / Math.sin(cur_point[0] + dt);
天知道当时怎么想到的把 db 除上一个 Sin 值,然后通过不断的修改系数,让记录下来绘制的路径看上去宽度大致是相同的。
方法4:
前面那个方法完全是凑出来的,虽然最后的结果还行。
后来我重新思考周边顶点的计算方式。找到与路径垂直,而且在球面上的点就可以实现功能。
令 S = P1 - P2 ,P1 和 P2 是 cur_point 和 last_point 的直角坐标,如果球心在原点的话,那么它们的直角坐标就是各自的方向向量了。
n = (P1 + P2) / 2,计算得到一个垂直于 S 的向量,计算 n x S 的结果 L,就可以得到与运动轨迹相垂直的向量了。将其归一化得到单位向量,再乘上比例系数,就可以用于计算了。
周边的四个顶点分别就可以用 P1 和 P2 加减 L 向量得到。之前说过,球心在原点,向量和坐标在值上是一样的。那么就得到周边四个顶点的直角坐标。
用 gl.TRIANGLES 绘制三角形,就可以把路径绘制成连续的平面。当然如果 L 向量的长度很小,最后得到的路径就很窄,反之路径就会很宽。
最终绘制出来的路径如果想要变成虚线的形式,就间隔几个时刻采点,然后绘制出来就像虚线的样子了。
或许也可以设置 gl.vertexAttribPointer(attributes_vertex_position, 3, gl.FLOAT, false, 0, 0); 这个函数的 stride 参数,间隔若干个点进行绘制,应该也可以实现成虚线的形式。
WebGL 踩坑系列-2的更多相关文章
- WebGL 踩坑系列-3
WebGL 踩坑系列-3 绘制球体 在 WebGL 中绘制物体时需要的顶点是以直角坐标表示的, 当然了,gl_Position 是一个四维的向量,一般将顶点赋值给 gl_Position 时,最后一维 ...
- WebGL 踩坑系列-1
WebGL 中的一些选项WebGL 中开启颜色混合(透明效果) gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALP ...
- jmeter踩坑系列
1.踩坑系列一: 抓包出来有host的字段,放到jmeter里面一起请求就报错了,去掉就请求正常了 1.踩坑系列二: 从花瓶复制过去 的values 前面有空格,肉眼看起来没有
- python踩坑系列之导入包时下划红线及报错“No module named”问题
python踩坑系列之导入包时下划红线及报错“No module named”问题 使用pycharm编写Python时,自己写了一个包(commontool),在同级另一个路径下(fileshand ...
- 踩坑系列の Oracle dbms_job简单使用
二话不说先上代码 --创建存储过程 create or replace procedure job_truncateState is begin --此处就是要定时执行的sql execute imm ...
- Vue踩坑系列
前言 前端开发对于vue的使用已经越来越多,它的优点就不做介绍了, 本篇是我对vue使用过程中遇到的问题中做的一些总结,帮助大家踩坑.如果喜欢的话可以点波赞,或者关注一下,希望本文可以帮到大家!!! ...
- 踩坑系列:MySql only_full_group_by配置,竟导致所有应用报错?
1. 踩坑经历 一个很平常的下午,大家都在埋头认真写bug呢,突然企业微信群里炸锅了,好多应用都出现大量的Error日志,而且都报同一个错误,就是下面这个: Caused by: com.mysql. ...
- 【踩坑系列】使用long类型处理金额,科学计数法导致金额转大写异常
1. 踩坑经历 上周,一个用户反馈他创建的某个销售单无法打开,但其余销售单都可以正常打开,当时查看了生产环境的ERROR日志,发现抛了这样的异常:java.lang.NumberFormatExcep ...
- electron踩坑系列之一
前言 以electron作为基础框架,已经开发两个项目了.第一个项目,我主要负责用react写页面,第二项目既负责electron部分+UI部分. 做项目,就是踩坑, 一路做项目,一路踩坑,坑多不可怕 ...
随机推荐
- 数据加密实战之记住密码、自动登录和加密保存数据运用DES和MD5混合使用
MD5的简介:MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致.是计算机广泛使用的杂凑算法之一(又译摘要算法.哈希算法),主流编程语言普遍已有 ...
- 【转】 robotframework(rf)中对时间操作的datetime库常用关键字
转自http://blog.csdn.net/r455678/article/details/52993765 DateTime库是robotframework内置的库 1.对固定日期进行操作,增加或 ...
- ubuntu安装hadoop经验
安装环境: 1 linux系统 2 或(windows下)虚拟机 本文在linux系统ubuntu下尝试安装hadoop 安装前提 1 安装JDK(安装oracle公司的JDK ) (1)检查是否已安 ...
- PyCharm中的Console调整字体大小
file-->settings-->Editor-->color Scheme-->Console Font --> size 调整大小
- Nodejs 文档概览
Node.js v8.11.1 Node.js v8.11.1 文档 今天大致浏览了一下Node.js的官方文档,走马观花的了解了大部分模块的api,对他们的使用场景做一个简单的笔记 assert 断 ...
- 【TED演讲】阿帕玛・饶:(幽默的高科技艺术)
身为艺术家和TED Fellow的阿帕玛・饶对熟悉的事物以惊奇的幽默的方式进行再次想像.通过和索伦・普尔兹的合作,她创作出一系列高科技的艺术作品-一个会发邮件的打字机,一个让你在屏幕上消失而跟踪拍摄你 ...
- 解决Eclipse 启动后总是Building WorkSpace(sleeping) Java报错和处理
发布者:Lynn.. 时间:2016-12-20 13:13:55 今天打开eclipse后eclipse总是在Building WorkSpace(sleeping),我的解决方案是 ...
- Linux之sersync数据实时同步
sersync其实是利用inotify和rsync两种软件技术来实现数据实时同步功能的,inotify是用于监听sersync所在服务器上的文件变化,结合rsync软件来进行数据同步,将数据实时同步给 ...
- 3.Best Time to Buy and Sell Stock(买卖股票)
Level: Easy 题目描述: Say you have an array for which the ith element is the price of a given stock ...
- Mybatis学习笔记(八) —— Mybatis整合spring
一.整合思路 1.SqlSessionFactory对象应该放到spring容器中作为单例存在. 2.传统dao的开发方式中,应该从spring容器中获得sqlsession对象. 3.Mapper代 ...