How to create a custom texture mapped sphere in CesiumGS?
Sometimes we need to change texture uv coordinates of the geometry CesiumGS provide by default.
The following code snippet implies how to implement it.
In the below code the function SphereBufferGeometry is very similiar to Three.js ‘s SphereBufferGeometry class.
function createCustomMappingSpherePrimitive(ballRadius, widthSegments, heightSegments ) {
let sphereGeometry = new SphereBufferGeometry( ballRadius, widthSegments, heightSegments );
let positions = sphereGeometry.position;
for ( let i = 0, l = positions.length / 3; i < l; i ++ ) {
let x = positions[ i * 3 + 0 ];
let y = positions[ i * 3 + 1 ];
let z = positions[ i * 3 + 2 ];
// three js axis direction to cesium js axis direction
positions[ i * 3 + 1 ] = z;
positions[ i * 3 + 2 ] = -y;
}
let normals = sphereGeometry.normal;
let uvs = sphereGeometry.uv;
const canvasHeight = 2048;
const canvasWidth = 2048;
const verticalFov = 360;
for ( let i = 0, l = normals.length / 3; i < l; i ++ ) {
let x = normals[ i * 3 + 0 ];
let y = normals[ i * 3 + 1 ];
let z = normals[ i * 3 + 2 ];
// radius center
let correction = ( x == 0 && z == 0 ) ? 1 : ( Math.acos( y ) / Math.sqrt( x * x + z * z ) ) * ( 2 / ((verticalFov * Math.PI) / 180) );
uvs[ i * 2 + 0 ] = x * ( (canvasHeight/2) / canvasWidth ) * correction + ( (canvasWidth/2) / canvasWidth );
uvs[ i * 2 + 1 ] = z * ( (canvasHeight/2) / canvasHeight ) * correction + ( (canvasHeight/2) / canvasHeight );
}
let position = new Cesium.GeometryAttribute({
componentDatatype: Cesium.ComponentDatatype.DOUBLE,
componentsPerAttribute: 3,
values: new Float64Array(sphereGeometry.position)
});
let normal = new Cesium.GeometryAttribute({
componentDatatype: Cesium.ComponentDatatype.FLOAT,
componentsPerAttribute: 3,
values: new Float32Array(sphereGeometry.normal)
});
let st = new Cesium.GeometryAttribute({
componentDatatype: Cesium.ComponentDatatype.FLOAT,
componentsPerAttribute: 2,
values: new Float32Array(sphereGeometry.uv)
});
let material = createMaterial(textureUrl, initialTransparency);
spherePrimitive = new Cesium.Primitive({
geometryInstances : new Cesium.GeometryInstance({
geometry: new Cesium.Geometry({
attributes: {
position: position,
normal: normal,
st: st
},
indices : new Uint16Array(sphereGeometry.index),
primitiveType: Cesium.PrimitiveType.TRIANGLES,
boundingSphere: Cesium.BoundingSphere.fromVertices(sphereGeometry.position)
}),
}),
appearance: new Cesium.MaterialAppearance({
material: material,
closed: true
}),
asynchronous: false
});
theViewer.scene.primitives.add(spherePrimitive);
spherePrimitive.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(defaultSpherePosition);
}
Hope you enjoy this code.