buildDrawCommands.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. import BlendingState from "../BlendingState.js";
  2. import Buffer from "../../Renderer/Buffer.js";
  3. import BufferUsage from "../../Renderer/BufferUsage.js";
  4. import clone from "../../Core/clone.js";
  5. import defined from "../../Core/defined.js";
  6. import DrawCommand from "../../Renderer/DrawCommand.js";
  7. import IndexDatatype from "../../Core/IndexDatatype.js";
  8. import ModelExperimentalFS from "../../Shaders/ModelExperimental/ModelExperimentalFS.js";
  9. import ModelExperimentalVS from "../../Shaders/ModelExperimental/ModelExperimentalVS.js";
  10. import Pass from "../../Renderer/Pass.js";
  11. import PrimitiveType from "../../Core/PrimitiveType.js";
  12. import RenderState from "../../Renderer/RenderState.js";
  13. import RuntimeError from "../../Core/RuntimeError.js";
  14. import StencilConstants from "../StencilConstants.js";
  15. import StyleCommandsNeeded from "./StyleCommandsNeeded.js";
  16. import VertexArray from "../../Renderer/VertexArray.js";
  17. import WireframeIndexGenerator from "../../Core/WireframeIndexGenerator.js";
  18. import BoundingSphere from "../../Core/BoundingSphere.js";
  19. import Matrix4 from "../../Core/Matrix4.js";
  20. import ShadowMode from "../ShadowMode.js";
  21. /**
  22. * Builds the DrawCommands for a {@link ModelExperimentalPrimitive} using its render resources.
  23. *
  24. * @param {PrimitiveRenderResources} primitiveRenderResources The render resources for a primitive.
  25. * @param {FrameState} frameState The frame state for creating GPU resources.
  26. *
  27. * @returns {DrawCommand[]} The generated DrawCommands.
  28. *
  29. * @private
  30. */
  31. export default function buildDrawCommands(
  32. primitiveRenderResources,
  33. frameState
  34. ) {
  35. const shaderBuilder = primitiveRenderResources.shaderBuilder;
  36. shaderBuilder.addVertexLines([ModelExperimentalVS]);
  37. shaderBuilder.addFragmentLines([ModelExperimentalFS]);
  38. const model = primitiveRenderResources.model;
  39. let primitiveType = primitiveRenderResources.primitiveType;
  40. const debugWireframe =
  41. model.debugWireframe && PrimitiveType.isTriangles(primitiveType);
  42. const indexBuffer = getIndexBuffer(
  43. primitiveRenderResources,
  44. debugWireframe,
  45. frameState
  46. );
  47. const vertexArray = new VertexArray({
  48. context: frameState.context,
  49. indexBuffer: indexBuffer,
  50. attributes: primitiveRenderResources.attributes,
  51. });
  52. model._resources.push(vertexArray);
  53. let renderState = primitiveRenderResources.renderStateOptions;
  54. if (model.opaquePass === Pass.CESIUM_3D_TILE) {
  55. // Set stencil values for classification on 3D Tiles
  56. renderState = clone(renderState, true);
  57. renderState.stencilTest = StencilConstants.setCesium3DTileBit();
  58. renderState.stencilMask = StencilConstants.CESIUM_3D_TILE_MASK;
  59. }
  60. renderState = RenderState.fromCache(renderState);
  61. const shaderProgram = shaderBuilder.buildShaderProgram(frameState.context);
  62. model._resources.push(shaderProgram);
  63. const pass = primitiveRenderResources.alphaOptions.pass;
  64. const sceneGraph = model.sceneGraph;
  65. const modelMatrix = Matrix4.multiply(
  66. sceneGraph.computedModelMatrix,
  67. primitiveRenderResources.runtimeNode.computedTransform,
  68. new Matrix4()
  69. );
  70. primitiveRenderResources.boundingSphere = BoundingSphere.transform(
  71. primitiveRenderResources.boundingSphere,
  72. modelMatrix,
  73. primitiveRenderResources.boundingSphere
  74. );
  75. let count = primitiveRenderResources.count;
  76. if (debugWireframe) {
  77. count = WireframeIndexGenerator.getWireframeIndicesCount(
  78. primitiveType,
  79. count
  80. );
  81. primitiveType = PrimitiveType.LINES;
  82. }
  83. const command = new DrawCommand({
  84. boundingVolume: primitiveRenderResources.boundingSphere,
  85. modelMatrix: modelMatrix,
  86. uniformMap: primitiveRenderResources.uniformMap,
  87. renderState: renderState,
  88. vertexArray: vertexArray,
  89. shaderProgram: shaderProgram,
  90. cull: model.cull,
  91. pass: pass,
  92. count: count,
  93. pickId: primitiveRenderResources.pickId,
  94. instanceCount: primitiveRenderResources.instanceCount,
  95. primitiveType: primitiveType,
  96. debugShowBoundingVolume: model.debugShowBoundingVolume,
  97. castShadows: ShadowMode.castShadows(model.shadows),
  98. receiveShadows: ShadowMode.receiveShadows(model.shadows),
  99. });
  100. const styleCommandsNeeded = primitiveRenderResources.styleCommandsNeeded;
  101. const commandList = [];
  102. if (defined(styleCommandsNeeded)) {
  103. const derivedCommands = createDerivedCommands(command);
  104. if (pass !== Pass.TRANSLUCENT) {
  105. switch (styleCommandsNeeded) {
  106. case StyleCommandsNeeded.ALL_OPAQUE:
  107. commandList.push(command);
  108. break;
  109. case StyleCommandsNeeded.ALL_TRANSLUCENT:
  110. commandList.push(derivedCommands.translucent);
  111. break;
  112. case StyleCommandsNeeded.OPAQUE_AND_TRANSLUCENT:
  113. // Push both opaque and translucent commands. The rendering of features based on opacity is handled in the shaders.
  114. commandList.push(command, derivedCommands.translucent);
  115. break;
  116. //>>includeStart('debug', pragmas.debug);
  117. default:
  118. throw new RuntimeError("styleCommandsNeeded is not a valid value.");
  119. //>>includeEnd('debug');
  120. }
  121. } else {
  122. // Command was originally translucent so no need to derive new commands;
  123. // as of now, a style can't change an originally translucent feature to
  124. // opaque since the style's alpha is modulated, not a replacement. When
  125. // this changes, we need to derive new opaque commands here.
  126. commandList.push(command);
  127. }
  128. } else {
  129. commandList.push(command);
  130. }
  131. return commandList;
  132. }
  133. /**
  134. * @private
  135. */
  136. function createDerivedCommands(command) {
  137. const derivedCommands = {};
  138. derivedCommands.translucent = deriveTranslucentCommand(command);
  139. return derivedCommands;
  140. }
  141. /**
  142. * @private
  143. */
  144. function deriveTranslucentCommand(command) {
  145. const derivedCommand = DrawCommand.shallowClone(command);
  146. derivedCommand.pass = Pass.TRANSLUCENT;
  147. const rs = clone(command.renderState, true);
  148. rs.cull.enabled = false;
  149. rs.depthTest.enabled = true;
  150. rs.depthMask = false;
  151. rs.blending = BlendingState.ALPHA_BLEND;
  152. derivedCommand.renderState = RenderState.fromCache(rs);
  153. return derivedCommand;
  154. }
  155. function getIndexBuffer(primitiveRenderResources, debugWireframe, frameState) {
  156. if (debugWireframe) {
  157. return createWireframeIndexBuffer(primitiveRenderResources, frameState);
  158. }
  159. const indices = primitiveRenderResources.indices;
  160. if (!defined(indices)) {
  161. return undefined;
  162. }
  163. if (defined(indices.buffer)) {
  164. return indices.buffer;
  165. }
  166. const typedArray = indices.typedArray;
  167. const indexDatatype = IndexDatatype.fromSizeInBytes(
  168. typedArray.BYTES_PER_ELEMENT
  169. );
  170. return Buffer.createIndexBuffer({
  171. context: frameState.context,
  172. typedArray: typedArray,
  173. usage: BufferUsage.STATIC_DRAW,
  174. indexDatatype: indexDatatype,
  175. });
  176. }
  177. /**
  178. * @private
  179. */
  180. function createWireframeIndexBuffer(primitiveRenderResources, frameState) {
  181. let positionAttribute;
  182. const attributes = primitiveRenderResources.attributes;
  183. const length = attributes.length;
  184. for (let i = 0; i < length; i++) {
  185. if (attributes[i].index === 0) {
  186. positionAttribute = attributes[i];
  187. break;
  188. }
  189. }
  190. const vertexCount = positionAttribute.count;
  191. const indices = primitiveRenderResources.indices;
  192. const context = frameState.context;
  193. let originalIndices;
  194. if (defined(indices)) {
  195. const indicesBuffer = indices.buffer;
  196. const indicesCount = indices.count;
  197. const useWebgl2 = context.webgl2;
  198. if (useWebgl2 && defined(indicesBuffer)) {
  199. originalIndices = IndexDatatype.createTypedArray(
  200. vertexCount,
  201. indicesCount
  202. );
  203. indicesBuffer.getBufferData(originalIndices);
  204. } else {
  205. originalIndices = indices.typedArray;
  206. }
  207. }
  208. const primitiveType = primitiveRenderResources.primitiveType;
  209. const wireframeIndices = WireframeIndexGenerator.createWireframeIndices(
  210. primitiveType,
  211. vertexCount,
  212. originalIndices
  213. );
  214. const indexDatatype = IndexDatatype.fromSizeInBytes(
  215. wireframeIndices.BYTES_PER_ELEMENT
  216. );
  217. return Buffer.createIndexBuffer({
  218. context: context,
  219. typedArray: wireframeIndices,
  220. usage: BufferUsage.STATIC_DRAW,
  221. indexDatatype: indexDatatype,
  222. });
  223. }