12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531 |
- import BoundingSphere from "../Core/BoundingSphere.js";
- import Cartesian2 from "../Core/Cartesian2.js";
- import Cartesian3 from "../Core/Cartesian3.js";
- import Cartesian4 from "../Core/Cartesian4.js";
- import Cartographic from "../Core/Cartographic.js";
- import clone from "../Core/clone.js";
- import Color from "../Core/Color.js";
- import combine from "../Core/combine.js";
- import ComponentDatatype from "../Core/ComponentDatatype.js";
- import defaultValue from "../Core/defaultValue.js";
- import defer from "../Core/defer.js";
- import defined from "../Core/defined.js";
- import destroyObject from "../Core/destroyObject.js";
- import DeveloperError from "../Core/DeveloperError.js";
- import EncodedCartesian3 from "../Core/EncodedCartesian3.js";
- import FeatureDetection from "../Core/FeatureDetection.js";
- import Geometry from "../Core/Geometry.js";
- import GeometryAttribute from "../Core/GeometryAttribute.js";
- import GeometryAttributes from "../Core/GeometryAttributes.js";
- import GeometryOffsetAttribute from "../Core/GeometryOffsetAttribute.js";
- import Intersect from "../Core/Intersect.js";
- import Matrix4 from "../Core/Matrix4.js";
- import Plane from "../Core/Plane.js";
- import RuntimeError from "../Core/RuntimeError.js";
- import subdivideArray from "../Core/subdivideArray.js";
- import TaskProcessor from "../Core/TaskProcessor.js";
- import BufferUsage from "../Renderer/BufferUsage.js";
- import ContextLimits from "../Renderer/ContextLimits.js";
- import DrawCommand from "../Renderer/DrawCommand.js";
- import Pass from "../Renderer/Pass.js";
- import RenderState from "../Renderer/RenderState.js";
- import ShaderProgram from "../Renderer/ShaderProgram.js";
- import ShaderSource from "../Renderer/ShaderSource.js";
- import VertexArray from "../Renderer/VertexArray.js";
- import BatchTable from "./BatchTable.js";
- import CullFace from "./CullFace.js";
- import DepthFunction from "./DepthFunction.js";
- import PrimitivePipeline from "./PrimitivePipeline.js";
- import PrimitiveState from "./PrimitiveState.js";
- import SceneMode from "./SceneMode.js";
- import ShadowMode from "./ShadowMode.js";
- /**
- * A primitive represents geometry in the {@link Scene}. The geometry can be from a single {@link GeometryInstance}
- * as shown in example 1 below, or from an array of instances, even if the geometry is from different
- * geometry types, e.g., an {@link RectangleGeometry} and an {@link EllipsoidGeometry} as shown in Code Example 2.
- * <p>
- * A primitive combines geometry instances with an {@link Appearance} that describes the full shading, including
- * {@link Material} and {@link RenderState}. Roughly, the geometry instance defines the structure and placement,
- * and the appearance defines the visual characteristics. Decoupling geometry and appearance allows us to mix
- * and match most of them and add a new geometry or appearance independently of each other.
- * </p>
- * <p>
- * Combining multiple instances into one primitive is called batching, and significantly improves performance for static data.
- * Instances can be individually picked; {@link Scene#pick} returns their {@link GeometryInstance#id}. Using
- * per-instance appearances like {@link PerInstanceColorAppearance}, each instance can also have a unique color.
- * </p>
- * <p>
- * {@link Geometry} can either be created and batched on a web worker or the main thread. The first two examples
- * show geometry that will be created on a web worker by using the descriptions of the geometry. The third example
- * shows how to create the geometry on the main thread by explicitly calling the <code>createGeometry</code> method.
- * </p>
- *
- * @alias Primitive
- * @constructor
- *
- * @param {Object} [options] Object with the following properties:
- * @param {GeometryInstance[]|GeometryInstance} [options.geometryInstances] The geometry instances - or a single geometry instance - to render.
- * @param {Appearance} [options.appearance] The appearance used to render the primitive.
- * @param {Appearance} [options.depthFailAppearance] The appearance used to shade this primitive when it fails the depth test.
- * @param {Boolean} [options.show=true] Determines if this primitive will be shown.
- * @param {Matrix4} [options.modelMatrix=Matrix4.IDENTITY] The 4x4 transformation matrix that transforms the primitive (all geometry instances) from model to world coordinates.
- * @param {Boolean} [options.vertexCacheOptimize=false] When <code>true</code>, geometry vertices are optimized for the pre and post-vertex-shader caches.
- * @param {Boolean} [options.interleave=false] When <code>true</code>, geometry vertex attributes are interleaved, which can slightly improve rendering performance but increases load time.
- * @param {Boolean} [options.compressVertices=true] When <code>true</code>, the geometry vertices are compressed, which will save memory.
- * @param {Boolean} [options.releaseGeometryInstances=true] When <code>true</code>, the primitive does not keep a reference to the input <code>geometryInstances</code> to save memory.
- * @param {Boolean} [options.allowPicking=true] When <code>true</code>, each geometry instance will only be pickable with {@link Scene#pick}. When <code>false</code>, GPU memory is saved.
- * @param {Boolean} [options.cull=true] When <code>true</code>, the renderer frustum culls and horizon culls the primitive's commands based on their bounding volume. Set this to <code>false</code> for a small performance gain if you are manually culling the primitive.
- * @param {Boolean} [options.asynchronous=true] Determines if the primitive will be created asynchronously or block until ready.
- * @param {Boolean} [options.debugShowBoundingVolume=false] For debugging only. Determines if this primitive's commands' bounding spheres are shown.
- * @param {ShadowMode} [options.shadows=ShadowMode.DISABLED] Determines whether this primitive casts or receives shadows from light sources.
- *
- * @example
- * // 1. Draw a translucent ellipse on the surface with a checkerboard pattern
- * const instance = new Cesium.GeometryInstance({
- * geometry : new Cesium.EllipseGeometry({
- * center : Cesium.Cartesian3.fromDegrees(-100.0, 20.0),
- * semiMinorAxis : 500000.0,
- * semiMajorAxis : 1000000.0,
- * rotation : Cesium.Math.PI_OVER_FOUR,
- * vertexFormat : Cesium.VertexFormat.POSITION_AND_ST
- * }),
- * id : 'object returned when this instance is picked and to get/set per-instance attributes'
- * });
- * scene.primitives.add(new Cesium.Primitive({
- * geometryInstances : instance,
- * appearance : new Cesium.EllipsoidSurfaceAppearance({
- * material : Cesium.Material.fromType('Checkerboard')
- * })
- * }));
- *
- * @example
- * // 2. Draw different instances each with a unique color
- * const rectangleInstance = new Cesium.GeometryInstance({
- * geometry : new Cesium.RectangleGeometry({
- * rectangle : Cesium.Rectangle.fromDegrees(-140.0, 30.0, -100.0, 40.0),
- * vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
- * }),
- * id : 'rectangle',
- * attributes : {
- * color : new Cesium.ColorGeometryInstanceAttribute(0.0, 1.0, 1.0, 0.5)
- * }
- * });
- * const ellipsoidInstance = new Cesium.GeometryInstance({
- * geometry : new Cesium.EllipsoidGeometry({
- * radii : new Cesium.Cartesian3(500000.0, 500000.0, 1000000.0),
- * vertexFormat : Cesium.VertexFormat.POSITION_AND_NORMAL
- * }),
- * modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
- * Cesium.Cartesian3.fromDegrees(-95.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 500000.0), new Cesium.Matrix4()),
- * id : 'ellipsoid',
- * attributes : {
- * color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.AQUA)
- * }
- * });
- * scene.primitives.add(new Cesium.Primitive({
- * geometryInstances : [rectangleInstance, ellipsoidInstance],
- * appearance : new Cesium.PerInstanceColorAppearance()
- * }));
- *
- * @example
- * // 3. Create the geometry on the main thread.
- * scene.primitives.add(new Cesium.Primitive({
- * geometryInstances : new Cesium.GeometryInstance({
- * geometry : Cesium.EllipsoidGeometry.createGeometry(new Cesium.EllipsoidGeometry({
- * radii : new Cesium.Cartesian3(500000.0, 500000.0, 1000000.0),
- * vertexFormat : Cesium.VertexFormat.POSITION_AND_NORMAL
- * })),
- * modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
- * Cesium.Cartesian3.fromDegrees(-95.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 500000.0), new Cesium.Matrix4()),
- * id : 'ellipsoid',
- * attributes : {
- * color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.AQUA)
- * }
- * }),
- * appearance : new Cesium.PerInstanceColorAppearance(),
- * asynchronous : false
- * }));
- *
- * @see GeometryInstance
- * @see Appearance
- * @see ClassificationPrimitive
- * @see GroundPrimitive
- */
- function Primitive(options) {
- options = defaultValue(options, defaultValue.EMPTY_OBJECT);
- /**
- * The geometry instances rendered with this primitive. This may
- * be <code>undefined</code> if <code>options.releaseGeometryInstances</code>
- * is <code>true</code> when the primitive is constructed.
- * <p>
- * Changing this property after the primitive is rendered has no effect.
- * </p>
- *
- * @readonly
- * @type GeometryInstance[]|GeometryInstance
- *
- * @default undefined
- */
- this.geometryInstances = options.geometryInstances;
- /**
- * The {@link Appearance} used to shade this primitive. Each geometry
- * instance is shaded with the same appearance. Some appearances, like
- * {@link PerInstanceColorAppearance} allow giving each instance unique
- * properties.
- *
- * @type Appearance
- *
- * @default undefined
- */
- this.appearance = options.appearance;
- this._appearance = undefined;
- this._material = undefined;
- /**
- * The {@link Appearance} used to shade this primitive when it fails the depth test. Each geometry
- * instance is shaded with the same appearance. Some appearances, like
- * {@link PerInstanceColorAppearance} allow giving each instance unique
- * properties.
- *
- * <p>
- * When using an appearance that requires a color attribute, like PerInstanceColorAppearance,
- * add a depthFailColor per-instance attribute instead.
- * </p>
- *
- * <p>
- * Requires the EXT_frag_depth WebGL extension to render properly. If the extension is not supported,
- * there may be artifacts.
- * </p>
- * @type Appearance
- *
- * @default undefined
- */
- this.depthFailAppearance = options.depthFailAppearance;
- this._depthFailAppearance = undefined;
- this._depthFailMaterial = undefined;
- /**
- * The 4x4 transformation matrix that transforms the primitive (all geometry instances) from model to world coordinates.
- * When this is the identity matrix, the primitive is drawn in world coordinates, i.e., Earth's WGS84 coordinates.
- * Local reference frames can be used by providing a different transformation matrix, like that returned
- * by {@link Transforms.eastNorthUpToFixedFrame}.
- *
- * <p>
- * This property is only supported in 3D mode.
- * </p>
- *
- * @type Matrix4
- *
- * @default Matrix4.IDENTITY
- *
- * @example
- * const origin = Cesium.Cartesian3.fromDegrees(-95.0, 40.0, 200000.0);
- * p.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin);
- */
- this.modelMatrix = Matrix4.clone(
- defaultValue(options.modelMatrix, Matrix4.IDENTITY)
- );
- this._modelMatrix = new Matrix4();
- /**
- * Determines if the primitive will be shown. This affects all geometry
- * instances in the primitive.
- *
- * @type Boolean
- *
- * @default true
- */
- this.show = defaultValue(options.show, true);
- this._vertexCacheOptimize = defaultValue(options.vertexCacheOptimize, false);
- this._interleave = defaultValue(options.interleave, false);
- this._releaseGeometryInstances = defaultValue(
- options.releaseGeometryInstances,
- true
- );
- this._allowPicking = defaultValue(options.allowPicking, true);
- this._asynchronous = defaultValue(options.asynchronous, true);
- this._compressVertices = defaultValue(options.compressVertices, true);
- /**
- * When <code>true</code>, the renderer frustum culls and horizon culls the primitive's commands
- * based on their bounding volume. Set this to <code>false</code> for a small performance gain
- * if you are manually culling the primitive.
- *
- * @type {Boolean}
- *
- * @default true
- */
- this.cull = defaultValue(options.cull, true);
- /**
- * This property is for debugging only; it is not for production use nor is it optimized.
- * <p>
- * Draws the bounding sphere for each draw command in the primitive.
- * </p>
- *
- * @type {Boolean}
- *
- * @default false
- */
- this.debugShowBoundingVolume = defaultValue(
- options.debugShowBoundingVolume,
- false
- );
- /**
- * @private
- */
- this.rtcCenter = options.rtcCenter;
- //>>includeStart('debug', pragmas.debug);
- if (
- defined(this.rtcCenter) &&
- (!defined(this.geometryInstances) ||
- (Array.isArray(this.geometryInstances) &&
- this.geometryInstances.length !== 1))
- ) {
- throw new DeveloperError(
- "Relative-to-center rendering only supports one geometry instance."
- );
- }
- //>>includeEnd('debug');
- /**
- * Determines whether this primitive casts or receives shadows from light sources.
- *
- * @type {ShadowMode}
- *
- * @default ShadowMode.DISABLED
- */
- this.shadows = defaultValue(options.shadows, ShadowMode.DISABLED);
- this._translucent = undefined;
- this._state = PrimitiveState.READY;
- this._geometries = [];
- this._error = undefined;
- this._numberOfInstances = 0;
- this._boundingSpheres = [];
- this._boundingSphereWC = [];
- this._boundingSphereCV = [];
- this._boundingSphere2D = [];
- this._boundingSphereMorph = [];
- this._perInstanceAttributeCache = [];
- this._instanceIds = [];
- this._lastPerInstanceAttributeIndex = 0;
- this._va = [];
- this._attributeLocations = undefined;
- this._primitiveType = undefined;
- this._frontFaceRS = undefined;
- this._backFaceRS = undefined;
- this._sp = undefined;
- this._depthFailAppearance = undefined;
- this._spDepthFail = undefined;
- this._frontFaceDepthFailRS = undefined;
- this._backFaceDepthFailRS = undefined;
- this._pickIds = [];
- this._colorCommands = [];
- this._pickCommands = [];
- this._createBoundingVolumeFunction = options._createBoundingVolumeFunction;
- this._createRenderStatesFunction = options._createRenderStatesFunction;
- this._createShaderProgramFunction = options._createShaderProgramFunction;
- this._createCommandsFunction = options._createCommandsFunction;
- this._updateAndQueueCommandsFunction =
- options._updateAndQueueCommandsFunction;
- this._createPickOffsets = options._createPickOffsets;
- this._pickOffsets = undefined;
- this._createGeometryResults = undefined;
- this._ready = false;
- this._readyPromise = defer();
- this._batchTable = undefined;
- this._batchTableAttributeIndices = undefined;
- this._offsetInstanceExtend = undefined;
- this._batchTableOffsetAttribute2DIndex = undefined;
- this._batchTableOffsetsUpdated = false;
- this._instanceBoundingSpheres = undefined;
- this._instanceBoundingSpheresCV = undefined;
- this._tempBoundingSpheres = undefined;
- this._recomputeBoundingSpheres = false;
- this._batchTableBoundingSpheresUpdated = false;
- this._batchTableBoundingSphereAttributeIndices = undefined;
- }
- Object.defineProperties(Primitive.prototype, {
- /**
- * When <code>true</code>, geometry vertices are optimized for the pre and post-vertex-shader caches.
- *
- * @memberof Primitive.prototype
- *
- * @type {Boolean}
- * @readonly
- *
- * @default true
- */
- vertexCacheOptimize: {
- get: function () {
- return this._vertexCacheOptimize;
- },
- },
- /**
- * Determines if geometry vertex attributes are interleaved, which can slightly improve rendering performance.
- *
- * @memberof Primitive.prototype
- *
- * @type {Boolean}
- * @readonly
- *
- * @default false
- */
- interleave: {
- get: function () {
- return this._interleave;
- },
- },
- /**
- * When <code>true</code>, the primitive does not keep a reference to the input <code>geometryInstances</code> to save memory.
- *
- * @memberof Primitive.prototype
- *
- * @type {Boolean}
- * @readonly
- *
- * @default true
- */
- releaseGeometryInstances: {
- get: function () {
- return this._releaseGeometryInstances;
- },
- },
- /**
- * When <code>true</code>, each geometry instance will only be pickable with {@link Scene#pick}. When <code>false</code>, GPU memory is saved. *
- *
- * @memberof Primitive.prototype
- *
- * @type {Boolean}
- * @readonly
- *
- * @default true
- */
- allowPicking: {
- get: function () {
- return this._allowPicking;
- },
- },
- /**
- * Determines if the geometry instances will be created and batched on a web worker.
- *
- * @memberof Primitive.prototype
- *
- * @type {Boolean}
- * @readonly
- *
- * @default true
- */
- asynchronous: {
- get: function () {
- return this._asynchronous;
- },
- },
- /**
- * When <code>true</code>, geometry vertices are compressed, which will save memory.
- *
- * @memberof Primitive.prototype
- *
- * @type {Boolean}
- * @readonly
- *
- * @default true
- */
- compressVertices: {
- get: function () {
- return this._compressVertices;
- },
- },
- /**
- * Determines if the primitive is complete and ready to render. If this property is
- * true, the primitive will be rendered the next time that {@link Primitive#update}
- * is called.
- *
- * @memberof Primitive.prototype
- *
- * @type {Boolean}
- * @readonly
- */
- ready: {
- get: function () {
- return this._ready;
- },
- },
- /**
- * Gets a promise that resolves when the primitive is ready to render.
- * @memberof Primitive.prototype
- * @type {Promise.<Primitive>}
- * @readonly
- */
- readyPromise: {
- get: function () {
- return this._readyPromise.promise;
- },
- },
- });
- function getCommonPerInstanceAttributeNames(instances) {
- const length = instances.length;
- const attributesInAllInstances = [];
- const attributes0 = instances[0].attributes;
- let name;
- for (name in attributes0) {
- if (attributes0.hasOwnProperty(name) && defined(attributes0[name])) {
- const attribute = attributes0[name];
- let inAllInstances = true;
- // Does this same attribute exist in all instances?
- for (let i = 1; i < length; ++i) {
- const otherAttribute = instances[i].attributes[name];
- if (
- !defined(otherAttribute) ||
- attribute.componentDatatype !== otherAttribute.componentDatatype ||
- attribute.componentsPerAttribute !==
- otherAttribute.componentsPerAttribute ||
- attribute.normalize !== otherAttribute.normalize
- ) {
- inAllInstances = false;
- break;
- }
- }
- if (inAllInstances) {
- attributesInAllInstances.push(name);
- }
- }
- }
- return attributesInAllInstances;
- }
- const scratchGetAttributeCartesian2 = new Cartesian2();
- const scratchGetAttributeCartesian3 = new Cartesian3();
- const scratchGetAttributeCartesian4 = new Cartesian4();
- function getAttributeValue(value) {
- const componentsPerAttribute = value.length;
- if (componentsPerAttribute === 1) {
- return value[0];
- } else if (componentsPerAttribute === 2) {
- return Cartesian2.unpack(value, 0, scratchGetAttributeCartesian2);
- } else if (componentsPerAttribute === 3) {
- return Cartesian3.unpack(value, 0, scratchGetAttributeCartesian3);
- } else if (componentsPerAttribute === 4) {
- return Cartesian4.unpack(value, 0, scratchGetAttributeCartesian4);
- }
- }
- function createBatchTable(primitive, context) {
- const geometryInstances = primitive.geometryInstances;
- const instances = Array.isArray(geometryInstances)
- ? geometryInstances
- : [geometryInstances];
- const numberOfInstances = instances.length;
- if (numberOfInstances === 0) {
- return;
- }
- const names = getCommonPerInstanceAttributeNames(instances);
- const length = names.length;
- const attributes = [];
- const attributeIndices = {};
- const boundingSphereAttributeIndices = {};
- let offset2DIndex;
- const firstInstance = instances[0];
- let instanceAttributes = firstInstance.attributes;
- let i;
- let name;
- let attribute;
- for (i = 0; i < length; ++i) {
- name = names[i];
- attribute = instanceAttributes[name];
- attributeIndices[name] = i;
- attributes.push({
- functionName: `czm_batchTable_${name}`,
- componentDatatype: attribute.componentDatatype,
- componentsPerAttribute: attribute.componentsPerAttribute,
- normalize: attribute.normalize,
- });
- }
- if (names.indexOf("distanceDisplayCondition") !== -1) {
- attributes.push(
- {
- functionName: "czm_batchTable_boundingSphereCenter3DHigh",
- componentDatatype: ComponentDatatype.FLOAT,
- componentsPerAttribute: 3,
- },
- {
- functionName: "czm_batchTable_boundingSphereCenter3DLow",
- componentDatatype: ComponentDatatype.FLOAT,
- componentsPerAttribute: 3,
- },
- {
- functionName: "czm_batchTable_boundingSphereCenter2DHigh",
- componentDatatype: ComponentDatatype.FLOAT,
- componentsPerAttribute: 3,
- },
- {
- functionName: "czm_batchTable_boundingSphereCenter2DLow",
- componentDatatype: ComponentDatatype.FLOAT,
- componentsPerAttribute: 3,
- },
- {
- functionName: "czm_batchTable_boundingSphereRadius",
- componentDatatype: ComponentDatatype.FLOAT,
- componentsPerAttribute: 1,
- }
- );
- boundingSphereAttributeIndices.center3DHigh = attributes.length - 5;
- boundingSphereAttributeIndices.center3DLow = attributes.length - 4;
- boundingSphereAttributeIndices.center2DHigh = attributes.length - 3;
- boundingSphereAttributeIndices.center2DLow = attributes.length - 2;
- boundingSphereAttributeIndices.radius = attributes.length - 1;
- }
- if (names.indexOf("offset") !== -1) {
- attributes.push({
- functionName: "czm_batchTable_offset2D",
- componentDatatype: ComponentDatatype.FLOAT,
- componentsPerAttribute: 3,
- });
- offset2DIndex = attributes.length - 1;
- }
- attributes.push({
- functionName: "czm_batchTable_pickColor",
- componentDatatype: ComponentDatatype.UNSIGNED_BYTE,
- componentsPerAttribute: 4,
- normalize: true,
- });
- const attributesLength = attributes.length;
- const batchTable = new BatchTable(context, attributes, numberOfInstances);
- for (i = 0; i < numberOfInstances; ++i) {
- const instance = instances[i];
- instanceAttributes = instance.attributes;
- for (let j = 0; j < length; ++j) {
- name = names[j];
- attribute = instanceAttributes[name];
- const value = getAttributeValue(attribute.value);
- const attributeIndex = attributeIndices[name];
- batchTable.setBatchedAttribute(i, attributeIndex, value);
- }
- const pickObject = {
- primitive: defaultValue(instance.pickPrimitive, primitive),
- };
- if (defined(instance.id)) {
- pickObject.id = instance.id;
- }
- const pickId = context.createPickId(pickObject);
- primitive._pickIds.push(pickId);
- const pickColor = pickId.color;
- const color = scratchGetAttributeCartesian4;
- color.x = Color.floatToByte(pickColor.red);
- color.y = Color.floatToByte(pickColor.green);
- color.z = Color.floatToByte(pickColor.blue);
- color.w = Color.floatToByte(pickColor.alpha);
- batchTable.setBatchedAttribute(i, attributesLength - 1, color);
- }
- primitive._batchTable = batchTable;
- primitive._batchTableAttributeIndices = attributeIndices;
- primitive._batchTableBoundingSphereAttributeIndices = boundingSphereAttributeIndices;
- primitive._batchTableOffsetAttribute2DIndex = offset2DIndex;
- }
- function cloneAttribute(attribute) {
- let clonedValues;
- if (Array.isArray(attribute.values)) {
- clonedValues = attribute.values.slice(0);
- } else {
- clonedValues = new attribute.values.constructor(attribute.values);
- }
- return new GeometryAttribute({
- componentDatatype: attribute.componentDatatype,
- componentsPerAttribute: attribute.componentsPerAttribute,
- normalize: attribute.normalize,
- values: clonedValues,
- });
- }
- function cloneGeometry(geometry) {
- const attributes = geometry.attributes;
- const newAttributes = new GeometryAttributes();
- for (const property in attributes) {
- if (attributes.hasOwnProperty(property) && defined(attributes[property])) {
- newAttributes[property] = cloneAttribute(attributes[property]);
- }
- }
- let indices;
- if (defined(geometry.indices)) {
- const sourceValues = geometry.indices;
- if (Array.isArray(sourceValues)) {
- indices = sourceValues.slice(0);
- } else {
- indices = new sourceValues.constructor(sourceValues);
- }
- }
- return new Geometry({
- attributes: newAttributes,
- indices: indices,
- primitiveType: geometry.primitiveType,
- boundingSphere: BoundingSphere.clone(geometry.boundingSphere),
- });
- }
- function cloneInstance(instance, geometry) {
- return {
- geometry: geometry,
- attributes: instance.attributes,
- modelMatrix: Matrix4.clone(instance.modelMatrix),
- pickPrimitive: instance.pickPrimitive,
- id: instance.id,
- };
- }
- const positionRegex = /attribute\s+vec(?:3|4)\s+(.*)3DHigh;/g;
- Primitive._modifyShaderPosition = function (
- primitive,
- vertexShaderSource,
- scene3DOnly
- ) {
- let match;
- let forwardDecl = "";
- let attributes = "";
- let computeFunctions = "";
- while ((match = positionRegex.exec(vertexShaderSource)) !== null) {
- const name = match[1];
- const functionName = `vec4 czm_compute${name[0].toUpperCase()}${name.substr(
- 1
- )}()`;
- // Don't forward-declare czm_computePosition because computePosition.glsl already does.
- if (functionName !== "vec4 czm_computePosition()") {
- forwardDecl += `${functionName};\n`;
- }
- if (!defined(primitive.rtcCenter)) {
- // Use GPU RTE
- if (!scene3DOnly) {
- attributes +=
- `attribute vec3 ${name}2DHigh;\n` + `attribute vec3 ${name}2DLow;\n`;
- computeFunctions +=
- `${functionName}\n` +
- `{\n` +
- ` vec4 p;\n` +
- ` if (czm_morphTime == 1.0)\n` +
- ` {\n` +
- ` p = czm_translateRelativeToEye(${name}3DHigh, ${name}3DLow);\n` +
- ` }\n` +
- ` else if (czm_morphTime == 0.0)\n` +
- ` {\n` +
- ` p = czm_translateRelativeToEye(${name}2DHigh.zxy, ${name}2DLow.zxy);\n` +
- ` }\n` +
- ` else\n` +
- ` {\n` +
- ` p = czm_columbusViewMorph(\n` +
- ` czm_translateRelativeToEye(${name}2DHigh.zxy, ${name}2DLow.zxy),\n` +
- ` czm_translateRelativeToEye(${name}3DHigh, ${name}3DLow),\n` +
- ` czm_morphTime);\n` +
- ` }\n` +
- ` return p;\n` +
- `}\n\n`;
- } else {
- computeFunctions +=
- `${functionName}\n` +
- `{\n` +
- ` return czm_translateRelativeToEye(${name}3DHigh, ${name}3DLow);\n` +
- `}\n\n`;
- }
- } else {
- // Use RTC
- vertexShaderSource = vertexShaderSource.replace(
- /attribute\s+vec(?:3|4)\s+position3DHigh;/g,
- ""
- );
- vertexShaderSource = vertexShaderSource.replace(
- /attribute\s+vec(?:3|4)\s+position3DLow;/g,
- ""
- );
- forwardDecl += "uniform mat4 u_modifiedModelView;\n";
- attributes += "attribute vec4 position;\n";
- computeFunctions +=
- `${functionName}\n` +
- `{\n` +
- ` return u_modifiedModelView * position;\n` +
- `}\n\n`;
- vertexShaderSource = vertexShaderSource.replace(
- /czm_modelViewRelativeToEye\s+\*\s+/g,
- ""
- );
- vertexShaderSource = vertexShaderSource.replace(
- /czm_modelViewProjectionRelativeToEye/g,
- "czm_projection"
- );
- }
- }
- return [forwardDecl, attributes, vertexShaderSource, computeFunctions].join(
- "\n"
- );
- };
- Primitive._appendShowToShader = function (primitive, vertexShaderSource) {
- if (!defined(primitive._batchTableAttributeIndices.show)) {
- return vertexShaderSource;
- }
- const renamedVS = ShaderSource.replaceMain(
- vertexShaderSource,
- "czm_non_show_main"
- );
- const showMain =
- "void main() \n" +
- "{ \n" +
- " czm_non_show_main(); \n" +
- " gl_Position *= czm_batchTable_show(batchId); \n" +
- "}";
- return `${renamedVS}\n${showMain}`;
- };
- Primitive._updateColorAttribute = function (
- primitive,
- vertexShaderSource,
- isDepthFail
- ) {
- // some appearances have a color attribute for per vertex color.
- // only remove if color is a per instance attribute.
- if (
- !defined(primitive._batchTableAttributeIndices.color) &&
- !defined(primitive._batchTableAttributeIndices.depthFailColor)
- ) {
- return vertexShaderSource;
- }
- if (vertexShaderSource.search(/attribute\s+vec4\s+color;/g) === -1) {
- return vertexShaderSource;
- }
- //>>includeStart('debug', pragmas.debug);
- if (
- isDepthFail &&
- !defined(primitive._batchTableAttributeIndices.depthFailColor)
- ) {
- throw new DeveloperError(
- "A depthFailColor per-instance attribute is required when using a depth fail appearance that uses a color attribute."
- );
- }
- //>>includeEnd('debug');
- let modifiedVS = vertexShaderSource;
- modifiedVS = modifiedVS.replace(/attribute\s+vec4\s+color;/g, "");
- if (!isDepthFail) {
- modifiedVS = modifiedVS.replace(
- /(\b)color(\b)/g,
- "$1czm_batchTable_color(batchId)$2"
- );
- } else {
- modifiedVS = modifiedVS.replace(
- /(\b)color(\b)/g,
- "$1czm_batchTable_depthFailColor(batchId)$2"
- );
- }
- return modifiedVS;
- };
- function appendPickToVertexShader(source) {
- const renamedVS = ShaderSource.replaceMain(source, "czm_non_pick_main");
- const pickMain =
- "varying vec4 v_pickColor; \n" +
- "void main() \n" +
- "{ \n" +
- " czm_non_pick_main(); \n" +
- " v_pickColor = czm_batchTable_pickColor(batchId); \n" +
- "}";
- return `${renamedVS}\n${pickMain}`;
- }
- function appendPickToFragmentShader(source) {
- return `varying vec4 v_pickColor;\n${source}`;
- }
- Primitive._updatePickColorAttribute = function (source) {
- let vsPick = source.replace(/attribute\s+vec4\s+pickColor;/g, "");
- vsPick = vsPick.replace(
- /(\b)pickColor(\b)/g,
- "$1czm_batchTable_pickColor(batchId)$2"
- );
- return vsPick;
- };
- Primitive._appendOffsetToShader = function (primitive, vertexShaderSource) {
- if (!defined(primitive._batchTableAttributeIndices.offset)) {
- return vertexShaderSource;
- }
- let attr = "attribute float batchId;\n";
- attr += "attribute float applyOffset;";
- let modifiedShader = vertexShaderSource.replace(
- /attribute\s+float\s+batchId;/g,
- attr
- );
- let str = "vec4 $1 = czm_computePosition();\n";
- str += " if (czm_sceneMode == czm_sceneMode3D)\n";
- str += " {\n";
- str +=
- " $1 = $1 + vec4(czm_batchTable_offset(batchId) * applyOffset, 0.0);";
- str += " }\n";
- str += " else\n";
- str += " {\n";
- str +=
- " $1 = $1 + vec4(czm_batchTable_offset2D(batchId) * applyOffset, 0.0);";
- str += " }\n";
- modifiedShader = modifiedShader.replace(
- /vec4\s+([A-Za-z0-9_]+)\s+=\s+czm_computePosition\(\);/g,
- str
- );
- return modifiedShader;
- };
- Primitive._appendDistanceDisplayConditionToShader = function (
- primitive,
- vertexShaderSource,
- scene3DOnly
- ) {
- if (
- !defined(primitive._batchTableAttributeIndices.distanceDisplayCondition)
- ) {
- return vertexShaderSource;
- }
- const renamedVS = ShaderSource.replaceMain(
- vertexShaderSource,
- "czm_non_distanceDisplayCondition_main"
- );
- let distanceDisplayConditionMain =
- "void main() \n" +
- "{ \n" +
- " czm_non_distanceDisplayCondition_main(); \n" +
- " vec2 distanceDisplayCondition = czm_batchTable_distanceDisplayCondition(batchId);\n" +
- " vec3 boundingSphereCenter3DHigh = czm_batchTable_boundingSphereCenter3DHigh(batchId);\n" +
- " vec3 boundingSphereCenter3DLow = czm_batchTable_boundingSphereCenter3DLow(batchId);\n" +
- " float boundingSphereRadius = czm_batchTable_boundingSphereRadius(batchId);\n";
- if (!scene3DOnly) {
- distanceDisplayConditionMain +=
- " vec3 boundingSphereCenter2DHigh = czm_batchTable_boundingSphereCenter2DHigh(batchId);\n" +
- " vec3 boundingSphereCenter2DLow = czm_batchTable_boundingSphereCenter2DLow(batchId);\n" +
- " vec4 centerRTE;\n" +
- " if (czm_morphTime == 1.0)\n" +
- " {\n" +
- " centerRTE = czm_translateRelativeToEye(boundingSphereCenter3DHigh, boundingSphereCenter3DLow);\n" +
- " }\n" +
- " else if (czm_morphTime == 0.0)\n" +
- " {\n" +
- " centerRTE = czm_translateRelativeToEye(boundingSphereCenter2DHigh.zxy, boundingSphereCenter2DLow.zxy);\n" +
- " }\n" +
- " else\n" +
- " {\n" +
- " centerRTE = czm_columbusViewMorph(\n" +
- " czm_translateRelativeToEye(boundingSphereCenter2DHigh.zxy, boundingSphereCenter2DLow.zxy),\n" +
- " czm_translateRelativeToEye(boundingSphereCenter3DHigh, boundingSphereCenter3DLow),\n" +
- " czm_morphTime);\n" +
- " }\n";
- } else {
- distanceDisplayConditionMain +=
- " vec4 centerRTE = czm_translateRelativeToEye(boundingSphereCenter3DHigh, boundingSphereCenter3DLow);\n";
- }
- distanceDisplayConditionMain +=
- " float radiusSq = boundingSphereRadius * boundingSphereRadius; \n" +
- " float distanceSq; \n" +
- " if (czm_sceneMode == czm_sceneMode2D) \n" +
- " { \n" +
- " distanceSq = czm_eyeHeight2D.y - radiusSq; \n" +
- " } \n" +
- " else \n" +
- " { \n" +
- " distanceSq = dot(centerRTE.xyz, centerRTE.xyz) - radiusSq; \n" +
- " } \n" +
- " distanceSq = max(distanceSq, 0.0); \n" +
- " float nearSq = distanceDisplayCondition.x * distanceDisplayCondition.x; \n" +
- " float farSq = distanceDisplayCondition.y * distanceDisplayCondition.y; \n" +
- " float show = (distanceSq >= nearSq && distanceSq <= farSq) ? 1.0 : 0.0; \n" +
- " gl_Position *= show; \n" +
- "}";
- return `${renamedVS}\n${distanceDisplayConditionMain}`;
- };
- function modifyForEncodedNormals(primitive, vertexShaderSource) {
- if (!primitive.compressVertices) {
- return vertexShaderSource;
- }
- const containsNormal =
- vertexShaderSource.search(/attribute\s+vec3\s+normal;/g) !== -1;
- const containsSt =
- vertexShaderSource.search(/attribute\s+vec2\s+st;/g) !== -1;
- if (!containsNormal && !containsSt) {
- return vertexShaderSource;
- }
- const containsTangent =
- vertexShaderSource.search(/attribute\s+vec3\s+tangent;/g) !== -1;
- const containsBitangent =
- vertexShaderSource.search(/attribute\s+vec3\s+bitangent;/g) !== -1;
- let numComponents = containsSt && containsNormal ? 2.0 : 1.0;
- numComponents += containsTangent || containsBitangent ? 1 : 0;
- const type = numComponents > 1 ? `vec${numComponents}` : "float";
- const attributeName = "compressedAttributes";
- const attributeDecl = `attribute ${type} ${attributeName};`;
- let globalDecl = "";
- let decode = "";
- if (containsSt) {
- globalDecl += "vec2 st;\n";
- const stComponent =
- numComponents > 1 ? `${attributeName}.x` : attributeName;
- decode += ` st = czm_decompressTextureCoordinates(${stComponent});\n`;
- }
- if (containsNormal && containsTangent && containsBitangent) {
- globalDecl += "vec3 normal;\n" + "vec3 tangent;\n" + "vec3 bitangent;\n";
- decode += ` czm_octDecode(${attributeName}.${
- containsSt ? "yz" : "xy"
- }, normal, tangent, bitangent);\n`;
- } else {
- if (containsNormal) {
- globalDecl += "vec3 normal;\n";
- decode += ` normal = czm_octDecode(${attributeName}${
- numComponents > 1 ? `.${containsSt ? "y" : "x"}` : ""
- });\n`;
- }
- if (containsTangent) {
- globalDecl += "vec3 tangent;\n";
- decode += ` tangent = czm_octDecode(${attributeName}.${
- containsSt && containsNormal ? "z" : "y"
- });\n`;
- }
- if (containsBitangent) {
- globalDecl += "vec3 bitangent;\n";
- decode += ` bitangent = czm_octDecode(${attributeName}.${
- containsSt && containsNormal ? "z" : "y"
- });\n`;
- }
- }
- let modifiedVS = vertexShaderSource;
- modifiedVS = modifiedVS.replace(/attribute\s+vec3\s+normal;/g, "");
- modifiedVS = modifiedVS.replace(/attribute\s+vec2\s+st;/g, "");
- modifiedVS = modifiedVS.replace(/attribute\s+vec3\s+tangent;/g, "");
- modifiedVS = modifiedVS.replace(/attribute\s+vec3\s+bitangent;/g, "");
- modifiedVS = ShaderSource.replaceMain(modifiedVS, "czm_non_compressed_main");
- const compressedMain =
- `${"void main() \n" + "{ \n"}${decode} czm_non_compressed_main(); \n` +
- `}`;
- return [attributeDecl, globalDecl, modifiedVS, compressedMain].join("\n");
- }
- function depthClampVS(vertexShaderSource) {
- let modifiedVS = ShaderSource.replaceMain(
- vertexShaderSource,
- "czm_non_depth_clamp_main"
- );
- modifiedVS +=
- "void main() {\n" +
- " czm_non_depth_clamp_main();\n" +
- " gl_Position = czm_depthClamp(gl_Position);" +
- "}\n";
- return modifiedVS;
- }
- function depthClampFS(fragmentShaderSource) {
- let modifiedFS = ShaderSource.replaceMain(
- fragmentShaderSource,
- "czm_non_depth_clamp_main"
- );
- modifiedFS +=
- "void main() {\n" +
- " czm_non_depth_clamp_main();\n" +
- "#if defined(GL_EXT_frag_depth)\n" +
- " #if defined(LOG_DEPTH)\n" +
- " czm_writeLogDepth();\n" +
- " #else\n" +
- " czm_writeDepthClamp();\n" +
- " #endif\n" +
- "#endif\n" +
- "}\n";
- modifiedFS = `${
- "#ifdef GL_EXT_frag_depth\n" +
- "#extension GL_EXT_frag_depth : enable\n" +
- "#endif\n"
- }${modifiedFS}`;
- return modifiedFS;
- }
- function validateShaderMatching(shaderProgram, attributeLocations) {
- // For a VAO and shader program to be compatible, the VAO must have
- // all active attribute in the shader program. The VAO may have
- // extra attributes with the only concern being a potential
- // performance hit due to extra memory bandwidth and cache pollution.
- // The shader source could have extra attributes that are not used,
- // but there is no guarantee they will be optimized out.
- //
- // Here, we validate that the VAO has all attributes required
- // to match the shader program.
- const shaderAttributes = shaderProgram.vertexAttributes;
- //>>includeStart('debug', pragmas.debug);
- for (const name in shaderAttributes) {
- if (shaderAttributes.hasOwnProperty(name)) {
- if (!defined(attributeLocations[name])) {
- throw new DeveloperError(
- `Appearance/Geometry mismatch. The appearance requires vertex shader attribute input '${name}', which was not computed as part of the Geometry. Use the appearance's vertexFormat property when constructing the geometry.`
- );
- }
- }
- }
- //>>includeEnd('debug');
- }
- function getUniformFunction(uniforms, name) {
- return function () {
- return uniforms[name];
- };
- }
- const numberOfCreationWorkers = Math.max(
- FeatureDetection.hardwareConcurrency - 1,
- 1
- );
- let createGeometryTaskProcessors;
- const combineGeometryTaskProcessor = new TaskProcessor("combineGeometry");
- function loadAsynchronous(primitive, frameState) {
- let instances;
- let geometry;
- let i;
- let j;
- const instanceIds = primitive._instanceIds;
- if (primitive._state === PrimitiveState.READY) {
- instances = Array.isArray(primitive.geometryInstances)
- ? primitive.geometryInstances
- : [primitive.geometryInstances];
- const length = (primitive._numberOfInstances = instances.length);
- const promises = [];
- let subTasks = [];
- for (i = 0; i < length; ++i) {
- geometry = instances[i].geometry;
- instanceIds.push(instances[i].id);
- //>>includeStart('debug', pragmas.debug);
- if (!defined(geometry._workerName)) {
- throw new DeveloperError(
- "_workerName must be defined for asynchronous geometry."
- );
- }
- //>>includeEnd('debug');
- subTasks.push({
- moduleName: geometry._workerName,
- geometry: geometry,
- });
- }
- if (!defined(createGeometryTaskProcessors)) {
- createGeometryTaskProcessors = new Array(numberOfCreationWorkers);
- for (i = 0; i < numberOfCreationWorkers; i++) {
- createGeometryTaskProcessors[i] = new TaskProcessor("createGeometry");
- }
- }
- let subTask;
- subTasks = subdivideArray(subTasks, numberOfCreationWorkers);
- for (i = 0; i < subTasks.length; i++) {
- let packedLength = 0;
- const workerSubTasks = subTasks[i];
- const workerSubTasksLength = workerSubTasks.length;
- for (j = 0; j < workerSubTasksLength; ++j) {
- subTask = workerSubTasks[j];
- geometry = subTask.geometry;
- if (defined(geometry.constructor.pack)) {
- subTask.offset = packedLength;
- packedLength += defaultValue(
- geometry.constructor.packedLength,
- geometry.packedLength
- );
- }
- }
- let subTaskTransferableObjects;
- if (packedLength > 0) {
- const array = new Float64Array(packedLength);
- subTaskTransferableObjects = [array.buffer];
- for (j = 0; j < workerSubTasksLength; ++j) {
- subTask = workerSubTasks[j];
- geometry = subTask.geometry;
- if (defined(geometry.constructor.pack)) {
- geometry.constructor.pack(geometry, array, subTask.offset);
- subTask.geometry = array;
- }
- }
- }
- promises.push(
- createGeometryTaskProcessors[i].scheduleTask(
- {
- subTasks: subTasks[i],
- },
- subTaskTransferableObjects
- )
- );
- }
- primitive._state = PrimitiveState.CREATING;
- Promise.all(promises)
- .then(function (results) {
- primitive._createGeometryResults = results;
- primitive._state = PrimitiveState.CREATED;
- })
- .catch(function (error) {
- setReady(primitive, frameState, PrimitiveState.FAILED, error);
- });
- } else if (primitive._state === PrimitiveState.CREATED) {
- const transferableObjects = [];
- instances = Array.isArray(primitive.geometryInstances)
- ? primitive.geometryInstances
- : [primitive.geometryInstances];
- const scene3DOnly = frameState.scene3DOnly;
- const projection = frameState.mapProjection;
- const promise = combineGeometryTaskProcessor.scheduleTask(
- PrimitivePipeline.packCombineGeometryParameters(
- {
- createGeometryResults: primitive._createGeometryResults,
- instances: instances,
- ellipsoid: projection.ellipsoid,
- projection: projection,
- elementIndexUintSupported: frameState.context.elementIndexUint,
- scene3DOnly: scene3DOnly,
- vertexCacheOptimize: primitive.vertexCacheOptimize,
- compressVertices: primitive.compressVertices,
- modelMatrix: primitive.modelMatrix,
- createPickOffsets: primitive._createPickOffsets,
- },
- transferableObjects
- ),
- transferableObjects
- );
- primitive._createGeometryResults = undefined;
- primitive._state = PrimitiveState.COMBINING;
- Promise.resolve(promise)
- .then(function (packedResult) {
- const result = PrimitivePipeline.unpackCombineGeometryResults(
- packedResult
- );
- primitive._geometries = result.geometries;
- primitive._attributeLocations = result.attributeLocations;
- primitive.modelMatrix = Matrix4.clone(
- result.modelMatrix,
- primitive.modelMatrix
- );
- primitive._pickOffsets = result.pickOffsets;
- primitive._offsetInstanceExtend = result.offsetInstanceExtend;
- primitive._instanceBoundingSpheres = result.boundingSpheres;
- primitive._instanceBoundingSpheresCV = result.boundingSpheresCV;
- if (
- defined(primitive._geometries) &&
- primitive._geometries.length > 0
- ) {
- primitive._recomputeBoundingSpheres = true;
- primitive._state = PrimitiveState.COMBINED;
- } else {
- setReady(primitive, frameState, PrimitiveState.FAILED, undefined);
- }
- })
- .catch(function (error) {
- setReady(primitive, frameState, PrimitiveState.FAILED, error);
- });
- }
- }
- function loadSynchronous(primitive, frameState) {
- const instances = Array.isArray(primitive.geometryInstances)
- ? primitive.geometryInstances
- : [primitive.geometryInstances];
- const length = (primitive._numberOfInstances = instances.length);
- const clonedInstances = new Array(length);
- const instanceIds = primitive._instanceIds;
- let instance;
- let i;
- let geometryIndex = 0;
- for (i = 0; i < length; i++) {
- instance = instances[i];
- const geometry = instance.geometry;
- let createdGeometry;
- if (defined(geometry.attributes) && defined(geometry.primitiveType)) {
- createdGeometry = cloneGeometry(geometry);
- } else {
- createdGeometry = geometry.constructor.createGeometry(geometry);
- }
- clonedInstances[geometryIndex++] = cloneInstance(instance, createdGeometry);
- instanceIds.push(instance.id);
- }
- clonedInstances.length = geometryIndex;
- const scene3DOnly = frameState.scene3DOnly;
- const projection = frameState.mapProjection;
- const result = PrimitivePipeline.combineGeometry({
- instances: clonedInstances,
- ellipsoid: projection.ellipsoid,
- projection: projection,
- elementIndexUintSupported: frameState.context.elementIndexUint,
- scene3DOnly: scene3DOnly,
- vertexCacheOptimize: primitive.vertexCacheOptimize,
- compressVertices: primitive.compressVertices,
- modelMatrix: primitive.modelMatrix,
- createPickOffsets: primitive._createPickOffsets,
- });
- primitive._geometries = result.geometries;
- primitive._attributeLocations = result.attributeLocations;
- primitive.modelMatrix = Matrix4.clone(
- result.modelMatrix,
- primitive.modelMatrix
- );
- primitive._pickOffsets = result.pickOffsets;
- primitive._offsetInstanceExtend = result.offsetInstanceExtend;
- primitive._instanceBoundingSpheres = result.boundingSpheres;
- primitive._instanceBoundingSpheresCV = result.boundingSpheresCV;
- if (defined(primitive._geometries) && primitive._geometries.length > 0) {
- primitive._recomputeBoundingSpheres = true;
- primitive._state = PrimitiveState.COMBINED;
- } else {
- setReady(primitive, frameState, PrimitiveState.FAILED, undefined);
- }
- }
- function recomputeBoundingSpheres(primitive, frameState) {
- const offsetIndex = primitive._batchTableAttributeIndices.offset;
- if (!primitive._recomputeBoundingSpheres || !defined(offsetIndex)) {
- primitive._recomputeBoundingSpheres = false;
- return;
- }
- let i;
- const offsetInstanceExtend = primitive._offsetInstanceExtend;
- const boundingSpheres = primitive._instanceBoundingSpheres;
- const length = boundingSpheres.length;
- let newBoundingSpheres = primitive._tempBoundingSpheres;
- if (!defined(newBoundingSpheres)) {
- newBoundingSpheres = new Array(length);
- for (i = 0; i < length; i++) {
- newBoundingSpheres[i] = new BoundingSphere();
- }
- primitive._tempBoundingSpheres = newBoundingSpheres;
- }
- for (i = 0; i < length; ++i) {
- let newBS = newBoundingSpheres[i];
- const offset = primitive._batchTable.getBatchedAttribute(
- i,
- offsetIndex,
- new Cartesian3()
- );
- newBS = boundingSpheres[i].clone(newBS);
- transformBoundingSphere(newBS, offset, offsetInstanceExtend[i]);
- }
- const combinedBS = [];
- const combinedWestBS = [];
- const combinedEastBS = [];
- for (i = 0; i < length; ++i) {
- const bs = newBoundingSpheres[i];
- const minX = bs.center.x - bs.radius;
- if (
- minX > 0 ||
- BoundingSphere.intersectPlane(bs, Plane.ORIGIN_ZX_PLANE) !==
- Intersect.INTERSECTING
- ) {
- combinedBS.push(bs);
- } else {
- combinedWestBS.push(bs);
- combinedEastBS.push(bs);
- }
- }
- let resultBS1 = combinedBS[0];
- let resultBS2 = combinedEastBS[0];
- let resultBS3 = combinedWestBS[0];
- for (i = 1; i < combinedBS.length; i++) {
- resultBS1 = BoundingSphere.union(resultBS1, combinedBS[i]);
- }
- for (i = 1; i < combinedEastBS.length; i++) {
- resultBS2 = BoundingSphere.union(resultBS2, combinedEastBS[i]);
- }
- for (i = 1; i < combinedWestBS.length; i++) {
- resultBS3 = BoundingSphere.union(resultBS3, combinedWestBS[i]);
- }
- const result = [];
- if (defined(resultBS1)) {
- result.push(resultBS1);
- }
- if (defined(resultBS2)) {
- result.push(resultBS2);
- }
- if (defined(resultBS3)) {
- result.push(resultBS3);
- }
- for (i = 0; i < result.length; i++) {
- const boundingSphere = result[i].clone(primitive._boundingSpheres[i]);
- primitive._boundingSpheres[i] = boundingSphere;
- primitive._boundingSphereCV[i] = BoundingSphere.projectTo2D(
- boundingSphere,
- frameState.mapProjection,
- primitive._boundingSphereCV[i]
- );
- }
- Primitive._updateBoundingVolumes(
- primitive,
- frameState,
- primitive.modelMatrix,
- true
- );
- primitive._recomputeBoundingSpheres = false;
- }
- const scratchBoundingSphereCenterEncoded = new EncodedCartesian3();
- const scratchBoundingSphereCartographic = new Cartographic();
- const scratchBoundingSphereCenter2D = new Cartesian3();
- const scratchBoundingSphere = new BoundingSphere();
- function updateBatchTableBoundingSpheres(primitive, frameState) {
- const hasDistanceDisplayCondition = defined(
- primitive._batchTableAttributeIndices.distanceDisplayCondition
- );
- if (
- !hasDistanceDisplayCondition ||
- primitive._batchTableBoundingSpheresUpdated
- ) {
- return;
- }
- const indices = primitive._batchTableBoundingSphereAttributeIndices;
- const center3DHighIndex = indices.center3DHigh;
- const center3DLowIndex = indices.center3DLow;
- const center2DHighIndex = indices.center2DHigh;
- const center2DLowIndex = indices.center2DLow;
- const radiusIndex = indices.radius;
- const projection = frameState.mapProjection;
- const ellipsoid = projection.ellipsoid;
- const batchTable = primitive._batchTable;
- const boundingSpheres = primitive._instanceBoundingSpheres;
- const length = boundingSpheres.length;
- for (let i = 0; i < length; ++i) {
- let boundingSphere = boundingSpheres[i];
- if (!defined(boundingSphere)) {
- continue;
- }
- const modelMatrix = primitive.modelMatrix;
- if (defined(modelMatrix)) {
- boundingSphere = BoundingSphere.transform(
- boundingSphere,
- modelMatrix,
- scratchBoundingSphere
- );
- }
- const center = boundingSphere.center;
- const radius = boundingSphere.radius;
- let encodedCenter = EncodedCartesian3.fromCartesian(
- center,
- scratchBoundingSphereCenterEncoded
- );
- batchTable.setBatchedAttribute(i, center3DHighIndex, encodedCenter.high);
- batchTable.setBatchedAttribute(i, center3DLowIndex, encodedCenter.low);
- if (!frameState.scene3DOnly) {
- const cartographic = ellipsoid.cartesianToCartographic(
- center,
- scratchBoundingSphereCartographic
- );
- const center2D = projection.project(
- cartographic,
- scratchBoundingSphereCenter2D
- );
- encodedCenter = EncodedCartesian3.fromCartesian(
- center2D,
- scratchBoundingSphereCenterEncoded
- );
- batchTable.setBatchedAttribute(i, center2DHighIndex, encodedCenter.high);
- batchTable.setBatchedAttribute(i, center2DLowIndex, encodedCenter.low);
- }
- batchTable.setBatchedAttribute(i, radiusIndex, radius);
- }
- primitive._batchTableBoundingSpheresUpdated = true;
- }
- const offsetScratchCartesian = new Cartesian3();
- const offsetCenterScratch = new Cartesian3();
- function updateBatchTableOffsets(primitive, frameState) {
- const hasOffset = defined(primitive._batchTableAttributeIndices.offset);
- if (
- !hasOffset ||
- primitive._batchTableOffsetsUpdated ||
- frameState.scene3DOnly
- ) {
- return;
- }
- const index2D = primitive._batchTableOffsetAttribute2DIndex;
- const projection = frameState.mapProjection;
- const ellipsoid = projection.ellipsoid;
- const batchTable = primitive._batchTable;
- const boundingSpheres = primitive._instanceBoundingSpheres;
- const length = boundingSpheres.length;
- for (let i = 0; i < length; ++i) {
- let boundingSphere = boundingSpheres[i];
- if (!defined(boundingSphere)) {
- continue;
- }
- const offset = batchTable.getBatchedAttribute(
- i,
- primitive._batchTableAttributeIndices.offset
- );
- if (Cartesian3.equals(offset, Cartesian3.ZERO)) {
- batchTable.setBatchedAttribute(i, index2D, Cartesian3.ZERO);
- continue;
- }
- const modelMatrix = primitive.modelMatrix;
- if (defined(modelMatrix)) {
- boundingSphere = BoundingSphere.transform(
- boundingSphere,
- modelMatrix,
- scratchBoundingSphere
- );
- }
- let center = boundingSphere.center;
- center = ellipsoid.scaleToGeodeticSurface(center, offsetCenterScratch);
- let cartographic = ellipsoid.cartesianToCartographic(
- center,
- scratchBoundingSphereCartographic
- );
- const center2D = projection.project(
- cartographic,
- scratchBoundingSphereCenter2D
- );
- const newPoint = Cartesian3.add(offset, center, offsetScratchCartesian);
- cartographic = ellipsoid.cartesianToCartographic(newPoint, cartographic);
- const newPointProjected = projection.project(
- cartographic,
- offsetScratchCartesian
- );
- const newVector = Cartesian3.subtract(
- newPointProjected,
- center2D,
- offsetScratchCartesian
- );
- const x = newVector.x;
- newVector.x = newVector.z;
- newVector.z = newVector.y;
- newVector.y = x;
- batchTable.setBatchedAttribute(i, index2D, newVector);
- }
- primitive._batchTableOffsetsUpdated = true;
- }
- function createVertexArray(primitive, frameState) {
- const attributeLocations = primitive._attributeLocations;
- const geometries = primitive._geometries;
- const scene3DOnly = frameState.scene3DOnly;
- const context = frameState.context;
- const va = [];
- const length = geometries.length;
- for (let i = 0; i < length; ++i) {
- const geometry = geometries[i];
- va.push(
- VertexArray.fromGeometry({
- context: context,
- geometry: geometry,
- attributeLocations: attributeLocations,
- bufferUsage: BufferUsage.STATIC_DRAW,
- interleave: primitive._interleave,
- })
- );
- if (defined(primitive._createBoundingVolumeFunction)) {
- primitive._createBoundingVolumeFunction(frameState, geometry);
- } else {
- primitive._boundingSpheres.push(
- BoundingSphere.clone(geometry.boundingSphere)
- );
- primitive._boundingSphereWC.push(new BoundingSphere());
- if (!scene3DOnly) {
- const center = geometry.boundingSphereCV.center;
- const x = center.x;
- const y = center.y;
- const z = center.z;
- center.x = z;
- center.y = x;
- center.z = y;
- primitive._boundingSphereCV.push(
- BoundingSphere.clone(geometry.boundingSphereCV)
- );
- primitive._boundingSphere2D.push(new BoundingSphere());
- primitive._boundingSphereMorph.push(new BoundingSphere());
- }
- }
- }
- primitive._va = va;
- primitive._primitiveType = geometries[0].primitiveType;
- if (primitive.releaseGeometryInstances) {
- primitive.geometryInstances = undefined;
- }
- primitive._geometries = undefined;
- setReady(primitive, frameState, PrimitiveState.COMPLETE, undefined);
- }
- function createRenderStates(primitive, context, appearance, twoPasses) {
- let renderState = appearance.getRenderState();
- let rs;
- if (twoPasses) {
- rs = clone(renderState, false);
- rs.cull = {
- enabled: true,
- face: CullFace.BACK,
- };
- primitive._frontFaceRS = RenderState.fromCache(rs);
- rs.cull.face = CullFace.FRONT;
- primitive._backFaceRS = RenderState.fromCache(rs);
- } else {
- primitive._frontFaceRS = RenderState.fromCache(renderState);
- primitive._backFaceRS = primitive._frontFaceRS;
- }
- rs = clone(renderState, false);
- if (defined(primitive._depthFailAppearance)) {
- rs.depthTest.enabled = false;
- }
- if (defined(primitive._depthFailAppearance)) {
- renderState = primitive._depthFailAppearance.getRenderState();
- rs = clone(renderState, false);
- rs.depthTest.func = DepthFunction.GREATER;
- if (twoPasses) {
- rs.cull = {
- enabled: true,
- face: CullFace.BACK,
- };
- primitive._frontFaceDepthFailRS = RenderState.fromCache(rs);
- rs.cull.face = CullFace.FRONT;
- primitive._backFaceDepthFailRS = RenderState.fromCache(rs);
- } else {
- primitive._frontFaceDepthFailRS = RenderState.fromCache(rs);
- primitive._backFaceDepthFailRS = primitive._frontFaceRS;
- }
- }
- }
- function createShaderProgram(primitive, frameState, appearance) {
- const context = frameState.context;
- const attributeLocations = primitive._attributeLocations;
- let vs = primitive._batchTable.getVertexShaderCallback()(
- appearance.vertexShaderSource
- );
- vs = Primitive._appendOffsetToShader(primitive, vs);
- vs = Primitive._appendShowToShader(primitive, vs);
- vs = Primitive._appendDistanceDisplayConditionToShader(
- primitive,
- vs,
- frameState.scene3DOnly
- );
- vs = appendPickToVertexShader(vs);
- vs = Primitive._updateColorAttribute(primitive, vs, false);
- vs = modifyForEncodedNormals(primitive, vs);
- vs = Primitive._modifyShaderPosition(primitive, vs, frameState.scene3DOnly);
- let fs = appearance.getFragmentShaderSource();
- fs = appendPickToFragmentShader(fs);
- primitive._sp = ShaderProgram.replaceCache({
- context: context,
- shaderProgram: primitive._sp,
- vertexShaderSource: vs,
- fragmentShaderSource: fs,
- attributeLocations: attributeLocations,
- });
- validateShaderMatching(primitive._sp, attributeLocations);
- if (defined(primitive._depthFailAppearance)) {
- vs = primitive._batchTable.getVertexShaderCallback()(
- primitive._depthFailAppearance.vertexShaderSource
- );
- vs = Primitive._appendShowToShader(primitive, vs);
- vs = Primitive._appendDistanceDisplayConditionToShader(
- primitive,
- vs,
- frameState.scene3DOnly
- );
- vs = appendPickToVertexShader(vs);
- vs = Primitive._updateColorAttribute(primitive, vs, true);
- vs = modifyForEncodedNormals(primitive, vs);
- vs = Primitive._modifyShaderPosition(primitive, vs, frameState.scene3DOnly);
- vs = depthClampVS(vs);
- fs = primitive._depthFailAppearance.getFragmentShaderSource();
- fs = appendPickToFragmentShader(fs);
- fs = depthClampFS(fs);
- primitive._spDepthFail = ShaderProgram.replaceCache({
- context: context,
- shaderProgram: primitive._spDepthFail,
- vertexShaderSource: vs,
- fragmentShaderSource: fs,
- attributeLocations: attributeLocations,
- });
- validateShaderMatching(primitive._spDepthFail, attributeLocations);
- }
- }
- const modifiedModelViewScratch = new Matrix4();
- const rtcScratch = new Cartesian3();
- function getUniforms(primitive, appearance, material, frameState) {
- // Create uniform map by combining uniforms from the appearance and material if either have uniforms.
- const materialUniformMap = defined(material) ? material._uniforms : undefined;
- const appearanceUniformMap = {};
- const appearanceUniforms = appearance.uniforms;
- if (defined(appearanceUniforms)) {
- // Convert to uniform map of functions for the renderer
- for (const name in appearanceUniforms) {
- if (appearanceUniforms.hasOwnProperty(name)) {
- //>>includeStart('debug', pragmas.debug);
- if (defined(materialUniformMap) && defined(materialUniformMap[name])) {
- // Later, we could rename uniforms behind-the-scenes if needed.
- throw new DeveloperError(
- `Appearance and material have a uniform with the same name: ${name}`
- );
- }
- //>>includeEnd('debug');
- appearanceUniformMap[name] = getUniformFunction(
- appearanceUniforms,
- name
- );
- }
- }
- }
- let uniforms = combine(appearanceUniformMap, materialUniformMap);
- uniforms = primitive._batchTable.getUniformMapCallback()(uniforms);
- if (defined(primitive.rtcCenter)) {
- uniforms.u_modifiedModelView = function () {
- const viewMatrix = frameState.context.uniformState.view;
- Matrix4.multiply(
- viewMatrix,
- primitive._modelMatrix,
- modifiedModelViewScratch
- );
- Matrix4.multiplyByPoint(
- modifiedModelViewScratch,
- primitive.rtcCenter,
- rtcScratch
- );
- Matrix4.setTranslation(
- modifiedModelViewScratch,
- rtcScratch,
- modifiedModelViewScratch
- );
- return modifiedModelViewScratch;
- };
- }
- return uniforms;
- }
- function createCommands(
- primitive,
- appearance,
- material,
- translucent,
- twoPasses,
- colorCommands,
- pickCommands,
- frameState
- ) {
- const uniforms = getUniforms(primitive, appearance, material, frameState);
- let depthFailUniforms;
- if (defined(primitive._depthFailAppearance)) {
- depthFailUniforms = getUniforms(
- primitive,
- primitive._depthFailAppearance,
- primitive._depthFailAppearance.material,
- frameState
- );
- }
- const pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE;
- let multiplier = twoPasses ? 2 : 1;
- multiplier *= defined(primitive._depthFailAppearance) ? 2 : 1;
- colorCommands.length = primitive._va.length * multiplier;
- const length = colorCommands.length;
- let vaIndex = 0;
- for (let i = 0; i < length; ++i) {
- let colorCommand;
- if (twoPasses) {
- colorCommand = colorCommands[i];
- if (!defined(colorCommand)) {
- colorCommand = colorCommands[i] = new DrawCommand({
- owner: primitive,
- primitiveType: primitive._primitiveType,
- });
- }
- colorCommand.vertexArray = primitive._va[vaIndex];
- colorCommand.renderState = primitive._backFaceRS;
- colorCommand.shaderProgram = primitive._sp;
- colorCommand.uniformMap = uniforms;
- colorCommand.pass = pass;
- ++i;
- }
- colorCommand = colorCommands[i];
- if (!defined(colorCommand)) {
- colorCommand = colorCommands[i] = new DrawCommand({
- owner: primitive,
- primitiveType: primitive._primitiveType,
- });
- }
- colorCommand.vertexArray = primitive._va[vaIndex];
- colorCommand.renderState = primitive._frontFaceRS;
- colorCommand.shaderProgram = primitive._sp;
- colorCommand.uniformMap = uniforms;
- colorCommand.pass = pass;
- if (defined(primitive._depthFailAppearance)) {
- if (twoPasses) {
- ++i;
- colorCommand = colorCommands[i];
- if (!defined(colorCommand)) {
- colorCommand = colorCommands[i] = new DrawCommand({
- owner: primitive,
- primitiveType: primitive._primitiveType,
- });
- }
- colorCommand.vertexArray = primitive._va[vaIndex];
- colorCommand.renderState = primitive._backFaceDepthFailRS;
- colorCommand.shaderProgram = primitive._spDepthFail;
- colorCommand.uniformMap = depthFailUniforms;
- colorCommand.pass = pass;
- }
- ++i;
- colorCommand = colorCommands[i];
- if (!defined(colorCommand)) {
- colorCommand = colorCommands[i] = new DrawCommand({
- owner: primitive,
- primitiveType: primitive._primitiveType,
- });
- }
- colorCommand.vertexArray = primitive._va[vaIndex];
- colorCommand.renderState = primitive._frontFaceDepthFailRS;
- colorCommand.shaderProgram = primitive._spDepthFail;
- colorCommand.uniformMap = depthFailUniforms;
- colorCommand.pass = pass;
- }
- ++vaIndex;
- }
- }
- Primitive._updateBoundingVolumes = function (
- primitive,
- frameState,
- modelMatrix,
- forceUpdate
- ) {
- let i;
- let length;
- let boundingSphere;
- if (forceUpdate || !Matrix4.equals(modelMatrix, primitive._modelMatrix)) {
- Matrix4.clone(modelMatrix, primitive._modelMatrix);
- length = primitive._boundingSpheres.length;
- for (i = 0; i < length; ++i) {
- boundingSphere = primitive._boundingSpheres[i];
- if (defined(boundingSphere)) {
- primitive._boundingSphereWC[i] = BoundingSphere.transform(
- boundingSphere,
- modelMatrix,
- primitive._boundingSphereWC[i]
- );
- if (!frameState.scene3DOnly) {
- primitive._boundingSphere2D[i] = BoundingSphere.clone(
- primitive._boundingSphereCV[i],
- primitive._boundingSphere2D[i]
- );
- primitive._boundingSphere2D[i].center.x = 0.0;
- primitive._boundingSphereMorph[i] = BoundingSphere.union(
- primitive._boundingSphereWC[i],
- primitive._boundingSphereCV[i]
- );
- }
- }
- }
- }
- // Update bounding volumes for primitives that are sized in pixels.
- // The pixel size in meters varies based on the distance from the camera.
- const pixelSize = primitive.appearance.pixelSize;
- if (defined(pixelSize)) {
- length = primitive._boundingSpheres.length;
- for (i = 0; i < length; ++i) {
- boundingSphere = primitive._boundingSpheres[i];
- const boundingSphereWC = primitive._boundingSphereWC[i];
- const pixelSizeInMeters = frameState.camera.getPixelSize(
- boundingSphere,
- frameState.context.drawingBufferWidth,
- frameState.context.drawingBufferHeight
- );
- const sizeInMeters = pixelSizeInMeters * pixelSize;
- boundingSphereWC.radius = boundingSphere.radius + sizeInMeters;
- }
- }
- };
- function updateAndQueueCommands(
- primitive,
- frameState,
- colorCommands,
- pickCommands,
- modelMatrix,
- cull,
- debugShowBoundingVolume,
- twoPasses
- ) {
- //>>includeStart('debug', pragmas.debug);
- if (
- frameState.mode !== SceneMode.SCENE3D &&
- !Matrix4.equals(modelMatrix, Matrix4.IDENTITY)
- ) {
- throw new DeveloperError(
- "Primitive.modelMatrix is only supported in 3D mode."
- );
- }
- //>>includeEnd('debug');
- Primitive._updateBoundingVolumes(primitive, frameState, modelMatrix);
- let boundingSpheres;
- if (frameState.mode === SceneMode.SCENE3D) {
- boundingSpheres = primitive._boundingSphereWC;
- } else if (frameState.mode === SceneMode.COLUMBUS_VIEW) {
- boundingSpheres = primitive._boundingSphereCV;
- } else if (
- frameState.mode === SceneMode.SCENE2D &&
- defined(primitive._boundingSphere2D)
- ) {
- boundingSpheres = primitive._boundingSphere2D;
- } else if (defined(primitive._boundingSphereMorph)) {
- boundingSpheres = primitive._boundingSphereMorph;
- }
- const commandList = frameState.commandList;
- const passes = frameState.passes;
- if (passes.render || passes.pick) {
- const allowPicking = primitive.allowPicking;
- const castShadows = ShadowMode.castShadows(primitive.shadows);
- const receiveShadows = ShadowMode.receiveShadows(primitive.shadows);
- const colorLength = colorCommands.length;
- let factor = twoPasses ? 2 : 1;
- factor *= defined(primitive._depthFailAppearance) ? 2 : 1;
- for (let j = 0; j < colorLength; ++j) {
- const sphereIndex = Math.floor(j / factor);
- const colorCommand = colorCommands[j];
- colorCommand.modelMatrix = modelMatrix;
- colorCommand.boundingVolume = boundingSpheres[sphereIndex];
- colorCommand.cull = cull;
- colorCommand.debugShowBoundingVolume = debugShowBoundingVolume;
- colorCommand.castShadows = castShadows;
- colorCommand.receiveShadows = receiveShadows;
- if (allowPicking) {
- colorCommand.pickId = "v_pickColor";
- } else {
- colorCommand.pickId = undefined;
- }
- commandList.push(colorCommand);
- }
- }
- }
- /**
- * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
- * get the draw commands needed to render this primitive.
- * <p>
- * Do not call this function directly. This is documented just to
- * list the exceptions that may be propagated when the scene is rendered:
- * </p>
- *
- * @exception {DeveloperError} All instance geometries must have the same primitiveType.
- * @exception {DeveloperError} Appearance and material have a uniform with the same name.
- * @exception {DeveloperError} Primitive.modelMatrix is only supported in 3D mode.
- * @exception {RuntimeError} Vertex texture fetch support is required to render primitives with per-instance attributes. The maximum number of vertex texture image units must be greater than zero.
- */
- Primitive.prototype.update = function (frameState) {
- if (
- (!defined(this.geometryInstances) && this._va.length === 0) ||
- (defined(this.geometryInstances) &&
- Array.isArray(this.geometryInstances) &&
- this.geometryInstances.length === 0) ||
- !defined(this.appearance) ||
- (frameState.mode !== SceneMode.SCENE3D && frameState.scene3DOnly) ||
- (!frameState.passes.render && !frameState.passes.pick)
- ) {
- return;
- }
- if (defined(this._error)) {
- throw this._error;
- }
- //>>includeStart('debug', pragmas.debug);
- if (defined(this.rtcCenter) && !frameState.scene3DOnly) {
- throw new DeveloperError(
- "RTC rendering is only available for 3D only scenes."
- );
- }
- //>>includeEnd('debug');
- if (this._state === PrimitiveState.FAILED) {
- return;
- }
- const context = frameState.context;
- if (!defined(this._batchTable)) {
- createBatchTable(this, context);
- }
- if (this._batchTable.attributes.length > 0) {
- if (ContextLimits.maximumVertexTextureImageUnits === 0) {
- throw new RuntimeError(
- "Vertex texture fetch support is required to render primitives with per-instance attributes. The maximum number of vertex texture image units must be greater than zero."
- );
- }
- this._batchTable.update(frameState);
- }
- if (
- this._state !== PrimitiveState.COMPLETE &&
- this._state !== PrimitiveState.COMBINED
- ) {
- if (this.asynchronous) {
- loadAsynchronous(this, frameState);
- } else {
- loadSynchronous(this, frameState);
- }
- }
- if (this._state === PrimitiveState.COMBINED) {
- updateBatchTableBoundingSpheres(this, frameState);
- updateBatchTableOffsets(this, frameState);
- createVertexArray(this, frameState);
- }
- if (!this.show || this._state !== PrimitiveState.COMPLETE) {
- return;
- }
- if (!this._batchTableOffsetsUpdated) {
- updateBatchTableOffsets(this, frameState);
- }
- if (this._recomputeBoundingSpheres) {
- recomputeBoundingSpheres(this, frameState);
- }
- // Create or recreate render state and shader program if appearance/material changed
- const appearance = this.appearance;
- const material = appearance.material;
- let createRS = false;
- let createSP = false;
- if (this._appearance !== appearance) {
- this._appearance = appearance;
- this._material = material;
- createRS = true;
- createSP = true;
- } else if (this._material !== material) {
- this._material = material;
- createSP = true;
- }
- const depthFailAppearance = this.depthFailAppearance;
- const depthFailMaterial = defined(depthFailAppearance)
- ? depthFailAppearance.material
- : undefined;
- if (this._depthFailAppearance !== depthFailAppearance) {
- this._depthFailAppearance = depthFailAppearance;
- this._depthFailMaterial = depthFailMaterial;
- createRS = true;
- createSP = true;
- } else if (this._depthFailMaterial !== depthFailMaterial) {
- this._depthFailMaterial = depthFailMaterial;
- createSP = true;
- }
- const translucent = this._appearance.isTranslucent();
- if (this._translucent !== translucent) {
- this._translucent = translucent;
- createRS = true;
- }
- if (defined(this._material)) {
- this._material.update(context);
- }
- const twoPasses = appearance.closed && translucent;
- if (createRS) {
- const rsFunc = defaultValue(
- this._createRenderStatesFunction,
- createRenderStates
- );
- rsFunc(this, context, appearance, twoPasses);
- }
- if (createSP) {
- const spFunc = defaultValue(
- this._createShaderProgramFunction,
- createShaderProgram
- );
- spFunc(this, frameState, appearance);
- }
- if (createRS || createSP) {
- const commandFunc = defaultValue(
- this._createCommandsFunction,
- createCommands
- );
- commandFunc(
- this,
- appearance,
- material,
- translucent,
- twoPasses,
- this._colorCommands,
- this._pickCommands,
- frameState
- );
- }
- const updateAndQueueCommandsFunc = defaultValue(
- this._updateAndQueueCommandsFunction,
- updateAndQueueCommands
- );
- updateAndQueueCommandsFunc(
- this,
- frameState,
- this._colorCommands,
- this._pickCommands,
- this.modelMatrix,
- this.cull,
- this.debugShowBoundingVolume,
- twoPasses
- );
- };
- const offsetBoundingSphereScratch1 = new BoundingSphere();
- const offsetBoundingSphereScratch2 = new BoundingSphere();
- function transformBoundingSphere(boundingSphere, offset, offsetAttribute) {
- if (offsetAttribute === GeometryOffsetAttribute.TOP) {
- const origBS = BoundingSphere.clone(
- boundingSphere,
- offsetBoundingSphereScratch1
- );
- const offsetBS = BoundingSphere.clone(
- boundingSphere,
- offsetBoundingSphereScratch2
- );
- offsetBS.center = Cartesian3.add(offsetBS.center, offset, offsetBS.center);
- boundingSphere = BoundingSphere.union(origBS, offsetBS, boundingSphere);
- } else if (offsetAttribute === GeometryOffsetAttribute.ALL) {
- boundingSphere.center = Cartesian3.add(
- boundingSphere.center,
- offset,
- boundingSphere.center
- );
- }
- return boundingSphere;
- }
- function createGetFunction(batchTable, instanceIndex, attributeIndex) {
- return function () {
- const attributeValue = batchTable.getBatchedAttribute(
- instanceIndex,
- attributeIndex
- );
- const attribute = batchTable.attributes[attributeIndex];
- const componentsPerAttribute = attribute.componentsPerAttribute;
- const value = ComponentDatatype.createTypedArray(
- attribute.componentDatatype,
- componentsPerAttribute
- );
- if (defined(attributeValue.constructor.pack)) {
- attributeValue.constructor.pack(attributeValue, value, 0);
- } else {
- value[0] = attributeValue;
- }
- return value;
- };
- }
- function createSetFunction(
- batchTable,
- instanceIndex,
- attributeIndex,
- primitive,
- name
- ) {
- return function (value) {
- //>>includeStart('debug', pragmas.debug);
- if (
- !defined(value) ||
- !defined(value.length) ||
- value.length < 1 ||
- value.length > 4
- ) {
- throw new DeveloperError(
- "value must be and array with length between 1 and 4."
- );
- }
- //>>includeEnd('debug');
- const attributeValue = getAttributeValue(value);
- batchTable.setBatchedAttribute(
- instanceIndex,
- attributeIndex,
- attributeValue
- );
- if (name === "offset") {
- primitive._recomputeBoundingSpheres = true;
- primitive._batchTableOffsetsUpdated = false;
- }
- };
- }
- const offsetScratch = new Cartesian3();
- function createBoundingSphereProperties(primitive, properties, index) {
- properties.boundingSphere = {
- get: function () {
- let boundingSphere = primitive._instanceBoundingSpheres[index];
- if (defined(boundingSphere)) {
- boundingSphere = boundingSphere.clone();
- const modelMatrix = primitive.modelMatrix;
- const offset = properties.offset;
- if (defined(offset)) {
- transformBoundingSphere(
- boundingSphere,
- Cartesian3.fromArray(offset.get(), 0, offsetScratch),
- primitive._offsetInstanceExtend[index]
- );
- }
- if (defined(modelMatrix)) {
- boundingSphere = BoundingSphere.transform(
- boundingSphere,
- modelMatrix
- );
- }
- }
- return boundingSphere;
- },
- };
- properties.boundingSphereCV = {
- get: function () {
- return primitive._instanceBoundingSpheresCV[index];
- },
- };
- }
- function createPickIdProperty(primitive, properties, index) {
- properties.pickId = {
- get: function () {
- return primitive._pickIds[index];
- },
- };
- }
- /**
- * Returns the modifiable per-instance attributes for a {@link GeometryInstance}.
- *
- * @param {*} id The id of the {@link GeometryInstance}.
- * @returns {Object} The typed array in the attribute's format or undefined if the is no instance with id.
- *
- * @exception {DeveloperError} must call update before calling getGeometryInstanceAttributes.
- *
- * @example
- * const attributes = primitive.getGeometryInstanceAttributes('an id');
- * attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.AQUA);
- * attributes.show = Cesium.ShowGeometryInstanceAttribute.toValue(true);
- * attributes.distanceDisplayCondition = Cesium.DistanceDisplayConditionGeometryInstanceAttribute.toValue(100.0, 10000.0);
- * attributes.offset = Cesium.OffsetGeometryInstanceAttribute.toValue(Cartesian3.IDENTITY);
- */
- Primitive.prototype.getGeometryInstanceAttributes = function (id) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(id)) {
- throw new DeveloperError("id is required");
- }
- if (!defined(this._batchTable)) {
- throw new DeveloperError(
- "must call update before calling getGeometryInstanceAttributes"
- );
- }
- //>>includeEnd('debug');
- let index = -1;
- const lastIndex = this._lastPerInstanceAttributeIndex;
- const ids = this._instanceIds;
- const length = ids.length;
- for (let i = 0; i < length; ++i) {
- const curIndex = (lastIndex + i) % length;
- if (id === ids[curIndex]) {
- index = curIndex;
- break;
- }
- }
- if (index === -1) {
- return undefined;
- }
- let attributes = this._perInstanceAttributeCache[index];
- if (defined(attributes)) {
- return attributes;
- }
- const batchTable = this._batchTable;
- const perInstanceAttributeIndices = this._batchTableAttributeIndices;
- attributes = {};
- const properties = {};
- for (const name in perInstanceAttributeIndices) {
- if (perInstanceAttributeIndices.hasOwnProperty(name)) {
- const attributeIndex = perInstanceAttributeIndices[name];
- properties[name] = {
- get: createGetFunction(batchTable, index, attributeIndex),
- set: createSetFunction(batchTable, index, attributeIndex, this, name),
- };
- }
- }
- createBoundingSphereProperties(this, properties, index);
- createPickIdProperty(this, properties, index);
- Object.defineProperties(attributes, properties);
- this._lastPerInstanceAttributeIndex = index;
- this._perInstanceAttributeCache[index] = attributes;
- return attributes;
- };
- /**
- * 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 Primitive#destroy
- */
- Primitive.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 Primitive#isDestroyed
- */
- Primitive.prototype.destroy = function () {
- let length;
- let i;
- this._sp = this._sp && this._sp.destroy();
- this._spDepthFail = this._spDepthFail && this._spDepthFail.destroy();
- const va = this._va;
- length = va.length;
- for (i = 0; i < length; ++i) {
- va[i].destroy();
- }
- this._va = undefined;
- const pickIds = this._pickIds;
- length = pickIds.length;
- for (i = 0; i < length; ++i) {
- pickIds[i].destroy();
- }
- this._pickIds = undefined;
- this._batchTable = this._batchTable && this._batchTable.destroy();
- //These objects may be fairly large and reference other large objects (like Entities)
- //We explicitly set them to undefined here so that the memory can be freed
- //even if a reference to the destroyed Primitive has been kept around.
- this._instanceIds = undefined;
- this._perInstanceAttributeCache = undefined;
- this._attributeLocations = undefined;
- return destroyObject(this);
- };
- function setReady(primitive, frameState, state, error) {
- primitive._error = error;
- primitive._state = state;
- frameState.afterRender.push(function () {
- primitive._ready =
- primitive._state === PrimitiveState.COMPLETE ||
- primitive._state === PrimitiveState.FAILED;
- if (!defined(error)) {
- primitive._readyPromise.resolve(primitive);
- } else {
- primitive._readyPromise.reject(error);
- }
- });
- }
- export default Primitive;
|