Is there any way to dynamically update the opacity and rotation of an image on a map?

Currently we are using a SingleImageTileProvider to display a jpg overlay on a Cesium map. We are able to adjust the opacity of this image on demand with no problem, but now we have a requirement to also rotate this image on the map.

Using a Rectangle Entity I am able to get an image on the map, rotate it, but can't update opacity:

      let rotation = Cesium.Math.toRadians(30);

      function getRotationValue() {
        rotation += 0.005;
        return rotation;
      }

      let image = ‘https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg’;

      window.test = viewer.entities.add({
        name: 'Rotating rectangle with rotating texture coordinate ',
        rectangle: {
          coordinates: Cesium.Rectangle.fromDegrees(-76.0, 35.0, -72.0, 38.0),
          material: image,
          rotation: new Cesium.CallbackProperty(getRotationValue, false),
          stRotation: new Cesium.CallbackProperty(getRotationValue, false),
        },
      });

In addition, the above method is causing bad lighting on the image in 2d mode, making it darker than it should be.

Trying to set a custom material on the entity throws an error: Unable to infer material type: [object Object]

      window.material = new Cesium.Material({
        fabric: {
          type: 'Image',
          uniforms: {
            image: url,
            alpha: 0.5,
          },
          components: {
            diffuse: 'texture2D(image, fract(repeat * materialInput.st)).rgb',
            alpha: 'texture2D(image, fract(repeat * materialInput.st)).a * alpha',
          },
        },
        translucent: true,
      });

      window.test = viewer.entities.add({
        name: 'Rotating rectangle with rotating texture coordinate ',
        rectangle: {
          coordinates: Cesium.Rectangle.fromDegrees(-76.0, 35.0, -72.0, 38.0),
          material: material,
          rotation: new Cesium.CallbackProperty(getRotationValue, false),
          stRotation: new Cesium.CallbackProperty(getRotationValue, false),
        },
      });

Dropping down to a primitive I can get rid of the lighting issue and allow dynamic opacity, but then I lose the ability to rotate. It looks like rotation can be achieved by modifying the modelMatrix property, but that is only supported in 2d mode:

      const materialApp = new Cesium.MaterialAppearance({
        material: new Cesium.Material({
          fabric: {
            type: 'Image',
            uniforms: {
              image: image,
              alpha: 0.5,
            },
            components: {
              diffuse: 'texture2D(image, fract(repeat * materialInput.st)).rgb',
              alpha: 'texture2D(image, fract(repeat * materialInput.st)).a * alpha',
            },
          },
          translucent: true,
        }),
        faceForward: true,
        flat: true,
      });

      const prim = new Cesium.Primitive({
        geometryInstances: [new Cesium.GeometryInstance({
          geometry: new Cesium.RectangleGeometry({
            rectangle: Cesium.Rectangle.fromDegrees(-76.0, 35.0, -72.0, 38.0),
            vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
          }),
        })],
        appearance: materialApp,
      });

      window.test = viewer.scene.primitives.add(prim);

      // window.test.appearance.material.uniforms.alpha = 0.4
      // dynamically update opacity

I've also experimented with drawing the image to a canvas, adjusting the opacity of the canvas, and using the Entity approach, but haven't had success there either.

Is there any way to accomplish this in Cesium? I feel like there must be some simple method using one of the previous code samples to get this working, but it evades me so far.

Running Cesium 1.21 right now, but if something exists in a newer version I would be interested to know about that as well.

Thanks!

In case someone is searching for the same thing I was, this is how I got it to work. Declare a color property for an entity with an alpha value < 0:

      let rotation = Cesium.Math.toRadians(30);
      let alpha = 0;
      let direction = 1;

      function getRotationValue() {
        rotation += 0.005;
        return rotation;
      }

      function getColor() {
        alpha += (0.01 * direction);
        if (alpha >= 1 || alpha <= 0) direction *= -1;
        return { red: 1, green: 1, blue: 1, alpha };
      }

      const image = ‘http://localhost/thumbnails/BrowseImagery_8.jpg’;

      window.test = viewer.entities.add({
        rectangle: {
          coordinates: Cesium.Rectangle.fromDegrees(-76.0, 35.0, -72.0, 38.0),
          material: new Cesium.ImageMaterialProperty({
            image,
            color: new Cesium.CallbackProperty(getColor, false),
            transparent: true,
          }),
          rotation: new Cesium.CallbackProperty(getRotationValue, false),
          stRotation: new Cesium.CallbackProperty(getRotationValue, false)
        }
      });

1 Like

Glad you got it working! Another solution is when you assign the material, use an **ImageMaterial **object directly and make sure you set the transparent option to true.

material: new Cesium.ImageMaterialProperty({

image: canvas,

color: new Cesium.Color.WHITE.withAlpha(0.5),

transparent: true

}),

``

Thanks,

Gabby

1 Like