three.js效果之热力图和轨迹线
1.热力图
开始的时候,是用一个网上找的canvas画渐变热点的demo,原理就是给定顶点坐标,然后画圆,颜色使用渐变色,根据权重决定渐变的层数(红色->橙色->绿色) 。
但是终究觉得这种方法不仅繁琐,而且画出来的效果不够自然。
后来发现有一个开源库heatmap效果很好,它是这样用的(官方demo地址链接):
var heatmapInstance = h337.create({
container: document.querySelector('.heatmap')
});
var data = {
max: max,
data: points
};
heatmapInstance.setData(data);
max值为所有points中权重属性的最大值。
看到这里,那我们要怎么在three.js中去使用heatmap呢,他是用dom去实例化heatmap对象的啊。
不用担心,我们可以creatElement('div'),然后在这个dom对象上实例化heatmap对象,并且
var canvas = heatmapdiv.getElementsByTagName('canvas')[];
获取绘制后的canvas对象。
let heatMapGeo = new THREE.PlaneGeometry(,);
let heatMapTexture = new THREE.Texture(canvas);
let heatMapMaterial = new THREE.MeshBasicMaterial({
map: heatMapTexture,
transparent:true
});
heatMapMaterial.map.needsUpdate = true;
var heatMapPlane = new THREE.Mesh(heatMapGeo,heatMapMaterial);
heatMapPlane.position.set(,0.1,);
heatMapPlane.rotation.x = -Math.PI/;
this.scene.add(heatMapPlane);
这样,用heatmap绘制的热力图就添加到了three.js创建的场景中去了。
2.轨迹线
轨迹线不难想,利用three.js提供的曲线来绘制,但是会存在如下两个问题:
q1.three.js的曲线貌似只能一次性整条绘制出来,没有api显示可以按百分比绘制曲线,所以只好自己写shader实现
q2.webgl渲染器不支持线宽属性(three.MeshLine支持线宽,不过没有研究是否支持按百分比绘制);
q3.着色器里面可以针对点设置pointsize来实现点的大小(间接实现曲线的宽度控制),但是点是二维的,默认存在于x-y平面,所以在x-z平面看的时候,如果点的数量不够多那么就会出现断断续续的效果,但是采样的点数量足够多又会影响性能。
上述的问题不能解决的话,后续的曲线样式优化(渐变)就无从谈起。
期间我想过,既然点存在于x-y平面,那么我们就将x-z平面的轨迹放到x-y平面来绘制,最后将这条线绕x轴旋转90度,但是因为对点进行处理的时候,首先正方形的点->圆点->渐变(抗锯齿),最后,结果如下:
看着好像成功了,但是由于深度检测机制(现在想来,是不是可以设置取消这条线的深度检测机制)的存在,某些角度下,这条线的本质(n个大号的点拼接)就变得很明显了,你会明显地看到这条线是由进行抗锯齿处理后的无数个点组成。
哎,好像又遇到困难了啊。
后来一想,既然three.js中一条线很细,那么10条线,100条线在一起呢?只要间距足够小,它们看上去就是一根线,一根麻绳!!!
PS:
回过头来看我当时的这个处理思路,其实在性能上还是有很大的提升空间的,至少增加了内存消耗;
当然后续查看meshline源码,你会发现他是将顶点作偏移绘制三角面来实现有宽度的“线”,并且每个顶点还传入了顶点的索引值属性,可用于进度的控制;
照着这个思路, 写了一个FatLine类:
import * as THREE from 'three'
/**
* Author:桔子桑
* Time:2019.10.12
*/ const vs =`
varying vec3 iPosition; void main(){
iPosition = vec3(position);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position.x,0.2,position.z,1.0);
}
`;
const fs = `
uniform float time;
varying vec3 iPosition;
uniform float alpha; void main( void ) {
if(iPosition.y > time){
discard;
}else{
gl_FragColor = vec4(0.813,0.124,0.334,alpha);
} }
`; function FatLine(vertices,width,scene){
this.width = width;
this.vertices = vertices;
this.start = ;
this.scene = scene;
this.linearr = [];
this.lines = [];
}
function createMaterial(vs, fs, start) {
var attributes = {};
var uniforms = {
time: {type: 'f', value: start},
size:{type:'f',value:25.0},
};
var meshMaterial = new THREE.ShaderMaterial({
uniforms: uniforms,
defaultAttributeValues : attributes,
vertexShader: vs,
fragmentShader: fs,
transparent: true
});
return meshMaterial;
} FatLine.prototype.draw = function() {
var size = this.vertices.length;
var length = Math.floor(this.width/);
var vm = this;
for(var j =;j<length;j++){
var lineadd = [];
var linereduce = [];
for ( var i = ; i <size; i ++ ) {
var Vector3 = this.vertices[i],
x = Vector3.x,
y = Vector3.y,
z = Vector3.z;
var zadd = z+j*0.001;
var zreduce = z-j*0.001;
lineadd.push( new THREE.Vector3(x,y,zadd ));
linereduce.push( new THREE.Vector3(x,y,zreduce ));
}
this.linearr.push(lineadd);
this.linearr.push(linereduce);
};
this.linearr.push(vm.vertices);
var pointsize = this.vertices.length * ;
for(var k = ,size=this.linearr.length;k<size;k++){
var vertices = this.linearr[k];
var alpha = (Math.floor(size/) - Math.floor(k/))/Math.floor(size/);
var curve = new THREE.CatmullRomCurve3(vertices);
var geometry = new THREE.Geometry();
geometry.vertices = curve.getPoints(pointsize);
var material = createMaterial(vs,fs,vm.start);
material.uniforms.alpha = {type:'f',value:alpha};
var line = new THREE.Line(geometry, material);
this.lines.push(line);
this.scene.add( line );
}
} FatLine.prototype.animate = function(speed,callback){
var time = this.lines[].material.uniforms.time.value;
for(var i = ,length=this.lines.length;i<length;i++){
var line = this.lines[i];
line.material.uniforms.time.value +=speed||0.3;
};
if(callback){
callback(time);
}
} export default FatLine;
你可以看到,着色器中还又一个uniform变量time,这个是用来在FatLine开启动画的时候,随着时间的进展来逐步绘制的。
ok,看到这你以为就完了?no!!!
刚开始的时候,按照常规当time++的时候,在x-z平面上轨迹点,我们判断x<time是否来控制曲线的绘制进度,但是一个问题出现了,人员轨迹点可能出现在一个房间兜圈子的情况(实际也是如此),这样就会存在第2个点和第200个点都满足x<2.0,那么总不能根据时间,第2秒的时候,直接把200秒时候的点也绘制出来了吧,这是不符合常理的。
在下班回家的路上,我想到了一个问题,在三维空间,一个点有(x,y,z)三个维度的坐标信息数据传进了着色器里面,但是我们的人员轨迹只会存在于场景的x-z平面,所以这个y坐标值在着色器里面是没有用到的,哈哈,那么这个y值可以充当时间维度值,第一个点y=1,第二个点y=2,第三个点y=3...,如此一来,当time++的时候,我们只要判断y<time就可以实现在时间维度上的控制了。
并且FatLine的animate函数还提供了一个回调函数,参数值是当前的time值,所以你可以用这个time值来绘制具体的点:
if(this.FatLine){
function addpoint(time){
for(var i = ,length=vm.vertices.length;i<length;i++){
var point = vm.vertices[i];
if(Math.abs(point.y-time)< 0.1){
vm.addpoint(point.x,point.z);
}
}
}
this.FatLine.animate(0.2,addpoint);
}
每一帧都会animate一下,也就是time++,并且判断进度是不是到了指定的某个点上,如果到了,那么就顺便把这个点也画出来,就像上述的动图一样。
最终可控制粗细和运动速度的曲线就完成了。
three.js效果之热力图和轨迹线的更多相关文章
- 类js效果
类似js效果,点击看看 代码 onclick="return confirm('您确定要看看吗?')" 放入a标签里面
- m.jd.com首页中的js效果
m.jd.com中的部分js效果 昨天把m.jd.com的首页布局写好了,今天写一下首页中部分js效果.头部背景色透明度的改变,焦点图轮播,京东快报的小轮播,以及秒杀倒计时.这里html,css样式就 ...
- Tab选项卡切换卡JS效果
<script type="text/javascript"> /* tab切换选项卡js效果 writed by *** 2010.08.13 1.currentid ...
- JS效果的步骤
一.写JS效果的步骤 1.先实现布局 (XHTML+CSS2) 2.实现原理 (1)希望把某个元素移除你的视线: a. display:none; 显示为无,不占据空间 b. vi ...
- Github上html页面(包括CSS样式和JS效果)如何显示出来
在看Github上项目时,发现有的html页面效果能很好的展现出来,而有的则不能.对这个问题很好奇,因此研究了一下,最终做到了将页面展示出来的目的.下面以我的Github的开源项目bootstrap- ...
- WebView 实现JS效果和a标签的点击事件
目前很多android app都可以显示web页面的界面,嵌入式开发,这个界面一般都是WebView这个控件加载出来的,学习该控件可以为你的app开发提升扩展性. 先说下WebView的一些优点: 可 ...
- 常用JS效果 需要时更新。。。
1.手风琴效果 JS: $(function() { var aMenuOneLi = $(".menu-one > li"); var aMenuTwo = ...
- js效果-多选只能选两项,如果超出自动取消第一次选的
这个效果很有意思,个人觉得难点在于点击选中状态的多选的数组操作,以下是代码,感谢落梨 <!DOCTYPE> <html> <head> <title> ...
- 用js效果做的简单焦点图
/*js代码*/ <script src="js/js/myfocus-2.0.1.min.js" type="text/javascript">& ...
随机推荐
- jsp的标签库
Java Server Pages Standard Tag Libray(JSTL):JSP 标准标签库,是一个定制标签类库的集合,用于解决一些常见的问题,例如迭代一个映射或者集合.条件测试.XML ...
- Event Binding in Angular
https://www.pluralsight.com/guides/angular-event-binding Introduction In this guide, we will explore ...
- WINCE7 SYMBOL MC32N0 SDK,VS2008调试程序,连接设备时,出现bootstrap 未能加载时
开发工具:visual studio 2008 手持设备: SYMBOL MC32NO工具->连接到设备->WINCE 7.00连接设备出现bootstrap 未能加载时,试下安装Mot ...
- jmeter结果树乱码的解决方案
- 如何在Google Maps 添加多个标记
JS如下: (function() { window.onload = function() { // Creating an object literal containin ...
- 03 JavaScript的使用
01 注册界面的校验 <!-- 作者:offline 时间:2018-09-05 描述:通常在CSS中使用类选择器,在JS中使用id选择器,两者区分开. 在页面跳转时要先把要跳转的页面用浏览器打 ...
- hdu 4810 Wall Painting (组合数+分类数位统计)
Wall Painting Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- Cogs 728. [网络流24题] 最小路径覆盖问题
[网络流24题] 最小路径覆盖问题 ★★☆ 输入文件:path3.in 输出文件:path3.out 评测插件 时间限制:1 s 内存限制:128 MB 算法实现题8-3 最小路径覆盖问题(习题8-1 ...
- codeforces405D
Toy Sum CodeForces - 405D Little Chris is very keen on his toy blocks. His teacher, however, wants C ...
- Selenium定位class包含空格的元素-复合class节点
在HTML中, 节点有三种常见属性, 分别是id, name和class, 其中class是一个特殊的属性, 支持多个类名, 以空格隔开, 如下图所示: 你是否注意到, 为什么selenium中的fi ...