要: 在WebGIS的浏览器端存在绘图效率差、不能直接支持矢量绘图等问题。为提高客户端的交互性和实时性,在解决浏览器不支持矢量绘图和渲染速度慢、存储空间小、传输速率慢这些问题的基础上,结合HTML5中的Canvas、WebSocket、WebStorage技术,构建了WebGIS实时客户端,有效地改善了客户端存在的问题,改善用户的体验。
0 引言
WebGIS是GIS技术与Internet的结合体,是对网络GIS的发展,它将GIS从一种使用计算机的处理地理信息的系统工具,变为一种网络共享资源,提高了地理信息的使用效率,使地理信息的价值得以充分体现[1]。WebGIS的实现手段主要是基于Web技术的多级B/S体系结构,即浏览器、GIS服务器、数据库等。B/S模式的构架简化了客户端系统的部署,降低了用户使用难度,同时也极大提高了系统的可维护性[2]。但是这种被动的工作模式无法满足用户实时性的需求。对于WebGIS的架构研究,以前主要是对服务器端技术的改进,如使用CGI、Server API等服务端技术,但是这些技术对于服务器及网络的要求较高。随着客户端技术的发展,Java Applet技术、Plug-in技术、Ajax技术的出现扩展了客户端的功能,但是用户需要预先安装这些插件,安装插件带来了一定的安全隐患和不方便性。对比这两种形式,使用HTML5的新技术实现的功能并不需要插件支持,且其本地存储功能和高效率的双向通信功能,还有动态快速绘图功能的提出,使实时客户端的实现成为可能。
1 实时客户端的WebGIS系统结构
HTML5是W3C推出的新标准,其强大功能已经被大部分的浏览器支持,同时,相对于以前的版本,HTML5的改变不仅仅是使用更方便。第一,它新增了更具有语义化的标签和使用更智能化的表单;第二,HTML5还新增了许多JavaScript API,如实时绘图(Canvas和SVG)、离线存储(WebStorage)、实时通信(WebSocket)API等,这些API为实现实时客户端提供了可能。用HTML5来实现WebGIS有地图无限缩放而图不失真,地图的显示渲染效果逼真的优势;且支持JavaScript脚本实现地图的漫游、缩放、查询等功能,这些功能都无需插件支持并可在不同平台与设备上运行[3]。根据这些特性,本文在传统架构的基础上,构建了图1所示的WebGIS实时客户端。
在客户端这些模块中使用HTML5和JavaScript技术,实现数据地图的绘制、本地存储、数据传输等功能,将部分简单的功能交给客户端完成,增加了WebGIS客户端的交互能力,减少了服务器的传输压力,也增加了数据传输的效率,实现了客户端的实时性。
2 WebGIS客户端的具体设计
2.1 数据实时更新与传输设计
空间数据格式有栅格数据和矢量数据。栅格数据交互性能差,可用来展示空间数据,矢量数据交互性较好,可用来表示空间对象,但是客户端不能直接支持矢量数据的二进制格式传输,所以数据在传输中就要进行格式编码,目前使用的比较多的数据传输格式是GeoJSON(基于JSON数据格式的地理要素表示格式)。JSON(JavaScript Object Notation)是轻量级数据交换格式,适合于服务器与浏览器(通过JavaScript)交互[4],在浏览器端JSON能够简单快速地解析成可以被客户端操作的JavaScript地理信息,不需要使用专门的文本解析API进行操作。空间数据传输大多使用Ajax的异步传输方式,但Ajax轮询方式的时延较长,传输的实时性不高,因此将Ajax用于地图数据的推送。实时性方面还是需要HTML5的WebSocket API实现。WebSocket使浏览器具有客户机/服务器(C/S)模式下应用程序的实时通信能力[5]。WebSocket的优势有:(1)为浏览器和服务器之间建立的更高效的双向通信提供支持。其连接本质为TCP连接,因此浏览器通过JavaScript向服务器发出建立WebSocket连接的请求,onopen事件接收消息,连接建立以后,客户端和服务器端就可通过TCP连接直接交换数据。(2)WebSocket有更为轻量级的Header,除了首次建立链接时需要发送头部与普通Web链接类似的数据之外,连接建立后,相互沟通的Header就会很简洁,大大减少了冗余的数据传输[6];通过新建WebSocket实例建立握手并完成与服务器的连接,建立好连接之后数据就可以以全双工模式在客户端与服务器之间进行双向传输,并一直保持连接,直到用户主动关闭[3]。图2是传统传输方式与WebSocket传输方式数据量的对比,从结果可以看出,当传输数据量增大时,WebSocket的效率更高。
需要在服务器端安装开源的WebSocket支持数据库,如Node.js、LibWebSockets、PHP WebSocket Server等,以调用接口使用。具体传输过程是:GIS服务器从空间数据库获取数据,将空间数据解析成JSON的格式,然后发送到已经与WebSocket服务器连接的客户端,客户端WebSocket实例的onmessage事件接收数据并使用JSON.parse函数将JSON字符串解析成JavaScript对象,再根据对象的内容在WebGIS的地图中解析显示。WebSocket API一个显著特点是,连接建立后,服务器可主动推送消息。支持WebSocket协议的服务端接受请求和处理WebSocket任务,在客户端可用WebStorage存储模块缓存传输过来的数据,WebSocket的中间传输机制就实现了数据实时更新。
2.2 客户端空间数据缓存设计
客户端缓存功能主要是由WebStorage API来实现,WebStorage API是以Key-Value形式来进行数据的持久性存储。传统客户端一般是使用Cookie存储数据,但是它效率低,存储空间小,不能满足大量矢量数据的存储。WebStorage提供的两种存储方式可以改善这个状况,一种是SessionStorage,它是一种会话级别的存储方式,存储的数据只在当前页面有效,当页面关闭时,数据也会随之删除,据此SessionStorage可以用在矢量图绘制的缓存方面,即让SessionStorage自动缓存解析好的JSON格式的矢量层数据,当需要数据时直接从SessionStorage中提取JSON数据,这比从空间数据库中获取再解析效率明显更高,数据显示模块可以直接从中获取数据进行绘制。另一种方式是LocalStorage,它是一个跨多窗口且数据永久存储的方式,只有使用清除函数clear、removeItem或手动删除数据时数据才会从浏览器中清除,同时它的数据可以在同源的窗口或标签共享使用。因此它可以用来永久存储空间分析后的数据或服务器发送的数据和用户数据,下次用户打开浏览器可直接使用这些数据。图3是具体矢量数据本地存储过程。将数据缓存到本地,不用与服务器发生交互,客户端存储的数据可以由JavaScript访问。
WebStorage存储技术和WebSocket技术可结合使用并与JavaScript一起实现数据的实时更新,减轻服务器压力。用户发送数据请求后,WebSocket建立连接,将得到的数据解析后存储在WebStorage预先定义好的空间中,等待用户提取。对于常须更新地图数据的操作采用这种预先存储的方式,可以加快数据的渲染效率。为了提高图3的实时更新效果,可以设定异步存储机制,过程如下:(1)创建并初始化WebStorage对象,设置缓存区大小(缓存区分段);(2)用户发出消息,触发onopen事件;(3)为WebSocket对象的信息添加侦听器;(4)服务器调用received函数处理事件;(5)客户端接收服务器发送的消息,触发缓存判断函数,判断缓存大小,如果超出,设置缓存片段的编号,对象异步sends数据请求服务器处理;(6)服务器将片段编号入队(服务端设置),直到传输完成,清除编号。这种传输方式将进一步减少网络流量,减少服务器的负载,提升传输效率。
2.3 数据显示设计
HTML5现提供了Canvas API,它可以解决传统开发浏览器支持度差、跨平台性不强和绘制矢量图形需要插件的问题,通过JavaScript在浏览器不依赖任何插件的情况下高效地绘制动态图形[7],避免了安装插件带来安全风险。
2.3.1 绘制方法
Canvas API使用比较简单,像其他HTML标签一样,只需在HTML5的页面中添加一个<canvas>元素即可。Canvas绘图首先要获得上下文(context),因为Canvas自己本身并没有绘图能力,所以所有的绘图工作要由JavaScript完成。它的工作过程为:先定义Canvas元素的id,然后通过getElementById函数找到自己前面创建好的Canvas元素,最后用JavaScript调用绘图API接口得到上下文绘图环境后就可在画布上绘制任何的图形了。但Canvas只支持一种基本图形——矩形,想使用Canvas绘制其他的图形,就要使用其提供的路径(Path)绘制函数[8],使用beginPath开始绘制,使用moveTo、lineTo绘制直线,绘制完毕后调用fill、stroke进行填充或者设置边框,最后调用closePath结束图形绘制。Canvas在矢量数据方面是像素级管理,Canvas的路径操作能充分满足矢量数据中的点要素、线要素、面要素以及符号的表达要求。
2.3.2 数据显示过程
用Canvas与JavaScript技术实现地图实时绘制。地理实体对象可以根据OGC的简单要素规范和GIS界的研究将其分为:点状实体、线状实体、面状实体、标注实体和栅格实体[3]。Canvas可直接使用这些实体,对于栅格实体,可以用JavaScript对象表示,通过API drawImage直接在HTML5 Canvas中绘制。矢量实体的地理要素从GeoJSON文本转化为JavaScript对象,根据该对象的信息,调用坐标转换对象,将坐标转换成Canvas元素里的屏幕坐标来对应显示要素。实现实时绘图的流程为:(1)服务器从数据库获取数据;(2)数据进行JSON格式解析;(3)浏览器加载地图,调用Canvas画布及函数实现绘图和地图的显示;(4)地图操作由自定义脚本实现地图渲染。Canvas在客户端展现地理数据的灵活性与互操作性要优于传统的切片技术,并且在地图加载速度方面有明显的优势[8],因此将Canvas和WebStorage结合起来,可以提高实时性能,将要显示或者要存储的数据先经过缓存,再进行显示或存储,这种机制效率明显更高。图4说明了从数据推送到显示的流程。
3 客户端整体过程
Canvas实现实时绘图和快速渲染,WebSocket API在通信方面提供了支持。WebStorage提供了客户端的本地存储技术,以地图放大操作为例,用户提交请求,数据获取函数可以从SessionStorage中获取数据,然后将缓存的数据转换成JavaScript对象,最后通过Canvas直接添加在地图中,同时,缓存中的数据不断更新。WebSocket的双向通信机制和WebStorage的异步存储机制加速了数据交换效率,空间数据库也通过WebGIS服务器,在实时通信的基础上,将数据以JSON文本格式传输到客户端,存入SessionStorage中,窗口关闭后,所有数据存入LocalStorage,供用户下次直接使用。这种方式的效率很明显会比从服务器获取数据的方式高,实时性要好,如需要执行其他的交互操作,也可以基于这种方式实现。
4 结论
随着Web技术的发展,客户端的交互性和实时性要求不断提升,据此,本文将HTML5的新特性与JavaScript技术结合,在WebSocket双向通信机制和WebStorage缓存机制实现异步存储提供的数据支撑,Canvas能实现动态绘图和快速渲染的基础上,提出了一种实时性更强的WebGIS客户端,为建立实时的WebGIS客户端提供了一种方案。HTML5中的新技术虽然强大,还是有需要加强的地方,WebStorage让数据能够缓存在本地,但是由于是存储在本地,数据容易泄漏,安全性还有欠缺。未来WebGIS的发展会随着数据量的增大实现云平台化,资源更庞大,数据更易共享,用户使用起来也会更方便。
参考文献
[1] 孟令奎,史文中,张鹏林,等.网络地理信息系统原理与技术[M].北京:科学出版社,2010.
[2] 李博霏,李欣,李艳明.基于浏览器的地理信息服务客户端技术研究[J].计算机工程与设计,2011(9):3031-3035.
[3] 龙云.基于HTML5的WebGIS研究[D].赣州:江西理工大学,2013.
[4] CROCKFORD D. The application/json media type for JavaScript Object Notation(JSON)[EB/OL]. [2006-07]. http://tools.ietf.org/html/rfc4627.
[5] 徐卓揆.基于HTML5、Ajax和Web Service的WebGIS研究[J].测绘科学,2012,37(1):145-147.
[6] 魏进锋,孙春华.应用HTML5的WebSocket实现BiDirection数据交换[EB/OL].[2012-12-28](2015-02-25).http://www.ibm.com/developerworks/cn/web/1112_weijf_websocket/.
[7] 王晓.基于HTML5的矢量地图发布关键技术研究[D].南京:南京师范大学,2011.
[8] 梁春雨,李新通.使用HTML5 Canvas构建基于GeoJSON的轻量级WebGIS[J].计算机科学与应用,2012(2):189-196.
数据可视化中,使用频率最高的展现方式肯定是地图可视化。基本上现有的大屏都是以地图作为主视图来呈现的,没有一幅地图放到大屏中央,已经不好意思给同行、媒体界通告自己企业数据分析有多牛了。
怎么将地理数据处理得更好,怎么把地图设计出更好的视觉效果也一直是我们研究的方向。亿信ABI作为亿信华辰自主研发的一款全能型数据分析产品,具备强大的数据地图功能,内置世界地图、五大洲地图、中国地图,囊括各省、市区县地图,每个地图都有flash、图片和html5三种格式,还能实现钻取、联动等功能。
下面带大家一起来看一下亿信ABI中地图可视化的那些事儿。
渲染地图适合展示数据在地理区块空间的分布状况,用颜色来区分数值大小。随意切换全国任意省市地图方便快捷,还可以通过事件联动其他组件和下钻。
标点地图主要用于展示地理区域内的空间分布,非常适合展示一组或多组数据在地理空间的分布状况,数据的地理属性确定点位置,数据大小则通过点的颜色来体现,通常会配以色带来映射颜色的取值范围和大小关系。
一般是用于数据中具有两个维度的地理信息,用于展示数据的流入&流出情况。其经常使用的场景包括:世界范围或者全国范围内的人口迁移,不同地区飞机/船舶/高铁等交通航线的繁忙程度和流向情况,不同地区包裹的寄出量或收货量等。
亿信ABI中的Flash地图只需要电脑安装有Flash插件即可使用,非常方便。通过简单的组件拖拽以及属性设置,就可以动态地在地图上显示属性信息,可以自定义Flash地图的区块颜色、注记、链接、音效等。不仅如此Flash地图是基于矢量结构储存,可以做到无极缩放、无缝连接的同时,图像质量并无损失,展示效果非凡。
亿信ABI中内置有集成百度地图、天地图、arcgis地图三大主流地图的应用接口,可以一键与多种分析手段相结合,将ABI中强大的报表分析引擎与GIS应用强强联合,实现动态参数、颜色渲染、地图标点分布、地图钻取、预警分析等会多重效果。
在需要按照地区分析数据时,更直观的展示数据我们可以使用3D地图,数值大小映射到柱形图的颜色和大小上,能够一目了然看出各个地区数据的分布,展示出来更加直观,增加地图的立体感,还可以360度旋转噢~如下图所示:
有了亿信ABI内置的地图组件,你只需要拖拉拽,不需要写代码,简单、快捷的实现地图可视化。
荐:使用NSDT 编辑器快速搭建3D应用场景
大多数 3D 对象是 使用建模工具创建,这是有充分理由的。创建复杂对象 (如飞机甚至建筑物)很难在代码中完成。建模工具 几乎总是有意义的,但也有例外!其中之一可能是案例 就像飞行拱廊岛连绵起伏的丘陵一样。我们最终使用了 我们发现更简单,甚至可能更直观的技术:一个 高度图。
高度图是一种 使用常规二维图像来描述 像岛屿或其他地形一样的表面。这是一种非常常见的使用方式 高程数据,不仅在游戏中,而且在地理信息系统中 制图师和地质学家使用的 (GIS)。
帮助您获得想法 有关其工作原理,请查看此交互式演示中的高度图。尝试绘图 ,然后检出生成的地形。
高度图背后的概念 很简单。在上图所示的图像中,纯黑色是 “地板”和纯白色是最高峰。介于两者之间的灰度颜色 表示相应的高程。这为我们提供了 256 个海拔高度,这 是我们游戏的大量细节。实际应用程序可能会使用完整的 色谱可存储更多层次的细节(2564=4,294,967,296 级 详细信息(如果包含 Alpha 通道)。
高度图有几个 与传统多边形网格相比的优势:
一、高度图很多 更紧凑。仅存储最重要的数据(高程)。它 需要以编程方式转换为 3D 对象,但这是 经典交易:您现在节省空间,稍后通过计算付款。通过存储 数据即图像,您将获得另一个空间优势:您可以利用标准 图像压缩技术并使数据变小(相比之下)!
其次,高度图是一个 生成、可视化和编辑地形的便捷方式。非常直观 当你看到一个。感觉有点像看地图。这被证明是 对飞行街机特别有用。我们设计和编辑了我们的岛屿 在 Photoshop 中!这使得根据需要进行小调整变得非常简单。 例如,当我们想确保跑道完全平坦时, 我们只是确保以单一颜色在该区域上绘画。
您可以看到高度图 下面的飞行拱廊。看看你是否能发现我们为 跑道和村庄。
飞行街机岛的高度图。它是在Photoshop中创建的,它基于着名的太平洋岛链中的“大岛”。有什么猜测吗?
在解码高度贴图后映射到生成的 3D 网格上的纹理。更多内容见下文。
我们用Babylon.js建造了飞行拱廊,Babylon给了我们一个漂亮的 从高度图到 3D 的简单路径。Babylon提供了一个 API 来生成 来自高度图图像的网格几何体:
ar ground=BABYLON.Mesh.CreateGroundFromHeightMap(
'your-mesh-name',
'/path/to/heightmap.png',
100, // width of the ground mesh (x axis)
100, // depth of the ground mesh (z axis)
40, // number of subdivisions
0, // min height
50, // max height
scene,
false, // updateable?
null // callback when mesh is ready
);`
细节量是 由该细分的财产决定。需要注意的是, 参数是指高度图两侧的细分数量 图像,而不是单元格总数。所以稍微增加这个数字可以 对网格中的顶点总数有很大影响。
在下一节中,我们将 了解如何为地面设置纹理,但在尝试使用高度贴图时 创建时,查看线框很有用。这是应用简单代码 线框纹理,因此很容易看到高度图数据是如何转换为的 网格的顶点:
// simple wireframe material
var material=new BABYLON.StandardMaterial('ground-material', scene);
material.wireframe=true;
ground.material=material;`
一旦我们有一个模型,映射一个 质地相对简单。对于飞行街机,我们简单地创建了一个 非常大的图像,与我们的高度图中的岛屿相匹配。图像得到 延伸到地形的轮廓上,所以纹理和高度图 保持相关性。这真的很容易想象,再一次,所有 制作工作是在Photoshop中完成的。
原始纹理图像是 创建于 4096x4096。那可是挺大的!(我们最终将尺寸减小了 为了保持下载合理,级别到2048x2048,但所有 使用全尺寸图像进行开发。这是来自 原始纹理。
原始岛屿纹理的全像素示例。整个城镇只有大约300平方像素。
这些矩形表示 岛上城镇的建筑。我们很快注意到 我们可以在地形和 其他 3D 模型。即使使用我们巨大的岛屿纹理,区别在于 令人分心的明显!
为了解决这个问题,我们“混合” 以随机噪声的形式进入地形纹理的附加细节。您可以 请参阅下面的之前和之后。注意额外的噪点如何增强外观 地形细节。
我们创建了一个自定义着色器 添加噪音。着色器为您提供了对 WebGL 3D 场景的渲染,这是着色器如何 有用。
WebGL着色器由两个组成 主要部分:顶点和片段着色器。顶点的主要目标 着色器是将顶点映射到渲染帧中的某个位置。片段(或 像素)着色器控制像素的结果颜色。
着色器是用 称为GLSL(图形库着色器语言)的高级语言,它 类似于C。此代码在 GPU 上执行。深入了解如何 着色器工作,请参阅此处 有关如何为 Babylon.js 创建自己的自定义着色器的教程,或参阅此图形着色器编码初学者指南。
我们不会改变我们的 纹理映射到地面网格体,因此我们的顶点着色器非常简单。 它只是计算标准映射并分配目标位置。
precision mediump float;
// Attributes
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
// Uniforms
uniform mat4 worldViewProjection;
// Varying
varying vec4 vPosition;
varying vec3 vNormal;
varying vec2 vUV;
void main() {
vec4 p=vec4( position, 1.0 );
vPosition=p;
vNormal=normal;
vUV=uv;
gl_Position=worldViewProjection * p;
}
我们的片段着色器有点 更复杂。它结合了两个不同的图像:基础图像和混合图像。 基础图像映射到整个地面网格。在飞行街机中,这个 是岛屿的彩色图像。混合图像是使用的小噪点图像 在近距离为地面提供一些纹理和细节。着色器 组合每个图像中的值以创建跨 岛。
飞行的最后一课 街机发生在有雾的日子,所以我们的像素着色器的另一个任务是 调整颜色以模拟雾。调整基于顶点的距离 来自相机,远处像素被“遮挡”得更厉害 在雾中。您将在函数中看到此距离计算 在主着色器代码上方。calcFogFactor
// #ifdef GL_ES
precision highp float;
// #endif
uniform mat4 worldView;
varying vec4 vPosition;
varying vec3 vNormal;
varying vec2 vUV;
// Refs
uniform sampler2D baseSampler;
uniform sampler2D blendSampler;
uniform float blendScaleU;
uniform float blendScaleV;
// #define FOGMODE_NONE 0.
// #define FOGMODE_EXP 1.
// #define FOGMODE_EXP2 2.
// #define FOGMODE_LINEAR 3.
// #define E 2.71828
uniform vec4 vFogInfos;
uniform vec3 vFogColor;
float calcFogFactor() {
// gets distance from camera to vertex
float fogDistance=gl_FragCoord.z / gl_FragCoord.w;
float fogCoeff=1.0;
float fogStart=vFogInfos.y;
float fogEnd=vFogInfos.z;
float fogDensity=vFogInfos.w;
if (FOGMODE_LINEAR==vFogInfos.x) {
fogCoeff=(fogEnd - fogDistance) / (fogEnd - fogStart);
}
else if (FOGMODE_EXP==vFogInfos.x) {
fogCoeff=1.0 / pow(E, fogDistance * fogDensity);
}
else if (FOGMODE_EXP2==vFogInfos.x) {
fogCoeff=1.0 / pow(E, fogDistance * fogDistance * fogDensity * fogDensity);
}
return clamp(fogCoeff, 0.0, 1.0);
}
void main(void) {
vec4 baseColor=texture2D(baseSampler, vUV);
vec2 blendUV=vec2(vUV.x * blendScaleU, vUV.y * blendScaleV);
vec4 blendColor=texture2D(blendSampler, blendUV);
// multiply type blending mode
vec4 color=baseColor * blendColor;
// factor in fog color
float fog=calcFogFactor();
color.rgb=fog * color.rgb + (1.0 - fog) * vFogColor;
gl_FragColor=color;
}
我们定制的最后一件作品 Blend shader 是 Babylon 使用的 JavaScript 代码。主要目的 此代码用于准备传递给顶点和像素着色器的参数。
function BlendMaterial(name, scene, options) {
this.name=name;
this.id=name;
this.options=options;
this.blendScaleU=options.blendScaleU || 1;
this.blendScaleV=options.blendScaleV || 1;
this._scene=scene;
scene.materials.push(this);
var assets=options.assetManager;
var textureTask=assets.addTextureTask('blend-material-base-task', options.baseImage);
textureTask.onSuccess=_.bind(function(task) {
this.baseTexture=task.texture;
this.baseTexture.uScale=1;
this.baseTexture.vScale=1;
if (options.baseHasAlpha) {
this.baseTexture.hasAlpha=true;
}
}, this);
textureTask=assets.addTextureTask('blend-material-blend-task', options.blendImage);
textureTask.onSuccess=_.bind(function(task) {
this.blendTexture=task.texture;
this.blendTexture.wrapU=BABYLON.Texture.MIRROR_ADDRESSMODE;
this.blendTexture.wrapV=BABYLON.Texture.MIRROR_ADDRESSMODE;
}, this);
}
BlendMaterial.prototype=Object.create(BABYLON.Material.prototype);
BlendMaterial.prototype.needAlphaBlending=function () {
return (this.options.baseHasAlpha===true);
};
BlendMaterial.prototype.needAlphaTesting=function () {
return false;
};
BlendMaterial.prototype.isReady=function (mesh) {
var engine=this._scene.getEngine();
// make sure textures are ready
if (!this.baseTexture || !this.blendTexture) {
return false;
}
if (!this._effect) {
this._effect=engine.createEffect(
// shader name
"blend",
// attributes describing topology of vertices
[ "position", "normal", "uv" ],
// uniforms (external variables) defined by the shaders
[ "worldViewProjection", "world", "blendScaleU", "blendScaleV", "vFogInfos", "vFogColor" ],
// samplers (objects used to read textures)
[ "baseSampler", "blendSampler" ],
// optional define string
"");
}
if (!this._effect.isReady()) {
return false;
}
return true;
};
BlendMaterial.prototype.bind=function (world, mesh) {
var scene=this._scene;
this._effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
this._effect.setColor3("vFogColor", scene.fogColor);
this._effect.setMatrix("world", world);
this._effect.setMatrix("worldViewProjection", world.multiply(scene.getTransformMatrix()));
// Textures
this._effect.setTexture("baseSampler", this.baseTexture);
this._effect.setTexture("blendSampler", this.blendTexture);
this._effect.setFloat("blendScaleU", this.blendScaleU);
this._effect.setFloat("blendScaleV", this.blendScaleV);
};
BlendMaterial.prototype.dispose=function () {
if (this.baseTexture) {
this.baseTexture.dispose();
}
if (this.blendTexture) {
this.blendTexture.dispose();
}
this.baseDispose();
};
Babylon.js使它变得容易 创建基于着色器的自定义材质。我们的混合材料相对简单, 但它确实对岛屿的外观产生了很大的影响,当 飞机低空飞到地面。着色器将 GPU 的强大功能带到 浏览器,扩展可应用于 3D 的创意效果类型 场景。在我们的案例中,这是画龙点名!
原文链接:使用 WebGL 为 HTML5 游戏创建逼真的地形
*请认真填写需求信息,我们会在24小时内与您取得联系。