Using wallpaper material with primitive collection?

Hi,
can someone explain me why this code doesn't works with primitive collection under scene but works just fine with viewer.entities?

//Call this once at application startup
Cesium.Material._materialCache.addMaterial('Wallpaper', {
    fabric : {
        type : 'Wallpaper',
        uniforms : {
            image : Cesium.Material.DefaultImageId,
            anchor : new Cesium.Cartesian2(0, 0)
        },
        components : {
            diffuse : 'texture2D(image, fract((gl_FragCoord.xy - anchor.xy) / vec2(imageDimensions.xy))).rgb',
            alpha : 'texture2D(image, fract((gl_FragCoord.xy - anchor.xy) / vec2(imageDimensions.xy))).a'
        }
    },
    translucent : false
});

//Create an instance and assign to anything that has a material property.
//scene - the scene
//image - the image (I think both a url or Image object are supported)
//anchor - A Cartesian3 that is the most southern and westard point of the geometry
var WallPaperMaterialProperty = function(scene, image, anchor) {
    this._scene = scene;
    this._image = image;
    this._anchor = anchor;
    this.definitionChanged = new Cesium.Event();
    this.isConstant = true;
};

WallPaperMaterialProperty.prototype.getType = function(time) {
    return 'Wallpaper';
};

WallPaperMaterialProperty.prototype.getValue = function(time, result) {
    if (!Cesium.defined(result)) {
        result = {
            image : undefined,
            anchor : undefined
        };
    }
    
    result.image = this._image;
    result.anchor = Cesium.SceneTransforms.wgs84ToDrawingBufferCoordinates(this._scene, this._anchor, result.anchor);
    if(Cesium.defined(result.anchor)){
        result.anchor.x = Math.floor(result.anchor.x);
        result.anchor.y = Math.floor(result.anchor.y);
    } else {
        result.anchor = new Cesium.Cartesian2(0, 0);
    }
    return result;
};

WallPaperMaterialProperty.prototype.equals = function(other) {
    return this === other || //
           (other instanceof WallPaperMaterialProperty && //
            this._image === other._image);
};

//Here's a working example.
var viewer = new Cesium.Viewer('cesiumContainer');

viewer.entities.add({
    polygon : {
        hierarchy : Cesium.Cartesian3.fromDegreesArray([-115.0, 37.0,
                                                        -115.0, 32.0,
                                                        -107.0, 33.0,
                                                        -102.0, 31.0,
                                                        -102.0, 35.0]),
        material : new WallPaperMaterialProperty(viewer.scene, '../images/checkerboard.png', Cesium.Cartesian3.fromDegrees(-115.0, 31))
    }
});

viewer.zoomTo(viewer.entities);

can you post a sample of how you’re generating your primitive

Sure,
I don't remember the syntax but I am just adding it to scene.primitives.add.

The WallPaperMaterialProperty object is specific to the Entity API, so to use it with the underlying primitive system requires a slightly different approach. The actual material is the same, but you need to manually update the anchor position each frame in order to maintain the desired effect. Here’s a complete example that works with the Primitive API.

//Call this once at application startup

Cesium.Material._materialCache.addMaterial(‘Wallpaper’, {

fabric : {

    type : 'Wallpaper',

    uniforms : {

        image : Cesium.Material.DefaultImageId,

        anchor : new Cesium.Cartesian2(0, 0)

    },

    components : {

        diffuse : 'texture2D(image, fract((gl_FragCoord.xy - anchor.xy) / vec2(imageDimensions.xy))).rgb',

        alpha : 'texture2D(image, fract((gl_FragCoord.xy - anchor.xy) / vec2(imageDimensions.xy))).a'

    }

},

translucent : false

});

var viewer = new Cesium.Viewer(‘cesiumContainer’);

var scene = viewer.scene;

//Create the material and assign the image

var material = Cesium.Material.fromType(‘Wallpaper’);

var uniforms = material.uniforms;

uniforms.image = ‘…/images/checkerboard.png’;

//Create a geometry with the material

scene.primitives.add(new Cesium.Primitive({

geometryInstances : new Cesium.GeometryInstance({

    geometry : new Cesium.RectangleGeometry({

        rectangle : Cesium.Rectangle.fromDegrees(-120.0, 30.0, -110.0, 40.0),

        vertexFormat : Cesium.MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat

    })

}),

appearance : new Cesium.MaterialAppearance({

    material : material,

    materialSupport : Cesium.MaterialAppearance.MaterialSupport.TEXTURED

})

}));

scene.preRender.addEventListener(function(){

//Each frame, the material's anchor needs to be updated with the

//screen space position of the anchor point.

var anchor = Cesium.Cartesian3.fromDegrees(-115.0, 35.0);

var result = Cesium.SceneTransforms.wgs84ToDrawingBufferCoordinates(scene, anchor, uniforms.anchor);

if(!Cesium.defined(result)){

    Cesium.Cartesian2.ZERO.clone(uniforms.anchor);

}

});

First of all - thanks a lot.

Another question - as i'm not familiar with custom materials I find it difficult to add the following:
Is there a way that when the map moves horizontally - the material won't move?

For instance - In case I have the following material(arrows material):
^
^
^
^
^

I don't want to be able to move it on the x axis but to move it on the y axis only.
Even more - I want the zoom to affect the way the material looks which means - as the zoom is closer you shall see more arrows(which happens with the current wallpaper material version).

Thanks a lot.

I have the same need... is it possible? (Just like Billboard does not change it's size when zooming...)

Thanks

gonengar, what you want is trival, just take my example and change

if(!Cesium.defined(result)){

Cesium.Cartesian2.ZERO.clone(uniforms.anchor);

}

to

if(!Cesium.defined(result)){

Cesium.Cartesian2.ZERO.clone(uniforms.anchor);

} else{

result.y = 0;

}

And it will behave as you describe.

Thanks.
Is there a way to rotate the material too?

I’m not sure how easy/hard it would be to add rotation in at the shader label, but depending on why type of shape you are using the material with, you can set the stRotation property. I believe Ellipse/Polygon/Rectangle all of it.

Am I doing something wrong?
I have added stRotation but it doesnt seem to rotate:
scene.primitives.add(new Cesium.Primitive({
    geometryInstances : new Cesium.GeometryInstance({
        geometry : new Cesium.RectangleGeometry({
            rectangle : Cesium.Rectangle.fromDegrees(-120.0, 30.0, -110.0, 40.0),
            vertexFormat : Cesium.MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat,
            stRotation: Math.PI/8
        })
    }),
    appearance : new Cesium.MaterialAppearance({
        material : material,
        materialSupport : Cesium.MaterialAppearance.MaterialSupport.TEXTURED
    })
}));