Cesium has solid arrows (PolylineArrow) and dashed lines (PolylineDash). I want to combine the two to make a PolylineDashArrow (An Arrow with a Dash Fill, or a dash line with an arrow head).
It sounds like this should be possible using Cesium's Fabric. Though I think I need to add a GLSL like the ones for arrow and dash. (The Fabric page doesn't say anything about how to add a custom GLSL to use for the source)
This seems like something that should be really easy to do but I can't find any information on anyone else trying to do this.
So, it should have been straightforward. But there's a small catch in that you don't want the dashes interrupting the arrow head itself. The arrow head should always be solid, or it looks wrong.
The biggest problem I ran into is that the dash material doesn't just mark the gaps between dashes as transparent, it actually marks them for discard. The good news is this is done with a Boolean value (not a raw discard
keyword) that can be tricked into becoming false again, to keep those gaps from interrupting the arrow head.
So I had to cheat a bit to disable the dashMaterial's discard, but I got it to work.
Here's what I ended up with: Sandcastle demo of dashed arrow.
The code for that demo looks like this:
var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;
// Create sample polyline primitive.
var polylines = scene.primitives.add(new Cesium.PolylineCollection());
var polyline = polylines.add({
positions : Cesium.PolylinePipeline.generateCartesianArc({
positions : Cesium.Cartesian3.fromDegreesArray([-110.0, 42.0,
-85.0, 36.0,
-100.0, 25.0,
-77.0, 12.0])
}),
width : 15.0
});
// Assign a new fabric material blend of arrow and dashes.
polyline.material = new Cesium.Material({
fabric : {
materials : {
// The arrowMaterial provides the color and overall shape.
arrowMaterial : {
type : 'PolylineArrow',
uniforms : {
color : Cesium.Color.YELLOW
}
},
// The dashMaterial will punch holes in the arrowMaterial.
// Uniforms could be added to control the dash parameters.
dashMaterial : {
type : 'PolylineDash',
},
// "headMaterial" is copy-paste of the arrow head size code, written to alpha.
// It is used to mask out the dashes, to keep them from destroying the arrow head.
// A small tail is included behind the arrow head, to keep it from becoming a triangle.
headMaterial : {
source :
'czm_material czm_getMaterial(czm_materialInput materialInput) { \n' +
' czm_material material = czm_getDefaultMaterial(materialInput); \n' +
' vec2 st = materialInput.st; \n' +
'#ifdef GL_OES_standard_derivatives \n' +
// Original multiplier "10.0" changed to "15.0" to add short tail to head.
' float base = 1.0 - abs(fwidth(st.s)) * 15.0 * czm_pixelRatio; \n' +
'#else \n' +
' float base = 0.975; // 2.5% of the line will be the arrow head \n' +
'#endif \n' +
' material.alpha = 1.0 - smoothstep(base - 0.0001, base, st.s); \n' +
' return material; \n' +
'} \n'
}
},
// Finally, the "alpha" contains a cheat, where we undo czm_discard from the dashMaterial.
components : {
diffuse : 'arrowMaterial.diffuse',
alpha : 'arrowMaterial.alpha * (1.0 - (headMaterial.alpha * (1.0 - dashMaterial.alpha))); czm_discard = false'
}
}
});