赞
踩
Cesium中针对3DTile瓦片的拾取、调试时设置瓦片颜色的两个过程需要BatchTexture.js这个类。
瓦片拾取的过程:瓦片拾取的过程是,创建每一个gltf模型时给模型绑定一个数值id,并使用这个数值id创建一个颜色,拾取的时候模型使用该颜色值渲染到一张图片上,渲染后再鼠标所在的坐标位置采集图片上的颜色值,根据颜色转换为原来的数值id,最后根据这个数值id找到对应的模型,例如:数值的123,将123转换成颜色RGBA, 将123分成4个8位,不足的再前面补0,则生成的值为RGBA=(123,0,0,0); 并将这个颜色做成图片为模型提供采样的纹理。
调试时的瓦片颜色【或者】Cesium3DTileStyle中根据属性设置颜色: cesium的这个调试方式还是很好的,如果是包围盒显示的杂乱,将每一个瓦片设置不同的颜色很好分辨,颜色的设置过程也比较简单,主要是根据瓦片中要素的数量创建相同的颜色个数,然后将每个瓦片的这些个颜色创建成一张图片,与瓦片的原有纹理在glsl中进行混合运算。
缺点:这个过程要创建很多的纹理,占用显存
具体的代码如下:
- /**
- * An object that manages color, show/hide and picking textures for a batch
- * table or feature table.
- * 一个对象,用于管理批次的颜色、显示/隐藏和拾取纹理表或特征表。
- *
- * @param {Object} options Object with the following properties:
- * @param {Number} featuresLength The number of features in the batch table or feature table
- * @param {Cesium3DTileContent|ModelFeatureTable} owner The owner of this batch texture. For 3D Tiles, this will be a {@link Cesium3DTileContent}. For glTF models, this will be a {@link ModelFeatureTable}.
- * @param {Object} [statistics] The statistics object to update with information about the batch texture.
- * @param {Function} [colorChangedCallback] A callback function that is called whenever the color of a feature changes.
- *
- * @alias BatchTexture
- * @constructor
- *
- * @private
- */
- export default function BatchTexture(options) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.number("options.featuresLength", options.featuresLength);
- Check.typeOf.object("options.owner", options.owner);
- //>>includeEnd('debug');
- // 要素个数
- var featuresLength = options.featuresLength;
-
- // PERFORMANCE_IDEA: These parallel arrays probably generate cache misses in get/set color/show
- // 这些并行数组可能会在get/set-color/show中生成缓存未命中,使用很多的内存,怎么时候很少的内存呢?
- // and use A LOT of memory. How can we use less memory?
-
- // 透明相关信息,两个字节,是否显示和透明度,是否显示使用0表示隐藏,255表示显示
- this._showAlphaProperties = undefined; // [Show (0 or 255), Alpha (0 to 255)] property for each feature
- // 批次表值
- this._batchValues = undefined; // Per-feature RGBA (A is based on the color's alpha and feature's show property)
-
- // 批次表值脏了
- this._batchValuesDirty = false;
- // 批次纹理
- this._batchTexture = undefined; // 漫反射 叠加 自定义颜色纹理(debug下的瓦片颜色)
- // 默认批次
- this._defaultTexture = undefined;
-
- // 拾取纹理
- this._pickTexture = undefined; // 拾取纹理
- // 拾取的id
- this._pickIds = [];
-
- // Dimensions for batch and pick textures
- // 批次表、拾取的纹理尺寸
- var textureDimensions;
- var textureStep;
-
- // 要素数量
- if (featuresLength > 0) {
- // PERFORMANCE_IDEA: this can waste memory in the last row in the uncommon case
- // when more than one row is needed (e.g., > 16K features in one tile) 在需要多行的情况下,这会浪费最后一行的内存
-
- // 纹理宽度
- var width = Math.min(featuresLength, ContextLimits.maximumTextureSize);
- // 纹理高度
- var height = Math.ceil(featuresLength / ContextLimits.maximumTextureSize);
- // x步长
- var stepX = 1.0 / width;
- var centerX = stepX * 0.5;
- // y步长
- var stepY = 1.0 / height;
- var centerY = stepY * 0.5;
-
- // 纹理大小
- textureDimensions = new Cartesian2(width, height);
- // 纹理步长
- textureStep = new Cartesian4(stepX, centerX, stepY, centerY);
- }
-
- // 透明要素长度
- this._translucentFeaturesLength = 0;
- // 要素数量
- this._featuresLength = featuresLength;
- // 纹理尺寸
- this._textureDimensions = textureDimensions;
- // 纹理步长
- this._textureStep = textureStep;
- // 主人
- this._owner = options.owner;
- // 统计
- this._statistics = options.statistics;
- // 颜色改变回调
- this._colorChangedCallback = options.colorChangedCallback;
- }
-
- Object.defineProperties(BatchTexture.prototype, {
- /**
- * Number of features that are translucent
- * 透明要素的数量
- *
- * @memberof BatchTexture.prototype
- * @type {Number}
- * @readonly
- * @private
- */
- translucentFeaturesLength: {
- get: function () {
- return this._translucentFeaturesLength;
- },
- },
-
- /**
- * Total size of all GPU resources used by this batch texture.
- * 批次表纹理显存
- *
- * @memberof BatchTexture.prototype
- * @type {Number}
- * @readonly
- * @private
- */
- memorySizeInBytes: {
- get: function () {
- var memory = 0;
- // 拾取纹理
- if (defined(this._pickTexture)) {
- memory += this._pickTexture.sizeInBytes;
- }
- // 批次表纹理
- if (defined(this._batchTexture)) {
- memory += this._batchTexture.sizeInBytes;
- }
- return memory;
- },
- },
-
- /**
- * Dimensions of the underlying batch texture.
- * 纹理尺寸
- *
- * @memberof BatchTexture.prototype
- * @type {Cartesian2}
- * @readonly
- * @private
- */
- textureDimensions: {
- get: function () {
- return this._textureDimensions;
- },
- },
-
- /**
- * Size of each texture and distance from side to center of a texel in
- * each direction. Stored as (stepX, centerX, stepY, centerY)
- * 步长
- *
- * @memberof BatchTexture.prototype
- * @type {Cartesian4}
- * @readonly
- * @private
- */
- textureStep: {
- get: function () {
- return this._textureStep;
- },
- },
-
- /**
- * The underlying texture used for styling. The texels are accessed
- * by batch ID, and the value is the color of this feature after accounting
- * for show/hide settings.
- * 批次纹理
- *
- * @memberof BatchTexture.prototype
- * @type {Texture}
- * @readonly
- * @private
- */
- batchTexture: {
- get: function () {
- return this._batchTexture;
- },
- },
-
- /**
- * The default texture to use when there are no batch values
- * 没有批次表时的默认纹理
- *
- * @memberof BatchTexture.prototype
- * @type {Texture}
- * @readonly
- * @private
- */
- defaultTexture: {
- get: function () {
- return this._defaultTexture;
- },
- },
-
- /**
- * The underlying texture used for picking. The texels are accessed by
- * batch ID, and the value is the pick color.
- * 拾取的纹理
- *
- * @memberof BatchTexture.prototype
- * @type {Texture}
- * @readonly
- * @private
- */
- pickTexture: {
- get: function () {
- return this._pickTexture;
- },
- },
- });
-
- BatchTexture.DEFAULT_COLOR_VALUE = Color.WHITE;
- BatchTexture.DEFAULT_SHOW_VALUE = true;
-
- // 批次表纹理数量
- function getByteLength(batchTexture) {
- var dimensions = batchTexture._textureDimensions;
- return dimensions.x * dimensions.y * 4;
- }
-
- // 获取批次表的值
- function getBatchValues(batchTexture) {
- if (!defined(batchTexture._batchValues)) {
- // Default batch texture to RGBA = 255: white highlight (RGB) and show/alpha = true/255 (A).
- var byteLength = getByteLength(batchTexture);
- // 创建内存
- var bytes = new Uint8Array(byteLength);
- // 填充255
- arrayFill(bytes, 255);
- // 批次表值
- batchTexture._batchValues = bytes;
- }
-
- return batchTexture._batchValues;
- }
-
- // 透明度值
- function getShowAlphaProperties(batchTexture) {
- if (!defined(batchTexture._showAlphaProperties)) {
- var byteLength = 2 * batchTexture._featuresLength;
- var bytes = new Uint8Array(byteLength);
- // [Show = true, Alpha = 255] 存储了两个值,一个是是否显示,一个是透明度
- arrayFill(bytes, 255);
- batchTexture._showAlphaProperties = bytes;
- }
- return batchTexture._showAlphaProperties;
- }
-
- // 检查批次表id
- function checkBatchId(batchId, featuresLength) {
- if (!defined(batchId) || batchId < 0 || batchId >= featuresLength) {
- throw new DeveloperError(
- "batchId is required and between zero and featuresLength - 1 (" +
- featuresLength -
- +")."
- );
- }
- }
-
- /**
- * Set whether a feature is visible.
- * 设置哪一个要素是可见的
- *
- * @param {Number} batchId the ID of the feature
- * @param {Boolean} show <code>true</code> if the feature should be shown, <code>false</code> otherwise
- * @private
- */
- BatchTexture.prototype.setShow = function (batchId, show) {
- //>>includeStart('debug', pragmas.debug);
- checkBatchId(batchId, this._featuresLength);
- Check.typeOf.bool("show", show);
- //>>includeEnd('debug');
- // 原来是显示的,别处修改了透明度,这里就需要处理,如果没有透明属性,就不在处理了
- if (show && !defined(this._showAlphaProperties)) {
- // Avoid allocating since the default is show = true
- return;
- }
-
- // 显示属性
- var showAlphaProperties = getShowAlphaProperties(this);
- // 存储了两个值,一个是是否显示,一个是透明度
- var propertyOffset = batchId * 2;
-
- // 显示
- var newShow = show ? 255 : 0;
- // 设置显示
- if (showAlphaProperties[propertyOffset] !== newShow) {
- showAlphaProperties[propertyOffset] = newShow;
-
- // 获取批次表值
- var batchValues = getBatchValues(this);
-
- // Compute alpha used in the shader based on show and color.alpha properties
- var offset = batchId * 4 + 3;
- // 设置批次表的显示透明度
- batchValues[offset] = show ? showAlphaProperties[propertyOffset + 1] : 0;
-
- // 批次表脏了
- this._batchValuesDirty = true;
- }
- };
-
- /**
- * Set the show for all features at once.
- * 显示所有的要素
- *
- * @param {Boolean} show <code>true</code> if the feature should be shown, <code>false</code> otherwise
- * @private
- */
- BatchTexture.prototype.setAllShow = function (show) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.bool("show", show);
- //>>includeEnd('debug');
- var featuresLength = this._featuresLength;
- for (var i = 0; i < featuresLength; ++i) {
- this.setShow(i, show);
- }
- };
-
- /**
- * Check the current show value for a feature
- * 获取当前的显示值
- *
- * @param {Number} batchId the ID of the feature
- * @return {Boolean} <code>true</code> if the feature is shown, or <code>false</code> otherwise
- * @private
- */
- BatchTexture.prototype.getShow = function (batchId) {
- //>>includeStart('debug', pragmas.debug);
- checkBatchId(batchId, this._featuresLength);
- //>>includeEnd('debug');
- if (!defined(this._showAlphaProperties)) {
- // Avoid allocating since the default is show = true
- return true;
- }
-
- var offset = batchId * 2;
- return this._showAlphaProperties[offset] === 255;
- };
-
- var scratchColorBytes = new Array(4);
-
- /**
- * Set the styling color of a feature
- * 设置要素的样式颜色
- *
- * @param {Number} batchId the ID of the feature
- * @param {Color} color the color to assign to this feature.
- *
- * @private
- */
- BatchTexture.prototype.setColor = function (batchId, color) {
- //>>includeStart('debug', pragmas.debug);
- checkBatchId(batchId, this._featuresLength);
- Check.typeOf.object("color", color);
- //>>includeEnd('debug');
- if (
- Color.equals(color, BatchTexture.DEFAULT_COLOR_VALUE) &&
- !defined(this._batchValues)
- ) {
- // Avoid allocating since the default is white
- return;
- }
-
- // 转换成颜色字节
- var newColor = color.toBytes(scratchColorBytes);
- // 新的颜色
- var newAlpha = newColor[3];
-
- var batchValues = getBatchValues(this);
- var offset = batchId * 4;
-
- var showAlphaProperties = getShowAlphaProperties(this);
- var propertyOffset = batchId * 2;
-
- if (
- batchValues[offset] !== newColor[0] ||
- batchValues[offset + 1] !== newColor[1] ||
- batchValues[offset + 2] !== newColor[2] ||
- showAlphaProperties[propertyOffset + 1] !== newAlpha
- ) {
- batchValues[offset] = newColor[0];
- batchValues[offset + 1] = newColor[1];
- batchValues[offset + 2] = newColor[2];
-
- var wasTranslucent = showAlphaProperties[propertyOffset + 1] !== 255;
-
- // Compute alpha used in the shader based on show and color.alpha properties
- var show = showAlphaProperties[propertyOffset] !== 0;
- batchValues[offset + 3] = show ? newAlpha : 0;
- showAlphaProperties[propertyOffset + 1] = newAlpha;
-
- // Track number of translucent features so we know if this tile needs
- // opaque commands, translucent commands, or both for rendering.
- var isTranslucent = newAlpha !== 255;
- if (isTranslucent && !wasTranslucent) {
- ++this._translucentFeaturesLength;
- } else if (!isTranslucent && wasTranslucent) {
- --this._translucentFeaturesLength;
- }
-
- this._batchValuesDirty = true;
-
- if (defined(this._colorChangedCallback)) {
- this._colorChangedCallback(batchId, color);
- }
- }
- };
-
- /**
- * Set the styling color for all features at once
- * 设置所有要素的颜色
- *
- * @param {Color} color the color to assign to all features.
- *
- * @private
- */
- BatchTexture.prototype.setAllColor = function (color) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("color", color);
- //>>includeEnd('debug');
- var featuresLength = this._featuresLength;
- for (var i = 0; i < featuresLength; ++i) {
- this.setColor(i, color);
- }
- };
-
- /**
- * Get the current color of a feature
- * 获取要素的当前颜色
- *
- * @param {Number} batchId The ID of the feature
- * @param {Color} result A color object where the result will be stored.
- * @return {Color} The color assigned to the selected feature
- *
- * @private
- */
- BatchTexture.prototype.getColor = function (batchId, result) {
- //>>includeStart('debug', pragmas.debug);
- checkBatchId(batchId, this._featuresLength);
- Check.typeOf.object("result", result);
- //>>includeEnd('debug');
- if (!defined(this._batchValues)) {
- return Color.clone(BatchTexture.DEFAULT_COLOR_VALUE, result);
- }
-
- var batchValues = this._batchValues;
- var offset = batchId * 4;
-
- var showAlphaProperties = this._showAlphaProperties;
- var propertyOffset = batchId * 2;
-
- return Color.fromBytes(
- batchValues[offset],
- batchValues[offset + 1],
- batchValues[offset + 2],
- showAlphaProperties[propertyOffset + 1],
- result
- );
- };
-
- /**
- * Get the pick color of a feature. This feature is an RGBA encoding of the
- * pick ID.
- * 获取拾取的颜色,
- *
- * @param {Number} batchId The ID of the feature
- * @return {PickId} The picking color assigned to this feature
- *
- * @private
- */
- BatchTexture.prototype.getPickColor = function (batchId) {
- //>>includeStart('debug', pragmas.debug);
- checkBatchId(batchId, this._featuresLength);
- //>>includeEnd('debug');
- return this._pickIds[batchId];
- };
-
- // 创建纹理
- function createTexture(batchTexture, context, bytes) {
- var dimensions = batchTexture._textureDimensions;
- // 创建纹理
- return new Texture({
- context: context, // webgl上下文
- pixelFormat: PixelFormat.RGBA, // 格式
- pixelDatatype: PixelDatatype.UNSIGNED_BYTE, // 像素数据的类型
- source: { // 数据源
- width: dimensions.x, // 纹理宽度
- height: dimensions.y, // 纹理高度
- arrayBufferView: bytes, // 纹理数据
- },
- flipY: false, // 是否反转Y
- sampler: Sampler.NEAREST, // 插值方式
- });
- }
-
- // 创建拾取纹理
- function createPickTexture(batchTexture, context) {
- // 要素数量
- var featuresLength = batchTexture._featuresLength;
- // 有要素、没有纹理
- if (!defined(batchTexture._pickTexture) && featuresLength > 0) {
- // 批次表id
- var pickIds = batchTexture._pickIds;
- // 批次表纹理占用的字节数量
- var byteLength = getByteLength(batchTexture);
- // 创建内存
- var bytes = new Uint8Array(byteLength);
- // 主人
- var owner = batchTexture._owner;
- // 统计信息
- var statistics = batchTexture._statistics;
-
- // PERFORMANCE_IDEA: we could skip the pick texture completely by allocating
- // a continuous range of pickIds and then converting the base pickId + batchId
- // to RGBA in the shader. The only consider is precision issues, which might
- // not be an issue in WebGL 2.
- // 我们可以通过分配连续范围的pickId,然后在着色器中将基础pickId+batchId转换为RGBA,从而完全跳过拾取纹理。
- // 唯一需要考虑的是精度问题,这在WebGL 2中可能不是一个问题。
-
- // 遍历要素
- for (var i = 0; i < featuresLength; ++i) {
- // 绑定拾取对象、颜色值
- var pickId = context.createPickId(owner.getFeature(i));
- // 将id添加到pickIds中
- pickIds.push(pickId);
- // 颜色
- var pickColor = pickId.color;
- // 偏移
- var offset = i * 4;
- // 设置pick颜色
- bytes[offset] = Color.floatToByte(pickColor.red);
- bytes[offset + 1] = Color.floatToByte(pickColor.green);
- bytes[offset + 2] = Color.floatToByte(pickColor.blue);
- bytes[offset + 3] = Color.floatToByte(pickColor.alpha);
- }
-
- // 创建拾取纹理
- batchTexture._pickTexture = createTexture(batchTexture, context, bytes);
- if (defined(statistics)) {
- // 批次表长度
- statistics.batchTableByteLength += batchTexture._pickTexture.sizeInBytes;
- }
- }
- }
-
- // 更新批次表pick纹理,将id拷贝到纹理上
- function updateBatchTexture(batchTexture) {
- // 纹理尺寸
- var dimensions = batchTexture._textureDimensions;
- // PERFORMANCE_IDEA: Instead of rewriting the entire texture, use fine-grained
- // texture updates when less than, for example, 10%, of the values changed. Or
- // even just optimize the common case when one feature show/color changed.
-
- // 将数据拷贝到纹理上
- batchTexture._batchTexture.copyFrom({
- source: {
- width: dimensions.x,
- height: dimensions.y,
- arrayBufferView: batchTexture._batchValues,
- },
- });
- }
-
- // 更新
- BatchTexture.prototype.update = function (tileset, frameState) {
- var context = frameState.context;
- // 默认纹理
- this._defaultTexture = context.defaultTexture;
-
- // 渲染那个过程
- var passes = frameState.passes;
- // 拾取的过程或者后处理的过程
- if (passes.pick || passes.postProcess) {
- // 创建拾取的纹理(没有就创建,有了就不在创建)
- createPickTexture(this, context);
- }
-
- // 批次表的pick颜色被修改了
- if (this._batchValuesDirty) {
- this._batchValuesDirty = false;
-
- // Create batch texture on-demand
- // 创建批次纹理(纹理大小改变了,重新创建纹理)-- 漫反射 叠加 自定义颜色(debug下的瓦片颜色)
- if (!defined(this._batchTexture)) {
- // 重新创建批次纹理
- this._batchTexture = createTexture(this, context, this._batchValues);
- if (defined(this._statistics)) {
- // 统计批次表所占的内存
- this._statistics.batchTableByteLength += this._batchTexture.sizeInBytes;
- }
- }
-
- // 用于每一个要素的显示和颜色更新
- updateBatchTexture(this); // Apply per-feature show/color updates
- }
- };
-
- /**
- * Returns true if this object was destroyed; otherwise, false.
- * <p>
- * If this object was destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
- * </p>
- *
- * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
- *
- * @see BatchTexture#destroy
- * @private
- */
- BatchTexture.prototype.isDestroyed = function () {
- return false;
- };
-
- /**
- * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
- * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
- * <p>
- * Once an object is destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
- * assign the return value (<code>undefined</code>) to the object as done in the example.
- * </p>
- *
- * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
- *
- * @example
- * e = e && e.destroy();
- *
- * @see BatchTexture#isDestroyed
- * @private
- */
- // 销毁
- BatchTexture.prototype.destroy = function () {
- // 批次纹理
- this._batchTexture = this._batchTexture && this._batchTexture.destroy();
- // 拾取纹理
- this._pickTexture = this._pickTexture && this._pickTexture.destroy();
-
- // 拾取id
- var pickIds = this._pickIds;
- // 拾取id
- var length = pickIds.length;
- for (var i = 0; i < length; ++i) {
- // 销毁
- pickIds[i].destroy();
- }
-
- return destroyObject(this);
- };
1、在构造函数BatchTexture中的的属性中:
a、featuresLength:代表要素的数量,这个要参考3dtile的数据规范,要素代表着一个瓦片中单体的数量;
b、_showAlphaProperties:这个属性的数量与要素数量相同,代表着每一个单体是否显示、以及透明度(透明度是瓦片原有纹理颜色和设置颜色的混合比例);
c、_batchValues:这个属性代表着混合的颜色值,以及与_showAlphaProperties中的alpha值相同的透明度;
d、_pickIds:这个参数是用于拾取的,是一个数组,其中包含了每个要素的对象信息,例如瓦片中模型的id,以及一个key,就是开头提到的颜色值,还有使用这个值创建的一个rgba颜色;
- // pick保存在一个对象中
- function PickId(pickObjects, key, color) {
- this._pickObjects = pickObjects; // 拾取的对象
- this.key = key; // 颜色number
- this.color = color; // 颜色rgba
- }
e、textureDimensions、textureStep:这两个属性存储的是根据要素数量创建的纹理的尺寸、纹素之间的距离,创建一张纹理要有宽度、高度,宽度的设定是依据要素数量和webgl本身支持的纹理大小决定的,要素数量大于webgl纹理尺寸就增加一行进行存储(浪费了部分空间),通常一个瓦片中的要素数量不会很多,所以只有一行;
- // 要素数量
- if (featuresLength > 0) {
- // PERFORMANCE_IDEA: this can waste memory in the last row in the uncommon case
- // when more than one row is needed (e.g., > 16K features in one tile) 在需要多行的情况下,这会浪费最后一行的内存
-
- // 纹理宽度
- var width = Math.min(featuresLength, ContextLimits.maximumTextureSize);
- // 纹理高度
- var height = Math.ceil(featuresLength / ContextLimits.maximumTextureSize);
- // x步长
- var stepX = 1.0 / width;
- var centerX = stepX * 0.5;
- // y步长
- var stepY = 1.0 / height;
- var centerY = stepY * 0.5;
-
- // 纹理大小
- textureDimensions = new Cartesian2(width, height);
- // 纹理步长
- textureStep = new Cartesian4(stepX, centerX, stepY, centerY);
- }
f、_statistics:用于统计当前场景的显存占用,统计的是顶点数量、三角形数量、顶点缓存、纹理缓存等相关信息;
以上就是本章的解析
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。