Combining multiple ElevationContour materials

Cesium is able to render terrain contour lines using the ElevationContour materials, great!

I’m trying to combine two ElevationContour materials such that the terrain would have Major contour lines(thicker width, more spacing) and Minor contour lines(thin width, less spacing).

Using the documentation on how to combine materials with fabric(link), I was able to come up with this:

Cesium.Material({
  fabric: {
    type: "MinorMajorElevationContour",
    materials: {
      minorContour: {
        type: "ElevationContour",
        uniforms: {
          width: 1.0,
          spacing: 5.0,
          color: Cesium.Color.WHITE.clone(),
        }
      },
      majorContour: {
        type: "ElevationContour",
        uniforms: {
          width: 2.0,
          spacing: 10.0,
          color: Cesium.Color.RED.clone(),
        },
      },
    },
    components: {
      diffuse: "minorContour.diffuse",
      alpha: "minorContour.alpha",
    },
  },
  translucent: false,
});

However, this only renders the “minorContour” material, the other material(majorContour) is not rendered. I don’t know what I’m doing wrong.
Please, how can I possibly combine multiple “ElevationContour” materials to achieve what I Major and Minor contour lines as described above?

I figured a way to do this though not using the fabric way of combining multiple materials.

I had to create a new material that extends the default ElevationContour glsl source(Github Link) such that it’s able to accept minorSpacing, majorSpacing, minorWidth, and majorWidth as uniforms. In my custom GLSL source, I was able to use those uniforms to conditionally build the material.

The GLSL source:

#ifdef GL_OES_standard_derivatives
    #extension GL_OES_standard_derivatives : enable
#endif

uniform vec4 color;
uniform float minorSpacing;
uniform float majorSpacing;
uniform float minorWidth;
uniform float majorWidth;

czm_material czm_getMaterial(czm_materialInput materialInput)
{
    czm_material material = czm_getDefaultMaterial(materialInput);

    float distanceToMinorContour = mod(materialInput.height, minorSpacing);
    float distanceToMajorContour = mod(materialInput.height, majorSpacing);

#ifdef GL_OES_standard_derivatives
    float dxc = abs(dFdx(materialInput.height));
    float dyc = abs(dFdy(materialInput.height));
    float minordF = max(dxc, dyc) * czm_pixelRatio * minorWidth;
    float majordF = max(dxc, dyc) * czm_pixelRatio * majorWidth;
    float alpha = ((distanceToMinorContour < minordF) || (distanceToMajorContour < majordF)) ? 1.0 : 0.0;
#else
    float alpha = ((distanceToMinorContour < (czm_pixelRatio * minorWidth)) || (distanceToMajorContour < (czm_pixelRatio * majorWidth))) ? 1.0 : 0.0;
#endif

    vec4 outColor = czm_gammaCorrect(vec4(color.rgb, alpha * color.a));
    material.diffuse = outColor.rgb;
    material.alpha = outColor.a;

    return material;
}

The material:

new Cesium.Material({
  fabric: {
    type: "MinMajorElevationContour",
    uniforms: {
      minorSpacing: 10.0,
      majorSpacing: 20.0,
      minorWidth: 1.0,
      majorWidth: 3.0,
      color: Cesium.Color.WHITE.clone(),
    },
    source: customShader,
  },
  translucent: false,
});
2 Likes

@Tunmise

I apologize for not getting to your original post. However, I am glad to see that you have found a solution.

I looked over your work and it seems robust. Thank you for sharing your solution - I will point other community members to this thread if similar issues arise in the future.

-Sam

1 Like