Modify custom primitive's color buffer

I've created a custom primitive with a couple of hundred thousand triangles.

Something like:

   var triangles = 2000000;

   var positions = new Float64Array(triangles * 3 * 3);
   var normals = new Float32Array(triangles * 3 * 3);
   var colors = new Float32Array(triangles * 3 * 3);

   /// ... fill in the buffers

   var instance = new GeometryInstance({
      geometry : new Geometry({
          attributes : {
            position : new GeometryAttribute({
               componentDatatype : ComponentDatatype.DOUBLE,
               componentsPerAttribute : 3,
               values : positions,
               normalize: false
            }),
            color : new GeometryAttribute({
              componentDatatype : ComponentDatatype.FLOAT,
              componentsPerAttribute : 3,
              values : colors,
              normalize: false
           }),
            normal : new GeometryAttribute({
               componentDatatype : ComponentDatatype.FLOAT,
               componentsPerAttribute : 3,
               values : normals,
               normalize: false
            })
         },
         primitiveType : PrimitiveType.TRIANGLES,
         boundingSphere : BoundingSphere.fromVertices(positions),
      })
   });
   var primitive = new Primitive({
      geometryInstances : instance,
      appearance : new PerInstanceColorAppearance({
         translucent : false
      })
   });

   viewer.scene.primitives.add(primitive);

At a later time, I am in need of updating the color buffer to a different set of colors.

  So I go:

   var triangles = 2000000;

   var colors = new Float32Array(triangles * 3 * 3);

   /// ... fill in the color buffer with new colors

   primitive._vaAttributes[0][primitive._attributeLocations.color].vertexBuffer.copyFromArrayView(colors.buffer, 0);

And it does not work.

   Any help appreciated.

Hi,

I can’t recommend reaching into _vaAttributes since it is an implementation detail that may change in the future. Perhaps recreate the geometry and primitive (use “asynchronous : false”) in the primitive constructor each time a color change is needed. If that is not fast enough, consider creating separate geometries (but still one primitive) and then following the example in “Updating Per-Instance Attributes” in the tutorial.

Patrick

Hi Patrick,

My current solution involves recreating the geometry. Although it flickers. I will try to make it synchronous as suggested to avoid flickering. I am not sure if it will be a viable option for when the colours will vary with time.

I can give per instance attribute thing a go but I am not sure if it will be a very good option for me. I am drawing a massive number of triangles to visualise the surface of massive structured grids with masked out empty regions. The grids are irregular and colors vary cell to cell. I am only rendering the faces and even if I was to draw each face of the grid with a rectangle, I would still need hundreds of thousands of geometries per primitive. I would have thought that was a lot of objects and updates to have inside JavaScript.

Is there no way to simply update the color array for the vertices? Or are there better solutions for what I am trying to achieve?

Cheers

Keep an eye on #932. This will be the solution you want, but it is at least a few months out.

Patrick

I have the same question and hoping there is now a solution. The code below draws two triangles with custom vertex colors but ultimately I will be drawing thousands. How do I update the colors without recreating the primitive? Thank you for the help!

Travis

triangles

var extent = Cesium.Rectangle.fromDegrees(-98, 30, -90, 39);
Cesium.Camera.DEFAULT_VIEW_RECTANGLE = extent;
Cesium.Camera.DEFAULT_VIEW_FACTOR = 0.5;

var viewer = new Cesium.Viewer(‘cesiumContainer’, {
navigationHelpButton: false, animation: false, timeline: false
});

var mypositions = Cesium.Cartesian3.fromDegreesArrayHeights([
// Triangle A
-90.6714, 35.9641, 322.543,
-94.6717, 38.9642, 325.51,
-97.6717, 35.9639, 324.724,
// Triangle B
-94.6717, 30.9639, 324.717,
-90.6717, 32.9639, 324.724,
-94.6717, 34.9639, 324.719 ]);

// unroll ‘mypositions’ into a flat array here
var numPositions = mypositions.length;

var pos = new Float64Array(numPositions * 3);
var normals = new Float32Array(numPositions * 3);
var colors = new Float32Array(numPositions * 4);
for (var i = 0; i < numPositions; ++i) {
pos[i * 3] = mypositions[i].x;
pos[i * 3 + 1] = mypositions[i].y;
pos[i * 3 + 2] = mypositions[i].z;
normals[i * 3] = 0.0;
normals[i * 3 + 1] = 0.0;
normals[i * 3 + 2] = 1.0;
if ( i == 0 || i == 5 ){
colors[i * 4 ]= 1
colors[i * 4 + 1]= 0
colors[i * 4 + 2]= 0
colors[i * 4 + 3]= 0.5
}
else {
colors[i * 4 ]= 0
colors[i * 4 + 1]= 0
colors[i * 4 + 2]= 1
colors[i * 4 + 3]= 0.5
}
console.log(i)
}

var geometry = new Cesium.Geometry({
attributes: {
position: new Cesium.GeometryAttribute({
componentDatatype: Cesium.ComponentDatatype.DOUBLE, // not FLOAT
componentsPerAttribute: 3,
values: pos
}),
normal: new Cesium.GeometryAttribute({
componentDatatype: Cesium.ComponentDatatype.FLOAT,
componentsPerAttribute: 4,
values: normals
}),
color: new Cesium.GeometryAttribute({
componentDatatype: Cesium.ComponentDatatype.FLOAT,
componentsPerAttribute: 4,
values: colors
}),
},
// Don’t need the following line if no vertices are shared.
//indices: new Uint32Array([0, 1, 2, 3, 4, 5]),
primitiveType: Cesium.PrimitiveType.TRIANGLES,
boundingSphere: Cesium.BoundingSphere.fromVertices(pos)
});

var myInstance = new Cesium.GeometryInstance({
geometry: geometry,
show: new Cesium.ShowGeometryInstanceAttribute(true),
id:‘triangles’,
});

var primitive = new Cesium.Primitive({
geometryInstances: [myInstance],
asynchronous: false,
appearance: new Cesium.PerInstanceColorAppearance({
closed: true,
translucent: true
})
})

viewer.scene.primitives.add(primitive);