Compare commits

..

2 Commits

Author SHA1 Message Date
Don McCurdy 6dd9ca1bd0 fix(BillboardCollection): Fix precision loss in billboard image texcoords 2025-11-24 17:05:28 -06:00
Don McCurdy 3849eb69d4 refactor(BillboardCollection): Require instancing 2025-11-24 15:31:22 -06:00
5 changed files with 77 additions and 368 deletions

View File

@ -193,21 +193,22 @@ Object.defineProperties(TextureAtlas.prototype, {
});
/**
* TODO
* Get the texture coordinates for reading the associated image in shaders.
* @param {number} index The index of the image region.
* @param {BoundingRectangle} [result] The object into which to store the result.
* @return {BoundingRectangle} The modified result parameter or a new BoundingRectangle instance if one was not provided.
* @private
* @example
* const index = await atlas.addImage("myImage", image);
* const rectangle = atlas.computeImageCoordinates(index);
* const rectangle = atlas.computeTextureCoordinates(index);
* BoundingRectangle.pack(rectangle, bufferView);
*/
TextureAtlas.prototype.computeImageCoordinates = function (index, result) {
TextureAtlas.prototype.computeTextureCoordinates = function (index, result) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.number.greaterThanOrEquals("index", index, 0);
//>>includeEnd('debug');
const texture = this._texture;
const rectangle = this._rectangles[index];
if (!defined(result)) {
@ -223,6 +224,11 @@ TextureAtlas.prototype.computeImageCoordinates = function (index, result) {
return result;
}
const atlasWidth = texture.width;
const atlasHeight = texture.height;
const width = rectangle.width;
const height = rectangle.height;
let x = rectangle.x;
let y = rectangle.y;
@ -234,36 +240,10 @@ TextureAtlas.prototype.computeImageCoordinates = function (index, result) {
y += parentRectangle.y;
}
result.x = x;
result.y = y;
result.width = rectangle.width;
result.height = rectangle.height;
return result;
};
/**
* Get the texture coordinates for reading the associated image in shaders.
* @param {number} index The index of the image region.
* @param {BoundingRectangle} [result] The object into which to store the result.
* @return {BoundingRectangle} The modified result parameter or a new BoundingRectangle instance if one was not provided.
* @private
* @example
* const index = await atlas.addImage("myImage", image);
* const rectangle = atlas.computeTextureCoordinates(index);
* BoundingRectangle.pack(rectangle, bufferView);
*/
TextureAtlas.prototype.computeTextureCoordinates = function (index, result) {
result = this.computeImageCoordinates(index, result);
const texture = this._texture;
const atlasWidth = texture.width;
const atlasHeight = texture.height;
result.x /= atlasWidth;
result.y /= atlasHeight;
result.width /= atlasWidth;
result.height /= atlasHeight;
result.x = x / atlasWidth;
result.y = y / atlasHeight;
result.width = width / atlasWidth;
result.height = height / atlasHeight;
return result;
};

View File

@ -1195,16 +1195,6 @@ Billboard._updateClamping = function (collection, owner) {
updateFunction(scratchCartographic);
};
/**
* Get the image coordinates for reading the loaded texture in shaders.
* @param {BoundingRectangle} [result] The modified result parameter or a new BoundingRectangle instance if one was not provided.
* @return {BoundingRectangle} The modified result parameter or a new BoundingRectangle instance if one was not provided.
* @private
*/
Billboard.prototype.computeImageCoordinates = function (result) {
return this._imageTexture.computeImageCoordinates(result);
};
/**
* Get the texture coordinates for reading the loaded texture in shaders.
* @param {BoundingRectangle} [result] The modified result parameter or a new BoundingRectangle instance if one was not provided.

View File

@ -59,29 +59,11 @@ const NUMBER_OF_PROPERTIES = Billboard.NUMBER_OF_PROPERTIES;
const scratchTextureSize = new Cartesian2();
let attributeLocations;
const attributeLocationsBatched = {
positionHighAndScale: 0,
positionLowAndRotation: 1,
compressedAttribute0: 2, // pixel offset, translate, horizontal origin, vertical origin, show, direction, image coordinates (px)
compressedAttribute1: 3, // aligned axis, translucency by distance, image width
compressedAttribute2: 4, // image height, color, pick color, size in meters, valid aligned axis, 13 bits free
eyeOffset: 5, // 4 bytes free
scaleByDistance: 6,
pixelOffsetScaleByDistance: 7,
compressedAttribute3: 8,
textureCoordinateBoundsOrLabelTranslate: 9,
a_batchId: 10,
sdf: 11,
splitDirection: 12,
};
const attributeLocationsInstanced = {
const attributeLocations = {
direction: 0,
positionHighAndScale: 1,
positionLowAndRotation: 2,
compressedAttribute0: 3, // image lower-left coordinates (px) in w
positionLowAndRotation: 2, // texture offset in w
compressedAttribute0: 3,
compressedAttribute1: 4,
compressedAttribute2: 5,
eyeOffset: 6,
@ -680,44 +662,7 @@ BillboardCollection.prototype.get = function (index) {
return this._billboards[index];
};
let getIndexBuffer;
function getIndexBufferBatched(context) {
const sixteenK = 16 * 1024;
let indexBuffer = context.cache.billboardCollection_indexBufferBatched;
if (defined(indexBuffer)) {
return indexBuffer;
}
// Subtract 6 because the last index is reserverd for primitive restart.
// https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.18
const length = sixteenK * 6 - 6;
const indices = new Uint16Array(length);
for (let i = 0, j = 0; i < length; i += 6, j += 4) {
indices[i] = j;
indices[i + 1] = j + 1;
indices[i + 2] = j + 2;
indices[i + 3] = j + 0;
indices[i + 4] = j + 2;
indices[i + 5] = j + 3;
}
// PERFORMANCE_IDEA: Should we reference count billboard collections, and eventually delete this?
// Is this too much memory to allocate up front? Should we dynamically grow it?
indexBuffer = Buffer.createIndexBuffer({
context: context,
typedArray: indices,
usage: BufferUsage.STATIC_DRAW,
indexDatatype: IndexDatatype.UNSIGNED_SHORT,
});
indexBuffer.vertexArrayDestroyable = false;
context.cache.billboardCollection_indexBufferBatched = indexBuffer;
return indexBuffer;
}
function getIndexBufferInstanced(context) {
function getIndexBuffer(context) {
let indexBuffer = context.cache.billboardCollection_indexBufferInstanced;
if (defined(indexBuffer)) {
return indexBuffer;
@ -767,14 +712,7 @@ BillboardCollection.prototype.computeNewBuffersUsage = function () {
return usageChanged;
};
function createVAF(
context,
numberOfBillboards,
buffersUsage,
instanced,
batchTable,
sdf,
) {
function createVAF(context, numberOfBillboards, buffersUsage, batchTable, sdf) {
const attributes = [
{
index: attributeLocations.positionHighAndScale,
@ -845,14 +783,12 @@ function createVAF(
];
// Instancing requires one non-instanced attribute.
if (instanced) {
attributes.push({
index: attributeLocations.direction,
componentsPerAttribute: 2,
componentDatatype: ComponentDatatype.FLOAT,
vertexBuffer: getVertexBufferInstanced(context),
});
}
attributes.push({
index: attributeLocations.direction,
componentsPerAttribute: 2,
componentDatatype: ComponentDatatype.FLOAT,
vertexBuffer: getVertexBufferInstanced(context),
});
if (defined(batchTable)) {
attributes.push({
@ -873,10 +809,8 @@ function createVAF(
}
// When instancing is enabled, only one vertex is needed for each billboard.
const sizeInVertices = instanced
? numberOfBillboards
: 4 * numberOfBillboards;
return new VertexArrayFacade(context, attributes, sizeInVertices, instanced);
const sizeInVertices = numberOfBillboards;
return new VertexArrayFacade(context, attributes, sizeInVertices, true);
}
///////////////////////////////////////////////////////////////////////////
@ -894,7 +828,6 @@ function writePositionScaleAndRotation(
vafWriters,
billboard,
) {
let i;
const positionHighWriter =
vafWriters[attributeLocations.positionHighAndScale];
const positionLowWriter =
@ -926,22 +859,9 @@ function writePositionScaleAndRotation(
const high = writePositionScratch.high;
const low = writePositionScratch.low;
if (billboardCollection._instanced) {
i = billboard._index;
positionHighWriter(i, high.x, high.y, high.z, scale);
positionLowWriter(i, low.x, low.y, low.z, rotation);
} else {
i = billboard._index * 4;
positionHighWriter(i + 0, high.x, high.y, high.z, scale);
positionHighWriter(i + 1, high.x, high.y, high.z, scale);
positionHighWriter(i + 2, high.x, high.y, high.z, scale);
positionHighWriter(i + 3, high.x, high.y, high.z, scale);
positionLowWriter(i + 0, low.x, low.y, low.z, rotation);
positionLowWriter(i + 1, low.x, low.y, low.z, rotation);
positionLowWriter(i + 2, low.x, low.y, low.z, rotation);
positionLowWriter(i + 3, low.x, low.y, low.z, rotation);
}
const i = billboard._index;
positionHighWriter(i, high.x, high.y, high.z, scale);
positionLowWriter(i, low.x, low.y, low.z, rotation);
}
const UPPER_BOUND = 32768.0; // 2^15
@ -956,11 +876,6 @@ const LEFT_SHIFT2 = 4.0;
const RIGHT_SHIFT8 = 1.0 / 256.0;
const LOWER_LEFT = 0.0;
const LOWER_RIGHT = 2.0;
const UPPER_RIGHT = 3.0;
const UPPER_LEFT = 1.0;
const scratchBoundingRectangle = new BoundingRectangle();
function writeCompressedAttrib0(
@ -969,7 +884,6 @@ function writeCompressedAttrib0(
vafWriters,
billboard,
) {
let i;
const writer = vafWriters[attributeLocations.compressedAttribute0];
const pixelOffset = billboard.pixelOffset;
const pixelOffsetX = pixelOffset.x;
@ -1007,17 +921,17 @@ function writeCompressedAttrib0(
billboardCollection._allVerticalCenter &&
verticalOrigin === VerticalOrigin.CENTER;
// Compute image coordinates and size, in pixels. Coordinates are from lower-left of texture atlas.Z
let imageX = 0;
let imageY = 0;
let imageWidth = 0;
let imageHeight = 0;
// Compute offset (in pixels) from lower-left of the texture atlas.
let imageOffsetX = 0;
let imageOffsetY = 0;
if (billboard.ready) {
billboard.computeImageCoordinates(scratchBoundingRectangle);
imageX = scratchBoundingRectangle.x;
imageY = scratchBoundingRectangle.y;
imageWidth = scratchBoundingRectangle.width;
imageHeight = scratchBoundingRectangle.height;
const imageRectangle = billboard.computeTextureCoordinates(
scratchBoundingRectangle,
);
const { width: atlasWidth, height: atlasHeight } =
billboardCollection.textureAtlas.texture;
imageOffsetX = imageRectangle.x * atlasWidth;
imageOffsetY = imageRectangle.y * atlasHeight;
}
let compressed0 =
@ -1055,48 +969,10 @@ function writeCompressedAttrib0(
compressed1 += upperTranslateY;
compressed2 += lowerTranslateY;
// Compress image coordinates (px), integers 0-2^12 from lower-left of atlas. Avoid
// `AttributeCompression.compressTextureCoordinates` for lossless pixel values.
const compressedImageLL = imageX * LEFT_SHIFT12 + imageY;
const compressedImageLR = (imageX + imageWidth) * LEFT_SHIFT12 + imageY;
const compressedImageUR =
(imageX + imageWidth) * LEFT_SHIFT12 + imageY + imageHeight;
const compressedImageUL = imageX * LEFT_SHIFT12 + imageY + imageHeight;
const compressedImageOffsetLL = imageOffsetX * LEFT_SHIFT16 + imageOffsetY;
if (billboardCollection._instanced) {
i = billboard._index;
writer(i, compressed0, compressed1, compressed2, compressedImageLL);
} else {
i = billboard._index * 4;
writer(
i + 0,
compressed0 + LOWER_LEFT,
compressed1,
compressed2,
compressedImageLL,
);
writer(
i + 1,
compressed0 + LOWER_RIGHT,
compressed1,
compressed2,
compressedImageLR,
);
writer(
i + 2,
compressed0 + UPPER_RIGHT,
compressed1,
compressed2,
compressedImageUR,
);
writer(
i + 3,
compressed0 + UPPER_LEFT,
compressed1,
compressed2,
compressedImageUL,
);
}
const i = billboard._index;
writer(i, compressed0, compressed1, compressed2, compressedImageOffsetLL);
}
function writeCompressedAttrib1(
@ -1105,7 +981,6 @@ function writeCompressedAttrib1(
vafWriters,
billboard,
) {
let i;
const writer = vafWriters[attributeLocations.compressedAttribute1];
const alignedAxis = billboard.alignedAxis;
if (!Cartesian3.equals(alignedAxis, Cartesian3.ZERO)) {
@ -1155,16 +1030,8 @@ function writeCompressedAttrib1(
farValue = farValue === 1.0 ? 255.0 : (farValue * 255.0) | 0;
compressed1 = compressed1 * LEFT_SHIFT8 + farValue;
if (billboardCollection._instanced) {
i = billboard._index;
writer(i, compressed0, compressed1, near, far);
} else {
i = billboard._index * 4;
writer(i + 0, compressed0, compressed1, near, far);
writer(i + 1, compressed0, compressed1, near, far);
writer(i + 2, compressed0, compressed1, near, far);
writer(i + 3, compressed0, compressed1, near, far);
}
const i = billboard._index;
writer(i, compressed0, compressed1, near, far);
}
function writeCompressedAttrib2(
@ -1173,7 +1040,6 @@ function writeCompressedAttrib2(
vafWriters,
billboard,
) {
let i;
const writer = vafWriters[attributeLocations.compressedAttribute2];
const color = billboard.color;
const pickColor = !defined(billboardCollection._batchTable)
@ -1213,16 +1079,8 @@ function writeCompressedAttrib2(
Color.floatToByte(pickColor.alpha) * LEFT_SHIFT8;
compressed2 += sizeInMeters * 2.0 + validAlignedAxis;
if (billboardCollection._instanced) {
i = billboard._index;
writer(i, compressed0, compressed1, compressed2, compressed3);
} else {
i = billboard._index * 4;
writer(i + 0, compressed0, compressed1, compressed2, compressed3);
writer(i + 1, compressed0, compressed1, compressed2, compressed3);
writer(i + 2, compressed0, compressed1, compressed2, compressed3);
writer(i + 3, compressed0, compressed1, compressed2, compressed3);
}
const i = billboard._index;
writer(i, compressed0, compressed1, compressed2, compressed3);
}
function writeEyeOffset(
@ -1231,7 +1089,6 @@ function writeEyeOffset(
vafWriters,
billboard,
) {
let i;
const writer = vafWriters[attributeLocations.eyeOffset];
const eyeOffset = billboard.eyeOffset;
@ -1247,16 +1104,8 @@ function writeEyeOffset(
Math.abs(eyeOffsetZ),
);
if (billboardCollection._instanced) {
i = billboard._index;
writer(i, eyeOffset.x, eyeOffset.y, eyeOffsetZ, 0.0);
} else {
i = billboard._index * 4;
writer(i + 0, eyeOffset.x, eyeOffset.y, eyeOffsetZ, 0.0);
writer(i + 1, eyeOffset.x, eyeOffset.y, eyeOffsetZ, 0.0);
writer(i + 2, eyeOffset.x, eyeOffset.y, eyeOffsetZ, 0.0);
writer(i + 3, eyeOffset.x, eyeOffset.y, eyeOffsetZ, 0.0);
}
const i = billboard._index;
writer(i, eyeOffset.x, eyeOffset.y, eyeOffsetZ, 0.0);
}
function writeScaleByDistance(
@ -1265,7 +1114,6 @@ function writeScaleByDistance(
vafWriters,
billboard,
) {
let i;
const writer = vafWriters[attributeLocations.scaleByDistance];
let near = 0.0;
let nearValue = 1.0;
@ -1286,16 +1134,8 @@ function writeScaleByDistance(
}
}
if (billboardCollection._instanced) {
i = billboard._index;
writer(i, near, nearValue, far, farValue);
} else {
i = billboard._index * 4;
writer(i + 0, near, nearValue, far, farValue);
writer(i + 1, near, nearValue, far, farValue);
writer(i + 2, near, nearValue, far, farValue);
writer(i + 3, near, nearValue, far, farValue);
}
const i = billboard._index;
writer(i, near, nearValue, far, farValue);
}
function writePixelOffsetScaleByDistance(
@ -1304,7 +1144,6 @@ function writePixelOffsetScaleByDistance(
vafWriters,
billboard,
) {
let i;
const writer = vafWriters[attributeLocations.pixelOffsetScaleByDistance];
let near = 0.0;
let nearValue = 1.0;
@ -1325,16 +1164,8 @@ function writePixelOffsetScaleByDistance(
}
}
if (billboardCollection._instanced) {
i = billboard._index;
writer(i, near, nearValue, far, farValue);
} else {
i = billboard._index * 4;
writer(i + 0, near, nearValue, far, farValue);
writer(i + 1, near, nearValue, far, farValue);
writer(i + 2, near, nearValue, far, farValue);
writer(i + 3, near, nearValue, far, farValue);
}
const i = billboard._index;
writer(i, near, nearValue, far, farValue);
}
function writeCompressedAttribute3(
@ -1343,7 +1174,6 @@ function writeCompressedAttribute3(
vafWriters,
billboard,
) {
let i;
const writer = vafWriters[attributeLocations.compressedAttribute3];
let near = 0.0;
let far = Number.MAX_VALUE;
@ -1387,16 +1217,8 @@ function writeCompressedAttribute3(
const h = Math.floor(CesiumMath.clamp(imageHeight, 0.0, LEFT_SHIFT12));
const dimensions = w * LEFT_SHIFT12 + h;
if (billboardCollection._instanced) {
i = billboard._index;
writer(i, near, far, disableDepthTestDistance, dimensions);
} else {
i = billboard._index * 4;
writer(i + 0, near, far, disableDepthTestDistance, dimensions);
writer(i + 1, near, far, disableDepthTestDistance, dimensions);
writer(i + 2, near, far, disableDepthTestDistance, dimensions);
writer(i + 3, near, far, disableDepthTestDistance, dimensions);
}
const i = billboard._index;
writer(i, near, far, disableDepthTestDistance, dimensions);
}
function writeTextureCoordinateBoundsOrLabelTranslate(
@ -1428,16 +1250,9 @@ function writeTextureCoordinateBoundsOrLabelTranslate(
translateX = billboard._labelTranslate.x;
translateY = billboard._labelTranslate.y;
}
if (billboardCollection._instanced) {
i = billboard._index;
writer(i, translateX, translateY, 0.0, 0.0);
} else {
i = billboard._index * 4;
writer(i + 0, translateX, translateY, 0.0, 0.0);
writer(i + 1, translateX, translateY, 0.0, 0.0);
writer(i + 2, translateX, translateY, 0.0, 0.0);
writer(i + 3, translateX, translateY, 0.0, 0.0);
}
i = billboard._index;
writer(i, translateX, translateY, 0.0, 0.0);
return;
}
@ -1459,16 +1274,8 @@ function writeTextureCoordinateBoundsOrLabelTranslate(
const maxX = minX + width;
const maxY = minY + height;
if (billboardCollection._instanced) {
i = billboard._index;
writer(i, minX, minY, maxX, maxY);
} else {
i = billboard._index * 4;
writer(i + 0, minX, minY, maxX, maxY);
writer(i + 1, minX, minY, maxX, maxY);
writer(i + 2, minX, minY, maxX, maxY);
writer(i + 3, minX, minY, maxX, maxY);
}
i = billboard._index;
writer(i, minX, minY, maxX, maxY);
}
function writeBatchId(billboardCollection, frameState, vafWriters, billboard) {
@ -1479,17 +1286,8 @@ function writeBatchId(billboardCollection, frameState, vafWriters, billboard) {
const writer = vafWriters[attributeLocations.a_batchId];
const id = billboard._batchIndex;
let i;
if (billboardCollection._instanced) {
i = billboard._index;
writer(i, id);
} else {
i = billboard._index * 4;
writer(i + 0, id);
writer(i + 1, id);
writer(i + 2, id);
writer(i + 3, id);
}
const i = billboard._index;
writer(i, id);
}
function writeSDF(billboardCollection, frameState, vafWriters, billboard) {
@ -1497,7 +1295,6 @@ function writeSDF(billboardCollection, frameState, vafWriters, billboard) {
return;
}
let i;
const writer = vafWriters[attributeLocations.sdf];
const outlineColor = billboard.outlineColor;
@ -1514,16 +1311,8 @@ function writeSDF(billboardCollection, frameState, vafWriters, billboard) {
Color.floatToByte(outlineColor.alpha) * LEFT_SHIFT16 +
Color.floatToByte(outlineDistance) * LEFT_SHIFT8;
if (billboardCollection._instanced) {
i = billboard._index;
writer(i, compressed0, compressed1);
} else {
i = billboard._index * 4;
writer(i + 0, compressed0 + LOWER_LEFT, compressed1);
writer(i + 1, compressed0 + LOWER_RIGHT, compressed1);
writer(i + 2, compressed0 + UPPER_RIGHT, compressed1);
writer(i + 3, compressed0 + UPPER_LEFT, compressed1);
}
const i = billboard._index;
writer(i, compressed0, compressed1);
}
function writeSplitDirection(
@ -1540,17 +1329,8 @@ function writeSplitDirection(
direction = split;
}
let i;
if (billboardCollection._instanced) {
i = billboard._index;
writer(i, direction);
} else {
i = billboard._index * 4;
writer(i + 0, direction);
writer(i + 1, direction);
writer(i + 2, direction);
writer(i + 3, direction);
}
const i = billboard._index;
writer(i, direction);
}
function writeBillboard(
@ -1762,13 +1542,6 @@ BillboardCollection.prototype.update = function (frameState) {
}
const context = frameState.context;
this._instanced = context.instancedArrays;
attributeLocations = this._instanced
? attributeLocationsInstanced
: attributeLocationsBatched;
getIndexBuffer = this._instanced
? getIndexBufferInstanced
: getIndexBufferBatched;
let billboards = this._billboards;
let billboardsLength = billboards.length;
@ -1841,7 +1614,6 @@ BillboardCollection.prototype.update = function (frameState) {
context,
billboardsLength,
this._buffersUsage,
this._instanced,
this._batchTable,
this._sdf,
);
@ -1881,9 +1653,7 @@ BillboardCollection.prototype.update = function (frameState) {
properties[SHOW_INDEX]
) {
writers.push(writeCompressedAttrib0);
if (this._instanced) {
writers.push(writeEyeOffset);
}
writers.push(writeEyeOffset);
}
if (
@ -1960,11 +1730,7 @@ BillboardCollection.prototype.update = function (frameState) {
writers[o](this, frameState, vafWriters, bb);
}
if (this._instanced) {
this._vaf.subCommit(bb._index, 1);
} else {
this._vaf.subCommit(bb._index * 4, 4);
}
this._vaf.subCommit(bb._index, 1);
}
this._vaf.endSubCommits();
}
@ -2098,9 +1864,6 @@ BillboardCollection.prototype.update = function (frameState) {
defines: vertDefines,
sources: [vsSource],
});
if (this._instanced) {
vs.defines.push("INSTANCED");
}
if (this._shaderRotation) {
vs.defines.push("ROTATION");
}
@ -2300,10 +2063,8 @@ BillboardCollection.prototype.update = function (frameState) {
command.debugShowBoundingVolume = this.debugShowBoundingVolume;
command.pickId = pickId;
if (this._instanced) {
command.count = 6;
command.instanceCount = billboardsLength;
}
command.count = 6;
command.instanceCount = billboardsLength;
commandList.push(command);
}

View File

@ -334,17 +334,6 @@ BillboardTexture.prototype.setImageSubRegion = function (index, subRegion) {
this.dirty = true;
};
/**
* Get the image coordinates for reading the loaded texture in shaders.
* @private
* @param {BoundingRectangle} [result] The modified result parameter or a new BoundingRectangle instance if one was not provided.
* @return {BoundingRectangle} The modified result parameter or a new BoundingRectangle instance if one was not provided.
*/
BillboardTexture.prototype.computeImageCoordinates = function (result) {
const atlas = this._billboardCollection.textureAtlas;
return atlas.computeImageCoordinates(this._index, result);
};
/**
* Get the texture coordinates for reading the loaded texture in shaders.
* @private

View File

@ -1,8 +1,6 @@
uniform vec2 u_atlasSize;
uniform float u_threePointDepthTestDistance;
#ifdef INSTANCED
in vec2 direction;
#endif
in vec4 positionHighAndScale;
in vec4 positionLowAndRotation;
in vec4 compressedAttribute0; // pixel offset, translate, horizontal origin, vertical origin, show, direction, texture coordinates (texture offset)
@ -148,12 +146,6 @@ void main()
float show = floor(compressed * SHIFT_RIGHT2);
compressed -= show * SHIFT_LEFT2;
#ifndef INSTANCED
vec2 direction;
direction.x = floor(compressed * SHIFT_RIGHT1);
direction.y = compressed - direction.x * SHIFT_LEFT1;
#endif
float temp = compressedAttribute0.y * SHIFT_RIGHT8;
pixelOffset.y = -(floor(temp) - UPPER_BOUND);
@ -168,19 +160,16 @@ void main()
translate.y -= UPPER_BOUND;
translate.y *= SHIFT_RIGHT2;
// TODO(donmccurdy): This is billboard size (px) on screen, not image size (px) in atlas?
float imageWidth = floor(compressedAttribute1.x * SHIFT_RIGHT8);
float imageHeight = floor(compressedAttribute2.w * SHIFT_RIGHT2);
vec2 imageSize = vec2(imageWidth, imageHeight);
temp = compressedAttribute1.x * SHIFT_RIGHT8;
float temp2 = floor(compressedAttribute2.w * SHIFT_RIGHT2);
float imageOffsetX = floor(compressedAttribute0.w * SHIFT_RIGHT12);
float imageOffsetY = compressedAttribute0.w - (imageOffsetX * SHIFT_LEFT12);
vec2 textureCoordinates = vec2(imageOffsetX + 0.5, imageOffsetY + 0.5) / u_atlasSize.xy;
vec2 imageSize = vec2(floor(temp), temp2);
#ifdef INSTANCED
vec2 textureCoordinatesRange = imageSize.xy / u_atlasSize.xy; // TODO(donmccurdy): Needs -1.0 offset?
textureCoordinates += direction * textureCoordinatesRange;
#endif
float imageOffsetX = floor(compressedAttribute0.w * SHIFT_RIGHT16);
float imageOffsetY = compressedAttribute0.w - (imageOffsetX * SHIFT_LEFT16);
vec2 textureCoordinatesBottomLeft = vec2(imageOffsetX, imageOffsetY) / u_atlasSize.xy;
vec2 textureCoordinatesRange = imageSize.xy / u_atlasSize.xy;
vec2 textureCoordinates = textureCoordinatesBottomLeft + direction * textureCoordinatesRange;
#ifdef FS_THREE_POINT_DEPTH_CHECK
float labelHorizontalOrigin = floor(compressedAttribute2.w - (temp2 * SHIFT_LEFT2));