Custom shader & attributes

Hi,

I think that there is no way at this moment to pass the FragmentInput struct to the custom shader PolylineMaterialAppearance :: fragmentShaderSource.

Is that correct ?

If it’s true, I would like to be able pass custom attributes :

Custom attributes are also available, though they are renamed to use lowercase letters and underscores. For example, an attribute called _SURFACE_TEMPERATURE in the model would become fsInput.attributes.surface_temperature in the shader.

cesium/Documentation/CustomShaderGuide/README.md at main · CesiumGS/cesium · GitHub

With fragmentShaderText it’s possible to pass the FragmentInput struct, but not with fragmentShaderSource

why ?

 fragmentShaderText: `void fragmentMain(
    FragmentInput fsInput,
    inout czm_modelMaterial material
  ) {

I’m interested to get the attributes in the call of the function czm_getMaterial()

I looked at the source of CesiumJS, and I found that :

function updateSetDynamicVaryingsFunction(shaderBuilder, attributeInfo) {
  const { semantic, setIndex } = attributeInfo.attribute;
  if (defined(semantic) && !defined(setIndex)) {
    // positions, normals, and tangents are handled statically in
    // GeometryStageVS
    return;
  }

  // In the vertex shader, we want things like
  // v_texCoord_1 = attributes.texCoord_1;
  let functionId = GeometryPipelineStage.FUNCTION_ID_SET_DYNAMIC_VARYINGS_VS;
  const variableName = attributeInfo.variableName;
  let line = `v_${variableName} = attributes.${variableName};`;
  shaderBuilder.addFunctionLines(functionId, [line]);

  // In the fragment shader, we do the opposite:
  // attributes.texCoord_1 = v_texCoord_1;
  functionId = GeometryPipelineStage.FUNCTION_ID_SET_DYNAMIC_VARYINGS_FS;
  line = `attributes.${variableName} = v_${variableName};`;
  shaderBuilder.addFunctionLines(functionId, [line]);
}

so maybe I don’t need the FragmentInput struct

I tried to do in the js file :

new Cesium.PolylineMaterialAppearance({
        ....
        translucent: false,
        vertexShaderSource: myVertex,
        fragmentShaderSource: myFragment,
       ...
new Cesium.GeometryInstance({
              geometry: new Cesium.PolylineGeometry({
                positions: Cesium.Cartesian3.fromDegreesArrayHeights(line.points),
                width: 2,
                vertexFormat: vertexFormat,
                arcType: Cesium.ArcType.GEODESIC,
                ...
              }),
              attributes:
              {
                myCustomAttribute: 5
                ....
              }
            })

and in the vertex shader :

// get it in the vertex shader : 
in int lineLength;
// give it to the fragment shader :
flat out int v_lineLength;

will it work ? Looks like not, when I’m using the debugger :

I looked at the variable attributeLocations in :

  const attributeLocations = shader._attributeLocations;
  if ((0,defined/* default */.A)(attributeLocations)) {
    for (const attribute in attributeLocations) {
      if (attributeLocations.hasOwnProperty(attribute)) {
        gl.bindAttribLocation(
          program,
          attributeLocations[attribute],
          attribute
        );
      }
    }
  }

but i didn’t find the attribute that I added …

I would like to know where in the source code, the attribute are passed to fragment shader ?

Thanks,

Hi @Mickael,

There are different systems for defining custom GLSL materials depending on where in the CesiumJS API the material being used. Custom Shaders specifically are used on models and 3D Tiles.

For Polylines, I’d recommend looking into the Fabric schema, which is used for creating materials for primitive geometries. That doc lists the attributes you have access to with czm_materialInput.

If you can provide some more info about what you are looking to accomplish with a custom material, we may be able to provide additional advise.

Thanks!
Gabby

Yes I’m using fabric in material, but how can I get the attribute in the fragment shader that is different for each geometry instance :


const geometryInstance1 = new Cesium.GeometryInstance(
	{
		geometry: new Cesium.PolylineGeometry({
		  positions : Cesium.Cartesian3.fromDegreesArray([
			0.0, 0.0,
			5.0, 0.0,
			5.0, 5.0
		  ]),
		  width : 10.0,
		  arcType: Cesium.ArcType.GEODESIC
		}),
		attributes: {
                    test: new Cesium.GeometryInstanceAttribute({
                               componentDatatype : Cesium.ComponentDatatype.FLOAT,
                               componentsPerAttribute : 1,
                               normalize : true,
                               value : [50]
                           })
		}
	}
);
const geometryInstance2 = new Cesium.GeometryInstance(
	{
		geometry: new Cesium.PolylineGeometry({
		  positions : Cesium.Cartesian3.fromDegreesArray([
			0.0, 0.0,
			-5.0, 0.0,
			-5.0, -5.0
		  ]),
		  width : 10.0,
		  arcType: Cesium.ArcType.GEODESIC
		}),
		attributes: {
                    test: new Cesium.GeometryInstanceAttribute({
                               componentDatatype : Cesium.ComponentDatatype.FLOAT,
                               componentsPerAttribute : 1,
                               normalize : true,
                               value : [50]
                           })
		}
	}
);





const primitive = new Cesium.Primitive({
  geometryInstances : [geometryInstance1, geometryInstance2],
  appearance: new Cesium.PolylineMaterialAppearance({
	translucent: false,
	vertexShaderSource: vertexShader,
	fragmentShaderSource: fragmentShader,
	material: new Cesium.Material({
	  // https://github.com/CesiumGS/cesium/wiki/Fabric
	  fabric: {
		materials: {
		  // The arrowMaterial provides the color and overall shape.
		  arrowMaterial: {
			uniforms: {
                              genericVariable that can be catched by the fragment shader
                              ....

@Gabby_Getz unfortunetly czm_materialInput don’t give me access to the the attribute specified in the Cesium.GeometryInstance