DrawCommand.js 17 KB

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