我在地图上绘制webgl点,目前工作正常。现在我想在地图上再加一层。我正试图找出最好的方法来实现这个目标。因为我的代码是这样写的,我给gl绘制函数发送了一个长数组,格式如下。
[lat, lng, r, g, b, a, id, lat, lng, r, g, b, a, id, etc...] //where id is used for selecting the marker.
这些点是用以下格式绘制的
this.delegate.gl.drawArrays(this.delegate.gl.POINTS, 0, numPoints);
当添加额外的图层时,我希望一个图层显示为圆形,另一个图层显示为方形。我的想法是在数组中添加另一个元素,该元素的代码是绘制圆形还是方形,即0或1,所以现在数组的步长是8。
[lat, lng, r, g, b, a, id, code, lat, lng, r, g, b, a, id, code etc...]
着色器代码就会决定是画圆还是画方块。这可能吗?我不知道如何将形状代码属性传递给着色器来决定绘制哪种形状.下面是着色器代码,目前有两个片段着色器程序。一个画圆,一个画方块。
<script id="vshader" type="x-shader/x-vertex">
uniform mat4 u_matrix;
attribute vec4 a_vertex;
attribute float a_pointSize;
attribute vec4 a_color;
varying vec4 v_color;
void main() {
gl_PointSize = a_pointSize;
gl_Position = u_matrix * a_vertex;
v_color = a_color;
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 v_color;
void main() {
float border = 0.05;
float radius = 0.5;
vec2 m = gl_PointCoord.xy - vec2(0.5, 0.5);
float dist = radius - sqrt(m.x * m.x + m.y * m.y);
float t = 0.0;
if (dist > border)
t = 1.0;
else if (dist > 0.0)
t = dist / border;
gl_FragColor = mix(vec4(0), v_color, t);
}
</script>
<script id="fshader-square" type="x-shader/x-fragment">
precision mediump float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
</script>
我的属性指针是这样设置的。
this.gl.vertexAttribPointer(vertLoc, 2, this.gl.FLOAT, false, fsize*7, 0);
我的属性指针是这样设置的: /vertex
this.gl.vertexAttribPointer(colorLoc, 4, this.gl.FLOAT, true, fsize*7, fsize*2);
/肤色
绘制不同形状的点最常用的方法是使用纹理,这样你的设计师可以使 记号笔 等。
不画也是常见的 POINTS
但却要画出四边形,由 TRIANGLES
. 谷歌地图和Mapbox都没有使用 POINTS
(你可以 验证自己)
POINTS
有两个问题
规范说,你可以画一个POINT的最大尺寸是取决于实现的,可以只是1像素。
当点的中心点离开屏幕时,点是否会立即消失取决于实现(这不是规范的一部分,但不幸的是这是事实
POINTS只能是对齐的正方形。
如果你想画的形状又高又细,你需要浪费一堆纹理空间,并且或过多地画一个足够大的正方形来容纳你想画的高细矩形。同样如果你想旋转图像,用三角形比用点来做要容易得多。
至于实现方式那就全靠你了。一些随机的想法
使用 POINTS
,增加一个 imageId
每点。使用 imageId
和 gl_PointCoord
从纹理图谱中选择图像
假设所有的图像都是相同大小
uniform vec2 textureAtlasSize; // eg 64x32
uniform vec2 imageSize; // eg 16x16
float imagesAcross = floor(textureAtlasSize.x / imageSize.x);
vec2 imageCoord = vec2(mod(imageId, imagesAcross), floor(imageId / imagesAcross));
vec2 uv = (imageCoord + imageSize * gl_PointCoord) / textureAtlasSize;
gl_FragColor = texture2D(textureAtlas, uv);
注意,如果你将imageIds设为vec2而不是float,并将id作为imageCoord传入,那么你就不需要在shader中使用imageCoord数学。
在着色器中使用 POINTS
纹理图谱,以及每个点的vec2偏移量,vec2范围。
现在,图像的大小不需要相同,但你需要为每个点设置适当的偏移和范围。
gl_FragColor = texture2D(textureAtlas, offset + range * gl_PointCoord);
使用 TRIANGLES
和 实例图
这其实和上面没有什么不同,只是你创建了一个单一的2个三角形四边形,然后使用 drawArrayInstanced
或 drawElementsInstanced
. 您需要将引用改为 gl_PointCoord
用你自己的纹理坐标,你需要计算顶点着色器中的点。
attribute vec2 reusedPosition; // the 6 points (1, -1)
... all the attributes you had before ...
uniform vec2 outputResolution; // gl.canvas.width, gl.canvas.height
varying vec2 ourPointCoord;
void main() {
... -- insert code that you had before above this line -- ...
// now take gl_Position and convert to point
float ourPointSize = ???
gl_Position.xy += reusedPosition * ourPointSize / outputResolution * gl_Position.w;
ourPointCoord = reusedPosition * 0.5 + 0.5;
使用 TRIANGLES
与合并的几何体。
这只是意味着每个点需要4个(如果有索引)或6个顶点,而不是一个顶点。
使用 TRIANGLES
只有一个id,把数据放在textures中。
如果更新4到6个顶点来移动一个点太费劲了(提示:可能不是)。那么你可以把数据放在纹理中,根据一个id来查找每个点的数据。所以你把每个点的4个id加上一些顶点id放在某个缓冲区(即id0,0,0,0,1,1,1,1,2,2,2,3,3,3,3,4,4,4,顶点id0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3),然后你就可以用这些来计算四边形坐标、纹理坐标和vs,在纹理中查找每个点的数据。优点是,如果你想移动一个点,你只需要更新每个点的一个值,而不是每个点的4到6个值。
注意:以上所有的情况都是假设你想在一次绘制调用中绘制1000个点。如果你要画250个或更少的点,甚至是1000-2000个点,用正常的方式在每个绘图调用中画一个点也许就可以了。 例如
for each point
setup uniforms
gl.drawXXX
不是积分,只是举例说明 WebGL水族馆 正在使用该循环。它没有以任何方式使用实例化或合并几何体。下面是另一个例子 只不过是每一次抽签都要抽一次