123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- import Check from "../Core/Check.js";
- import ComponentDatatype from "../Core/ComponentDatatype.js";
- import defined from "../Core/defined.js";
- import IndexDatatype from "../Core/IndexDatatype.js";
- import Buffer from "../Renderer/Buffer.js";
- import BufferUsage from "../Renderer/BufferUsage.js";
- import AttributeType from "./AttributeType.js";
- import ModelComponents from "./ModelComponents.js";
- import PrimitiveOutlineGenerator from "./Model/PrimitiveOutlineGenerator.js";
- /**
- * Simple struct for tracking whether an attribute will be loaded as a buffer
- * or typed array after post-processing.
- *
- * @alias PrimitiveLoadPlan.AttributeLoadPlan
- * @constructor
- *
- * @param {ModelComponents.Attribute} attribute The attribute to be updated
- *
- * @private
- */
- function AttributeLoadPlan(attribute) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("attribute", attribute);
- //>>includeEnd('debug');
- /**
- * The attribute to track.
- *
- * @type {ModelComponents.Attribute}
- * @readonly
- * @private
- */
- this.attribute = attribute;
- /**
- * Whether the attribute will be loaded as a GPU buffer by the time
- * {@link PrimitiveLoadPlan#postProcess} is finished.
- *
- * @type {boolean}
- * @private
- */
- this.loadBuffer = false;
- /**
- * Whether the attribute will be loaded as a packed typed array by the time
- * {@link PrimitiveLoadPlan#postProcess} is finished.
- *
- * @type {boolean}
- * @private
- */
- this.loadTypedArray = false;
- }
- /**
- * Simple struct for tracking whether an index buffer will be loaded as a buffer
- * or typed array after post-processing.
- *
- * @alias PrimitiveLoadPlan.IndicesLoadPlan
- * @constructor
- *
- * @param {ModelComponents.Indices} indices The indices to be updated
- *
- * @private
- */
- function IndicesLoadPlan(indices) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("indices", indices);
- //>>includeEnd('debug');
- /**
- * The indices to track.
- *
- * @type {ModelComponents.Indices}
- * @readonly
- * @private
- */
- this.indices = indices;
- /**
- * Whether the indices will be loaded as a GPU buffer by the time
- * {@link PrimitiveLoadPlan#postProcess} is finished.
- *
- * @type {boolean}
- * @private
- */
- this.loadBuffer = false;
- /**
- * Whether the indices will be loaded as a typed array copy of the GPU
- * buffer by the time {@link PrimitiveLoadPlan#postProcess} is finished.
- *
- * @type {boolean}
- * @private
- */
- this.loadTypedArray = false;
- }
- /**
- * Primitives may need post-processing steps after their attributes and indices
- * have loaded, such as generating outlines for the CESIUM_primitive_outline glTF
- * extension. This object tracks what indices and attributes need to be
- * post-processed.
- *
- * @alias PrimitiveLoadPlan
- * @constructor
- *
- * @param {ModelComponents.Primitive} primitive The primitive to track
- *
- * @private
- */
- function PrimitiveLoadPlan(primitive) {
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("primitive", primitive);
- //>>includeEnd('debug');
- /**
- * The primitive to track.
- *
- * @type {ModelComponents.Primitive}
- * @readonly
- * @private
- */
- this.primitive = primitive;
- /**
- * A flat list of attributes that need to be post-processed. This includes
- * both regular attributes and morph target attributes.
- *
- * @type {PrimitiveLoadPlan.AttributeLoadPlan[]}
- * @private
- */
- this.attributePlans = [];
- /**
- * Information about the triangle indices that need to be post-processed,
- * if they exist.
- *
- * @type {PrimitiveLoadPlan.IndicesLoadPlan}
- * @private
- */
- this.indicesPlan = undefined;
- /**
- * Set this true to indicate that the primitive has the
- * CESIUM_primitive_outline extension and needs to be post-processed
- *
- * @type {boolean}
- * @private
- */
- this.needsOutlines = false;
- /**
- * The outline edge indices from the CESIUM_primitive_outline extension
- *
- * @type {number[]}
- * @private
- */
- this.outlineIndices = undefined;
- }
- /**
- * Apply post-processing steps that may modify geometry such as generating
- * outline coordinates. If no post-processing steps are needed, this function
- * is a no-op.
- *
- * @param {Context} context The context for generating buffers on the GPU
- */
- PrimitiveLoadPlan.prototype.postProcess = function (context) {
- // Handle CESIUM_primitive_outline. This modifies indices and attributes and
- // also generates a new attribute for the outline coordinates. These steps
- // are synchronous.
- if (this.needsOutlines) {
- generateOutlines(this);
- generateBuffers(this, context);
- }
- };
- function generateOutlines(loadPlan) {
- const primitive = loadPlan.primitive;
- const indices = primitive.indices;
- const vertexCount = primitive.attributes[0].count;
- const generator = new PrimitiveOutlineGenerator({
- triangleIndices: indices.typedArray,
- outlineIndices: loadPlan.outlineIndices,
- originalVertexCount: vertexCount,
- });
- // The generator modifies/adds indices. In some uncommon cases it may have
- // to upgrade to 16- or 32-bit indices so the datatype may change.
- indices.typedArray = generator.updatedTriangleIndices;
- indices.indexDatatype = IndexDatatype.fromTypedArray(indices.typedArray);
- // The outline generator creates a new attribute for the outline coordinates
- // that are used with a lookup texture.
- const outlineCoordinates = makeOutlineCoordinatesAttribute(
- generator.outlineCoordinates
- );
- const outlineCoordinatesPlan = new AttributeLoadPlan(outlineCoordinates);
- outlineCoordinatesPlan.loadBuffer = true;
- outlineCoordinatesPlan.loadTypedArray = false;
- loadPlan.attributePlans.push(outlineCoordinatesPlan);
- primitive.outlineCoordinates = outlineCoordinatesPlan.attribute;
- // Some vertices may be copied due to the addition of the new attribute
- // which may have multiple values at a vertex depending on the face
- const attributePlans = loadPlan.attributePlans;
- const attributesLength = loadPlan.attributePlans.length;
- for (let i = 0; i < attributesLength; i++) {
- const attribute = attributePlans[i].attribute;
- attribute.typedArray = generator.updateAttribute(attribute.typedArray);
- }
- }
- function makeOutlineCoordinatesAttribute(outlineCoordinatesTypedArray) {
- const attribute = new ModelComponents.Attribute();
- attribute.name = "_OUTLINE_COORDINATES";
- attribute.typedArray = outlineCoordinatesTypedArray;
- attribute.componentDatatype = ComponentDatatype.FLOAT;
- attribute.type = AttributeType.VEC3;
- attribute.normalized = false;
- attribute.count = outlineCoordinatesTypedArray.length / 3;
- return attribute;
- }
- function generateBuffers(loadPlan, context) {
- generateAttributeBuffers(loadPlan.attributePlans, context);
- if (defined(loadPlan.indicesPlan)) {
- generateIndexBuffers(loadPlan.indicesPlan, context);
- }
- }
- function generateAttributeBuffers(attributePlans, context) {
- const attributesLength = attributePlans.length;
- for (let i = 0; i < attributesLength; i++) {
- const attributePlan = attributePlans[i];
- const attribute = attributePlan.attribute;
- const typedArray = attribute.typedArray;
- if (attributePlan.loadBuffer) {
- const buffer = Buffer.createVertexBuffer({
- typedArray: typedArray,
- context: context,
- usage: BufferUsage.STATIC_DRAW,
- });
- buffer.vertexArrayDestroyable = false;
- attribute.buffer = buffer;
- }
- if (!attributePlan.loadTypedArray) {
- attribute.typedArray = undefined;
- }
- }
- }
- function generateIndexBuffers(indicesPlan, context) {
- const indices = indicesPlan.indices;
- if (indicesPlan.loadBuffer) {
- const buffer = Buffer.createIndexBuffer({
- typedArray: indices.typedArray,
- context: context,
- usage: BufferUsage.STATIC_DRAW,
- indexDatatype: indices.indexDatatype,
- });
- indices.buffer = buffer;
- buffer.vertexArrayDestroyable = false;
- }
- if (!indicesPlan.loadTypedArray) {
- indices.typedArray = undefined;
- }
- }
- PrimitiveLoadPlan.AttributeLoadPlan = AttributeLoadPlan;
- PrimitiveLoadPlan.IndicesLoadPlan = IndicesLoadPlan;
- export default PrimitiveLoadPlan;
|