Material.hx 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557
  1. //
  2. // This module builds upon Cycles nodes work licensed as
  3. // Copyright 2011-2013 Blender Foundation
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. package arm.node;
  18. import zui.Nodes;
  19. import iron.data.SceneFormat;
  20. import arm.node.MaterialShader;
  21. using StringTools;
  22. class Material {
  23. static var con: MaterialShaderContext;
  24. static var vert: MaterialShader;
  25. static var frag: MaterialShader;
  26. static var geom: MaterialShader;
  27. static var tesc: MaterialShader;
  28. static var tese: MaterialShader;
  29. static var curshader: MaterialShader;
  30. static var matcon: TMaterialContext;
  31. static var parsed: Array<String>;
  32. static var nodes: Array<TNode>;
  33. static var links: Array<TNodeLink>;
  34. static var parsing_disp: Bool;
  35. static var normal_written: Bool; // Normal socket is linked on shader node - overwrite fs normal
  36. static var cotangentFrameWritten: Bool;
  37. static var sample_bump: Bool;
  38. static var sample_bump_res: String;
  39. public static var customNodes = untyped __js__("new Map()");
  40. public static var parse_surface = true;
  41. public static var parse_opacity = true;
  42. public static var parse_height = false;
  43. public static var parse_height_as_channel = false;
  44. public static var parse_emission = false;
  45. public static var parse_subsurface = false;
  46. public static var triplanar = false; // Sample using texCoord/1/2 & texCoordBlend
  47. public static var arm_export_tangents = true;
  48. public static var out_normaltan: String; // Raw tangent space normal parsed from normal map
  49. public static function getNode(id: Int): TNode {
  50. for (n in nodes) if (n.id == id) return n;
  51. return null;
  52. }
  53. public static function getLink(id: Int): TNodeLink {
  54. for (l in links) if (l.id == id) return l;
  55. return null;
  56. }
  57. public static function getInputLink(inp: TNodeSocket): TNodeLink {
  58. for (l in links) {
  59. if (l.to_id == inp.node_id) {
  60. var node = getNode(inp.node_id);
  61. if (node.inputs.length <= l.to_socket) return null;
  62. if (node.inputs[l.to_socket] == inp) return l;
  63. }
  64. }
  65. return null;
  66. }
  67. public static function getOutputLinks(out: TNodeSocket): Array<TNodeLink> {
  68. var ls: Array<TNodeLink> = null;
  69. for (l in links) {
  70. if (l.from_id == out.node_id) {
  71. var node = getNode(out.node_id);
  72. if (node.outputs.length <= l.from_socket) continue;
  73. if (node.outputs[l.from_socket] == out) {
  74. if (ls == null) ls = [];
  75. ls.push(l);
  76. }
  77. }
  78. }
  79. return ls;
  80. }
  81. public static function parse(canvas: TNodeCanvas, _con: MaterialShaderContext, _vert: MaterialShader, _frag: MaterialShader, _geom: MaterialShader, _tesc: MaterialShader, _tese: MaterialShader, _matcon: TMaterialContext, _parse_displacement = false): TShaderOut {
  82. nodes = canvas.nodes;
  83. links = canvas.links;
  84. parsed = [];
  85. con = _con;
  86. vert = _vert;
  87. frag = _frag;
  88. geom = _geom;
  89. tesc = _tesc;
  90. tese = _tese;
  91. curshader = frag;
  92. matcon = _matcon;
  93. parsing_disp = false;
  94. normal_written = false;
  95. cotangentFrameWritten = false;
  96. sample_bump = false;
  97. sample_bump_res = "";
  98. out_normaltan = "vec3(0.5, 0.5, 1.0)";
  99. var output_node = node_by_type(nodes, "OUTPUT_MATERIAL");
  100. if (output_node != null) {
  101. return parse_output(output_node);
  102. }
  103. output_node = node_by_type(nodes, "OUTPUT_MATERIAL_PBR");
  104. if (output_node != null) {
  105. return parse_output_pbr(output_node);
  106. }
  107. return null;
  108. }
  109. public static function finalize(con: MaterialShaderContext) {
  110. var vert = con.vert;
  111. var frag = con.frag;
  112. if (frag.dotNV) { frag.vVec = true; frag.n = true; }
  113. if (frag.vVec) vert.wposition = true;
  114. if (frag.bposition) {
  115. if (triplanar) {
  116. frag.write_attrib('vec3 bposition = vec3(
  117. texCoord1.x * texCoordBlend.y + texCoord2.x * texCoordBlend.z,
  118. texCoord.x * texCoordBlend.x + texCoord2.y * texCoordBlend.z,
  119. texCoord.y * texCoordBlend.x + texCoord1.y * texCoordBlend.y);');
  120. }
  121. else if (frag.ndcpos) {
  122. vert.add_out("vec3 bposition");
  123. vert.write('bposition = (ndc.xyz / ndc.w);');
  124. }
  125. else {
  126. vert.add_out("vec3 bposition");
  127. vert.add_uniform("vec3 dim", "_dim");
  128. vert.add_uniform("vec3 hdim", "_halfDim");
  129. vert.write_attrib('bposition = (pos.xyz + hdim) / dim;');
  130. }
  131. }
  132. if (frag.wposition) {
  133. vert.add_uniform("mat4 W", "_worldMatrix");
  134. vert.add_out("vec3 wposition");
  135. vert.write_attrib('wposition = vec4(mul(vec4(pos.xyz, 1.0), W)).xyz;');
  136. }
  137. else if (vert.wposition) {
  138. vert.add_uniform("mat4 W", "_worldMatrix");
  139. vert.write_attrib('vec3 wposition = vec4(mul(vec4(pos.xyz, 1.0), W)).xyz;');
  140. }
  141. if (frag.vposition) {
  142. vert.add_uniform("mat4 WV", "_worldViewMatrix");
  143. vert.add_out("vec3 vposition");
  144. vert.write_attrib('vposition = vec4(mul(vec4(pos.xyz, 1.0), WV)).xyz;');
  145. }
  146. if (frag.mposition) {
  147. vert.add_out("vec3 mposition");
  148. if (frag.ndcpos) {
  149. vert.write('mposition = (ndc.xyz / ndc.w);');
  150. }
  151. else {
  152. vert.write_attrib('mposition = pos.xyz;');
  153. }
  154. }
  155. if (frag.wtangent) {
  156. con.add_elem("tang", "short4norm");
  157. vert.add_uniform("mat3 N", "_normalMatrix");
  158. vert.add_out("vec3 wtangent");
  159. vert.write_attrib('wtangent = normalize(mul(tang, N));');
  160. }
  161. if (frag.vVecCam) {
  162. vert.add_uniform("mat4 WV", "_worldViewMatrix");
  163. vert.add_out("vec3 eyeDirCam");
  164. vert.write_attrib('eyeDirCam = vec4(mul(vec4(pos.xyz, 1.0), WV)).xyz; eyeDirCam.z *= -1.0;');
  165. frag.write_attrib('vec3 vVecCam = normalize(eyeDirCam);');
  166. }
  167. if (frag.vVec) {
  168. vert.add_uniform("vec3 eye", "_cameraPosition");
  169. vert.add_out("vec3 eyeDir");
  170. vert.write_attrib('eyeDir = eye - wposition;');
  171. frag.write_attrib('vec3 vVec = normalize(eyeDir);');
  172. }
  173. if (frag.n) {
  174. vert.add_uniform("mat3 N", "_normalMatrix");
  175. vert.add_out("vec3 wnormal");
  176. vert.write_attrib('wnormal = mul(vec3(nor.xy, pos.w), N);');
  177. frag.write_attrib('vec3 n = normalize(wnormal);');
  178. }
  179. else if (vert.n) {
  180. vert.add_uniform("mat3 N", "_normalMatrix");
  181. vert.write_attrib('vec3 wnormal = normalize(mul(vec3(nor.xy, pos.w), N));');
  182. }
  183. if (frag.nAttr) {
  184. vert.add_out("vec3 nAttr");
  185. vert.write_attrib('nAttr = vec3(nor.xy, pos.w);');
  186. }
  187. if (frag.dotNV) {
  188. frag.write_attrib('float dotNV = max(dot(n, vVec), 0.0);');
  189. }
  190. if (frag.wvpposition) {
  191. vert.add_out("vec4 wvpposition");
  192. vert.write_end('wvpposition = gl_Position;');
  193. }
  194. }
  195. static function parse_output(node: TNode): TShaderOut {
  196. if (parse_surface || parse_opacity) {
  197. return parse_shader_input(node.inputs[0]);
  198. }
  199. return null;
  200. // Parse volume, displacement..
  201. }
  202. static function parse_output_pbr(node: TNode): TShaderOut {
  203. if (parse_surface || parse_opacity) {
  204. return parse_shader(node, null);
  205. }
  206. return null;
  207. // Parse volume, displacement..
  208. }
  209. static function parse_group(node: TNode, socket: TNodeSocket) { // Entering group
  210. // index = socket_index(node, socket)
  211. // output_node = node_by_type(node.node_tree.nodes, 'GROUP_OUTPUT')
  212. // if output_node == None:
  213. // return
  214. // inp = output_node.inputs[index]
  215. // parents.push(node)
  216. // out_group = parse_input(inp)
  217. // parents.pop()
  218. // return out_group
  219. }
  220. static function parse_group_input(node: TNode, socket: TNodeSocket) {
  221. // index = socket_index(node, socket)
  222. // parent = parents.pop() # Leaving group
  223. // inp = parent.inputs[index]
  224. // res = parse_input(inp)
  225. // parents.push(parent) # Return to group
  226. // return res
  227. }
  228. static function parse_input(inp: TNodeSocket): Dynamic {
  229. if (inp.type == "SHADER") {
  230. return parse_shader_input(inp);
  231. }
  232. else if (inp.type == "RGB") {
  233. return parse_vector_input(inp);
  234. }
  235. else if (inp.type == "RGBA") {
  236. return parse_vector_input(inp);
  237. }
  238. else if (inp.type == "VECTOR") {
  239. return parse_vector_input(inp);
  240. }
  241. else if (inp.type == "VALUE") {
  242. return parse_value_input(inp);
  243. }
  244. return null;
  245. }
  246. static function parse_shader_input(inp: TNodeSocket): TShaderOut {
  247. var l = getInputLink(inp);
  248. if (l != null) {
  249. var from_node = getNode(l.from_id);
  250. if (from_node.type == "REROUTE") {
  251. return parse_shader_input(from_node.inputs[0]);
  252. }
  253. return parse_shader(from_node, from_node.outputs[l.from_socket]);
  254. }
  255. else {
  256. return {
  257. out_basecol: "vec3(0.8, 0.8, 0.8)",
  258. out_roughness: "0.0",
  259. out_metallic: "0.0",
  260. out_occlusion: "1.0",
  261. out_opacity: "1.0",
  262. out_height: "0.0",
  263. out_emission: "0.0",
  264. out_subsurface: "0.0"
  265. };
  266. }
  267. }
  268. static function parse_shader(node: TNode, socket: TNodeSocket): TShaderOut {
  269. var sout: TShaderOut = {
  270. out_basecol: "vec3(0.8, 0.8, 0.8)",
  271. out_roughness: "0.0",
  272. out_metallic: "0.0",
  273. out_occlusion: "1.0",
  274. out_opacity: "1.0",
  275. out_height: "0.0",
  276. out_emission: "0.0",
  277. out_subsurface: "0.0"
  278. }
  279. if (node.type == "OUTPUT_MATERIAL_PBR") {
  280. if (parse_surface) {
  281. // Normal - parsed first to retrieve uv coords
  282. parse_normal_map_color_input(node.inputs[5]);
  283. // Base color
  284. sout.out_basecol = parse_vector_input(node.inputs[0]);
  285. // Occlusion
  286. sout.out_occlusion = parse_value_input(node.inputs[2]);
  287. // Roughness
  288. sout.out_roughness = parse_value_input(node.inputs[3]);
  289. // Metallic
  290. sout.out_metallic = parse_value_input(node.inputs[4]);
  291. // Emission
  292. if (parse_emission) {
  293. sout.out_emission = parse_value_input(node.inputs[6]);
  294. }
  295. // Subsurface
  296. if (parse_subsurface) {
  297. sout.out_subsurface = parse_value_input(node.inputs[8]);
  298. }
  299. }
  300. if (parse_opacity) {
  301. sout.out_opacity = parse_value_input(node.inputs[1]);
  302. }
  303. // Displacement / Height
  304. if (node.inputs.length > 7 && parse_height) {
  305. if (!parse_height_as_channel) curshader = vert;
  306. sout.out_height = parse_value_input(node.inputs[7]);
  307. if (!parse_height_as_channel) curshader = frag;
  308. }
  309. }
  310. return sout;
  311. }
  312. static function parse_vector_input(inp: TNodeSocket): String {
  313. var l = getInputLink(inp);
  314. if (l != null) {
  315. var from_node = getNode(l.from_id);
  316. if (from_node.type == "REROUTE") {
  317. return parse_vector_input(from_node.inputs[0]);
  318. }
  319. var res_var = write_result(l);
  320. var st = from_node.outputs[l.from_socket].type;
  321. if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
  322. return res_var;
  323. }
  324. else {// VALUE
  325. return to_vec3(res_var);
  326. }
  327. }
  328. else {
  329. if (inp.type == "VALUE") { //# Unlinked reroute
  330. return vec3([0.0, 0.0, 0.0]);
  331. }
  332. else {
  333. return vec3(inp.default_value);
  334. }
  335. }
  336. }
  337. static function parse_vector(node: TNode, socket: TNodeSocket): String {
  338. // RGB
  339. // if (node.type == 'GROUP')
  340. // return parse_group(node, socket)
  341. // else if (node.type == 'GROUP_INPUT')
  342. // return parse_group_input(node, socket)
  343. if (node.type == "ATTRIBUTE") {
  344. if (socket == node.outputs[0]) { // Color
  345. curshader.context.add_elem("col", "short4norm"); // Vcols only for now
  346. // return "vcolor";
  347. return "vec3(0.0, 0.0, 0.0)";
  348. }
  349. else { // Vector
  350. curshader.context.add_elem("tex", "short2norm"); // UVMaps only for now
  351. return "vec3(texCoord.x, 1.0 - texCoord.y, 0.0)";
  352. }
  353. }
  354. else if (node.type == "RGB") {
  355. return vec3(socket.default_value);
  356. }
  357. else if (node.type == "TEX_BRICK") {
  358. curshader.add_function(MaterialFunctions.str_tex_brick);
  359. var co = getCoord(node);
  360. var col1 = parse_vector_input(node.inputs[1]);
  361. var col2 = parse_vector_input(node.inputs[2]);
  362. var col3 = parse_vector_input(node.inputs[3]);
  363. var scale = parse_value_input(node.inputs[4]);
  364. var res = 'tex_brick($co * $scale, $col1, $col2, $col3)';
  365. if (sample_bump) write_bump(node, res);
  366. return res;
  367. }
  368. else if (node.type == "TEX_CHECKER") {
  369. curshader.add_function(MaterialFunctions.str_tex_checker);
  370. var co = getCoord(node);
  371. var col1 = parse_vector_input(node.inputs[1]);
  372. var col2 = parse_vector_input(node.inputs[2]);
  373. var scale = parse_value_input(node.inputs[3]);
  374. var res = 'tex_checker($co, $col1, $col2, $scale)';
  375. if (sample_bump) write_bump(node, res);
  376. return res;
  377. }
  378. else if (node.type == "TEX_GRADIENT") {
  379. var co = getCoord(node);
  380. var but = node.buttons[0]; //gradient_type;
  381. var grad: String = but.data[but.default_value].toUpperCase();
  382. grad = grad.replace(" ", "_");
  383. var f = getGradient(grad, co);
  384. var res = to_vec3('clamp($f, 0.0, 1.0)');
  385. if (sample_bump) write_bump(node, res);
  386. return res;
  387. }
  388. else if (node.type == "TEX_IMAGE") {
  389. // Already fetched
  390. if (parsed.indexOf(res_var_name(node, node.outputs[1])) >= 0) { // TODO: node.outputs[0]
  391. var varname = store_var_name(node);
  392. return '$varname.rgb';
  393. }
  394. var tex_name = node_name(node);
  395. var tex = make_texture(node, tex_name);
  396. if (tex != null) {
  397. var to_linear = node.buttons[1].default_value == 1; // srgb to linear
  398. var texstore = texture_store(node, tex, tex_name, to_linear);
  399. return '$texstore.rgb';
  400. }
  401. else {
  402. var tex_store = store_var_name(node); // Pink color for missing texture
  403. curshader.write('vec4 $tex_store = vec4(1.0, 0.0, 1.0, 1.0);');
  404. return '$tex_store.rgb';
  405. }
  406. }
  407. else if (node.type == "TEX_MAGIC") {
  408. curshader.add_function(MaterialFunctions.str_tex_magic);
  409. var co = getCoord(node);
  410. var scale = parse_value_input(node.inputs[1]);
  411. var res = 'tex_magic($co * $scale * 4.0)';
  412. if (sample_bump) write_bump(node, res);
  413. return res;
  414. }
  415. else if (node.type == "TEX_MUSGRAVE") {
  416. curshader.add_function(MaterialFunctions.str_tex_musgrave);
  417. var co = getCoord(node);
  418. var scale = parse_value_input(node.inputs[1]);
  419. var res = to_vec3('tex_musgrave_f($co * $scale * 0.5)');
  420. if (sample_bump) write_bump(node, res);
  421. return res;
  422. }
  423. else if (node.type == "TEX_NOISE") {
  424. curshader.add_function(MaterialFunctions.str_tex_noise);
  425. curshader.add_uniform("sampler2D snoise256", "$noise256.k");
  426. var co = getCoord(node);
  427. var scale = parse_value_input(node.inputs[1]);
  428. var res = 'vec3(tex_noise($co * $scale), tex_noise($co * $scale + 0.33), tex_noise($co * $scale + 0.66))';
  429. if (sample_bump) write_bump(node, res);
  430. return res;
  431. }
  432. else if (node.type == "TEX_VORONOI") {
  433. curshader.add_function(MaterialFunctions.str_tex_voronoi);
  434. curshader.add_uniform("sampler2D snoise256", "$noise256.k");
  435. var co = getCoord(node);
  436. var scale = parse_value_input(node.inputs[1]);
  437. var but = node.buttons[0]; //coloring;
  438. var coloring: String = but.data[but.default_value].toUpperCase();
  439. coloring = coloring.replace(" ", "_");
  440. var res = "";
  441. if (coloring == "INTENSITY") {
  442. res = to_vec3('tex_voronoi($co * $scale).a');
  443. }
  444. else { // Cells
  445. res = 'tex_voronoi($co * $scale).rgb';
  446. }
  447. if (sample_bump) write_bump(node, res);
  448. return res;
  449. }
  450. else if (node.type == "TEX_WAVE") {
  451. curshader.add_function(MaterialFunctions.str_tex_wave);
  452. var co = getCoord(node);
  453. var scale = parse_value_input(node.inputs[1]);
  454. var res = to_vec3('tex_wave_f($co * $scale)');
  455. if (sample_bump) write_bump(node, res);
  456. return res;
  457. }
  458. else if (node.type == "BRIGHTCONTRAST") {
  459. var out_col = parse_vector_input(node.inputs[0]);
  460. var bright = parse_value_input(node.inputs[1]);
  461. var contr = parse_value_input(node.inputs[2]);
  462. curshader.add_function(MaterialFunctions.str_brightcontrast);
  463. return 'brightcontrast($out_col, $bright, $contr)';
  464. }
  465. else if (node.type == "GAMMA") {
  466. var out_col = parse_vector_input(node.inputs[0]);
  467. var gamma = parse_value_input(node.inputs[1]);
  468. return 'pow($out_col, ' + to_vec3('$gamma') + ")";
  469. }
  470. else if (node.type == "BLUR") {
  471. // Image nodes only for now
  472. var out_col = parse_vector_input(node.inputs[0]);
  473. out_col = parsedMap.get(out_col);
  474. if (out_col == null) return "vec3(0.0, 0.0, 0.0)";
  475. out_col = textureMap.get(out_col.split(".")[0]);
  476. if (out_col == null) return "vec3(0.0, 0.0, 0.0)";
  477. out_col += ".rgb";
  478. var strength = parse_value_input(node.inputs[1]);
  479. if (strength == "0.0") return "vec3(0.0, 0.0, 0.0)";
  480. var steps = 'int($strength * 10 + 1)';
  481. var texture = out_col.substring(out_col.indexOf("(") + 1, out_col.indexOf(","));
  482. curshader.write('vec2 _texCoord = texCoord;');
  483. curshader.write('vec3 res1 = vec3(0.0, 0.0, 0.0);');
  484. curshader.write('for (int i = -$steps; i <= $steps; ++i) {');
  485. curshader.write('for (int j = -$steps; j <= $steps; ++j) {');
  486. curshader.write('texCoord = _texCoord + vec2(i, j) / textureSize($texture, 0);');
  487. curshader.write('res1 += $out_col;');
  488. curshader.write('}');
  489. curshader.write('}');
  490. curshader.write('texCoord = _texCoord;');
  491. curshader.write('res1 /= ($steps * 2 + 1) * ($steps * 2 + 1);');
  492. return "res1";
  493. }
  494. else if (node.type == "HUE_SAT") {
  495. curshader.add_function(MaterialFunctions.str_hue_sat);
  496. var hue = parse_value_input(node.inputs[0]);
  497. var sat = parse_value_input(node.inputs[1]);
  498. var val = parse_value_input(node.inputs[2]);
  499. var fac = parse_value_input(node.inputs[3]);
  500. var col = parse_vector_input(node.inputs[4]);
  501. return "hue_sat($col, vec4($hue-0.5, $sat, $val, 1.0-$fac))";
  502. }
  503. else if (node.type == "INVERT") {
  504. var fac = parse_value_input(node.inputs[0]);
  505. var out_col = parse_vector_input(node.inputs[1]);
  506. return 'mix($out_col, vec3(1.0, 1.0, 1.0) - ($out_col), $fac)';
  507. }
  508. else if (node.type == "MIX_RGB") {
  509. var fac = parse_value_input(node.inputs[0]);
  510. var fac_var = node_name(node) + "_fac";
  511. curshader.write('float $fac_var = $fac;');
  512. var col1 = parse_vector_input(node.inputs[1]);
  513. var col2 = parse_vector_input(node.inputs[2]);
  514. var but = node.buttons[0]; // blend_type
  515. var blend: String = but.data[but.default_value].toUpperCase();
  516. blend = blend.replace(" ", "_");
  517. but = node.buttons[1]; // use_clamp
  518. var use_clamp = but.default_value == "true";
  519. var out_col = "";
  520. if (blend == "MIX") {
  521. out_col = 'mix($col1, $col2, $fac_var)';
  522. }
  523. else if (blend == "DARKEN") {
  524. out_col = 'min($col1, $col2 * $fac_var)';
  525. }
  526. else if (blend == "MULTIPLY") {
  527. out_col = 'mix($col1, $col1 * $col2, $fac_var)';
  528. }
  529. else if (blend == "BURN") {
  530. out_col = 'mix($col1, vec3(1.0, 1.0, 1.0) - (vec3(1.0, 1.0, 1.0) - $col1) / $col2, $fac_var)';
  531. }
  532. else if (blend == "LIGHTEN") {
  533. out_col = 'max($col1, $col2 * $fac_var)';
  534. }
  535. else if (blend == "SCREEN") {
  536. out_col = '(vec3(1.0, 1.0, 1.0) - (' + to_vec3('1.0 - $fac_var') + ' + $fac_var * (vec3(1.0, 1.0, 1.0) - $col2)) * (vec3(1.0, 1.0, 1.0) - $col1))';
  537. }
  538. else if (blend == "DODGE") {
  539. out_col = 'mix($col1, $col1 / (vec3(1.0, 1.0, 1.0) - $col2), $fac_var)';
  540. }
  541. else if (blend == "ADD") {
  542. out_col = 'mix($col1, $col1 + $col2, $fac_var)';
  543. }
  544. else if (blend == "OVERLAY") {
  545. out_col = '($col1 < vec3(0.5, 0.5, 0.5) ? vec3(2.0, 2.0, 2.0) * $col1 * $col2 : vec3(1.0, 1.0, 1.0) - vec3(2.0, 2.0, 2.0) * (vec3(1.0, 1.0, 1.0) - $col2) * (vec3(1.0, 1.0, 1.0) - $col1))';
  546. }
  547. else if (blend == "SOFT_LIGHT") {
  548. out_col = '((1.0 - $fac_var) * $col1 + $fac_var * ((vec3(1.0, 1.0, 1.0) - $col1) * $col2 * $col1 + $col1 * (vec3(1.0, 1.0, 1.0) - (vec3(1.0, 1.0, 1.0) - $col2) * (vec3(1.0, 1.0, 1.0) - $col1))))';
  549. }
  550. else if (blend == "LINEAR_LIGHT") {
  551. out_col = '($col1 + $fac_var * (vec3(2.0, 2.0, 2.0) * ($col2 - vec3(0.5, 0.5, 0.5))))';
  552. }
  553. else if (blend == "DIFFERENCE") {
  554. out_col = 'mix($col1, abs($col1 - $col2), $fac_var)';
  555. }
  556. else if (blend == "SUBTRACT") {
  557. out_col = 'mix($col1, $col1 - $col2, $fac_var)';
  558. }
  559. else if (blend == "DIVIDE") {
  560. out_col = "(" + to_vec3('(1.0 - $fac_var) * $col1 + $fac_var * $col1 / $col2') + ")";
  561. }
  562. else if (blend == "HUE") {
  563. curshader.add_function(MaterialFunctions.str_hue_sat);
  564. out_col = 'mix($col1, hsv_to_rgb(vec3(rgb_to_hsv($col2).r, rgb_to_hsv($col1).g, rgb_to_hsv($col1).b)), $fac_var)';
  565. }
  566. else if (blend == "SATURATION") {
  567. curshader.add_function(MaterialFunctions.str_hue_sat);
  568. out_col = 'mix($col1, hsv_to_rgb(vec3(rgb_to_hsv($col1).r, rgb_to_hsv($col2).g, rgb_to_hsv($col1).b)), $fac_var)';
  569. }
  570. else if (blend == "COLOR") {
  571. curshader.add_function(MaterialFunctions.str_hue_sat);
  572. out_col = 'mix($col1, hsv_to_rgb(vec3(rgb_to_hsv($col2).r, rgb_to_hsv($col2).g, rgb_to_hsv($col1).b)), $fac_var)';
  573. }
  574. else if (blend == "VALUE") {
  575. curshader.add_function(MaterialFunctions.str_hue_sat);
  576. out_col = 'mix($col1, hsv_to_rgb(vec3(rgb_to_hsv($col1).r, rgb_to_hsv($col1).g, rgb_to_hsv($col2).b)), $fac_var)';
  577. }
  578. if (use_clamp) return 'clamp($out_col, vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0))';
  579. else return out_col;
  580. }
  581. else if (node.type == "VALTORGB") { // ColorRamp
  582. var fac = parse_value_input(node.inputs[0]);
  583. var interp = node.buttons[0].data == 0 ? "LINEAR" : "CONSTANT";
  584. var elems = node.buttons[0].default_value;
  585. if (elems.length == 1) {
  586. return vec3(elems[0]);
  587. }
  588. // Write cols array
  589. var cols_var = node_name(node) + "_cols";
  590. curshader.write('vec3 $cols_var[${elems.length}];'); // TODO: Make const
  591. for (i in 0...elems.length) {
  592. curshader.write('$cols_var[$i] = ${vec3(elems[i])};');
  593. }
  594. // Get index
  595. var fac_var = node_name(node) + "_fac";
  596. curshader.write('float $fac_var = $fac;');
  597. var index = "0";
  598. for (i in 1...elems.length) {
  599. index += ' + ($fac_var > ${elems[i][4]} ? 1 : 0)';
  600. }
  601. // Write index
  602. var index_var = node_name(node) + "_i";
  603. curshader.write('int $index_var = $index;');
  604. if (interp == "CONSTANT") {
  605. return '$cols_var[$index_var]';
  606. }
  607. else { // Linear
  608. // Write facs array
  609. var facs_var = node_name(node) + "_facs";
  610. curshader.write('float $facs_var[${elems.length}];'); // TODO: Make const
  611. for (i in 0...elems.length) {
  612. curshader.write('$facs_var[$i] = ${elems[i][4]};');
  613. }
  614. // Mix color
  615. // float f = (pos - start) * (1.0 / (finish - start))
  616. return 'mix($cols_var[$index_var], $cols_var[$index_var + 1], ($fac_var - $facs_var[$index_var]) * (1.0 / ($facs_var[$index_var + 1] - $facs_var[$index_var]) ))';
  617. }
  618. }
  619. else if (node.type == "CURVE_VEC") {
  620. var fac = parse_value_input(node.inputs[0]);
  621. var vec = parse_vector_input(node.inputs[1]);
  622. var curves = node.buttons[0].default_value;
  623. var name = node_name(node);
  624. var vc0 = vector_curve(name + "0", vec + ".x", curves[0]);
  625. var vc1 = vector_curve(name + "1", vec + ".y", curves[1]);
  626. var vc2 = vector_curve(name + "2", vec + ".z", curves[2]);
  627. // mapping.curves[0].points[0].handle_type # bezier curve
  628. return '(vec3($vc0, $vc1, $vc2) * $fac)';
  629. }
  630. else if (node.type == "CURVE_RGB") { // RGB Curves
  631. var fac = parse_value_input(node.inputs[0]);
  632. var vec = parse_vector_input(node.inputs[1]);
  633. var curves = node.buttons[0].default_value;
  634. var name = node_name(node);
  635. // mapping.curves[0].points[0].handle_type
  636. var vc0 = vector_curve(name + "0", vec + ".x", curves[0]);
  637. var vc1 = vector_curve(name + "1", vec + ".y", curves[1]);
  638. var vc2 = vector_curve(name + "2", vec + ".z", curves[2]);
  639. var vc3a = vector_curve(name + "3a", vec + ".x", curves[3]);
  640. var vc3b = vector_curve(name + "3b", vec + ".y", curves[3]);
  641. var vc3c = vector_curve(name + "3c", vec + ".z", curves[3]);
  642. return '(sqrt(vec3($vc0, $vc1, $vc2) * vec3($vc3a, $vc3b, $vc3c)) * $fac)';
  643. }
  644. else if (node.type == "COMBHSV") {
  645. curshader.add_function(MaterialFunctions.str_hue_sat);
  646. var h = parse_value_input(node.inputs[0]);
  647. var s = parse_value_input(node.inputs[1]);
  648. var v = parse_value_input(node.inputs[2]);
  649. return 'hsv_to_rgb(vec3($h, $s, $v))';
  650. }
  651. else if (node.type == "COMBRGB") {
  652. var r = parse_value_input(node.inputs[0]);
  653. var g = parse_value_input(node.inputs[1]);
  654. var b = parse_value_input(node.inputs[2]);
  655. return 'vec3($r, $g, $b)';
  656. }
  657. else if (node.type == "WAVELENGTH") {
  658. curshader.add_function(MaterialFunctions.str_wavelength_to_rgb);
  659. var wl = parse_value_input(node.inputs[0]);
  660. curshader.add_function(MaterialFunctions.str_wavelength_to_rgb);
  661. return 'wavelength_to_rgb(($wl - 450.0) / 150.0)';
  662. }
  663. else if (node.type == "CAMERA") {
  664. curshader.vVecCam = true;
  665. return "vVecCam";
  666. }
  667. else if (node.type == "LAYER") {
  668. if (socket == node.outputs[0]) { // Base
  669. var l = node.buttons[0].default_value;
  670. curshader.add_uniform("sampler2D texpaint", "_texpaint" + l);
  671. return "texture(texpaint, texCoord).rgb";
  672. }
  673. else if (socket == node.outputs[5]) { // Normal
  674. var l = node.buttons[0].default_value;
  675. curshader.add_uniform("sampler2D texpaint_nor", "_texpaint_nor" + l);
  676. return "texture(texpaint_nor, texCoord).rgb";
  677. }
  678. }
  679. else if (node.type == "MATERIAL") {
  680. return "vec3(0.0, 0.0, 0.0)";
  681. }
  682. else if (node.type == "NEW_GEOMETRY") {
  683. if (socket == node.outputs[0]) { // Position
  684. curshader.wposition = true;
  685. return "wposition";
  686. }
  687. else if (socket == node.outputs[1]) { // Normal
  688. curshader.n = true;
  689. return "n";
  690. }
  691. else if (socket == node.outputs[2]) { // Tangent
  692. curshader.wtangent = true;
  693. return "wtangent";
  694. }
  695. else if (socket == node.outputs[3]) { // True Normal
  696. curshader.n = true;
  697. return "n";
  698. }
  699. else if (socket == node.outputs[4]) { // Incoming
  700. curshader.vVec = true;
  701. return "vVec";
  702. }
  703. else if (socket == node.outputs[5]) { // Parametric
  704. curshader.mposition = true;
  705. return "mposition";
  706. }
  707. }
  708. else if (node.type == "OBJECT_INFO") {
  709. curshader.wposition = true;
  710. return "wposition";
  711. }
  712. // else if (node.type == "PARTICLE_INFO") {
  713. // if (socket == node.outputs[3]) { // Location
  714. // return "vec3(0.0, 0.0, 0.0)";
  715. // }
  716. // else if (socket == node.outputs[5]) { // Velocity
  717. // return "vec3(0.0, 0.0, 0.0)";
  718. // }
  719. // else if (socket == node.outputs[6]) { // Angular Velocity
  720. // return "vec3(0.0, 0.0, 0.0)";
  721. // }
  722. // }
  723. else if (node.type == "TANGENT") {
  724. curshader.wtangent = true;
  725. return "wtangent";
  726. }
  727. else if (node.type == "TEX_COORD") {
  728. if (socket == node.outputs[0]) { // Generated - bounds
  729. curshader.bposition = true;
  730. return "bposition";
  731. }
  732. else if (socket == node.outputs[1]) { // Normal
  733. curshader.n = true;
  734. return "n";
  735. }
  736. else if (socket == node.outputs[2]) {// UV
  737. curshader.context.add_elem("tex", "short2norm");
  738. return "vec3(texCoord.x, 1.0 - texCoord.y, 0.0)";
  739. }
  740. else if (socket == node.outputs[3]) { // Object
  741. curshader.mposition = true;
  742. return "mposition";
  743. }
  744. else if (socket == node.outputs[4]) { // Camera
  745. curshader.vposition = true;
  746. return "vposition";
  747. }
  748. else if (socket == node.outputs[5]) { // Window
  749. curshader.wvpposition = true;
  750. return "wvpposition.xyz";
  751. }
  752. else if (socket == node.outputs[6]) { // Reflection
  753. return "vec3(0.0, 0.0, 0.0)";
  754. }
  755. }
  756. else if (node.type == "UVMAP") {
  757. curshader.context.add_elem("tex", "short2norm");
  758. return "vec3(texCoord.x, 1.0 - texCoord.y, 0.0)";
  759. }
  760. else if (node.type == "BUMP") {
  761. var res = "";
  762. // Interpolation strength
  763. var strength = parse_value_input(node.inputs[0]);
  764. // Height multiplier
  765. // var distance = parse_value_input(node.inputs[1]);
  766. sample_bump = true;
  767. var height = parse_value_input(node.inputs[2]);
  768. sample_bump = false;
  769. var nor = parse_vector_input(node.inputs[3]);
  770. if (sample_bump_res != "") {
  771. curshader.nAttr = true;
  772. curshader.write('${sample_bump_res}_x *= ($strength) * 16.0;');
  773. curshader.write('${sample_bump_res}_y *= ($strength) * 16.0;');
  774. curshader.write('vec3 ${sample_bump_res}_a = normalize(vec3(1.0, 0.0, ${sample_bump_res}_x));');
  775. curshader.write('vec3 ${sample_bump_res}_b = normalize(vec3(0.0, 1.0, ${sample_bump_res}_y));');
  776. res = 'normalize(mul(nAttr, mat3(${sample_bump_res}_a, ${sample_bump_res}_b, normalize(vec3(${sample_bump_res}_x, ${sample_bump_res}_y, 1.0)))))';
  777. sample_bump_res = "";
  778. }
  779. else {
  780. curshader.n = true;
  781. res = "n";
  782. }
  783. res = '($res + $nor)';
  784. if (!curshader.invTBN) {
  785. curshader.invTBN = true;
  786. curshader.nAttr = true;
  787. curshader.add_function(MaterialFunctions.str_cotangentFrame);
  788. curshader.write('mat3 invTBN = transpose(cotangentFrame(nAttr, -nAttr, texCoord));');
  789. }
  790. res = '(normalize(mul($res, invTBN)) * 0.5 + 0.5)';
  791. return res;
  792. }
  793. else if (node.type == "MAPPING") {
  794. var out = parse_vector_input(node.inputs[0]);
  795. var node_translation = node.buttons[0].default_value;
  796. var node_rotation = node.buttons[1].default_value;
  797. var node_scale = node.buttons[2].default_value;
  798. if (node_scale[0] != 1.0 || node_scale[1] != 1.0 || node_scale[2] != 1.0) {
  799. out = '($out * ${vec3(node_scale)})';
  800. }
  801. if (node_rotation[2] != 0.0) {
  802. // ZYX rotation, Z axis for now..
  803. var a = node_rotation[2];
  804. // x * cos(theta) - y * sin(theta)
  805. // x * sin(theta) + y * cos(theta)
  806. out = 'vec3(${out}.x * ${Math.cos(a)} - (${out}.y) * ${Math.sin(a)}, ${out}.x * ${Math.sin(a)} + (${out}.y) * ${Math.cos(a)}, 0.0)';
  807. }
  808. // if node.rotation[1] != 0.0:
  809. // a = node.rotation[1]
  810. // out = 'vec3({0}.x * {1} - {0}.z * {2}, {0}.x * {2} + {0}.z * {1}, 0.0)'.format(out, math.cos(a), math.sin(a))
  811. // if node.rotation[0] != 0.0:
  812. // a = node.rotation[0]
  813. // out = 'vec3({0}.y * {1} - {0}.z * {2}, {0}.y * {2} + {0}.z * {1}, 0.0)'.format(out, math.cos(a), math.sin(a))
  814. if (node_translation[0] != 0.0 || node_translation[1] != 0.0 || node_translation[2] != 0.0) {
  815. out = '($out + ${vec3(node_translation)})';
  816. }
  817. // if node.use_min:
  818. // out = 'max({0}, vec3({1}, {2}, {3}))'.format(out, node.min[0], node.min[1])
  819. // if node.use_max:
  820. // out = 'min({0}, vec3({1}, {2}, {3}))'.format(out, node.max[0], node.max[1])
  821. return out;
  822. }
  823. else if (node.type == "NORMAL") {
  824. if (socket == node.outputs[0]) {
  825. return vec3(node.outputs[0].default_value);
  826. }
  827. else if (socket == node.outputs[1]) {
  828. var nor = parse_vector_input(node.inputs[0]);
  829. var norout = vec3(node.outputs[0].default_value);
  830. return to_vec3('dot($norout, $nor)');
  831. }
  832. }
  833. else if (node.type == "NORMAL_MAP") {
  834. var strength = parse_value_input(node.inputs[0]);
  835. parse_normal_map_color_input(node.inputs[1], strength);
  836. return null;
  837. }
  838. else if (node.type == "VECT_TRANSFORM") {
  839. // #type = node.vector_type
  840. // #conv_from = node.convert_from
  841. // #conv_to = node.convert_to
  842. // # Pass throuh
  843. // return parse_vector_input(node.inputs[0])
  844. }
  845. else if (node.type == "COMBXYZ") {
  846. var x = parse_value_input(node.inputs[0]);
  847. var y = parse_value_input(node.inputs[1]);
  848. var z = parse_value_input(node.inputs[2]);
  849. return 'vec3($x, $y, $z)';
  850. }
  851. else if (node.type == "VECT_MATH") {
  852. var vec1 = parse_vector_input(node.inputs[0]);
  853. var vec2 = parse_vector_input(node.inputs[1]);
  854. var but = node.buttons[0]; //operation;
  855. var op: String = but.data[but.default_value].toUpperCase();
  856. op = op.replace(" ", "_");
  857. if (op == "ADD") {
  858. return '($vec1 + $vec2)';
  859. }
  860. else if (op == "SUBTRACT") {
  861. return '($vec1 - $vec2)';
  862. }
  863. else if (op == "AVERAGE") {
  864. return '(($vec1 + $vec2) / 2.0)';
  865. }
  866. else if (op == "DOT_PRODUCT") {
  867. return to_vec3('dot($vec1, $vec2)');
  868. }
  869. else if (op == "CROSS_PRODUCT") {
  870. return 'cross($vec1, $vec2)';
  871. }
  872. else if (op == "NORMALIZE") {
  873. return 'normalize($vec1)';
  874. }
  875. }
  876. else if (node.type == "Displacement") {
  877. var height = parse_value_input(node.inputs[0]);
  878. return to_vec3('$height');
  879. }
  880. else if (customNodes.get(node.type) != null) {
  881. return customNodes.get(node.type)();
  882. }
  883. return "vec3(0.0, 0.0, 0.0)";
  884. }
  885. static function parse_normal_map_color_input(inp: TNodeSocket, strength = "1.0") {
  886. frag.write_normal++;
  887. out_normaltan = parse_vector_input(inp);
  888. if (!arm_export_tangents) {
  889. frag.write('vec3 texn = ($out_normaltan) * 2.0 - 1.0;');
  890. frag.write('texn.y = -texn.y;');
  891. if (!cotangentFrameWritten) {
  892. cotangentFrameWritten = true;
  893. frag.add_function(MaterialFunctions.str_cotangentFrame);
  894. }
  895. frag.n = true;
  896. #if (kha_direct3d11 || kha_direct3d12)
  897. frag.write('mat3 TBN = cotangentFrame(n, vVec, texCoord);');
  898. #else
  899. frag.write('mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
  900. #end
  901. frag.write('n = mul(normalize(texn), TBN);');
  902. }
  903. frag.write_normal--;
  904. }
  905. static function parse_value_input(inp: TNodeSocket): String {
  906. var l = getInputLink(inp);
  907. if (l != null) {
  908. var from_node = getNode(l.from_id);
  909. if (from_node.type == "REROUTE") {
  910. return parse_value_input(from_node.inputs[0]);
  911. }
  912. var res_var = write_result(l);
  913. var st = from_node.outputs[l.from_socket].type;
  914. if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
  915. return '$res_var.x';
  916. }
  917. else { // VALUE
  918. return res_var;
  919. }
  920. }
  921. else {
  922. return vec1(inp.default_value);
  923. }
  924. }
  925. static function parse_value(node: TNode, socket: TNodeSocket): String {
  926. if (node.type == "ATTRIBUTE") {
  927. curshader.add_uniform("float time", "_time");
  928. return "time";
  929. }
  930. else if (node.type == "CAMERA") {
  931. if (socket == node.outputs[1]) { // View Z Depth
  932. curshader.add_uniform("vec2 cameraProj", "_cameraPlaneProj");
  933. #if (kha_direct3d11 || kha_direct3d12)
  934. curshader.wvpposition = true;
  935. return "(cameraProj.y / ((wvpposition.z / wvpposition.w) - cameraProj.x))";
  936. #else
  937. return "(cameraProj.y / (gl_FragCoord.z - cameraProj.x))";
  938. #end
  939. }
  940. else { // View Distance
  941. curshader.add_uniform("vec3 eye", "_cameraPosition");
  942. curshader.wposition = true;
  943. return "distance(eye, wposition)";
  944. }
  945. }
  946. else if (node.type == "LAYER") {
  947. if (socket == node.outputs[1]) { // Opac
  948. var l = node.buttons[0].default_value;
  949. curshader.add_uniform("sampler2D texpaint", "_texpaint" + l);
  950. return "texture(texpaint, texCoord).a";
  951. }
  952. else if (socket == node.outputs[2]) { // Occ
  953. var l = node.buttons[0].default_value;
  954. curshader.add_uniform("sampler2D texpaint_pack", "_texpaint_pack" + l);
  955. return "texture(texpaint_pack, texCoord).r";
  956. }
  957. else if (socket == node.outputs[3]) { // Rough
  958. var l = node.buttons[0].default_value;
  959. curshader.add_uniform("sampler2D texpaint_pack", "_texpaint_pack" + l);
  960. return "texture(texpaint_pack, texCoord).g";
  961. }
  962. else if (socket == node.outputs[4]) { // Metal
  963. var l = node.buttons[0].default_value;
  964. curshader.add_uniform("sampler2D texpaint_pack", "_texpaint_pack" + l);
  965. return "texture(texpaint_pack, texCoord).b";
  966. }
  967. else if (socket == node.outputs[7]) { // Height
  968. var l = node.buttons[0].default_value;
  969. curshader.add_uniform("sampler2D texpaint_pack", "_texpaint_pack" + l);
  970. return "texture(texpaint_pack, texCoord).a";
  971. }
  972. }
  973. else if (node.type == "LAYER_MASK") {
  974. if (socket == node.outputs[0]) {
  975. var l = node.buttons[0].default_value;
  976. curshader.add_uniform("sampler2D texpaint_mask", "_texpaint_mask" + l);
  977. return "texture(texpaint_mask, texCoord).r";
  978. }
  979. }
  980. else if (node.type == "MATERIAL") {
  981. return "0.0";
  982. }
  983. else if (node.type == "FRESNEL") {
  984. var ior = parse_value_input(node.inputs[0]);
  985. curshader.dotNV = true;
  986. return 'pow(1.0 - dotNV, 7.25 / $ior)';
  987. }
  988. else if (node.type == "NEW_GEOMETRY") {
  989. if (socket == node.outputs[6]) { // Backfacing
  990. #if (kha_direct3d11 || kha_direct3d12)
  991. return "0.0"; // SV_IsFrontFace
  992. #else
  993. return "(1.0 - float(gl_FrontFacing))";
  994. #end
  995. }
  996. else if (socket == node.outputs[7]) { // Pointiness
  997. return "0.0";
  998. }
  999. }
  1000. else if (node.type == "HAIR_INFO") {
  1001. return "0.5";
  1002. }
  1003. else if (node.type == "LAYER_WEIGHT") {
  1004. var blend = parse_value_input(node.inputs[0]);
  1005. if (socket == node.outputs[0]) { // Fresnel
  1006. curshader.dotNV = true;
  1007. return 'clamp(pow(1.0 - dotNV, (1.0 - $blend) * 10.0), 0.0, 1.0)';
  1008. }
  1009. else if (socket == node.outputs[1]) { // Facing
  1010. curshader.dotNV = true;
  1011. return '((1.0 - dotNV) * $blend)';
  1012. }
  1013. }
  1014. else if (node.type == "OBJECT_INFO") {
  1015. if (socket == node.outputs[1]) { // Object Index
  1016. curshader.add_uniform("float objectInfoIndex", "_objectInfoIndex");
  1017. return "objectInfoIndex";
  1018. }
  1019. else if (socket == node.outputs[2]) { // Material Index
  1020. curshader.add_uniform("float objectInfoMaterialIndex", "_objectInfoMaterialIndex");
  1021. return "objectInfoMaterialIndex";
  1022. }
  1023. else if (socket == node.outputs[3]) { // Random
  1024. curshader.add_uniform("float objectInfoRandom", "_objectInfoRandom");
  1025. return "objectInfoRandom";
  1026. }
  1027. }
  1028. else if (node.type == "VALUE") {
  1029. return vec1(node.outputs[0].default_value);
  1030. }
  1031. else if (node.type == "TEX_BRICK") {
  1032. curshader.add_function(MaterialFunctions.str_tex_brick);
  1033. var co = getCoord(node);
  1034. var scale = parse_value_input(node.inputs[4]);
  1035. var res = 'tex_brick_f($co * $scale)';
  1036. if (sample_bump) write_bump(node, res);
  1037. return res;
  1038. }
  1039. else if (node.type == "TEX_CHECKER") {
  1040. curshader.add_function(MaterialFunctions.str_tex_checker);
  1041. var co = getCoord(node);
  1042. var scale = parse_value_input(node.inputs[3]);
  1043. var res = 'tex_checker_f($co, $scale)';
  1044. if (sample_bump) write_bump(node, res);
  1045. return res;
  1046. }
  1047. else if (node.type == "TEX_GRADIENT") {
  1048. var co = getCoord(node);
  1049. var but = node.buttons[0]; //gradient_type;
  1050. var grad: String = but.data[but.default_value].toUpperCase();
  1051. grad = grad.replace(" ", "_");
  1052. var f = getGradient(grad, co);
  1053. var res = '(clamp($f, 0.0, 1.0))';
  1054. if (sample_bump) write_bump(node, res);
  1055. return res;
  1056. }
  1057. else if (node.type == "TEX_IMAGE") {
  1058. // Already fetched
  1059. if (parsed.indexOf(res_var_name(node, node.outputs[0])) >= 0) { // TODO: node.outputs[1]
  1060. var varname = store_var_name(node);
  1061. return '$varname.a';
  1062. }
  1063. var tex_name = node_name(node);
  1064. var tex = make_texture(node, tex_name);
  1065. if (tex != null) {
  1066. var to_linear = node.buttons[1].default_value == 1; // srgb to linear
  1067. var texstore = texture_store(node, tex, tex_name, to_linear);
  1068. return '$texstore.a';
  1069. }
  1070. }
  1071. else if (node.type == "TEX_MAGIC") {
  1072. curshader.add_function(MaterialFunctions.str_tex_magic);
  1073. var co = getCoord(node);
  1074. var scale = parse_value_input(node.inputs[1]);
  1075. var res = 'tex_magic_f($co * $scale * 4.0)';
  1076. if (sample_bump) write_bump(node, res);
  1077. return res;
  1078. }
  1079. else if (node.type == "TEX_MUSGRAVE") {
  1080. curshader.add_function(MaterialFunctions.str_tex_musgrave);
  1081. var co = getCoord(node);
  1082. var scale = parse_value_input(node.inputs[1]);
  1083. var res = 'tex_musgrave_f($co * $scale * 0.5)';
  1084. if (sample_bump) write_bump(node, res);
  1085. return res;
  1086. }
  1087. else if (node.type == "TEX_NOISE") {
  1088. curshader.add_function(MaterialFunctions.str_tex_noise);
  1089. curshader.add_uniform("sampler2D snoise256", "$noise256.k");
  1090. var co = getCoord(node);
  1091. var scale = parse_value_input(node.inputs[1]);
  1092. var res = 'tex_noise($co * $scale)';
  1093. if (sample_bump) write_bump(node, res);
  1094. return res;
  1095. }
  1096. else if (node.type == "TEX_VORONOI") {
  1097. curshader.add_function(MaterialFunctions.str_tex_voronoi);
  1098. curshader.add_uniform("sampler2D snoise256", "$noise256.k");
  1099. var co = getCoord(node);
  1100. var scale = parse_value_input(node.inputs[1]);
  1101. var but = node.buttons[0]; // coloring
  1102. var coloring: String = but.data[but.default_value].toUpperCase();
  1103. coloring = coloring.replace(" ", "_");
  1104. var res = "";
  1105. if (coloring == "INTENSITY") {
  1106. res = 'tex_voronoi($co * $scale).a';
  1107. }
  1108. else { // Cells
  1109. res = 'tex_voronoi($co * $scale).r';
  1110. }
  1111. if (sample_bump) write_bump(node, res);
  1112. return res;
  1113. }
  1114. else if (node.type == "TEX_WAVE") {
  1115. curshader.add_function(MaterialFunctions.str_tex_wave);
  1116. var co = getCoord(node);
  1117. var scale = parse_value_input(node.inputs[1]);
  1118. var res = 'tex_wave_f($co * $scale)';
  1119. if (sample_bump) write_bump(node, res);
  1120. return res;
  1121. }
  1122. else if (node.type == "NORMAL") {
  1123. var nor = parse_vector_input(node.inputs[0]);
  1124. var norout = vec3(node.outputs[0].default_value);
  1125. return 'dot($norout, $nor)';
  1126. }
  1127. else if (node.type == "MATH") {
  1128. var val1 = parse_value_input(node.inputs[0]);
  1129. var val2 = parse_value_input(node.inputs[1]);
  1130. var but = node.buttons[0]; // operation
  1131. var op: String = but.data[but.default_value].toUpperCase();
  1132. op = op.replace(" ", "_");
  1133. but = node.buttons[1]; // use_clamp
  1134. var use_clamp = but.default_value == "true";
  1135. var out_val = "";
  1136. if (op == "ADD") {
  1137. out_val = '($val1 + $val2)';
  1138. }
  1139. else if (op == "SUBTRACT") {
  1140. out_val = '($val1 - $val2)';
  1141. }
  1142. else if (op == "MULTIPLY") {
  1143. out_val = '($val1 * $val2)';
  1144. }
  1145. else if (op == "DIVIDE") {
  1146. out_val = '($val1 / $val2)';
  1147. }
  1148. else if (op == "POWER") {
  1149. out_val = 'pow($val1, $val2)';
  1150. }
  1151. else if (op == "LOGARITHM") {
  1152. out_val = 'log($val1)';
  1153. }
  1154. else if (op == "SQUARE_ROOT") {
  1155. out_val = 'sqrt($val1)';
  1156. }
  1157. else if (op == "ABSOLUTE") {
  1158. out_val = 'abs($val1)';
  1159. }
  1160. else if (op == "MINIMUM") {
  1161. out_val = 'min($val1, $val2)';
  1162. }
  1163. else if (op == "MAXIMUM") {
  1164. out_val = 'max($val1, $val2)';
  1165. }
  1166. else if (op == "LESS_THAN") {
  1167. out_val = 'float($val1 < $val2)';
  1168. }
  1169. else if (op == "GREATER_THAN") {
  1170. out_val = 'float($val1 > $val2)';
  1171. }
  1172. else if (op == "ROUND") {
  1173. out_val = 'floor($val1 + 0.5)';
  1174. }
  1175. else if (op == "FLOOR") {
  1176. out_val = 'floor($val1)';
  1177. }
  1178. else if (op == "CEIL") {
  1179. out_val = 'ceil($val1)';
  1180. }
  1181. else if (op == "FRACT") {
  1182. out_val = 'fract($val1)';
  1183. }
  1184. else if (op == "MODULO") {
  1185. out_val = 'mod($val1, $val2)';
  1186. }
  1187. else if (op == "SINE") {
  1188. out_val = 'sin($val1)';
  1189. }
  1190. else if (op == "COSINE") {
  1191. out_val = 'cos($val1)';
  1192. }
  1193. else if (op == "TANGENT") {
  1194. out_val = 'tan($val1)';
  1195. }
  1196. else if (op == "ARCSINE") {
  1197. out_val = 'asin($val1)';
  1198. }
  1199. else if (op == "ARCCOSINE") {
  1200. out_val = 'acos($val1)';
  1201. }
  1202. else if (op == "ARCTANGENT") {
  1203. out_val = 'atan($val1)';
  1204. }
  1205. else if (op == "ARCTAN2") {
  1206. out_val = 'atan2($val1, $val2)';
  1207. }
  1208. if (use_clamp) {
  1209. return 'clamp($out_val, 0.0, 1.0)';
  1210. }
  1211. else {
  1212. return out_val;
  1213. }
  1214. }
  1215. else if (node.type == "RGBTOBW") {
  1216. var col = parse_vector_input(node.inputs[0]);
  1217. return '((($col.r * 0.3 + $col.g * 0.59 + $col.b * 0.11) / 3.0) * 2.5)';
  1218. }
  1219. else if (node.type == "SEPRGB") {
  1220. var col = parse_vector_input(node.inputs[0]);
  1221. if (socket == node.outputs[0]) {
  1222. return '$col.r';
  1223. }
  1224. else if (socket == node.outputs[1]) {
  1225. return '$col.g';
  1226. }
  1227. else if (socket == node.outputs[2]) {
  1228. return '$col.b';
  1229. }
  1230. }
  1231. else if (node.type == "SEPXYZ") {
  1232. var vec = parse_vector_input(node.inputs[0]);
  1233. if (socket == node.outputs[0]) {
  1234. return '$vec.x';
  1235. }
  1236. else if (socket == node.outputs[1]) {
  1237. return '$vec.y';
  1238. }
  1239. else if (socket == node.outputs[2]) {
  1240. return '$vec.z';
  1241. }
  1242. }
  1243. else if (node.type == "VECT_MATH") {
  1244. var vec1 = parse_vector_input(node.inputs[0]);
  1245. var vec2 = parse_vector_input(node.inputs[1]);
  1246. var but = node.buttons[0]; //operation;
  1247. var op: String = but.data[but.default_value].toUpperCase();
  1248. op = op.replace(" ", "_");
  1249. if (op == "DOT_PRODUCT") {
  1250. return 'dot($vec1, $vec2)';
  1251. }
  1252. else {
  1253. return "0.0";
  1254. }
  1255. }
  1256. else if (customNodes.get(node.type) != null) {
  1257. return customNodes.get(node.type)();
  1258. }
  1259. return "0.0";
  1260. }
  1261. static function getCoord(node: TNode): String {
  1262. if (getInputLink(node.inputs[0]) != null) {
  1263. return parse_vector_input(node.inputs[0]);
  1264. }
  1265. else {
  1266. curshader.bposition = true;
  1267. return "bposition";
  1268. }
  1269. }
  1270. static function getGradient(grad: String, co: String): String {
  1271. if (grad == "LINEAR") {
  1272. return '$co.x';
  1273. }
  1274. else if (grad == "QUADRATIC") {
  1275. return "0.0";
  1276. }
  1277. else if (grad == "EASING") {
  1278. return "0.0";
  1279. }
  1280. else if (grad == "DIAGONAL") {
  1281. return '($co.x + $co.y) * 0.5';
  1282. }
  1283. else if (grad == "RADIAL") {
  1284. return 'atan($co.y, $co.x) / (3.141592 * 2.0) + 0.5';
  1285. }
  1286. else if (grad == "QUADRATIC_SPHERE") {
  1287. return "0.0";
  1288. }
  1289. else { // "SPHERICAL"
  1290. return 'max(1.0 - sqrt($co.x * $co.x + $co.y * $co.y + $co.z * $co.z), 0.0)';
  1291. }
  1292. }
  1293. static function vector_curve(name: String, fac: String, points: Array<Float>): String {
  1294. // Write Ys array
  1295. var ys_var = name + "_ys";
  1296. var num = Std.int(points.length / 2);
  1297. curshader.write('float $ys_var[$num];'); // TODO: Make const
  1298. for (i in 0...num) {
  1299. curshader.write('$ys_var[$i] = ${points[i * 2 + 1]};');
  1300. }
  1301. // Get index
  1302. var fac_var = name + "_fac";
  1303. curshader.write('float $fac_var = $fac;');
  1304. var index = "0";
  1305. for (i in 1...num) {
  1306. index += ' + ($fac_var > ${points[i * 2]} ? 1 : 0)';
  1307. }
  1308. // Write index
  1309. var index_var = name + "_i";
  1310. curshader.write('int $index_var = $index;');
  1311. // Linear
  1312. // Write Xs array
  1313. var facs_var = name + "_xs";
  1314. curshader.write('float $facs_var[$num];'); // TODO: Make const
  1315. for (i in 0...num) {
  1316. curshader.write('$facs_var[$i] = ${points[i * 2]};');
  1317. }
  1318. // Map vector
  1319. return 'mix($ys_var[$index_var], $ys_var[$index_var + 1], ($fac_var - $facs_var[$index_var]) * (1.0 / ($facs_var[$index_var + 1] - $facs_var[$index_var])))';
  1320. }
  1321. static function res_var_name(node: TNode, socket: TNodeSocket): String {
  1322. return node_name(node) + "_" + safesrc(socket.name) + "_res";
  1323. }
  1324. static var parsedMap = new Map<String, String>();
  1325. static var textureMap = new Map<String, String>();
  1326. static function write_result(l: TNodeLink): String {
  1327. var from_node = getNode(l.from_id);
  1328. var from_socket = from_node.outputs[l.from_socket];
  1329. var res_var = res_var_name(from_node, from_socket);
  1330. var st = from_socket.type;
  1331. if (parsed.indexOf(res_var) < 0) {
  1332. parsed.push(res_var);
  1333. if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
  1334. var res = parse_vector(from_node, from_socket);
  1335. if (res == null) {
  1336. return null;
  1337. }
  1338. parsedMap.set(res_var, res);
  1339. curshader.write('vec3 $res_var = $res;');
  1340. }
  1341. else if (st == "VALUE") {
  1342. var res = parse_value(from_node, from_socket);
  1343. if (res == null) {
  1344. return null;
  1345. }
  1346. parsedMap.set(res_var, res);
  1347. curshader.write('float $res_var = $res;');
  1348. }
  1349. }
  1350. return res_var;
  1351. }
  1352. static function store_var_name(node: TNode): String {
  1353. return node_name(node) + "_store";
  1354. }
  1355. static function texture_store(node: TNode, tex: TBindTexture, tex_name: String, to_linear = false): String {
  1356. matcon.bind_textures.push(tex);
  1357. curshader.context.add_elem("tex", "short2norm");
  1358. curshader.add_uniform("sampler2D " + tex_name);
  1359. var uv_name = "";
  1360. if (getInputLink(node.inputs[0]) != null) {
  1361. uv_name = parse_vector_input(node.inputs[0]);
  1362. }
  1363. else {
  1364. uv_name = "texCoord";
  1365. }
  1366. var tex_store = store_var_name(node);
  1367. if (triplanar) {
  1368. curshader.write('vec4 $tex_store = vec4(0.0, 0.0, 0.0, 0.0);');
  1369. curshader.write('if (texCoordBlend.x > 0) $tex_store += texture($tex_name, ${uv_name}.xy) * texCoordBlend.x;');
  1370. curshader.write('if (texCoordBlend.y > 0) $tex_store += texture($tex_name, ${uv_name}1.xy) * texCoordBlend.y;');
  1371. curshader.write('if (texCoordBlend.z > 0) $tex_store += texture($tex_name, ${uv_name}2.xy) * texCoordBlend.z;');
  1372. }
  1373. else {
  1374. textureMap.set(tex_store, 'texture($tex_name, $uv_name.xy)');
  1375. curshader.write('vec4 $tex_store = texture($tex_name, $uv_name.xy);');
  1376. }
  1377. if (sample_bump) {
  1378. sample_bump_res = tex_store;
  1379. curshader.write('float ${tex_store}_x = dFdx($tex_store).x;');
  1380. curshader.write('float ${tex_store}_y = dFdy($tex_store).x;');
  1381. sample_bump = false;
  1382. }
  1383. if (to_linear) {
  1384. curshader.write('$tex_store.rgb = pow($tex_store.rgb, vec3(2.2, 2.2, 2.2));');
  1385. }
  1386. return tex_store;
  1387. }
  1388. static function write_bump(node: TNode, res: String) {
  1389. sample_bump_res = store_var_name(node) + "_bump";
  1390. curshader.write('float ${sample_bump_res}_x = dFdx($res);');
  1391. curshader.write('float ${sample_bump_res}_y = dFdy($res);');
  1392. sample_bump = false;
  1393. }
  1394. static function vec1(v: Float): String {
  1395. #if kha_webgl
  1396. return 'float($v)';
  1397. #else
  1398. return '$v';
  1399. #end
  1400. }
  1401. static function vec3(v: Array<Float>): String {
  1402. #if kha_webgl
  1403. return 'vec3(float(${v[0]}), float(${v[1]}), float(${v[2]}))';
  1404. #else
  1405. return 'vec3(${v[0]}, ${v[1]}, ${v[2]})';
  1406. #end
  1407. }
  1408. static function to_vec3(s: String): String {
  1409. #if (kha_direct3d11 || kha_direct3d12)
  1410. return '($s).xxx';
  1411. #else
  1412. return 'vec3($s)';
  1413. #end
  1414. }
  1415. static function node_by_type(nodes: Array<TNode>, ntype: String): TNode {
  1416. for (n in nodes) if (n.type == ntype) return n;
  1417. return null;
  1418. }
  1419. static function socket_index(node: TNode, socket: TNodeSocket): Int {
  1420. for (i in 0...node.outputs.length) if (node.outputs[i] == socket) return i;
  1421. return -1;
  1422. }
  1423. static function node_name(node: TNode): String {
  1424. var s = safesrc(node.name) + node.id;
  1425. return s;
  1426. }
  1427. static function safesrc(s: String): String {
  1428. for (i in 0...s.length) {
  1429. var code = s.charCodeAt(i);
  1430. var letter = (code >= 65 && code <= 90) || (code >= 97 && code <= 122);
  1431. if (!letter) s = s.replace(s.charAt(i), "_");
  1432. }
  1433. return s;
  1434. }
  1435. public static function enumData(s: String): String {
  1436. for (a in Project.assets) if (a.name == s) return a.file;
  1437. return "";
  1438. }
  1439. static function make_texture(image_node: TNode, tex_name: String, matname: String = null): TBindTexture {
  1440. var filepath = enumData(App.enumTexts(image_node.type)[image_node.buttons[0].default_value]);
  1441. if (filepath == "" || filepath.indexOf(".") == -1) {
  1442. return null;
  1443. }
  1444. var tex: TBindTexture = {
  1445. name: tex_name,
  1446. file: filepath
  1447. };
  1448. if (arm.ui.UITrait.inst.textureFilter) {
  1449. tex.min_filter = "anisotropic";
  1450. tex.mag_filter = "linear";
  1451. tex.mipmap_filter = "linear";
  1452. }
  1453. else {
  1454. tex.min_filter = "point";
  1455. tex.mag_filter = "point";
  1456. tex.mipmap_filter = "no";
  1457. }
  1458. tex.generate_mipmaps = true;
  1459. tex.u_addressing = "repeat";
  1460. tex.v_addressing = "repeat";
  1461. return tex;
  1462. }
  1463. static function is_pow(num: Int): Bool {
  1464. return ((num & (num - 1)) == 0) && num != 0;
  1465. }
  1466. static function asset_path(s: String): String {
  1467. return s;
  1468. }
  1469. static function extract_filename(s: String): String {
  1470. var ar = s.split(".");
  1471. return ar[ar.length - 2] + "." + ar[ar.length - 1];
  1472. }
  1473. static function safestr(s: String): String {
  1474. return s;
  1475. }
  1476. }
  1477. typedef TShaderOut = {
  1478. var out_basecol: String;
  1479. var out_roughness: String;
  1480. var out_metallic: String;
  1481. var out_occlusion: String;
  1482. var out_opacity: String;
  1483. var out_height: String;
  1484. var out_emission: String;
  1485. var out_subsurface: String;
  1486. }