Appearance.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import clone from "../Core/clone.js";
  2. import combine from "../Core/combine.js";
  3. import defaultValue from "../Core/defaultValue.js";
  4. import defined from "../Core/defined.js";
  5. import BlendingState from "./BlendingState.js";
  6. import CullFace from "./CullFace.js";
  7. /**
  8. * An appearance defines the full GLSL vertex and fragment shaders and the
  9. * render state used to draw a {@link Primitive}. All appearances implement
  10. * this base <code>Appearance</code> interface.
  11. *
  12. * @alias Appearance
  13. * @constructor
  14. *
  15. * @param {object} [options] Object with the following properties:
  16. * @param {boolean} [options.translucent=true] When <code>true</code>, the geometry is expected to appear translucent so {@link Appearance#renderState} has alpha blending enabled.
  17. * @param {boolean} [options.closed=false] When <code>true</code>, the geometry is expected to be closed so {@link Appearance#renderState} has backface culling enabled.
  18. * @param {Material} [options.material=Material.ColorType] The material used to determine the fragment color.
  19. * @param {string} [options.vertexShaderSource] Optional GLSL vertex shader source to override the default vertex shader.
  20. * @param {string} [options.fragmentShaderSource] Optional GLSL fragment shader source to override the default fragment shader.
  21. * @param {object} [options.renderState] Optional render state to override the default render state.
  22. *
  23. * @see MaterialAppearance
  24. * @see EllipsoidSurfaceAppearance
  25. * @see PerInstanceColorAppearance
  26. * @see DebugAppearance
  27. * @see PolylineColorAppearance
  28. * @see PolylineMaterialAppearance
  29. *
  30. * @demo {@link https://sandcastle.cesium.com/index.html?src=Geometry%20and%20Appearances.html|Geometry and Appearances Demo}
  31. */
  32. function Appearance(options) {
  33. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  34. /**
  35. * The material used to determine the fragment color. Unlike other {@link Appearance}
  36. * properties, this is not read-only, so an appearance's material can change on the fly.
  37. *
  38. * @type Material
  39. *
  40. * @see {@link https://github.com/CesiumGS/cesium/wiki/Fabric|Fabric}
  41. */
  42. this.material = options.material;
  43. /**
  44. * When <code>true</code>, the geometry is expected to appear translucent.
  45. *
  46. * @type {boolean}
  47. *
  48. * @default true
  49. */
  50. this.translucent = defaultValue(options.translucent, true);
  51. this._vertexShaderSource = options.vertexShaderSource;
  52. this._fragmentShaderSource = options.fragmentShaderSource;
  53. this._renderState = options.renderState;
  54. this._closed = defaultValue(options.closed, false);
  55. }
  56. Object.defineProperties(Appearance.prototype, {
  57. /**
  58. * The GLSL source code for the vertex shader.
  59. *
  60. * @memberof Appearance.prototype
  61. *
  62. * @type {string}
  63. * @readonly
  64. */
  65. vertexShaderSource: {
  66. get: function () {
  67. return this._vertexShaderSource;
  68. },
  69. },
  70. /**
  71. * The GLSL source code for the fragment shader. The full fragment shader
  72. * source is built procedurally taking into account the {@link Appearance#material}.
  73. * Use {@link Appearance#getFragmentShaderSource} to get the full source.
  74. *
  75. * @memberof Appearance.prototype
  76. *
  77. * @type {string}
  78. * @readonly
  79. */
  80. fragmentShaderSource: {
  81. get: function () {
  82. return this._fragmentShaderSource;
  83. },
  84. },
  85. /**
  86. * The WebGL fixed-function state to use when rendering the geometry.
  87. *
  88. * @memberof Appearance.prototype
  89. *
  90. * @type {object}
  91. * @readonly
  92. */
  93. renderState: {
  94. get: function () {
  95. return this._renderState;
  96. },
  97. },
  98. /**
  99. * When <code>true</code>, the geometry is expected to be closed.
  100. *
  101. * @memberof Appearance.prototype
  102. *
  103. * @type {boolean}
  104. * @readonly
  105. *
  106. * @default false
  107. */
  108. closed: {
  109. get: function () {
  110. return this._closed;
  111. },
  112. },
  113. });
  114. /**
  115. * Procedurally creates the full GLSL fragment shader source for this appearance
  116. * taking into account {@link Appearance#fragmentShaderSource} and {@link Appearance#material}.
  117. *
  118. * @returns {string} The full GLSL fragment shader source.
  119. */
  120. Appearance.prototype.getFragmentShaderSource = function () {
  121. const parts = [];
  122. if (this.flat) {
  123. parts.push("#define FLAT");
  124. }
  125. if (this.faceForward) {
  126. parts.push("#define FACE_FORWARD");
  127. }
  128. if (defined(this.material)) {
  129. parts.push(this.material.shaderSource);
  130. }
  131. parts.push(this.fragmentShaderSource);
  132. return parts.join("\n");
  133. };
  134. /**
  135. * Determines if the geometry is translucent based on {@link Appearance#translucent} and {@link Material#isTranslucent}.
  136. *
  137. * @returns {boolean} <code>true</code> if the appearance is translucent.
  138. */
  139. Appearance.prototype.isTranslucent = function () {
  140. return (
  141. (defined(this.material) && this.material.isTranslucent()) ||
  142. (!defined(this.material) && this.translucent)
  143. );
  144. };
  145. /**
  146. * Creates a render state. This is not the final render state instance; instead,
  147. * it can contain a subset of render state properties identical to the render state
  148. * created in the context.
  149. *
  150. * @returns {object} The render state.
  151. */
  152. Appearance.prototype.getRenderState = function () {
  153. const translucent = this.isTranslucent();
  154. const rs = clone(this.renderState, false);
  155. if (translucent) {
  156. rs.depthMask = false;
  157. rs.blending = BlendingState.ALPHA_BLEND;
  158. } else {
  159. rs.depthMask = true;
  160. }
  161. return rs;
  162. };
  163. /**
  164. * @private
  165. */
  166. Appearance.getDefaultRenderState = function (translucent, closed, existing) {
  167. let rs = {
  168. depthTest: {
  169. enabled: true,
  170. },
  171. };
  172. if (translucent) {
  173. rs.depthMask = false;
  174. rs.blending = BlendingState.ALPHA_BLEND;
  175. }
  176. if (closed) {
  177. rs.cull = {
  178. enabled: true,
  179. face: CullFace.BACK,
  180. };
  181. }
  182. if (defined(existing)) {
  183. rs = combine(existing, rs, true);
  184. }
  185. return rs;
  186. };
  187. export default Appearance;