需求:绘制斑点在球面上走过的路径

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

为了方便,上一时刻斑点所在位置记为 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,就可以得到与运动轨迹相垂直的向量了。将其归一化得到单位向量,再乘上比例系数,就可以用于计算了。

周边的四个顶点分别就可以用 P1P2 加减 L 向量得到。之前说过,球心在原点,向量和坐标在值上是一样的。那么就得到周边四个顶点的直角坐标。

用 gl.TRIANGLES 绘制三角形,就可以把路径绘制成连续的平面。当然如果 L 向量的长度很小,最后得到的路径就很窄,反之路径就会很宽。

最终绘制出来的路径如果想要变成虚线的形式,就间隔几个时刻采点,然后绘制出来就像虚线的样子了。

或许也可以设置 gl.vertexAttribPointer(attributes_vertex_position, 3, gl.FLOAT, false, 0, 0); 这个函数的 stride 参数,间隔若干个点进行绘制,应该也可以实现成虚线的形式。

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

  1. WebGL 踩坑系列-3

    WebGL 踩坑系列-3 绘制球体 在 WebGL 中绘制物体时需要的顶点是以直角坐标表示的, 当然了,gl_Position 是一个四维的向量,一般将顶点赋值给 gl_Position 时,最后一维 ...

  2. WebGL 踩坑系列-1

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

  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. javascript 实现类似百度联想输入,自动补全功能

    js  实现类似百度联想输入,自动补全功能 方案一: search是搜索框id="search" //点击页面隐藏自动补全提示框 document.onclick = functi ...

  2. Mybatis+maven自动构建dao、mapper、model

    1.Pom.xml文件配置: 代码: <plugins> <!-- Mybatis generator代码生成插件 配置 --> <plugin> <grou ...

  3. java 学习第一篇简单基础

    Java基础 Java Java 和C#有着极为相似的语法. 和C#都是面向对象的高级程序语言. JAVA是一个开源,公开的语言,有着极其丰富的开源库和其他资源. JAVA分类 JAVA分SE EE ...

  4. iOS Programming GitHub

    我把学习<iOS编程(第4版)>的相关代码放在了GitHub上: https://github.com/palanceli/iOSProgramming 学了一段时间之后,当要用到某个知识 ...

  5. [SinGuLaRiTy] NOIP模拟赛(TSY)-Day 1

    [SinGuLaRiTy-1032] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved.                              ...

  6. ObjectARXWizards & AutoCAD .NET Wizards 下载地址

    Autodesk Developer Network ObjectARX Wizards The ObjectARX Wizards for AutoCAD 2016 for  Visual Stud ...

  7. P3768 简单的数学题 杜教筛+推式子

    \(\color{#0066ff}{ 题目描述 }\) 由于出题人懒得写背景了,题目还是简单一点好. 输入一个整数n和一个整数p,你需要求出(\(\sum_{i=1}^n\sum_{j=1}^n ij ...

  8. DP【洛谷P3089】 [USACO13NOV]POGO的牛Pogo-Cow

    [洛谷P3089] [USACO13NOV]POGO的牛Pogo-Cow FJ给奶牛贝西的脚安装上了弹簧,使它可以在农场里快速地跳跃,但是它还没有学会如何降低速度. FJ觉得让贝西在一条直线的一维线路 ...

  9. iOS 11导航栏设置BarButtonItem变形问题和错位问题

    升级到 iOS 11,你可能会发现你的 App 的工具栏的行为出了点异常.比如奇点,我在使用过程中,发现工具栏时灵时不灵,感觉很难点到.这是怎么回事?通过 Xcode 的 Debug View Hie ...

  10. Drop user 报ORA-00600 [KTSSDRP1]

    一客户删除一个数据库用户THH时报错: 说明在获取seg$时没有找到相应的条目,先来解释下这个600错误的参数含义: Arg [a] Tablespace number Arg [b] File nu ...