inputBlock.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. import { NodeMaterialBlock } from '../../nodeMaterialBlock';
  2. import { NodeMaterialBlockConnectionPointTypes } from '../../nodeMaterialBlockConnectionPointTypes';
  3. import { NodeMaterialBlockConnectionPointMode } from '../../NodeMaterialBlockConnectionPointMode';
  4. import { NodeMaterialWellKnownValues } from '../../nodeMaterialWellKnownValues';
  5. import { Nullable } from '../../../../types';
  6. import { Effect } from '../../../../Materials/effect';
  7. import { Matrix, Vector2, Vector3 } from '../../../../Maths/math.vector';
  8. import { Scene } from '../../../../scene';
  9. import { NodeMaterialConnectionPoint } from '../../nodeMaterialBlockConnectionPoint';
  10. import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
  11. import { NodeMaterialBlockTargets } from '../../nodeMaterialBlockTargets';
  12. import { _TypeStore } from '../../../../Misc/typeStore';
  13. /**
  14. * Block used to expose an input value
  15. */
  16. export class InputBlock extends NodeMaterialBlock {
  17. private _mode = NodeMaterialBlockConnectionPointMode.Undefined;
  18. private _associatedVariableName: string;
  19. private _storedValue: any;
  20. private _valueCallback: () => any;
  21. private _type: NodeMaterialBlockConnectionPointTypes;
  22. /** @hidden */
  23. public _wellKnownValue: Nullable<NodeMaterialWellKnownValues> = null;
  24. /**
  25. * Gets or sets the connection point type (default is float)
  26. */
  27. public get type(): NodeMaterialBlockConnectionPointTypes {
  28. if (this._type === NodeMaterialBlockConnectionPointTypes.AutoDetect) {
  29. if (this.isUniform && this.value != null) {
  30. if (!isNaN(this.value)) {
  31. return NodeMaterialBlockConnectionPointTypes.Float;
  32. }
  33. switch (this.value.getClassName()) {
  34. case "Vector2":
  35. return NodeMaterialBlockConnectionPointTypes.Vector2;
  36. case "Vector3":
  37. return NodeMaterialBlockConnectionPointTypes.Vector3;
  38. case "Vector4":
  39. return NodeMaterialBlockConnectionPointTypes.Vector4;
  40. case "Color3":
  41. return NodeMaterialBlockConnectionPointTypes.Color3;
  42. case "Color4":
  43. return NodeMaterialBlockConnectionPointTypes.Color4;
  44. }
  45. }
  46. if (this.isAttribute) {
  47. switch (this.name) {
  48. case "position":
  49. case "normal":
  50. case "tangent":
  51. return NodeMaterialBlockConnectionPointTypes.Vector3;
  52. case "uv":
  53. case "uv2":
  54. return NodeMaterialBlockConnectionPointTypes.Vector2;
  55. }
  56. }
  57. if (this.isWellKnownValue) {
  58. switch (this._wellKnownValue) {
  59. case NodeMaterialWellKnownValues.World:
  60. case NodeMaterialWellKnownValues.WorldView:
  61. case NodeMaterialWellKnownValues.WorldViewProjection:
  62. case NodeMaterialWellKnownValues.View:
  63. case NodeMaterialWellKnownValues.ViewProjection:
  64. case NodeMaterialWellKnownValues.Projection:
  65. return NodeMaterialBlockConnectionPointTypes.Matrix;
  66. case NodeMaterialWellKnownValues.CameraPosition:
  67. return NodeMaterialBlockConnectionPointTypes.Vector3;
  68. }
  69. }
  70. }
  71. return this._type;
  72. }
  73. /**
  74. * Creates a new InputBlock
  75. * @param name defines the block name
  76. * @param target defines the target of that block (Vertex by default)
  77. * @param type defines the type of the input (can be set to NodeMaterialBlockConnectionPointTypes.AutoDetect)
  78. */
  79. public constructor(name: string, target = NodeMaterialBlockTargets.Vertex, type: NodeMaterialBlockConnectionPointTypes = NodeMaterialBlockConnectionPointTypes.AutoDetect) {
  80. super(name, target, false, true);
  81. this._type = type;
  82. this.registerOutput("output", type);
  83. }
  84. /**
  85. * Gets the output component
  86. */
  87. public get output(): NodeMaterialConnectionPoint {
  88. return this._outputs[0];
  89. }
  90. /**
  91. * Set the source of this connection point to a vertex attribute
  92. * @param attributeName defines the attribute name (position, uv, normal, etc...). If not specified it will take the connection point name
  93. * @returns the current connection point
  94. */
  95. public setAsAttribute(attributeName?: string): InputBlock {
  96. if (attributeName) {
  97. this.name = attributeName;
  98. }
  99. this._mode = NodeMaterialBlockConnectionPointMode.Attribute;
  100. return this;
  101. }
  102. /**
  103. * Set the source of this connection point to a well known value
  104. * @param value define the well known value to use (world, view, etc...) or null to switch to manual value
  105. * @returns the current connection point
  106. */
  107. public setAsWellKnownValue(value: Nullable<NodeMaterialWellKnownValues>): InputBlock {
  108. this.wellKnownValue = value;
  109. return this;
  110. }
  111. /**
  112. * Gets or sets the value of that point.
  113. * Please note that this value will be ignored if valueCallback is defined
  114. */
  115. public get value(): any {
  116. return this._storedValue;
  117. }
  118. public set value(value: any) {
  119. this._storedValue = value;
  120. this._mode = NodeMaterialBlockConnectionPointMode.Uniform;
  121. }
  122. /**
  123. * Gets or sets a callback used to get the value of that point.
  124. * Please note that setting this value will force the connection point to ignore the value property
  125. */
  126. public get valueCallback(): () => any {
  127. return this._valueCallback;
  128. }
  129. public set valueCallback(value: () => any) {
  130. this._valueCallback = value;
  131. this._mode = NodeMaterialBlockConnectionPointMode.Uniform;
  132. }
  133. /**
  134. * Gets or sets the associated variable name in the shader
  135. */
  136. public get associatedVariableName(): string {
  137. return this._associatedVariableName;
  138. }
  139. public set associatedVariableName(value: string) {
  140. this._associatedVariableName = value;
  141. }
  142. /**
  143. * Gets a boolean indicating that this connection point not defined yet
  144. */
  145. public get isUndefined(): boolean {
  146. return this._mode === NodeMaterialBlockConnectionPointMode.Undefined;
  147. }
  148. /**
  149. * Gets or sets a boolean indicating that this connection point is coming from an uniform.
  150. * In this case the connection point name must be the name of the uniform to use.
  151. * Can only be set on inputs
  152. */
  153. public get isUniform(): boolean {
  154. return this._mode === NodeMaterialBlockConnectionPointMode.Uniform;
  155. }
  156. public set isUniform(value: boolean) {
  157. this._mode = value ? NodeMaterialBlockConnectionPointMode.Uniform : NodeMaterialBlockConnectionPointMode.Undefined;
  158. this.associatedVariableName = "";
  159. }
  160. /**
  161. * Gets or sets a boolean indicating that this connection point is coming from an attribute.
  162. * In this case the connection point name must be the name of the attribute to use
  163. * Can only be set on inputs
  164. */
  165. public get isAttribute(): boolean {
  166. return this._mode === NodeMaterialBlockConnectionPointMode.Attribute;
  167. }
  168. public set isAttribute(value: boolean) {
  169. this._mode = value ? NodeMaterialBlockConnectionPointMode.Attribute : NodeMaterialBlockConnectionPointMode.Undefined;
  170. this.associatedVariableName = "";
  171. }
  172. /**
  173. * Gets or sets a boolean indicating that this connection point is generating a varying variable.
  174. * Can only be set on exit points
  175. */
  176. public get isVarying(): boolean {
  177. return this._mode === NodeMaterialBlockConnectionPointMode.Varying;
  178. }
  179. public set isVarying(value: boolean) {
  180. this._mode = value ? NodeMaterialBlockConnectionPointMode.Varying : NodeMaterialBlockConnectionPointMode.Undefined;
  181. this.associatedVariableName = "";
  182. }
  183. /**
  184. * Gets a boolean indicating that the current connection point is a well known value
  185. */
  186. public get isWellKnownValue(): boolean {
  187. return this._wellKnownValue != null;
  188. }
  189. /**
  190. * Gets or sets the current well known value or null if not defined as well know value
  191. */
  192. public get wellKnownValue(): Nullable<NodeMaterialWellKnownValues> {
  193. return this._wellKnownValue;
  194. }
  195. public set wellKnownValue(value: Nullable<NodeMaterialWellKnownValues>) {
  196. this._mode = NodeMaterialBlockConnectionPointMode.Uniform;
  197. this.associatedVariableName = "";
  198. this._wellKnownValue = value;
  199. }
  200. /**
  201. * Gets the current class name
  202. * @returns the class name
  203. */
  204. public getClassName() {
  205. return "InputBlock";
  206. }
  207. private _emitDefine(define: string): string {
  208. if (define[0] === "!") {
  209. return `#ifndef ${define.substring(1)}\r\n`;
  210. }
  211. return `#ifdef ${define}\r\n`;
  212. }
  213. /**
  214. * Set the input block to its default value (based on its type)
  215. */
  216. public setDefaultValue() {
  217. switch (this.type) {
  218. case NodeMaterialBlockConnectionPointTypes.Float:
  219. this.value = 0;
  220. break;
  221. case NodeMaterialBlockConnectionPointTypes.Vector2:
  222. this.value = Vector2.Zero();
  223. break;
  224. case NodeMaterialBlockConnectionPointTypes.Vector3:
  225. case NodeMaterialBlockConnectionPointTypes.Color3:
  226. case NodeMaterialBlockConnectionPointTypes.Vector3OrColor3:
  227. this.value = Vector3.Zero();
  228. break;
  229. case NodeMaterialBlockConnectionPointTypes.Matrix:
  230. this.value = Matrix.Identity();
  231. break;
  232. }
  233. }
  234. private _emit(state: NodeMaterialBuildState, define?: string) {
  235. // Uniforms
  236. if (this.isUniform) {
  237. if (!this.associatedVariableName) {
  238. this.associatedVariableName = state._getFreeVariableName("u_" + this.name);
  239. }
  240. if (state.uniforms.indexOf(this.associatedVariableName) !== -1) {
  241. return;
  242. }
  243. state.uniforms.push(this.associatedVariableName);
  244. if (define) {
  245. state._uniformDeclaration += this._emitDefine(define);
  246. }
  247. state._uniformDeclaration += `uniform ${state._getGLType(this.type)} ${this.associatedVariableName};\r\n`;
  248. if (define) {
  249. state._uniformDeclaration += `#endif\r\n`;
  250. }
  251. // well known
  252. let hints = state.sharedData.hints;
  253. if (this._wellKnownValue !== null) {
  254. switch (this._wellKnownValue) {
  255. case NodeMaterialWellKnownValues.WorldView:
  256. hints.needWorldViewMatrix = true;
  257. break;
  258. case NodeMaterialWellKnownValues.WorldViewProjection:
  259. hints.needWorldViewProjectionMatrix = true;
  260. break;
  261. }
  262. }
  263. return;
  264. }
  265. // Attribute
  266. if (this.isAttribute) {
  267. this.associatedVariableName = this.name;
  268. if (this.target === NodeMaterialBlockTargets.Vertex && state._vertexState) { // Attribute for fragment need to be carried over by varyings
  269. this._emit(state._vertexState, define);
  270. return;
  271. }
  272. if (state.attributes.indexOf(this.associatedVariableName) !== -1) {
  273. return;
  274. }
  275. state.attributes.push(this.associatedVariableName);
  276. if (define) {
  277. state._attributeDeclaration += this._emitDefine(define);
  278. }
  279. state._attributeDeclaration += `attribute ${state._getGLType(this.type)} ${this.associatedVariableName};\r\n`;
  280. if (define) {
  281. state._attributeDeclaration += `#endif\r\n`;
  282. }
  283. }
  284. }
  285. /** @hidden */
  286. public _transmitWorld(effect: Effect, world: Matrix, worldView: Matrix, worldViewProjection: Matrix) {
  287. if (!this._wellKnownValue) {
  288. return;
  289. }
  290. let variableName = this.associatedVariableName;
  291. switch (this._wellKnownValue) {
  292. case NodeMaterialWellKnownValues.World:
  293. effect.setMatrix(variableName, world);
  294. break;
  295. case NodeMaterialWellKnownValues.WorldView:
  296. effect.setMatrix(variableName, worldView);
  297. break;
  298. case NodeMaterialWellKnownValues.WorldViewProjection:
  299. effect.setMatrix(variableName, worldViewProjection);
  300. break;
  301. }
  302. }
  303. /** @hidden */
  304. public _transmit(effect: Effect, scene: Scene) {
  305. if (this.isAttribute) {
  306. return;
  307. }
  308. let variableName = this.associatedVariableName;
  309. if (this._wellKnownValue) {
  310. switch (this._wellKnownValue) {
  311. case NodeMaterialWellKnownValues.World:
  312. case NodeMaterialWellKnownValues.WorldView:
  313. case NodeMaterialWellKnownValues.WorldViewProjection:
  314. return;
  315. case NodeMaterialWellKnownValues.View:
  316. effect.setMatrix(variableName, scene.getViewMatrix());
  317. break;
  318. case NodeMaterialWellKnownValues.Projection:
  319. effect.setMatrix(variableName, scene.getProjectionMatrix());
  320. break;
  321. case NodeMaterialWellKnownValues.ViewProjection:
  322. effect.setMatrix(variableName, scene.getTransformMatrix());
  323. break;
  324. case NodeMaterialWellKnownValues.CameraPosition:
  325. effect.setVector3(variableName, scene.activeCamera!.globalPosition);
  326. break;
  327. case NodeMaterialWellKnownValues.FogColor:
  328. effect.setColor3(variableName, scene.fogColor);
  329. break;
  330. }
  331. return;
  332. }
  333. let value = this._valueCallback ? this._valueCallback() : this._storedValue;
  334. if (value === null) {
  335. return;
  336. }
  337. switch (this.type) {
  338. case NodeMaterialBlockConnectionPointTypes.Float:
  339. effect.setFloat(variableName, value);
  340. break;
  341. case NodeMaterialBlockConnectionPointTypes.Int:
  342. effect.setInt(variableName, value);
  343. break;
  344. case NodeMaterialBlockConnectionPointTypes.Color3:
  345. effect.setColor3(variableName, value);
  346. break;
  347. case NodeMaterialBlockConnectionPointTypes.Color4:
  348. effect.setDirectColor4(variableName, value);
  349. break;
  350. case NodeMaterialBlockConnectionPointTypes.Vector2:
  351. effect.setVector2(variableName, value);
  352. break;
  353. case NodeMaterialBlockConnectionPointTypes.Vector3:
  354. effect.setVector3(variableName, value);
  355. break;
  356. case NodeMaterialBlockConnectionPointTypes.Color3OrColor4:
  357. effect.setFloat4(variableName, value.r, value.g, value.b, value.a || 1.0);
  358. break;
  359. case NodeMaterialBlockConnectionPointTypes.Vector4OrColor4:
  360. case NodeMaterialBlockConnectionPointTypes.Vector4:
  361. effect.setVector4(variableName, value);
  362. break;
  363. case NodeMaterialBlockConnectionPointTypes.Matrix:
  364. effect.setMatrix(variableName, value);
  365. break;
  366. }
  367. }
  368. protected _buildBlock(state: NodeMaterialBuildState) {
  369. super._buildBlock(state);
  370. if (this.isUniform || this.isWellKnownValue) {
  371. state.sharedData.inputBlocks.push(this);
  372. }
  373. this._emit(state);
  374. }
  375. }
  376. _TypeStore.RegisteredTypes["BABYLON.InputBlock"] = InputBlock;