DrawCommand.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. import defaultValue from "../Core/defaultValue.js";
  2. import defined from "../Core/defined.js";
  3. import PrimitiveType from "../Core/PrimitiveType.js";
  4. /**
  5. * Represents a command to the renderer for drawing.
  6. *
  7. * @private
  8. */
  9. function DrawCommand(options) {
  10. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  11. this._boundingVolume = options.boundingVolume;
  12. this._orientedBoundingBox = options.orientedBoundingBox;
  13. this._cull = defaultValue(options.cull, true);
  14. this._occlude = defaultValue(options.occlude, true);
  15. this._modelMatrix = options.modelMatrix;
  16. this._primitiveType = defaultValue(
  17. options.primitiveType,
  18. PrimitiveType.TRIANGLES
  19. );
  20. this._vertexArray = options.vertexArray;
  21. this._count = options.count;
  22. this._offset = defaultValue(options.offset, 0);
  23. this._instanceCount = defaultValue(options.instanceCount, 0);
  24. this._shaderProgram = options.shaderProgram;
  25. this._uniformMap = options.uniformMap;
  26. this._renderState = options.renderState;
  27. this._framebuffer = options.framebuffer;
  28. this._pass = options.pass;
  29. this._executeInClosestFrustum = defaultValue(
  30. options.executeInClosestFrustum,
  31. false
  32. );
  33. this._owner = options.owner;
  34. this._debugShowBoundingVolume = defaultValue(
  35. options.debugShowBoundingVolume,
  36. false
  37. );
  38. this._debugOverlappingFrustums = 0;
  39. this._castShadows = defaultValue(options.castShadows, false);
  40. this._receiveShadows = defaultValue(options.receiveShadows, false);
  41. this._pickId = options.pickId;
  42. this._pickOnly = defaultValue(options.pickOnly, false);
  43. this.dirty = true;
  44. this.lastDirtyTime = 0;
  45. /**
  46. * @private
  47. */
  48. this.derivedCommands = {};
  49. }
  50. Object.defineProperties(DrawCommand.prototype, {
  51. /**
  52. * The bounding volume of the geometry in world space. This is used for culling and frustum selection.
  53. * <p>
  54. * For best rendering performance, use the tightest possible bounding volume. Although
  55. * <code>undefined</code> is allowed, always try to provide a bounding volume to
  56. * allow the tightest possible near and far planes to be computed for the scene, and
  57. * minimize the number of frustums needed.
  58. * </p>
  59. *
  60. * @memberof DrawCommand.prototype
  61. * @type {Object}
  62. * @default undefined
  63. *
  64. * @see DrawCommand#debugShowBoundingVolume
  65. */
  66. boundingVolume: {
  67. get: function () {
  68. return this._boundingVolume;
  69. },
  70. set: function (value) {
  71. if (this._boundingVolume !== value) {
  72. this._boundingVolume = value;
  73. this.dirty = true;
  74. }
  75. },
  76. },
  77. /**
  78. * The oriented bounding box of the geometry in world space. If this is defined, it is used instead of
  79. * {@link DrawCommand#boundingVolume} for plane intersection testing.
  80. *
  81. * @memberof DrawCommand.prototype
  82. * @type {OrientedBoundingBox}
  83. * @default undefined
  84. *
  85. * @see DrawCommand#debugShowBoundingVolume
  86. */
  87. orientedBoundingBox: {
  88. get: function () {
  89. return this._orientedBoundingBox;
  90. },
  91. set: function (value) {
  92. if (this._orientedBoundingBox !== value) {
  93. this._orientedBoundingBox = value;
  94. this.dirty = true;
  95. }
  96. },
  97. },
  98. /**
  99. * When <code>true</code>, the renderer frustum and horizon culls the command based on its {@link DrawCommand#boundingVolume}.
  100. * If the command was already culled, set this to <code>false</code> for a performance improvement.
  101. *
  102. * @memberof DrawCommand.prototype
  103. * @type {Boolean}
  104. * @default true
  105. */
  106. cull: {
  107. get: function () {
  108. return this._cull;
  109. },
  110. set: function (value) {
  111. if (this._cull !== value) {
  112. this._cull = value;
  113. this.dirty = true;
  114. }
  115. },
  116. },
  117. /**
  118. * When <code>true</code>, the horizon culls the command based on its {@link DrawCommand#boundingVolume}.
  119. * {@link DrawCommand#cull} must also be <code>true</code> in order for the command to be culled.
  120. *
  121. * @memberof DrawCommand.prototype
  122. * @type {Boolean}
  123. * @default true
  124. */
  125. occlude: {
  126. get: function () {
  127. return this._occlude;
  128. },
  129. set: function (value) {
  130. if (this._occlude !== value) {
  131. this._occlude = value;
  132. this.dirty = true;
  133. }
  134. },
  135. },
  136. /**
  137. * The transformation from the geometry in model space to world space.
  138. * <p>
  139. * When <code>undefined</code>, the geometry is assumed to be defined in world space.
  140. * </p>
  141. *
  142. * @memberof DrawCommand.prototype
  143. * @type {Matrix4}
  144. * @default undefined
  145. */
  146. modelMatrix: {
  147. get: function () {
  148. return this._modelMatrix;
  149. },
  150. set: function (value) {
  151. if (this._modelMatrix !== value) {
  152. this._modelMatrix = value;
  153. this.dirty = true;
  154. }
  155. },
  156. },
  157. /**
  158. * The type of geometry in the vertex array.
  159. *
  160. * @memberof DrawCommand.prototype
  161. * @type {PrimitiveType}
  162. * @default PrimitiveType.TRIANGLES
  163. */
  164. primitiveType: {
  165. get: function () {
  166. return this._primitiveType;
  167. },
  168. set: function (value) {
  169. if (this._primitiveType !== value) {
  170. this._primitiveType = value;
  171. this.dirty = true;
  172. }
  173. },
  174. },
  175. /**
  176. * The vertex array.
  177. *
  178. * @memberof DrawCommand.prototype
  179. * @type {VertexArray}
  180. * @default undefined
  181. */
  182. vertexArray: {
  183. get: function () {
  184. return this._vertexArray;
  185. },
  186. set: function (value) {
  187. if (this._vertexArray !== value) {
  188. this._vertexArray = value;
  189. this.dirty = true;
  190. }
  191. },
  192. },
  193. /**
  194. * The number of vertices to draw in the vertex array.
  195. *
  196. * @memberof DrawCommand.prototype
  197. * @type {Number}
  198. * @default undefined
  199. */
  200. count: {
  201. get: function () {
  202. return this._count;
  203. },
  204. set: function (value) {
  205. if (this._count !== value) {
  206. this._count = value;
  207. this.dirty = true;
  208. }
  209. },
  210. },
  211. /**
  212. * The offset to start drawing in the vertex array.
  213. *
  214. * @memberof DrawCommand.prototype
  215. * @type {Number}
  216. * @default 0
  217. */
  218. offset: {
  219. get: function () {
  220. return this._offset;
  221. },
  222. set: function (value) {
  223. if (this._offset !== value) {
  224. this._offset = value;
  225. this.dirty = true;
  226. }
  227. },
  228. },
  229. /**
  230. * The number of instances to draw.
  231. *
  232. * @memberof DrawCommand.prototype
  233. * @type {Number}
  234. * @default 0
  235. */
  236. instanceCount: {
  237. get: function () {
  238. return this._instanceCount;
  239. },
  240. set: function (value) {
  241. if (this._instanceCount !== value) {
  242. this._instanceCount = value;
  243. this.dirty = true;
  244. }
  245. },
  246. },
  247. /**
  248. * The shader program to apply.
  249. *
  250. * @memberof DrawCommand.prototype
  251. * @type {ShaderProgram}
  252. * @default undefined
  253. */
  254. shaderProgram: {
  255. get: function () {
  256. return this._shaderProgram;
  257. },
  258. set: function (value) {
  259. if (this._shaderProgram !== value) {
  260. this._shaderProgram = value;
  261. this.dirty = true;
  262. }
  263. },
  264. },
  265. /**
  266. * Whether this command should cast shadows when shadowing is enabled.
  267. *
  268. * @memberof DrawCommand.prototype
  269. * @type {Boolean}
  270. * @default false
  271. */
  272. castShadows: {
  273. get: function () {
  274. return this._castShadows;
  275. },
  276. set: function (value) {
  277. if (this._castShadows !== value) {
  278. this._castShadows = value;
  279. this.dirty = true;
  280. }
  281. },
  282. },
  283. /**
  284. * Whether this command should receive shadows when shadowing is enabled.
  285. *
  286. * @memberof DrawCommand.prototype
  287. * @type {Boolean}
  288. * @default false
  289. */
  290. receiveShadows: {
  291. get: function () {
  292. return this._receiveShadows;
  293. },
  294. set: function (value) {
  295. if (this._receiveShadows !== value) {
  296. this._receiveShadows = value;
  297. this.dirty = true;
  298. }
  299. },
  300. },
  301. /**
  302. * An object with functions whose names match the uniforms in the shader program
  303. * and return values to set those uniforms.
  304. *
  305. * @memberof DrawCommand.prototype
  306. * @type {Object}
  307. * @default undefined
  308. */
  309. uniformMap: {
  310. get: function () {
  311. return this._uniformMap;
  312. },
  313. set: function (value) {
  314. if (this._uniformMap !== value) {
  315. this._uniformMap = value;
  316. this.dirty = true;
  317. }
  318. },
  319. },
  320. /**
  321. * The render state.
  322. *
  323. * @memberof DrawCommand.prototype
  324. * @type {RenderState}
  325. * @default undefined
  326. */
  327. renderState: {
  328. get: function () {
  329. return this._renderState;
  330. },
  331. set: function (value) {
  332. if (this._renderState !== value) {
  333. this._renderState = value;
  334. this.dirty = true;
  335. }
  336. },
  337. },
  338. /**
  339. * The framebuffer to draw to.
  340. *
  341. * @memberof DrawCommand.prototype
  342. * @type {Framebuffer}
  343. * @default undefined
  344. */
  345. framebuffer: {
  346. get: function () {
  347. return this._framebuffer;
  348. },
  349. set: function (value) {
  350. if (this._framebuffer !== value) {
  351. this._framebuffer = value;
  352. this.dirty = true;
  353. }
  354. },
  355. },
  356. /**
  357. * The pass when to render.
  358. *
  359. * @memberof DrawCommand.prototype
  360. * @type {Pass}
  361. * @default undefined
  362. */
  363. pass: {
  364. get: function () {
  365. return this._pass;
  366. },
  367. set: function (value) {
  368. if (this._pass !== value) {
  369. this._pass = value;
  370. this.dirty = true;
  371. }
  372. },
  373. },
  374. /**
  375. * Specifies if this command is only to be executed in the frustum closest
  376. * to the eye containing the bounding volume. Defaults to <code>false</code>.
  377. *
  378. * @memberof DrawCommand.prototype
  379. * @type {Boolean}
  380. * @default false
  381. */
  382. executeInClosestFrustum: {
  383. get: function () {
  384. return this._executeInClosestFrustum;
  385. },
  386. set: function (value) {
  387. if (this._executeInClosestFrustum !== value) {
  388. this._executeInClosestFrustum = value;
  389. this.dirty = true;
  390. }
  391. },
  392. },
  393. /**
  394. * The object who created this command. This is useful for debugging command
  395. * execution; it allows us to see who created a command when we only have a
  396. * reference to the command, and can be used to selectively execute commands
  397. * with {@link Scene#debugCommandFilter}.
  398. *
  399. * @memberof DrawCommand.prototype
  400. * @type {Object}
  401. * @default undefined
  402. *
  403. * @see Scene#debugCommandFilter
  404. */
  405. owner: {
  406. get: function () {
  407. return this._owner;
  408. },
  409. set: function (value) {
  410. if (this._owner !== value) {
  411. this._owner = value;
  412. this.dirty = true;
  413. }
  414. },
  415. },
  416. /**
  417. * This property is for debugging only; it is not for production use nor is it optimized.
  418. * <p>
  419. * Draws the {@link DrawCommand#boundingVolume} for this command, assuming it is a sphere, when the command executes.
  420. * </p>
  421. *
  422. * @memberof DrawCommand.prototype
  423. * @type {Boolean}
  424. * @default false
  425. *
  426. * @see DrawCommand#boundingVolume
  427. */
  428. debugShowBoundingVolume: {
  429. get: function () {
  430. return this._debugShowBoundingVolume;
  431. },
  432. set: function (value) {
  433. if (this._debugShowBoundingVolume !== value) {
  434. this._debugShowBoundingVolume = value;
  435. this.dirty = true;
  436. }
  437. },
  438. },
  439. /**
  440. * Used to implement Scene.debugShowFrustums.
  441. * @private
  442. */
  443. debugOverlappingFrustums: {
  444. get: function () {
  445. return this._debugOverlappingFrustums;
  446. },
  447. set: function (value) {
  448. if (this._debugOverlappingFrustums !== value) {
  449. this._debugOverlappingFrustums = value;
  450. this.dirty = true;
  451. }
  452. },
  453. },
  454. /**
  455. * A GLSL string that will evaluate to a pick id. When <code>undefined</code>, the command will only draw depth
  456. * during the pick pass.
  457. *
  458. * @memberof DrawCommand.prototype
  459. * @type {String}
  460. * @default undefined
  461. */
  462. pickId: {
  463. get: function () {
  464. return this._pickId;
  465. },
  466. set: function (value) {
  467. if (this._pickId !== value) {
  468. this._pickId = value;
  469. this.dirty = true;
  470. }
  471. },
  472. },
  473. /**
  474. * Whether this command should be executed in the pick pass only.
  475. *
  476. * @memberof DrawCommand.prototype
  477. * @type {Boolean}
  478. * @default false
  479. */
  480. pickOnly: {
  481. get: function () {
  482. return this._pickOnly;
  483. },
  484. set: function (value) {
  485. if (this._pickOnly !== value) {
  486. this._pickOnly = value;
  487. this.dirty = true;
  488. }
  489. },
  490. },
  491. });
  492. /**
  493. * @private
  494. */
  495. DrawCommand.shallowClone = function (command, result) {
  496. if (!defined(command)) {
  497. return undefined;
  498. }
  499. if (!defined(result)) {
  500. result = new DrawCommand();
  501. }
  502. result._boundingVolume = command._boundingVolume;
  503. result._orientedBoundingBox = command._orientedBoundingBox;
  504. result._cull = command._cull;
  505. result._occlude = command._occlude;
  506. result._modelMatrix = command._modelMatrix;
  507. result._primitiveType = command._primitiveType;
  508. result._vertexArray = command._vertexArray;
  509. result._count = command._count;
  510. result._offset = command._offset;
  511. result._instanceCount = command._instanceCount;
  512. result._shaderProgram = command._shaderProgram;
  513. result._uniformMap = command._uniformMap;
  514. result._renderState = command._renderState;
  515. result._framebuffer = command._framebuffer;
  516. result._pass = command._pass;
  517. result._executeInClosestFrustum = command._executeInClosestFrustum;
  518. result._owner = command._owner;
  519. result._debugShowBoundingVolume = command._debugShowBoundingVolume;
  520. result._debugOverlappingFrustums = command._debugOverlappingFrustums;
  521. result._castShadows = command._castShadows;
  522. result._receiveShadows = command._receiveShadows;
  523. result._pickId = command._pickId;
  524. result._pickOnly = command._pickOnly;
  525. result.dirty = true;
  526. result.lastDirtyTime = 0;
  527. return result;
  528. };
  529. /**
  530. * Executes the draw command.
  531. *
  532. * @param {Context} context The renderer context in which to draw.
  533. * @param {PassState} [passState] The state for the current render pass.
  534. */
  535. DrawCommand.prototype.execute = function (context, passState) {
  536. context.draw(this, passState);
  537. };
  538. export default DrawCommand;