WebGL 绘制Line的bug(三)
之前铺垫了许多,今天可以来分享点纯干货了。
上一篇已经讲述了通过面模拟线条时候,每一个顶点的顶点数据包括:端点坐标、偏移量、前一个端点坐标、后一个端点坐标,当然如果我们通过索引的方式来绘制的话,还包括索引数组,下面的代码通过传递一组线条的端点数组来创建上述相关数据:
bk.Line3D = function (points,colors){
this.points = points;
this.colors = colors;
} bk.Line3D.prototype.computeData = function() {
var len = this.points.length;
var count = len * 3 * 2;
var position = new Float32Array(count);
var positionPrev = new Float32Array(count);
var positionNext = new Float32Array(count);
var color = new Float32Array(count); var offset = new Float32Array(len * 2);
var indicesCount = 3 * 2 * (len - 1);
var indices = new Uint16Array(indicesCount);
var triangleOffset = 0,vertexOffset = 0;
for(var i = 0; i < len; i ++){
var i3 = i * 3 * 2;
var point = this.points[i];
position[i3 + 0] = point.x;
position[i3 + 1] = point.y;
position[i3 + 2] = point.z;
position[i3 + 3] = point.x;
position[i3 + 4] = point.y;
position[i3 + 5] = point.z; var r = (i + 1) / len;
var g = Math.random();
var b = Math.random();
g = r;
b = 0;
r = 1- r;
color[i3 + 0] = r;
color[i3 + 1] = g;
color[i3 + 2] = b;
color[i3 + 3] = r;
color[i3 + 4] = g;
color[i3 + 5] = b; if (i < count - 1) {
var i3p = i3 + 6;
positionNext[i3p + 0] = point.x;
positionNext[i3p + 1] = point.y;
positionNext[i3p + 2] = point.z; positionNext[i3p + 3] = point.x;
positionNext[i3p + 4] = point.y;
positionNext[i3p + 5] = point.z;
}
if (i > 0) {
var i3n = i3 - 6;
positionPrev[i3n + 0] = point.x;
positionPrev[i3n + 1] = point.y;
positionPrev[i3n + 2] = point.z; positionPrev[i3n + 3] = point.x;
positionPrev[i3n + 4] = point.y;
positionPrev[i3n + 5] = point.z;
} var idx = 3 * i; var i2 = i * 2;
offset[i2 + 0] = 5;
offset[i2 + 1] = -5;
}
var end = count - 1;
for(i = 0;i < 6 ;i ++){
positionNext[i] = positionNext[i + 6];
positionPrev[end - i] = positionPrev[end - i - 6];
}
for(i = 0;i < indicesCount ;i ++){
if(i % 2 == 0){
indices[triangleOffset ++] = i;
indices[triangleOffset ++] = i + 1;
indices[triangleOffset ++] = i + 2;
}else{
indices[triangleOffset ++] = i + 1;
indices[triangleOffset ++] = i;
indices[triangleOffset ++] = i + 2;
}
} this.position = position;
this.positionNext = positionNext;
this.positionPrev = positionPrev;
this.color = color;
this.offset = offset;
this.indices = indices;
};
代码首先定义了一个类,该类构造函数可以传入端点数组;在该类上定义了一个方法 computeData,用来计算顶点数组,每个顶点包括上文所述的4个信息,另外增加了一个颜色信息。
读者,可以结合第二篇的思路和上面的代码来来理解,此处不再详述 代码的细节。
另外一个比较重要的代码是顶点着色器中,通过传入的这些顶点信息来计算最终的顶点坐标,代码如下:
var lineVS = `
attribute vec3 aPosition;
attribute vec3 aPositionPre;
attribute vec3 aPositionNext;
attribute float aOffset;
attribute vec3 aColor;
varying vec3 vColor; uniform mat4 uWorldViewProjection;
uniform vec4 uViewport;
uniform float uNear; uniform mat4 uViewMatrix;
uniform mat4 uProjectMatrix; vec4 clipNear(vec4 p1,vec4 p2){
float n = (p1.w - uNear) / (p1.w - p2.w);
return vec4(mix(p1.xy,p2.xy,n),-uNear,uNear);
} void main(){ vec4 prevProj = uWorldViewProjection * vec4(aPositionPre, 1.0);
vec4 currProj = uWorldViewProjection * vec4(aPosition, 1.0);
vec4 nextProj = uWorldViewProjection * vec4(aPositionNext, 1.0);
if (currProj.w < 0.0) {
if (prevProj.w < 0.0) {
currProj = clipNear(currProj, nextProj);
}else {
currProj = clipNear(currProj, prevProj);
}
}
vec2 prevScreen = (prevProj.xy / abs(prevProj.w) + 1.0) * 0.5 * uViewport.zw;
vec2 currScreen = (currProj.xy / abs(currProj.w) + 1.0) * 0.5 * uViewport.zw;
vec2 nextScreen = (nextProj.xy / abs(nextProj.w) + 1.0) * 0.5 * uViewport.zw;
vec2 dir;
float len = aOffset;
if(aPosition == aPositionPre){
dir = normalize(nextScreen - currScreen);
}else if(aPosition == aPositionNext){
dir = normalize(currScreen - prevScreen);
}else {
vec2 dirA = normalize(currScreen - prevScreen);
vec2 dirB = normalize(nextScreen - currScreen);
vec2 tanget = normalize(dirA + dirB);
float miter = 1.0 / max(dot(tanget,dirA),0.5);
len *= miter;
dir = tanget;
}
dir = vec2(-dir.y,dir.x) * len;
currScreen += dir;
currProj.xy = (currScreen / uViewport.zw - 0.5) * 2.0 * abs(currProj.w);
vec4 pos = uProjectMatrix * uViewMatrix * vec4(aPosition,1.0);
vColor = aColor;
gl_Position = currProj;
}
`;
计算的原理,也可以参考第二篇的论述,此处需要注意的是,为了能够计算顶点在屏幕上的最终位置,需要把canvans的尺寸大小传递给着色器(uniform 变量 uViewport),同样为了计算裁剪,需要把镜头的near值传递给着色器(uniform 变量 uNear),而变量uWorldViewProjection表示模型视图透视变换的矩阵,熟悉WebGL的同学一定清楚。
如果你对WebGL 感兴趣,可以了解下我们用WebGL开发的3D机房项目:
无插件纯Web 3D机房,HTML5+WebGL倾力打造
关于这个话题就先分享到这里了,如果大家对其它方面与兴趣的,我们也可以一起来探讨。
WebGL 绘制Line的bug(三)的更多相关文章
- WebGL 绘制Line的bug(二)
上一篇文章简单介绍了WebGL绘制Line的bug,不少朋友给我发了私信,看来这个问题大家都遇上过哈.今天这篇文章会讲述解决这个问题的work around. 基本思路 上一篇文章结尾简单提了下解决的 ...
- WebGL 绘制Line的bug(一)
今天说点跟WebGL相关的事儿,不知道大家有没有碰到过类似的烦恼. 熟悉WebGL的同学都知道,WebGL绘制模式有点.线.面三种:通过点的绘制可以实现粒子系统等,通过线可以绘制一些连线关系:面就强大 ...
- WebGL绘制有端头的线
关于WebGL绘制线原理不明白的小伙伴,可以看看我之前的文章WebGL绘制有宽度的线.这一篇我们主要来介绍端头的绘制,先看效果图. 端头一般被称为lineCap,主要有以下三种形式: butt最简单等 ...
- WebGL绘制有宽度的线
WebGL中有宽度的线一直都是初学者的一道门槛,因为在windows系统中底层的渲染接口都是D3D提供的,所以无论你的lineWidth设置为多少,最终绘制出来的只有一像素.即使在移动端可以设置有宽度 ...
- 一篇文章理清WebGL绘制流程
转自:https://www.jianshu.com/p/e3d8a244f3d9 目录 初始化WebGL环境 顶点着色器(Vertex Shader)与片元着色器(Fragment Shader) ...
- 利用javascript和WebGL绘制地球 【翻译】
利用javascript和WebGL绘制地球 [翻译] 原翻译:利用javascript和WebGL绘制地球 [翻译] 在我们所有已知的HTML5API中,WebGL可能是最有意思的一个,利用这个AP ...
- WebGL入门教程(二)-webgl绘制三角形
前面已经介绍过了webgl,WebGL入门教程(一)-初识webgl(http://www.cnblogs.com/bsman/p/6128447.html),也知道了如何绘制一个点,接下来就用web ...
- ArcGIS JS 3.x使用webgl绘制热力图
ArcGIS Js Api 3.x 热力图在数据量达到三万左右的时候,绘制速度不尽人意,数据量再大些,缩放时候就会很卡,非常影响客户体验. 参考了一下网上webgl热力图,能达到更流畅 ...
- FireFox下Canvas使用图像合成绘制SVG的Bug
本文适合适合对canvas绘制.图形学.前端可视化感兴趣的读者阅读. 楔子 所有的事情都会有一个起因.最近产品上需要做一个这样的功能:给一些图形进行染色处理.想想这还不是顺手拈来的事情,早就研究过图形 ...
随机推荐
- shell初级-----数据呈现方式
输入与输出 Linux系统将每个对象当作文件处理,这包括输入和输出进程.Linux用文件描述符来标识每个文件对象.文件描述符是一个非负整数,可以唯一标识会话中打开的文件.每个进程一次多可以有九个文件描 ...
- e_pro list 1
uncle n. 叔叔; 伯父; 舅父; 姑父,姨父; farm n. 农家; 农田; 农场,农庄; 畜牧场; corner n. 拐角; 角落,角; 困境; [商] 囤积; vi. 驾车转 ...
- hdoj5024【BFS/暴力】
题意: 在可以行走的区域内,只能转一次90度的弯,问你最长这条路可以多长. 思路: 我们可以看到 /* 123 8 4 765 */ 转90度的路径会是横竖,也就是1-3-5-7; 还有斜的:2-4- ...
- POJ1861 kruskal.
#include <iostream> #include <stdio.h> #include <string.h> #include <stack> ...
- StructLayoutLayout 属性无法通过GetCustomAttributes 或者 Attributes获得
http://stackoverflow.com/questions/17684664/retrieve-the-structlayout-attribute-of-a-struct 这是一个type ...
- 2019年BAT面试通关宝典:数据结构+JVM+并发编程+分布式...
前言 金三银四俗称跳槽黄金季,很多同学都想趁着这段时间拿高薪,去更牛逼的公司工作,认识更多大牛,提升自己的职场竞争力. 那怎样才能通过BAT面试官的考核?怎样成为一名Offer收割机? 收割Offer ...
- svn项目添加到tomcat后,tomcat无法打开问题解决
1,tomcat版本更改 由7.0.81更改至8.0.47(8.5.23在添加至eclipse后版本不符无法使用) 更改版本后记得修改Server Locations-->双击服务器--> ...
- PKI体系下的 SSL TLS HTTPS 详解
背景: SSL(Secure Socket Layer 安全套接层)是一个加密函数库,它可以将应用层上所有明文传输的数据,通过调用SSL库,即可摇身一变成为安全通信连接,SSL最初是由网景公司(Net ...
- redis启停
1 查看服务器上启动的redis服务 开了两个redis单机服务,监听在两个端口. 开了一个集群,监听在6个端口. [root@localhost bin]# ps aux | grep redis ...
- Hdu 5451 Best Solver (2015 ACM/ICPC Asia Regional Shenyang Online) 暴力找循环节 + 递推
题目链接: Hdu 5451 Best Solver 题目描述: 对于,给出x和mod,求y向下取整后取余mod的值为多少? 解题思路: x的取值为[1, 232],看到这个指数,我的心情是异常崩 ...