MaterialParser.hx 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939
  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.shader;
  18. import zui.Nodes;
  19. import iron.data.SceneFormat;
  20. import arm.shader.NodeShader;
  21. class MaterialParser {
  22. static var con: NodeShaderContext;
  23. static var vert: NodeShader;
  24. static var frag: NodeShader;
  25. static var curshader: NodeShader;
  26. static var matcon: TMaterialContext;
  27. static var parsed: Array<String>;
  28. static var parents: Array<TNode>;
  29. static var canvases: Array<TNodeCanvas>;
  30. static var nodes: Array<TNode>;
  31. static var links: Array<TNodeLink>;
  32. static var cotangentFrameWritten: Bool;
  33. static var tex_coord = "texCoord";
  34. static inline var eps = 0.000001;
  35. public static var customNodes = js.Syntax.code("new Map()");
  36. public static var parse_surface = true;
  37. public static var parse_opacity = true;
  38. public static var parse_height = false;
  39. public static var parse_height_as_channel = false;
  40. public static var parse_emission = false;
  41. public static var parse_subsurface = false;
  42. public static var parsing_basecolor = false;
  43. public static var triplanar = false; // Sample using texCoord/1/2 & texCoordBlend
  44. public static var sample_keep_aspect = false; // Adjust uvs to preserve texture aspect ratio
  45. public static var sample_uv_scale = '1.0';
  46. public static var transform_color_space = true;
  47. public static var blur_passthrough = false;
  48. public static var warp_passthrough = false;
  49. public static var bake_passthrough = false;
  50. public static var bake_passthrough_strength = "0.0";
  51. public static var bake_passthrough_radius = "0.0";
  52. public static var bake_passthrough_offset = "0.0";
  53. public static var start_group: TNodeCanvas = null;
  54. public static var start_parents: Array<TNode> = null;
  55. public static var start_node: TNode = null;
  56. public static var arm_export_tangents = true;
  57. public static var out_normaltan: String; // Raw tangent space normal parsed from normal map
  58. public static var script_links: Map<String, String> = null;
  59. public static function getNode(id: Int): TNode {
  60. for (n in nodes) if (n.id == id) return n;
  61. return null;
  62. }
  63. public static function getLink(id: Int): TNodeLink {
  64. for (l in links) if (l.id == id) return l;
  65. return null;
  66. }
  67. public static function getInputLink(inp: TNodeSocket): TNodeLink {
  68. for (l in links) {
  69. if (l.to_id == inp.node_id) {
  70. var node = getNode(inp.node_id);
  71. if (node.inputs.length <= l.to_socket) return null;
  72. if (node.inputs[l.to_socket] == inp) return l;
  73. }
  74. }
  75. return null;
  76. }
  77. public static function getOutputLinks(out: TNodeSocket): Array<TNodeLink> {
  78. var ls: Array<TNodeLink> = null;
  79. for (l in links) {
  80. if (l.from_id == out.node_id) {
  81. var node = getNode(out.node_id);
  82. if (node.outputs.length <= l.from_socket) continue;
  83. if (node.outputs[l.from_socket] == out) {
  84. if (ls == null) ls = [];
  85. ls.push(l);
  86. }
  87. }
  88. }
  89. return ls;
  90. }
  91. static function init() {
  92. parsed = [];
  93. parents = [];
  94. cotangentFrameWritten = false;
  95. out_normaltan = "vec3(0.5, 0.5, 1.0)";
  96. script_links = null;
  97. parsing_basecolor = false;
  98. }
  99. public static function parse(canvas: TNodeCanvas, _con: NodeShaderContext, _vert: NodeShader, _frag: NodeShader, _matcon: TMaterialContext): TShaderOut {
  100. init();
  101. canvases = [canvas];
  102. nodes = canvas.nodes;
  103. links = canvas.links;
  104. con = _con;
  105. vert = _vert;
  106. frag = _frag;
  107. curshader = frag;
  108. matcon = _matcon;
  109. if (start_group != null) {
  110. push_group(start_group);
  111. parents = start_parents;
  112. }
  113. if (start_node != null) {
  114. var link: TNodeLink = { id: 99999, from_id: start_node.id, from_socket: 0, to_id: -1, to_socket: -1 };
  115. write_result(link);
  116. return {
  117. out_basecol: 'vec3(0.0, 0.0, 0.0)',
  118. out_roughness: '0.0',
  119. out_metallic: '0.0',
  120. out_occlusion: '1.0',
  121. out_opacity: '1.0',
  122. out_height: '0.0',
  123. out_emission: '0.0',
  124. out_subsurface: '0.0'
  125. }
  126. }
  127. var output_node = node_by_type(nodes, "OUTPUT_MATERIAL");
  128. if (output_node != null) {
  129. return parse_output(output_node);
  130. }
  131. output_node = node_by_type(nodes, "OUTPUT_MATERIAL_PBR");
  132. if (output_node != null) {
  133. return parse_output_pbr(output_node);
  134. }
  135. return null;
  136. }
  137. public static function finalize(con: NodeShaderContext) {
  138. var vert = con.vert;
  139. var frag = con.frag;
  140. if (frag.dotNV) {
  141. frag.vVec = true;
  142. frag.n = true;
  143. }
  144. if (frag.vVec) {
  145. vert.wposition = true;
  146. }
  147. if (frag.bposition) {
  148. if (triplanar) {
  149. frag.write_attrib('vec3 bposition = vec3(
  150. texCoord1.x * texCoordBlend.y + texCoord2.x * texCoordBlend.z,
  151. texCoord.x * texCoordBlend.x + texCoord2.y * texCoordBlend.z,
  152. texCoord.y * texCoordBlend.x + texCoord1.y * texCoordBlend.y);');
  153. }
  154. else if (frag.ndcpos) {
  155. vert.add_out("vec3 bposition");
  156. vert.write('bposition = (ndc.xyz / ndc.w);');
  157. }
  158. else {
  159. vert.add_out("vec3 bposition");
  160. vert.add_uniform("vec3 dim", "_dim");
  161. vert.add_uniform("vec3 hdim", "_halfDim");
  162. vert.write_attrib('bposition = (pos.xyz + hdim) / dim;');
  163. }
  164. }
  165. if (frag.wposition) {
  166. vert.add_uniform("mat4 W", "_worldMatrix");
  167. vert.add_out("vec3 wposition");
  168. vert.write_attrib('wposition = vec4(mul(vec4(pos.xyz, 1.0), W)).xyz;');
  169. }
  170. else if (vert.wposition) {
  171. vert.add_uniform("mat4 W", "_worldMatrix");
  172. vert.write_attrib('vec3 wposition = vec4(mul(vec4(pos.xyz, 1.0), W)).xyz;');
  173. }
  174. if (frag.vposition) {
  175. vert.add_uniform("mat4 WV", "_worldViewMatrix");
  176. vert.add_out("vec3 vposition");
  177. vert.write_attrib('vposition = vec4(mul(vec4(pos.xyz, 1.0), WV)).xyz;');
  178. }
  179. if (frag.mposition) {
  180. vert.add_out("vec3 mposition");
  181. if (frag.ndcpos) {
  182. vert.write('mposition = (ndc.xyz / ndc.w);');
  183. }
  184. else {
  185. vert.write_attrib('mposition = pos.xyz;');
  186. }
  187. }
  188. if (frag.wtangent) {
  189. // con.add_elem("tang", "short4norm");
  190. // vert.add_uniform("mat3 N", "_normalMatrix");
  191. vert.add_out("vec3 wtangent");
  192. // vert.write_attrib('wtangent = normalize(mul(tang.xyz, N));');
  193. vert.write_attrib('wtangent = vec3(0.0, 0.0, 0.0);');
  194. }
  195. if (frag.vVecCam) {
  196. vert.add_uniform("mat4 WV", "_worldViewMatrix");
  197. vert.add_out("vec3 eyeDirCam");
  198. vert.write_attrib('eyeDirCam = vec4(mul(vec4(pos.xyz, 1.0), WV)).xyz; eyeDirCam.z *= -1.0;');
  199. frag.write_attrib('vec3 vVecCam = normalize(eyeDirCam);');
  200. }
  201. if (frag.vVec) {
  202. vert.add_uniform("vec3 eye", "_cameraPosition");
  203. vert.add_out("vec3 eyeDir");
  204. vert.write_attrib('eyeDir = eye - wposition;');
  205. frag.write_attrib('vec3 vVec = normalize(eyeDir);');
  206. }
  207. if (frag.n) {
  208. vert.add_uniform("mat3 N", "_normalMatrix");
  209. vert.add_out("vec3 wnormal");
  210. vert.write_attrib('wnormal = mul(vec3(nor.xy, pos.w), N);');
  211. frag.write_attrib('vec3 n = normalize(wnormal);');
  212. }
  213. else if (vert.n) {
  214. vert.add_uniform("mat3 N", "_normalMatrix");
  215. vert.write_attrib('vec3 wnormal = normalize(mul(vec3(nor.xy, pos.w), N));');
  216. }
  217. if (frag.nAttr) {
  218. vert.add_out("vec3 nAttr");
  219. vert.write_attrib('nAttr = vec3(nor.xy, pos.w);');
  220. }
  221. if (frag.dotNV) {
  222. frag.write_attrib('float dotNV = max(dot(n, vVec), 0.0);');
  223. }
  224. if (frag.wvpposition) {
  225. vert.add_out("vec4 wvpposition");
  226. vert.write_end('wvpposition = gl_Position;');
  227. }
  228. if (con.is_elem('col')) {
  229. vert.add_out('vec3 vcolor');
  230. vert.write_attrib('vcolor = col.rgb;');
  231. }
  232. }
  233. static function parse_output(node: TNode): TShaderOut {
  234. if (parse_surface || parse_opacity) {
  235. return parse_shader_input(node.inputs[0]);
  236. }
  237. return null;
  238. // Parse volume, displacement..
  239. }
  240. static function parse_output_pbr(node: TNode): TShaderOut {
  241. if (parse_surface || parse_opacity) {
  242. return parse_shader(node, null);
  243. }
  244. return null;
  245. // Parse volume, displacement..
  246. }
  247. static function get_group(name: String): TNodeCanvas {
  248. for (g in Project.materialGroups) if (g.canvas.name == name) return g.canvas;
  249. return null;
  250. }
  251. static function push_group(g: TNodeCanvas) {
  252. canvases.push(g);
  253. nodes = g.nodes;
  254. links = g.links;
  255. }
  256. static function pop_group() {
  257. canvases.pop();
  258. var g = canvases[canvases.length - 1];
  259. nodes = g.nodes;
  260. links = g.links;
  261. }
  262. static function parse_group(node: TNode, socket: TNodeSocket): String { // Entering group
  263. parents.push(node);
  264. push_group(get_group(node.name));
  265. var output_node = node_by_type(nodes, 'GROUP_OUTPUT');
  266. if (output_node == null) return null;
  267. var index = socket_index(node, socket);
  268. var inp = output_node.inputs[index];
  269. var out_group = parse_input(inp);
  270. parents.pop();
  271. pop_group();
  272. return out_group;
  273. }
  274. static function parse_group_input(node: TNode, socket: TNodeSocket): String {
  275. var parent = parents.pop(); // Leaving group
  276. pop_group();
  277. var index = socket_index(node, socket);
  278. var inp = parent.inputs[index];
  279. var res = parse_input(inp);
  280. parents.push(parent); // Return to group
  281. push_group(get_group(parent.name));
  282. return res;
  283. }
  284. static function parse_input(inp: TNodeSocket): String {
  285. if (inp.type == "RGB") {
  286. return parse_vector_input(inp);
  287. }
  288. else if (inp.type == "RGBA") {
  289. return parse_vector_input(inp);
  290. }
  291. else if (inp.type == "VECTOR") {
  292. return parse_vector_input(inp);
  293. }
  294. else if (inp.type == "VALUE") {
  295. return parse_value_input(inp);
  296. }
  297. return null;
  298. }
  299. static function parse_shader_input(inp: TNodeSocket): TShaderOut {
  300. var l = getInputLink(inp);
  301. var from_node = l != null ? getNode(l.from_id) : null;
  302. if (from_node != null) {
  303. if (from_node.type == "REROUTE") {
  304. return parse_shader_input(from_node.inputs[0]);
  305. }
  306. return parse_shader(from_node, from_node.outputs[l.from_socket]);
  307. }
  308. else {
  309. return {
  310. out_basecol: "vec3(0.8, 0.8, 0.8)",
  311. out_roughness: "0.0",
  312. out_metallic: "0.0",
  313. out_occlusion: "1.0",
  314. out_opacity: "1.0",
  315. out_height: "0.0",
  316. out_emission: "0.0",
  317. out_subsurface: "0.0"
  318. };
  319. }
  320. }
  321. static function parse_shader(node: TNode, socket: TNodeSocket): TShaderOut {
  322. var sout: TShaderOut = {
  323. out_basecol: "vec3(0.8, 0.8, 0.8)",
  324. out_roughness: "0.0",
  325. out_metallic: "0.0",
  326. out_occlusion: "1.0",
  327. out_opacity: "1.0",
  328. out_height: "0.0",
  329. out_emission: "0.0",
  330. out_subsurface: "0.0"
  331. }
  332. if (node.type == "OUTPUT_MATERIAL_PBR") {
  333. if (parse_surface) {
  334. // Normal - parsed first to retrieve uv coords
  335. parse_normal_map_color_input(node.inputs[5]);
  336. // Base color
  337. parsing_basecolor = true;
  338. sout.out_basecol = parse_vector_input(node.inputs[0]);
  339. parsing_basecolor = false;
  340. // Occlusion
  341. sout.out_occlusion = parse_value_input(node.inputs[2]);
  342. // Roughness
  343. sout.out_roughness = parse_value_input(node.inputs[3]);
  344. // Metallic
  345. sout.out_metallic = parse_value_input(node.inputs[4]);
  346. // Emission
  347. if (parse_emission) {
  348. sout.out_emission = parse_value_input(node.inputs[6]);
  349. }
  350. // Subsurface
  351. if (parse_subsurface) {
  352. sout.out_subsurface = parse_value_input(node.inputs[8]);
  353. }
  354. }
  355. if (parse_opacity) {
  356. sout.out_opacity = parse_value_input(node.inputs[1]);
  357. }
  358. // Displacement / Height
  359. if (node.inputs.length > 7 && parse_height) {
  360. if (!parse_height_as_channel) curshader = vert;
  361. sout.out_height = parse_value_input(node.inputs[7]);
  362. if (!parse_height_as_channel) curshader = frag;
  363. }
  364. }
  365. return sout;
  366. }
  367. static function parse_vector_input(inp: TNodeSocket): String {
  368. var l = getInputLink(inp);
  369. var from_node = l != null ? getNode(l.from_id) : null;
  370. if (from_node != null) {
  371. if (from_node.type == "REROUTE") {
  372. return parse_vector_input(from_node.inputs[0]);
  373. }
  374. var res_var = write_result(l);
  375. var st = from_node.outputs[l.from_socket].type;
  376. if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
  377. return res_var;
  378. }
  379. else {// VALUE
  380. return to_vec3(res_var);
  381. }
  382. }
  383. else {
  384. if (inp.type == "VALUE") { //# Unlinked reroute
  385. return vec3([0.0, 0.0, 0.0]);
  386. }
  387. else {
  388. return vec3(inp.default_value);
  389. }
  390. }
  391. }
  392. static function parse_vector(node: TNode, socket: TNodeSocket): String {
  393. if (node.type == 'GROUP') {
  394. return parse_group(node, socket);
  395. }
  396. else if (node.type == 'GROUP_INPUT') {
  397. return parse_group_input(node, socket);
  398. }
  399. else if (node.type == "ATTRIBUTE") {
  400. if (socket == node.outputs[0]) { // Color
  401. if (curshader.context.allow_vcols) {
  402. curshader.context.add_elem("col", "short4norm"); // Vcols only for now
  403. return "vcolor";
  404. }
  405. else {
  406. return("vec3(0.0, 0.0, 0.0)");
  407. }
  408. }
  409. else { // Vector
  410. curshader.context.add_elem("tex", "short2norm"); // UVMaps only for now
  411. return "vec3(texCoord.x, texCoord.y, 0.0)";
  412. }
  413. }
  414. else if (node.type == "VERTEX_COLOR") {
  415. if (curshader.context.allow_vcols) {
  416. curshader.context.add_elem("col", "short4norm");
  417. return "vcolor";
  418. }
  419. else {
  420. return("vec3(0.0, 0.0, 0.0)");
  421. }
  422. }
  423. else if (node.type == "RGB") {
  424. return vec3(socket.default_value);
  425. }
  426. else if (node.type == "TEX_BRICK") {
  427. curshader.add_function(ShaderFunctions.str_tex_brick);
  428. var co = getCoord(node);
  429. var col1 = parse_vector_input(node.inputs[1]);
  430. var col2 = parse_vector_input(node.inputs[2]);
  431. var col3 = parse_vector_input(node.inputs[3]);
  432. var scale = parse_value_input(node.inputs[4]);
  433. var res = 'tex_brick($co * $scale, $col1, $col2, $col3)';
  434. return res;
  435. }
  436. else if (node.type == "TEX_CHECKER") {
  437. curshader.add_function(ShaderFunctions.str_tex_checker);
  438. var co = getCoord(node);
  439. var col1 = parse_vector_input(node.inputs[1]);
  440. var col2 = parse_vector_input(node.inputs[2]);
  441. var scale = parse_value_input(node.inputs[3]);
  442. var res = 'tex_checker($co, $col1, $col2, $scale)';
  443. return res;
  444. }
  445. else if (node.type == "TEX_GRADIENT") {
  446. var co = getCoord(node);
  447. var but = node.buttons[0]; //gradient_type;
  448. var grad: String = but.data[but.default_value].toUpperCase();
  449. grad = grad.replace(" ", "_");
  450. var f = getGradient(grad, co);
  451. var res = to_vec3('clamp($f, 0.0, 1.0)');
  452. return res;
  453. }
  454. else if (node.type == "TEX_IMAGE") {
  455. // Already fetched
  456. if (parsed.indexOf(res_var_name(node, node.outputs[1])) >= 0) { // TODO: node.outputs[0]
  457. var varname = store_var_name(node);
  458. return '$varname.rgb';
  459. }
  460. var tex_name = node_name(node);
  461. var tex = make_texture(node, tex_name);
  462. if (tex != null) {
  463. var color_space = node.buttons[1].default_value;
  464. var texstore = texture_store(node, tex, tex_name, color_space);
  465. return '$texstore.rgb';
  466. }
  467. else {
  468. var tex_store = store_var_name(node); // Pink color for missing texture
  469. curshader.write('vec4 $tex_store = vec4(1.0, 0.0, 1.0, 1.0);');
  470. return '$tex_store.rgb';
  471. }
  472. }
  473. else if (node.type == "TEX_MAGIC") {
  474. curshader.add_function(ShaderFunctions.str_tex_magic);
  475. var co = getCoord(node);
  476. var scale = parse_value_input(node.inputs[1]);
  477. var res = 'tex_magic($co * $scale * 4.0)';
  478. return res;
  479. }
  480. else if (node.type == "TEX_NOISE") {
  481. curshader.add_function(ShaderFunctions.str_tex_noise);
  482. var co = getCoord(node);
  483. var scale = parse_value_input(node.inputs[1]);
  484. var res = 'vec3(tex_noise($co * $scale), tex_noise($co * $scale + 0.33), tex_noise($co * $scale + 0.66))';
  485. return res;
  486. }
  487. else if (node.type == "TEX_VORONOI") {
  488. curshader.add_function(ShaderFunctions.str_tex_voronoi);
  489. curshader.add_uniform("sampler2D snoise256", "$noise256.k");
  490. var co = getCoord(node);
  491. var scale = parse_value_input(node.inputs[1]);
  492. var but = node.buttons[0]; //coloring;
  493. var coloring: String = but.data[but.default_value].toUpperCase();
  494. coloring = coloring.replace(" ", "_");
  495. var res = "";
  496. if (coloring == "INTENSITY") {
  497. res = to_vec3('tex_voronoi($co * $scale, texturePass(snoise256)).a');
  498. }
  499. else { // Cells
  500. res = 'tex_voronoi($co * $scale, texturePass(snoise256)).rgb';
  501. }
  502. return res;
  503. }
  504. else if (node.type == "TEX_WAVE") {
  505. curshader.add_function(ShaderFunctions.str_tex_wave);
  506. var co = getCoord(node);
  507. var scale = parse_value_input(node.inputs[1]);
  508. var res = to_vec3('tex_wave_f($co * $scale)');
  509. return res;
  510. }
  511. else if (node.type == "BRIGHTCONTRAST") {
  512. var out_col = parse_vector_input(node.inputs[0]);
  513. var bright = parse_value_input(node.inputs[1]);
  514. var contr = parse_value_input(node.inputs[2]);
  515. curshader.add_function(ShaderFunctions.str_brightcontrast);
  516. return 'brightcontrast($out_col, $bright, $contr)';
  517. }
  518. else if (node.type == "GAMMA") {
  519. var out_col = parse_vector_input(node.inputs[0]);
  520. var gamma = parse_value_input(node.inputs[1]);
  521. return 'pow($out_col, ' + to_vec3('$gamma') + ")";
  522. }
  523. else if (node.type == "DIRECT_WARP") {
  524. if (warp_passthrough) return parse_vector_input(node.inputs[0]);
  525. var angle = parse_value_input(node.inputs[1], true);
  526. var mask = parse_value_input(node.inputs[2], true);
  527. var tex_name = "texwarp_" + node_name(node);
  528. curshader.add_uniform("sampler2D " + tex_name, "_" + tex_name);
  529. var store = store_var_name(node);
  530. curshader.write('float ${store}_rad = $angle * (${Math.PI} / 180);');
  531. curshader.write('float ${store}_x = cos(${store}_rad);');
  532. curshader.write('float ${store}_y = sin(${store}_rad);');
  533. return 'texture($tex_name, texCoord + vec2(${store}_x, ${store}_y) * $mask).rgb;';
  534. }
  535. else if (node.type == "BLUR") {
  536. if (blur_passthrough) return parse_vector_input(node.inputs[0]);
  537. var strength = parse_value_input(node.inputs[1]);
  538. if (strength == "0.0") return "vec3(0.0, 0.0, 0.0)";
  539. var steps = 'int($strength * 10 + 1)';
  540. var tex_name = "texblur_" + node_name(node);
  541. curshader.add_uniform("sampler2D " + tex_name, "_" + tex_name);
  542. var store = store_var_name(node);
  543. curshader.write('vec3 ${store}_res = vec3(0.0, 0.0, 0.0);');
  544. curshader.write('for (int i = -$steps; i <= $steps; ++i) {');
  545. curshader.write('for (int j = -$steps; j <= $steps; ++j) {');
  546. curshader.write('${store}_res += texture($tex_name, texCoord + vec2(i, j) / vec2(textureSize($tex_name, 0))).rgb;');
  547. curshader.write('}');
  548. curshader.write('}');
  549. curshader.write('${store}_res /= ($steps * 2 + 1) * ($steps * 2 + 1);');
  550. return '${store}_res';
  551. }
  552. else if (node.type == "HUE_SAT") {
  553. curshader.add_function(ShaderFunctions.str_hue_sat);
  554. var hue = parse_value_input(node.inputs[0]);
  555. var sat = parse_value_input(node.inputs[1]);
  556. var val = parse_value_input(node.inputs[2]);
  557. var fac = parse_value_input(node.inputs[3]);
  558. var col = parse_vector_input(node.inputs[4]);
  559. return 'hue_sat($col, vec4($hue-0.5, $sat, $val, 1.0-$fac))';
  560. }
  561. else if (node.type == "INVERT") {
  562. var fac = parse_value_input(node.inputs[0]);
  563. var out_col = parse_vector_input(node.inputs[1]);
  564. return 'mix($out_col, vec3(1.0, 1.0, 1.0) - ($out_col), $fac)';
  565. }
  566. else if (node.type == "MIX_RGB") {
  567. var fac = parse_value_input(node.inputs[0]);
  568. var fac_var = node_name(node) + "_fac";
  569. curshader.write('float $fac_var = $fac;');
  570. var col1 = parse_vector_input(node.inputs[1]);
  571. var col2 = parse_vector_input(node.inputs[2]);
  572. var but = node.buttons[0]; // blend_type
  573. var blend: String = but.data[but.default_value].toUpperCase();
  574. blend = blend.replace(" ", "_");
  575. var use_clamp = node.buttons[1].default_value == true;
  576. var out_col = "";
  577. if (blend == "MIX") {
  578. out_col = 'mix($col1, $col2, $fac_var)';
  579. }
  580. else if (blend == "DARKEN") {
  581. out_col = 'min($col1, $col2 * $fac_var)';
  582. }
  583. else if (blend == "MULTIPLY") {
  584. out_col = 'mix($col1, $col1 * $col2, $fac_var)';
  585. }
  586. else if (blend == "BURN") {
  587. out_col = 'mix($col1, vec3(1.0, 1.0, 1.0) - (vec3(1.0, 1.0, 1.0) - $col1) / $col2, $fac_var)';
  588. }
  589. else if (blend == "LIGHTEN") {
  590. out_col = 'max($col1, $col2 * $fac_var)';
  591. }
  592. else if (blend == "SCREEN") {
  593. 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))';
  594. }
  595. else if (blend == "DODGE") {
  596. out_col = 'mix($col1, $col1 / (vec3(1.0, 1.0, 1.0) - $col2), $fac_var)';
  597. }
  598. else if (blend == "ADD") {
  599. out_col = 'mix($col1, $col1 + $col2, $fac_var)';
  600. }
  601. else if (blend == "OVERLAY") {
  602. out_col = 'mix($col1, vec3(
  603. $col1.r < 0.5 ? 2.0 * $col1.r * $col2.r : 1.0 - 2.0 * (1.0 - $col1.r) * (1.0 - $col2.r),
  604. $col1.g < 0.5 ? 2.0 * $col1.g * $col2.g : 1.0 - 2.0 * (1.0 - $col1.g) * (1.0 - $col2.g),
  605. $col1.b < 0.5 ? 2.0 * $col1.b * $col2.b : 1.0 - 2.0 * (1.0 - $col1.b) * (1.0 - $col2.b)
  606. ), $fac_var)';
  607. }
  608. else if (blend == "SOFT_LIGHT") {
  609. 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))))';
  610. }
  611. else if (blend == "LINEAR_LIGHT") {
  612. out_col = '($col1 + $fac_var * (vec3(2.0, 2.0, 2.0) * ($col2 - vec3(0.5, 0.5, 0.5))))';
  613. }
  614. else if (blend == "DIFFERENCE") {
  615. out_col = 'mix($col1, abs($col1 - $col2), $fac_var)';
  616. }
  617. else if (blend == "SUBTRACT") {
  618. out_col = 'mix($col1, $col1 - $col2, $fac_var)';
  619. }
  620. else if (blend == "DIVIDE") {
  621. var eps = 0.000001;
  622. col2 = 'max($col2, vec3($eps, $eps, $eps))';
  623. out_col = "(" + to_vec3('(1.0 - $fac_var) * $col1 + $fac_var * $col1 / $col2') + ")";
  624. }
  625. else if (blend == "HUE") {
  626. curshader.add_function(ShaderFunctions.str_hue_sat);
  627. 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)';
  628. }
  629. else if (blend == "SATURATION") {
  630. curshader.add_function(ShaderFunctions.str_hue_sat);
  631. 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)';
  632. }
  633. else if (blend == "COLOR") {
  634. curshader.add_function(ShaderFunctions.str_hue_sat);
  635. 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)';
  636. }
  637. else if (blend == "VALUE") {
  638. curshader.add_function(ShaderFunctions.str_hue_sat);
  639. 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)';
  640. }
  641. if (use_clamp) return 'clamp($out_col, vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0))';
  642. else return out_col;
  643. }
  644. else if (node.type == "QUANTIZE") {
  645. var strength = parse_value_input(node.inputs[0]);
  646. var col = parse_vector_input(node.inputs[1]);
  647. return '(floor(100.0 * $strength * $col) / (100.0 * $strength))';
  648. }
  649. else if (node.type == "VALTORGB") { // ColorRamp
  650. var fac = parse_value_input(node.inputs[0]);
  651. var interp = node.buttons[0].data == 0 ? "LINEAR" : "CONSTANT";
  652. var elems: Array<Array<Float>> = node.buttons[0].default_value;
  653. if (elems.length == 1) {
  654. return vec3(elems[0]);
  655. }
  656. // Write cols array
  657. var cols_var = node_name(node) + "_cols";
  658. curshader.write('vec3 $cols_var[${elems.length}];'); // TODO: Make const
  659. for (i in 0...elems.length) {
  660. curshader.write('$cols_var[$i] = ${vec3(elems[i])};');
  661. }
  662. // Get index
  663. var fac_var = node_name(node) + "_fac";
  664. curshader.write('float $fac_var = $fac;');
  665. var index = "0";
  666. for (i in 1...elems.length) {
  667. index += ' + ($fac_var > ${elems[i][4]} ? 1 : 0)';
  668. }
  669. // Write index
  670. var index_var = node_name(node) + "_i";
  671. curshader.write('int $index_var = $index;');
  672. if (interp == "CONSTANT") {
  673. return '$cols_var[$index_var]';
  674. }
  675. else { // Linear
  676. // Write facs array
  677. var facs_var = node_name(node) + "_facs";
  678. curshader.write('float $facs_var[${elems.length}];'); // TODO: Make const
  679. for (i in 0...elems.length) {
  680. curshader.write('$facs_var[$i] = ${elems[i][4]};');
  681. }
  682. // Mix color
  683. // float f = (pos - start) * (1.0 / (finish - start))
  684. 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]) ))';
  685. }
  686. }
  687. else if (node.type == "CURVE_VEC") {
  688. var fac = parse_value_input(node.inputs[0]);
  689. var vec = parse_vector_input(node.inputs[1]);
  690. var curves = node.buttons[0].default_value;
  691. var name = node_name(node);
  692. var vc0 = vector_curve(name + "0", vec + ".x", curves[0]);
  693. var vc1 = vector_curve(name + "1", vec + ".y", curves[1]);
  694. var vc2 = vector_curve(name + "2", vec + ".z", curves[2]);
  695. // mapping.curves[0].points[0].handle_type # bezier curve
  696. return '(vec3($vc0, $vc1, $vc2) * $fac)';
  697. }
  698. else if (node.type == "CURVE_RGB") { // RGB Curves
  699. var fac = parse_value_input(node.inputs[0]);
  700. var vec = parse_vector_input(node.inputs[1]);
  701. var curves = node.buttons[0].default_value;
  702. var name = node_name(node);
  703. // mapping.curves[0].points[0].handle_type
  704. var vc0 = vector_curve(name + "0", vec + ".x", curves[0]);
  705. var vc1 = vector_curve(name + "1", vec + ".y", curves[1]);
  706. var vc2 = vector_curve(name + "2", vec + ".z", curves[2]);
  707. var vc3a = vector_curve(name + "3a", vec + ".x", curves[3]);
  708. var vc3b = vector_curve(name + "3b", vec + ".y", curves[3]);
  709. var vc3c = vector_curve(name + "3c", vec + ".z", curves[3]);
  710. return '(sqrt(vec3($vc0, $vc1, $vc2) * vec3($vc3a, $vc3b, $vc3c)) * $fac)';
  711. }
  712. else if (node.type == "COMBHSV") {
  713. curshader.add_function(ShaderFunctions.str_hue_sat);
  714. var h = parse_value_input(node.inputs[0]);
  715. var s = parse_value_input(node.inputs[1]);
  716. var v = parse_value_input(node.inputs[2]);
  717. return 'hsv_to_rgb(vec3($h, $s, $v))';
  718. }
  719. else if (node.type == "COMBRGB") {
  720. var r = parse_value_input(node.inputs[0]);
  721. var g = parse_value_input(node.inputs[1]);
  722. var b = parse_value_input(node.inputs[2]);
  723. return 'vec3($r, $g, $b)';
  724. }
  725. else if (node.type == "WAVELENGTH") {
  726. curshader.add_function(ShaderFunctions.str_wavelength_to_rgb);
  727. var wl = parse_value_input(node.inputs[0]);
  728. curshader.add_function(ShaderFunctions.str_wavelength_to_rgb);
  729. return 'wavelength_to_rgb(($wl - 450.0) / 150.0)';
  730. }
  731. else if (node.type == "CAMERA") {
  732. curshader.vVecCam = true;
  733. return "vVecCam";
  734. }
  735. else if (node.type == "LAYER") {
  736. var l = node.buttons[0].default_value;
  737. if (socket == node.outputs[0]) { // Base
  738. curshader.add_uniform("sampler2D texpaint" + l, "_texpaint" + l);
  739. return "texture(texpaint" + l + ", texCoord).rgb";
  740. }
  741. else if (socket == node.outputs[5]) { // Normal
  742. curshader.add_uniform("sampler2D texpaint_nor" + l, "_texpaint_nor" + l);
  743. return "texture(texpaint_nor" + l + ", texCoord).rgb";
  744. }
  745. }
  746. else if (node.type == "MATERIAL") {
  747. var result = "vec3(0.0, 0.0, 0.0)";
  748. var mi = node.buttons[0].default_value;
  749. if (mi >= Project.materials.length) return result;
  750. var m = Project.materials[mi];
  751. var _nodes = nodes;
  752. var _links = links;
  753. nodes = m.canvas.nodes;
  754. links = m.canvas.links;
  755. parents.push(node);
  756. var output_node = node_by_type(nodes, "OUTPUT_MATERIAL_PBR");
  757. if (socket == node.outputs[0]) { // Base
  758. result = parse_vector_input(output_node.inputs[0]);
  759. }
  760. else if (socket == node.outputs[5]) { // Normal
  761. result = parse_vector_input(output_node.inputs[5]);
  762. }
  763. nodes = _nodes;
  764. links = _links;
  765. parents.pop();
  766. return result;
  767. }
  768. else if (node.type == "PICKER") {
  769. if (socket == node.outputs[0]) { // Base
  770. curshader.add_uniform("vec3 pickerBase", "_pickerBase");
  771. return "pickerBase";
  772. }
  773. else if (socket == node.outputs[5]) { // Normal
  774. curshader.add_uniform("vec3 pickerNormal", "_pickerNormal");
  775. return "pickerNormal";
  776. }
  777. }
  778. else if (node.type == "NEW_GEOMETRY") {
  779. if (socket == node.outputs[0]) { // Position
  780. curshader.wposition = true;
  781. return "wposition";
  782. }
  783. else if (socket == node.outputs[1]) { // Normal
  784. curshader.n = true;
  785. return "n";
  786. }
  787. else if (socket == node.outputs[2]) { // Tangent
  788. curshader.wtangent = true;
  789. return "wtangent";
  790. }
  791. else if (socket == node.outputs[3]) { // True Normal
  792. curshader.n = true;
  793. return "n";
  794. }
  795. else if (socket == node.outputs[4]) { // Incoming
  796. curshader.vVec = true;
  797. return "vVec";
  798. }
  799. else if (socket == node.outputs[5]) { // Parametric
  800. curshader.mposition = true;
  801. return "mposition";
  802. }
  803. }
  804. else if (node.type == "OBJECT_INFO") {
  805. if (socket == node.outputs[0]) { // Location
  806. curshader.wposition = true;
  807. return "wposition";
  808. }
  809. else if (socket == node.outputs[1]) { // Color
  810. return "vec3(0.0, 0.0, 0.0)";
  811. }
  812. }
  813. // else if (node.type == "PARTICLE_INFO") {
  814. // if (socket == node.outputs[3]) { // Location
  815. // return "vec3(0.0, 0.0, 0.0)";
  816. // }
  817. // else if (socket == node.outputs[5]) { // Velocity
  818. // return "vec3(0.0, 0.0, 0.0)";
  819. // }
  820. // else if (socket == node.outputs[6]) { // Angular Velocity
  821. // return "vec3(0.0, 0.0, 0.0)";
  822. // }
  823. // }
  824. else if (node.type == "TANGENT") {
  825. curshader.wtangent = true;
  826. return "wtangent";
  827. }
  828. else if (node.type == "TEX_COORD") {
  829. if (socket == node.outputs[0]) { // Generated - bounds
  830. curshader.bposition = true;
  831. return "bposition";
  832. }
  833. else if (socket == node.outputs[1]) { // Normal
  834. curshader.n = true;
  835. return "n";
  836. }
  837. else if (socket == node.outputs[2]) {// UV
  838. curshader.context.add_elem("tex", "short2norm");
  839. return "vec3(texCoord.x, texCoord.y, 0.0)";
  840. }
  841. else if (socket == node.outputs[3]) { // Object
  842. curshader.mposition = true;
  843. return "mposition";
  844. }
  845. else if (socket == node.outputs[4]) { // Camera
  846. curshader.vposition = true;
  847. return "vposition";
  848. }
  849. else if (socket == node.outputs[5]) { // Window
  850. curshader.wvpposition = true;
  851. return "wvpposition.xyz";
  852. }
  853. else if (socket == node.outputs[6]) { // Reflection
  854. return "vec3(0.0, 0.0, 0.0)";
  855. }
  856. }
  857. else if (node.type == "UVMAP") {
  858. curshader.context.add_elem("tex", "short2norm");
  859. return "vec3(texCoord.x, texCoord.y, 0.0)";
  860. }
  861. else if (node.type == "BUMP") {
  862. var strength = parse_value_input(node.inputs[0]);
  863. // var distance = parse_value_input(node.inputs[1]);
  864. var height = parse_value_input(node.inputs[2]);
  865. var nor = parse_vector_input(node.inputs[3]);
  866. var sample_bump_res = store_var_name(node) + "_bump";
  867. curshader.write('float ${sample_bump_res}_x = dFdx(float($height)) * ($strength) * 16.0;');
  868. curshader.write('float ${sample_bump_res}_y = dFdy(float($height)) * ($strength) * 16.0;');
  869. return '(normalize(vec3(${sample_bump_res}_x, ${sample_bump_res}_y, 1.0) + $nor) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5))';
  870. }
  871. else if (node.type == "MAPPING") {
  872. var out = parse_vector_input(node.inputs[0]);
  873. var node_translation = parse_vector_input(node.inputs[1]);
  874. var node_rotation = parse_vector_input(node.inputs[2]);
  875. var node_scale = parse_vector_input(node.inputs[3]);
  876. if (node_scale != 'vec3(1, 1, 1)') {
  877. out = '($out * $node_scale)';
  878. }
  879. if (node_rotation != 'vec3(0, 0, 0)') {
  880. // ZYX rotation, Z axis for now..
  881. var a = '${node_rotation}.z * (3.1415926535 / 180)';
  882. // x * cos(theta) - y * sin(theta)
  883. // x * sin(theta) + y * cos(theta)
  884. out = 'vec3(${out}.x * cos($a) - ${out}.y * sin($a), ${out}.x * sin($a) + ${out}.y * cos($a), 0.0)';
  885. }
  886. // if node.rotation[1] != 0.0:
  887. // a = node.rotation[1]
  888. // out = 'vec3({0}.x * {1} - {0}.z * {2}, {0}.x * {2} + {0}.z * {1}, 0.0)'.format(out, math.cos(a), math.sin(a))
  889. // if node.rotation[0] != 0.0:
  890. // a = node.rotation[0]
  891. // out = 'vec3({0}.y * {1} - {0}.z * {2}, {0}.y * {2} + {0}.z * {1}, 0.0)'.format(out, math.cos(a), math.sin(a))
  892. if (node_translation != 'vec3(0, 0, 0)') {
  893. out = '($out + $node_translation)';
  894. }
  895. // if node.use_min:
  896. // out = 'max({0}, vec3({1}, {2}, {3}))'.format(out, node.min[0], node.min[1])
  897. // if node.use_max:
  898. // out = 'min({0}, vec3({1}, {2}, {3}))'.format(out, node.max[0], node.max[1])
  899. return out;
  900. }
  901. else if (node.type == "NORMAL") {
  902. if (socket == node.outputs[0]) {
  903. return vec3(node.outputs[0].default_value);
  904. }
  905. else if (socket == node.outputs[1]) {
  906. var nor = parse_vector_input(node.inputs[0]);
  907. var norout = vec3(node.outputs[0].default_value);
  908. return to_vec3('dot($norout, $nor)');
  909. }
  910. }
  911. else if (node.type == "NORMAL_MAP") {
  912. var strength = parse_value_input(node.inputs[0]);
  913. var norm = parse_vector_input(node.inputs[1]);
  914. var store = store_var_name(node);
  915. curshader.write('vec3 ${store}_texn = $norm * 2.0 - 1.0;');
  916. curshader.write('${store}_texn.xy = $strength * ${store}_texn.xy;');
  917. curshader.write('${store}_texn = normalize(${store}_texn);');
  918. return '(0.5 * ${store}_texn + 0.5)';
  919. }
  920. else if (node.type == "MIX_NORMAL_MAP") {
  921. var nm1 = parse_vector_input(node.inputs[0]);
  922. var nm2 = parse_vector_input(node.inputs[1]);
  923. var but = node.buttons[0];
  924. var blend: String = but.data[but.default_value].toUpperCase(); // blend_type
  925. blend = blend.replace(" ", "_");
  926. var store = store_var_name(node);
  927. // The blending algorithms are based on the paper 'Blending in Detail' by Colin Barré-Brisebois and Stephen Hill 2012
  928. // https://blog.selfshadow.com/publications/blending-in-detail/
  929. if (blend == "PARTIAL_DERIVATIVE") { //partial derivate blending
  930. curshader.write('vec3 ${store}_n1 = $nm1 * 2.0 - 1.0;');
  931. curshader.write('vec3 ${store}_n2 = $nm2 * 2.0 - 1.0;');
  932. return '0.5 * normalize(vec3(${store}_n1.xy * ${store}_n2.z + ${store}_n2.xy * ${store}_n1.z, ${store}_n1.z * ${store}_n2.z)) + 0.5;';
  933. }
  934. else if (blend == "WHITEOUT") { //whiteout blending
  935. curshader.write('vec3 ${store}_n1 = $nm1 * 2.0 - 1.0;');
  936. curshader.write('vec3 ${store}_n2 = $nm2 * 2.0 - 1.0;');
  937. return '0.5 * normalize(vec3(${store}_n1.xy + ${store}_n2.xy, ${store}_n1.z * ${store}_n2.z)) + 0.5;';
  938. }
  939. else if (blend == "REORIENTED") { //reoriented normal mapping
  940. curshader.write('vec3 ${store}_n1 = $nm1 * 2.0 - vec3(1.0, 1.0, 0.0);');
  941. curshader.write('vec3 ${store}_n2 = $nm2 * vec3(-2.0, -2.0, 2.0) - vec3(-1.0, -1.0, 1.0);');
  942. return '0.5 * normalize(${store}_n1 * dot(${store}_n1, ${store}_n2) - ${store}_n2 * ${store}_n1.z) + 0.5';
  943. }
  944. }
  945. else if (node.type == "VECT_TRANSFORM") {
  946. // #type = node.vector_type
  947. // #conv_from = node.convert_from
  948. // #conv_to = node.convert_to
  949. // # Pass throuh
  950. // return parse_vector_input(node.inputs[0])
  951. }
  952. else if (node.type == "COMBXYZ") {
  953. var x = parse_value_input(node.inputs[0]);
  954. var y = parse_value_input(node.inputs[1]);
  955. var z = parse_value_input(node.inputs[2]);
  956. return 'vec3($x, $y, $z)';
  957. }
  958. else if (node.type == "VECT_MATH") {
  959. var vec1 = parse_vector_input(node.inputs[0]);
  960. var vec2 = parse_vector_input(node.inputs[1]);
  961. var but = node.buttons[0]; //operation;
  962. var op: String = but.data[but.default_value].toUpperCase();
  963. op = op.replace(" ", "_");
  964. if (op == "ADD") {
  965. return '($vec1 + $vec2)';
  966. }
  967. else if (op == "SUBTRACT") {
  968. return '($vec1 - $vec2)';
  969. }
  970. else if (op == "AVERAGE") {
  971. return '(($vec1 + $vec2) / 2.0)';
  972. }
  973. else if (op == "DOT_PRODUCT") {
  974. return to_vec3('dot($vec1, $vec2)');
  975. }
  976. else if (op == "LENGTH") {
  977. return to_vec3('length($vec1)');
  978. }
  979. else if (op == "DISTANCE") {
  980. return to_vec3('distance($vec1, $vec2)');
  981. }
  982. else if (op == "CROSS_PRODUCT") {
  983. return 'cross($vec1, $vec2)';
  984. }
  985. else if (op == "NORMALIZE") {
  986. return 'normalize($vec1)';
  987. }
  988. else if (op == "MULTIPLY") {
  989. return '($vec1 * $vec2)';
  990. }
  991. else if (op == "DIVIDE") {
  992. return 'vec3(${vec1}.x / (${vec2}.x == 0 ? 0.000001 : ${vec2}.x), ${vec1}.y / (${vec2}.y == 0 ? 0.000001 : ${vec2}.y), ${vec1}.z / (${vec2}.z == 0 ? 0.000001 : ${vec2}.z))';
  993. }
  994. else if (op == "PROJECT") {
  995. return '(dot($vec1, $vec2) / dot($vec2, $vec2) * $vec2)';
  996. }
  997. else if (op == "REFLECT") {
  998. return 'reflect($vec1, normalize($vec2))';
  999. }
  1000. else if (op == "SCALE") {
  1001. return '(${vec2}.x * $vec1)';
  1002. }
  1003. else if (op == "ABSOLUTE") {
  1004. return 'abs($vec1)';
  1005. }
  1006. else if (op == "MINIMUM") {
  1007. return 'min($vec1, $vec2)';
  1008. }
  1009. else if (op == "MAXIMUM") {
  1010. return 'max($vec1, $vec2)';
  1011. }
  1012. else if (op == "FLOOR") {
  1013. return 'floor($vec1)';
  1014. }
  1015. else if (op == "CEIL") {
  1016. return 'ceil($vec1)';
  1017. }
  1018. else if (op == "FRACTION") {
  1019. return 'fract($vec1)';
  1020. }
  1021. else if (op == "MODULO") {
  1022. return 'mod($vec1, $vec2)';
  1023. }
  1024. else if(op == "SNAP") {
  1025. return '(floor($vec1 / $vec2) * $vec2)';
  1026. }
  1027. else if (op == "SINE") {
  1028. return 'sin($vec1)';
  1029. }
  1030. else if (op == "COSINE") {
  1031. return 'cos($vec1)';
  1032. }
  1033. else if (op == "TANGENT") {
  1034. return 'tan($vec1)';
  1035. }
  1036. }
  1037. else if (node.type == "Displacement") {
  1038. var height = parse_value_input(node.inputs[0]);
  1039. return to_vec3('$height');
  1040. }
  1041. else if (customNodes.get(node.type) != null) {
  1042. return customNodes.get(node.type)(node, socket);
  1043. }
  1044. return "vec3(0.0, 0.0, 0.0)";
  1045. }
  1046. static function parse_normal_map_color_input(inp: TNodeSocket) {
  1047. frag.write_normal++;
  1048. out_normaltan = parse_vector_input(inp);
  1049. if (!arm_export_tangents) {
  1050. frag.write('vec3 texn = ($out_normaltan) * 2.0 - 1.0;');
  1051. frag.write('texn.y = -texn.y;');
  1052. if (!cotangentFrameWritten) {
  1053. cotangentFrameWritten = true;
  1054. frag.add_function(ShaderFunctions.str_cotangentFrame);
  1055. }
  1056. frag.n = true;
  1057. #if (kha_direct3d11 || kha_direct3d12 || kha_metal || kha_vulkan)
  1058. frag.write('mat3 TBN = cotangentFrame(n, vVec, texCoord);');
  1059. #else
  1060. frag.write('mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
  1061. #end
  1062. frag.write('n = mul(normalize(texn), TBN);');
  1063. }
  1064. frag.write_normal--;
  1065. }
  1066. static function parse_value_input(inp: TNodeSocket, vector_as_grayscale = false) : String {
  1067. var l = getInputLink(inp);
  1068. var from_node = l != null ? getNode(l.from_id) : null;
  1069. if (from_node != null) {
  1070. if (from_node.type == "REROUTE") {
  1071. return parse_value_input(from_node.inputs[0]);
  1072. }
  1073. var res_var = write_result(l);
  1074. var st = from_node.outputs[l.from_socket].type;
  1075. if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
  1076. if (vector_as_grayscale) {
  1077. return 'dot($res_var.rbg, vec3(0.299, 0.587, 0.114))';
  1078. }
  1079. else {
  1080. return '$res_var.x';
  1081. }
  1082. }
  1083. else { // VALUE
  1084. return res_var;
  1085. }
  1086. }
  1087. else {
  1088. return vec1(inp.default_value);
  1089. }
  1090. }
  1091. static function parse_value(node: TNode, socket: TNodeSocket): String {
  1092. if (node.type == 'GROUP') {
  1093. return parse_group(node, socket);
  1094. }
  1095. else if (node.type == 'GROUP_INPUT') {
  1096. return parse_group_input(node, socket);
  1097. }
  1098. else if (node.type == "ATTRIBUTE") {
  1099. curshader.add_uniform("float time", "_time");
  1100. return "time";
  1101. }
  1102. else if (node.type == "VERTEX_COLOR") {
  1103. return "1.0";
  1104. }
  1105. else if (node.type == "WIREFRAME") {
  1106. curshader.add_uniform('sampler2D texuvmap', '_texuvmap');
  1107. var use_pixel_size = node.buttons[0].default_value == "true";
  1108. var pixel_size = parse_value_input(node.inputs[0]);
  1109. return "textureLod(texuvmap, texCoord, 0.0).r";
  1110. }
  1111. else if (node.type == "CAMERA") {
  1112. if (socket == node.outputs[1]) { // View Z Depth
  1113. curshader.add_uniform("vec2 cameraProj", "_cameraPlaneProj");
  1114. #if (kha_direct3d11 || kha_direct3d12 || kha_metal || kha_vulkan)
  1115. curshader.wvpposition = true;
  1116. return "(cameraProj.y / ((wvpposition.z / wvpposition.w) - cameraProj.x))";
  1117. #else
  1118. return "(cameraProj.y / (gl_FragCoord.z - cameraProj.x))";
  1119. #end
  1120. }
  1121. else { // View Distance
  1122. curshader.add_uniform("vec3 eye", "_cameraPosition");
  1123. curshader.wposition = true;
  1124. return "distance(eye, wposition)";
  1125. }
  1126. }
  1127. else if (node.type == "LAYER") {
  1128. var l = node.buttons[0].default_value;
  1129. if (socket == node.outputs[1]) { // Opac
  1130. curshader.add_uniform("sampler2D texpaint" + l, "_texpaint" + l);
  1131. return "texture(texpaint" + l + ", texCoord).a";
  1132. }
  1133. else if (socket == node.outputs[2]) { // Occ
  1134. curshader.add_uniform("sampler2D texpaint_pack" + l, "_texpaint_pack" + l);
  1135. return "texture(texpaint_pack" + l + ", texCoord).r";
  1136. }
  1137. else if (socket == node.outputs[3]) { // Rough
  1138. curshader.add_uniform("sampler2D texpaint_pack" + l, "_texpaint_pack" + l);
  1139. return "texture(texpaint_pack" + l + ", texCoord).g";
  1140. }
  1141. else if (socket == node.outputs[4]) { // Metal
  1142. curshader.add_uniform("sampler2D texpaint_pack" + l, "_texpaint_pack" + l);
  1143. return "texture(texpaint_pack" + l + ", texCoord).b";
  1144. }
  1145. else if (socket == node.outputs[7]) { // Height
  1146. curshader.add_uniform("sampler2D texpaint_pack" + l, "_texpaint_pack" + l);
  1147. return "texture(texpaint_pack" + l + ", texCoord).a";
  1148. }
  1149. }
  1150. else if (node.type == "LAYER_MASK") {
  1151. if (socket == node.outputs[0]) {
  1152. var l = node.buttons[0].default_value;
  1153. curshader.add_uniform("sampler2D texpaint" + l, "_texpaint" + l);
  1154. return "texture(texpaint" + l + ", texCoord).r";
  1155. }
  1156. }
  1157. else if (node.type == "MATERIAL") {
  1158. var result = "0.0";
  1159. var mi = node.buttons[0].default_value;
  1160. if (mi >= Project.materials.length) return result;
  1161. var m = Project.materials[mi];
  1162. var _nodes = nodes;
  1163. var _links = links;
  1164. nodes = m.canvas.nodes;
  1165. links = m.canvas.links;
  1166. parents.push(node);
  1167. var output_node = node_by_type(nodes, "OUTPUT_MATERIAL_PBR");
  1168. if (socket == node.outputs[1]) { // Opac
  1169. result = parse_value_input(output_node.inputs[1]);
  1170. }
  1171. else if (socket == node.outputs[2]) { // Occ
  1172. result = parse_value_input(output_node.inputs[2]);
  1173. }
  1174. else if (socket == node.outputs[3]) { // Rough
  1175. result = parse_value_input(output_node.inputs[3]);
  1176. }
  1177. else if (socket == node.outputs[4]) { // Metal
  1178. result = parse_value_input(output_node.inputs[4]);
  1179. }
  1180. else if (socket == node.outputs[7]) { // Height
  1181. result = parse_value_input(output_node.inputs[7]);
  1182. }
  1183. nodes = _nodes;
  1184. links = _links;
  1185. parents.pop();
  1186. return result;
  1187. }
  1188. else if (node.type == "PICKER") {
  1189. if (socket == node.outputs[1]) {
  1190. curshader.add_uniform("float pickerOpacity", "_pickerOpacity");
  1191. return "pickerOpacity";
  1192. }
  1193. else if (socket == node.outputs[2]) {
  1194. curshader.add_uniform("float pickerOcclusion", "_pickerOcclusion");
  1195. return "pickerOcclusion";
  1196. }
  1197. else if (socket == node.outputs[3]) {
  1198. curshader.add_uniform("float pickerRoughness", "_pickerRoughness");
  1199. return "pickerRoughness";
  1200. }
  1201. else if (socket == node.outputs[4]) {
  1202. curshader.add_uniform("float pickerMetallic", "_pickerMetallic");
  1203. return "pickerMetallic";
  1204. }
  1205. else if (socket == node.outputs[7]) {
  1206. curshader.add_uniform("float pickerHeight", "_pickerHeight");
  1207. return "pickerHeight";
  1208. }
  1209. }
  1210. else if (node.type == "FRESNEL") {
  1211. var ior = parse_value_input(node.inputs[0]);
  1212. curshader.dotNV = true;
  1213. return 'pow(1.0 - dotNV, 7.25 / $ior)';
  1214. }
  1215. else if (node.type == "NEW_GEOMETRY") {
  1216. if (socket == node.outputs[6]) { // Backfacing
  1217. #if (kha_direct3d11 || kha_direct3d12 || kha_metal || kha_vulkan)
  1218. return "0.0"; // SV_IsFrontFace
  1219. #else
  1220. return "(1.0 - float(gl_FrontFacing))";
  1221. #end
  1222. }
  1223. else if (socket == node.outputs[7]) { // Pointiness
  1224. var strength = 1.0;
  1225. var radius = 1.0;
  1226. var offset = 0.0;
  1227. var store = store_var_name(node);
  1228. curshader.n = true;
  1229. curshader.write('vec3 ${store}_dx = dFdx(n);');
  1230. curshader.write('vec3 ${store}_dy = dFdy(n);');
  1231. curshader.write('float ${store}_curvature = max(dot(${store}_dx, ${store}_dx), dot(${store}_dy, ${store}_dy));');
  1232. curshader.write('${store}_curvature = clamp(pow(${store}_curvature, (1.0 / ' + radius + ') * 0.25) * ' + strength + ' * 2.0 + ' + offset + ' / 10.0, 0.0, 1.0);');
  1233. return '${store}_curvature';
  1234. }
  1235. else if (socket == node.outputs[8]) { // Random Per Island
  1236. return "0.0";
  1237. }
  1238. }
  1239. else if (node.type == "HAIR_INFO") {
  1240. return "0.5";
  1241. }
  1242. else if (node.type == "LAYER_WEIGHT") {
  1243. var blend = parse_value_input(node.inputs[0]);
  1244. if (socket == node.outputs[0]) { // Fresnel
  1245. curshader.dotNV = true;
  1246. return 'clamp(pow(1.0 - dotNV, (1.0 - $blend) * 10.0), 0.0, 1.0)';
  1247. }
  1248. else if (socket == node.outputs[1]) { // Facing
  1249. curshader.dotNV = true;
  1250. return '((1.0 - dotNV) * $blend)';
  1251. }
  1252. }
  1253. else if (node.type == "OBJECT_INFO") {
  1254. if (socket == node.outputs[1]) { // Object Index
  1255. curshader.add_uniform("float objectInfoIndex", "_objectInfoIndex");
  1256. return "objectInfoIndex";
  1257. }
  1258. else if (socket == node.outputs[2]) { // Material Index
  1259. curshader.add_uniform("float objectInfoMaterialIndex", "_objectInfoMaterialIndex");
  1260. return "objectInfoMaterialIndex";
  1261. }
  1262. else if (socket == node.outputs[3]) { // Random
  1263. curshader.add_uniform("float objectInfoRandom", "_objectInfoRandom");
  1264. return "objectInfoRandom";
  1265. }
  1266. }
  1267. else if (node.type == "VALUE") {
  1268. return vec1(node.outputs[0].default_value);
  1269. }
  1270. else if (node.type == "TEX_BRICK") {
  1271. curshader.add_function(ShaderFunctions.str_tex_brick);
  1272. var co = getCoord(node);
  1273. var scale = parse_value_input(node.inputs[4]);
  1274. var res = 'tex_brick_f($co * $scale)';
  1275. return res;
  1276. }
  1277. else if (node.type == "TEX_CHECKER") {
  1278. curshader.add_function(ShaderFunctions.str_tex_checker);
  1279. var co = getCoord(node);
  1280. var scale = parse_value_input(node.inputs[3]);
  1281. var res = 'tex_checker_f($co, $scale)';
  1282. return res;
  1283. }
  1284. else if (node.type == "TEX_GRADIENT") {
  1285. var co = getCoord(node);
  1286. var but = node.buttons[0]; //gradient_type;
  1287. var grad: String = but.data[but.default_value].toUpperCase();
  1288. grad = grad.replace(" ", "_");
  1289. var f = getGradient(grad, co);
  1290. var res = '(clamp($f, 0.0, 1.0))';
  1291. return res;
  1292. }
  1293. else if (node.type == "TEX_IMAGE") {
  1294. // Already fetched
  1295. if (parsed.indexOf(res_var_name(node, node.outputs[0])) >= 0) { // TODO: node.outputs[1]
  1296. var varname = store_var_name(node);
  1297. return '$varname.a';
  1298. }
  1299. var tex_name = node_name(node);
  1300. var tex = make_texture(node, tex_name);
  1301. if (tex != null) {
  1302. var color_space = node.buttons[1].default_value;
  1303. var texstore = texture_store(node, tex, tex_name, color_space);
  1304. return '$texstore.a';
  1305. }
  1306. }
  1307. else if (node.type == "TEX_MAGIC") {
  1308. curshader.add_function(ShaderFunctions.str_tex_magic);
  1309. var co = getCoord(node);
  1310. var scale = parse_value_input(node.inputs[1]);
  1311. var res = 'tex_magic_f($co * $scale * 4.0)';
  1312. return res;
  1313. }
  1314. else if (node.type == "TEX_MUSGRAVE") {
  1315. curshader.add_function(ShaderFunctions.str_tex_musgrave);
  1316. var co = getCoord(node);
  1317. var scale = parse_value_input(node.inputs[1]);
  1318. var res = 'tex_musgrave_f($co * $scale * 0.5)';
  1319. return res;
  1320. }
  1321. else if (node.type == "TEX_NOISE") {
  1322. curshader.add_function(ShaderFunctions.str_tex_noise);
  1323. var co = getCoord(node);
  1324. var scale = parse_value_input(node.inputs[1]);
  1325. var res = 'tex_noise($co * $scale)';
  1326. return res;
  1327. }
  1328. else if (node.type == "TEX_VORONOI") {
  1329. curshader.add_function(ShaderFunctions.str_tex_voronoi);
  1330. curshader.add_uniform("sampler2D snoise256", "$noise256.k");
  1331. var co = getCoord(node);
  1332. var scale = parse_value_input(node.inputs[1]);
  1333. var but = node.buttons[0]; // coloring
  1334. var coloring: String = but.data[but.default_value].toUpperCase();
  1335. coloring = coloring.replace(" ", "_");
  1336. var res = "";
  1337. if (coloring == "INTENSITY") {
  1338. res = 'tex_voronoi($co * $scale, texturePass(snoise256)).a';
  1339. }
  1340. else { // Cells
  1341. res = 'tex_voronoi($co * $scale, texturePass(snoise256)).r';
  1342. }
  1343. return res;
  1344. }
  1345. else if (node.type == "TEX_WAVE") {
  1346. curshader.add_function(ShaderFunctions.str_tex_wave);
  1347. var co = getCoord(node);
  1348. var scale = parse_value_input(node.inputs[1]);
  1349. var res = 'tex_wave_f($co * $scale)';
  1350. return res;
  1351. }
  1352. else if (node.type == "BAKE_CURVATURE") {
  1353. if (bake_passthrough) {
  1354. bake_passthrough_strength = parse_value_input(node.inputs[0]);
  1355. bake_passthrough_radius = parse_value_input(node.inputs[1]);
  1356. bake_passthrough_offset = parse_value_input(node.inputs[2]);
  1357. return "0.0";
  1358. }
  1359. var tex_name = "texbake_" + node_name(node);
  1360. curshader.add_uniform("sampler2D " + tex_name, "_" + tex_name);
  1361. var store = store_var_name(node);
  1362. curshader.write('float ${store}_res = texture($tex_name, texCoord).r;');
  1363. return '${store}_res';
  1364. }
  1365. else if (node.type == "NORMAL") {
  1366. var nor = parse_vector_input(node.inputs[0]);
  1367. var norout = vec3(node.outputs[0].default_value);
  1368. return 'dot($norout, $nor)';
  1369. }
  1370. else if (node.type == "COLMASK") {
  1371. var inputColor = parse_vector_input(node.inputs[0]);
  1372. var maskColor = parse_vector_input(node.inputs[1]);
  1373. var radius = parse_value_input(node.inputs[2]);
  1374. var fuzziness = parse_value_input(node.inputs[3]);
  1375. return 'clamp(1.0 - (distance($inputColor, $maskColor) - $radius) / max($fuzziness, $eps), 0.0, 1.0)';
  1376. }
  1377. else if (node.type == "MATH") {
  1378. var val1 = parse_value_input(node.inputs[0]);
  1379. var val2 = parse_value_input(node.inputs[1]);
  1380. var but = node.buttons[0]; // operation
  1381. var op: String = but.data[but.default_value].toUpperCase();
  1382. op = op.replace(" ", "_");
  1383. var use_clamp = node.buttons[1].default_value == true;
  1384. var out_val = "";
  1385. if (op == "ADD") {
  1386. out_val = '($val1 + $val2)';
  1387. }
  1388. else if (op == "SUBTRACT") {
  1389. out_val = '($val1 - $val2)';
  1390. }
  1391. else if (op == "MULTIPLY") {
  1392. out_val = '($val1 * $val2)';
  1393. }
  1394. else if (op == "DIVIDE") {
  1395. val2 = '($val2 == 0.0 ? $eps : $val2)';
  1396. out_val = '($val1 / $val2)';
  1397. }
  1398. else if (op == "POWER") {
  1399. out_val = 'pow($val1, $val2)';
  1400. }
  1401. else if (op == "LOGARITHM") {
  1402. out_val = 'log($val1)';
  1403. }
  1404. else if (op == "SQUARE_ROOT") {
  1405. out_val = 'sqrt($val1)';
  1406. }
  1407. else if(op == "INVERSE_SQUARE_ROOT") {
  1408. out_val = 'inversesqrt($val1)';
  1409. }
  1410. else if (op == "EXPONENT") {
  1411. out_val = 'exp($val1)';
  1412. }
  1413. else if (op == "ABSOLUTE") {
  1414. out_val = 'abs($val1)';
  1415. }
  1416. else if (op == "MINIMUM") {
  1417. out_val = 'min($val1, $val2)';
  1418. }
  1419. else if (op == "MAXIMUM") {
  1420. out_val = 'max($val1, $val2)';
  1421. }
  1422. else if (op == "LESS_THAN") {
  1423. out_val = 'float($val1 < $val2)';
  1424. }
  1425. else if (op == "GREATER_THAN") {
  1426. out_val = 'float($val1 > $val2)';
  1427. }
  1428. else if (op == "SIGN") {
  1429. out_val = 'sign($val1)';
  1430. }
  1431. else if (op == "ROUND") {
  1432. out_val = 'floor($val1 + 0.5)';
  1433. }
  1434. else if (op == "FLOOR") {
  1435. out_val = 'floor($val1)';
  1436. }
  1437. else if (op == "CEIL") {
  1438. out_val = 'ceil($val1)';
  1439. }
  1440. else if(op == "SNAP") {
  1441. out_val = '(floor($val1 / $val2) * $val2)';
  1442. }
  1443. else if (op == "TRUNCATE") {
  1444. out_val = 'trunc($val1)';
  1445. }
  1446. else if (op == "FRACTION") {
  1447. out_val = 'fract($val1)';
  1448. }
  1449. else if (op == "MODULO") {
  1450. out_val = 'mod($val1, $val2)';
  1451. }
  1452. else if (op == "PING-PONG") {
  1453. out_val = '(($val2 != 0.0) ? abs(fract(($val1 - $val2) / ($val2 * 2.0)) * $val2 * 2.0 - $val2) : 0.0)';
  1454. }
  1455. else if (op == "SINE") {
  1456. out_val = 'sin($val1)';
  1457. }
  1458. else if (op == "COSINE") {
  1459. out_val = 'cos($val1)';
  1460. }
  1461. else if (op == "TANGENT") {
  1462. out_val = 'tan($val1)';
  1463. }
  1464. else if (op == "ARCSINE") {
  1465. out_val = 'asin($val1)';
  1466. }
  1467. else if (op == "ARCCOSINE") {
  1468. out_val = 'acos($val1)';
  1469. }
  1470. else if (op == "ARCTANGENT") {
  1471. out_val = 'atan($val1)';
  1472. }
  1473. else if (op == "ARCTAN2") {
  1474. out_val = 'atan2($val1, $val2)';
  1475. }
  1476. else if (op == "HYPERBOLIC_SINE") {
  1477. out_val = 'sinh($val1)';
  1478. }
  1479. else if (op == "HYPERBOLIC_COSINE") {
  1480. out_val = 'cosh($val1)';
  1481. }
  1482. else if (op == "HYPERBOLIC_TANGENT") {
  1483. out_val = 'tanh($val1)';
  1484. }
  1485. else if (op == "TO_RADIANS") {
  1486. out_val = 'radians($val1)';
  1487. }
  1488. else if (op == "TO_DEGREES") {
  1489. out_val = 'degrees($val1)';
  1490. }
  1491. if (use_clamp) {
  1492. return 'clamp($out_val, 0.0, 1.0)';
  1493. }
  1494. else {
  1495. return out_val;
  1496. }
  1497. }
  1498. else if (node.type == "SCRIPT_CPU") {
  1499. if (script_links == null) script_links = [];
  1500. var script = node.buttons[0].default_value;
  1501. var link = node_name(node);
  1502. script_links.set(link, script);
  1503. curshader.add_uniform("float " + link, "_" + link);
  1504. return link;
  1505. }
  1506. else if (node.type == "SHADER_GPU") {
  1507. var shader = node.buttons[0].default_value;
  1508. return shader == "" ? "0.0" : shader;
  1509. }
  1510. else if (node.type == "RGBTOBW") {
  1511. var col = parse_vector_input(node.inputs[0]);
  1512. return '((($col.r * 0.3 + $col.g * 0.59 + $col.b * 0.11) / 3.0) * 2.5)';
  1513. }
  1514. else if (node.type == "SEPHSV") {
  1515. curshader.add_function(ShaderFunctions.str_hue_sat);
  1516. var col = parse_vector_input(node.inputs[0]);
  1517. if (socket == node.outputs[0]) {
  1518. return 'rgb_to_hsv($col).r';
  1519. }
  1520. else if (socket == node.outputs[1]) {
  1521. return 'rgb_to_hsv($col).g';
  1522. }
  1523. else if (socket == node.outputs[2]) {
  1524. return 'rgb_to_hsv($col).b';
  1525. }
  1526. }
  1527. else if (node.type == "SEPRGB") {
  1528. var col = parse_vector_input(node.inputs[0]);
  1529. if (socket == node.outputs[0]) {
  1530. return '$col.r';
  1531. }
  1532. else if (socket == node.outputs[1]) {
  1533. return '$col.g';
  1534. }
  1535. else if (socket == node.outputs[2]) {
  1536. return '$col.b';
  1537. }
  1538. }
  1539. else if (node.type == "SEPXYZ") {
  1540. var vec = parse_vector_input(node.inputs[0]);
  1541. if (socket == node.outputs[0]) {
  1542. return '$vec.x';
  1543. }
  1544. else if (socket == node.outputs[1]) {
  1545. return '$vec.y';
  1546. }
  1547. else if (socket == node.outputs[2]) {
  1548. return '$vec.z';
  1549. }
  1550. }
  1551. else if (node.type == "VECT_MATH") {
  1552. var vec1 = parse_vector_input(node.inputs[0]);
  1553. var vec2 = parse_vector_input(node.inputs[1]);
  1554. var but = node.buttons[0]; //operation;
  1555. var op: String = but.data[but.default_value].toUpperCase();
  1556. op = op.replace(" ", "_");
  1557. if (op == "DOT_PRODUCT") {
  1558. return 'dot($vec1, $vec2)';
  1559. }
  1560. else if (op == "LENGTH") {
  1561. return 'length($vec1)';
  1562. }
  1563. else if (op == "DISTANCE") {
  1564. return 'distance($vec1, $vec2)';
  1565. }
  1566. else {
  1567. return "0.0";
  1568. }
  1569. }
  1570. else if (node.type == "CLAMP") {
  1571. var val = parse_value_input(node.inputs[0]);
  1572. var min = parse_value_input(node.inputs[1]);
  1573. var max = parse_value_input(node.inputs[2]);
  1574. var but = node.buttons[0]; //operation;
  1575. var op: String = but.data[but.default_value].toUpperCase();
  1576. op = op.replace(" ", "_");
  1577. if (op == "MIN_MAX") {
  1578. return '(clamp($val, $min, $max))';
  1579. }
  1580. else if (op == "RANGE") {
  1581. return '(clamp($val, min($min, $max), max($min, $max)))';
  1582. }
  1583. }
  1584. else if (node.type == "MAPRANGE") {
  1585. var val = parse_value_input(node.inputs[0]);
  1586. var fmin = parse_value_input(node.inputs[1]);
  1587. var fmax = parse_value_input(node.inputs[2]);
  1588. var tmin = parse_value_input(node.inputs[3]);
  1589. var tmax = parse_value_input(node.inputs[4]);
  1590. var use_clamp = node.buttons[0].default_value == true;
  1591. var a = '(($tmin - $tmax) / ($fmin - $fmax))';
  1592. var out_val = '($a * $val + $tmin - $a * $fmin)';
  1593. if (use_clamp) {
  1594. return '(clamp($out_val, $tmin, $tmax))';
  1595. }
  1596. else {
  1597. return out_val;
  1598. }
  1599. }
  1600. else if (customNodes.get(node.type) != null) {
  1601. return customNodes.get(node.type)(node, socket);
  1602. }
  1603. return "0.0";
  1604. }
  1605. static function getCoord(node: TNode): String {
  1606. if (getInputLink(node.inputs[0]) != null) {
  1607. return parse_vector_input(node.inputs[0]);
  1608. }
  1609. else {
  1610. curshader.bposition = true;
  1611. return "bposition";
  1612. }
  1613. }
  1614. static function getGradient(grad: String, co: String): String {
  1615. if (grad == "LINEAR") {
  1616. return '$co.x';
  1617. }
  1618. else if (grad == "QUADRATIC") {
  1619. return "0.0";
  1620. }
  1621. else if (grad == "EASING") {
  1622. return "0.0";
  1623. }
  1624. else if (grad == "DIAGONAL") {
  1625. return '($co.x + $co.y) * 0.5';
  1626. }
  1627. else if (grad == "RADIAL") {
  1628. return 'atan2($co.x, $co.y) / (3.141592 * 2.0) + 0.5';
  1629. }
  1630. else if (grad == "QUADRATIC_SPHERE") {
  1631. return "0.0";
  1632. }
  1633. else { // "SPHERICAL"
  1634. return 'max(1.0 - sqrt($co.x * $co.x + $co.y * $co.y + $co.z * $co.z), 0.0)';
  1635. }
  1636. }
  1637. static function vector_curve(name: String, fac: String, points: Array<kha.arrays.Float32Array>): String {
  1638. // Write Ys array
  1639. var ys_var = name + "_ys";
  1640. var num = points.length;
  1641. curshader.write('float $ys_var[$num];'); // TODO: Make const
  1642. for (i in 0...num) {
  1643. curshader.write('$ys_var[$i] = ${points[i][1]};');
  1644. }
  1645. // Get index
  1646. var fac_var = name + "_fac";
  1647. curshader.write('float $fac_var = $fac;');
  1648. var index = "0";
  1649. for (i in 1...num) {
  1650. index += ' + ($fac_var > ${points[i][0]} ? 1 : 0)';
  1651. }
  1652. // Write index
  1653. var index_var = name + "_i";
  1654. curshader.write('int $index_var = $index;');
  1655. // Linear
  1656. // Write Xs array
  1657. var facs_var = name + "_xs";
  1658. curshader.write('float $facs_var[$num];'); // TODO: Make const
  1659. for (i in 0...num) {
  1660. curshader.write('$facs_var[$i] = ${points[i][0]};');
  1661. }
  1662. // Map vector
  1663. 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])))';
  1664. }
  1665. static function res_var_name(node: TNode, socket: TNodeSocket): String {
  1666. return node_name(node) + "_" + safesrc(socket.name) + "_res";
  1667. }
  1668. static var parsedMap = new Map<String, String>();
  1669. static var textureMap = new Map<String, String>();
  1670. static function write_result(l: TNodeLink): String {
  1671. var from_node = getNode(l.from_id);
  1672. var from_socket = from_node.outputs[l.from_socket];
  1673. var res_var = res_var_name(from_node, from_socket);
  1674. var st = from_socket.type;
  1675. if (parsed.indexOf(res_var) < 0) {
  1676. parsed.push(res_var);
  1677. if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
  1678. var res = parse_vector(from_node, from_socket);
  1679. if (res == null) {
  1680. return null;
  1681. }
  1682. parsedMap.set(res_var, res);
  1683. curshader.write('vec3 $res_var = $res;');
  1684. }
  1685. else if (st == "VALUE") {
  1686. var res = parse_value(from_node, from_socket);
  1687. if (res == null) {
  1688. return null;
  1689. }
  1690. parsedMap.set(res_var, res);
  1691. curshader.write('float $res_var = $res;');
  1692. }
  1693. }
  1694. return res_var;
  1695. }
  1696. static function store_var_name(node: TNode): String {
  1697. return node_name(node) + "_store";
  1698. }
  1699. static function texture_store(node: TNode, tex: TBindTexture, tex_name: String, color_space: Int): String {
  1700. matcon.bind_textures.push(tex);
  1701. curshader.context.add_elem("tex", "short2norm");
  1702. curshader.add_uniform("sampler2D " + tex_name);
  1703. var uv_name = "";
  1704. if (getInputLink(node.inputs[0]) != null) {
  1705. uv_name = parse_vector_input(node.inputs[0]);
  1706. }
  1707. else {
  1708. uv_name = tex_coord;
  1709. }
  1710. var tex_store = store_var_name(node);
  1711. if (sample_keep_aspect) {
  1712. curshader.write('vec2 ${tex_store}_size = textureSize($tex_name, 0);');
  1713. curshader.write('float ${tex_store}_ax = ${tex_store}_size.x / ${tex_store}_size.y;');
  1714. curshader.write('float ${tex_store}_ay = ${tex_store}_size.y / ${tex_store}_size.x;');
  1715. curshader.write('vec2 ${tex_store}_uv = ((${uv_name}.xy / ${sample_uv_scale} - vec2(0.5, 0.5)) * vec2(max(${tex_store}_ay, 1.0), max(${tex_store}_ax, 1.0))) + vec2(0.5, 0.5);');
  1716. curshader.write('if (${tex_store}_uv.x < 0.0 || ${tex_store}_uv.y < 0.0 || ${tex_store}_uv.x > 1.0 || ${tex_store}_uv.y > 1.0) discard;');
  1717. curshader.write('${tex_store}_uv *= ${sample_uv_scale};');
  1718. uv_name = '${tex_store}_uv';
  1719. }
  1720. if (triplanar) {
  1721. curshader.write('vec4 $tex_store = vec4(0.0, 0.0, 0.0, 0.0);');
  1722. curshader.write('if (texCoordBlend.x > 0) $tex_store += texture($tex_name, ${uv_name}.xy) * texCoordBlend.x;');
  1723. curshader.write('if (texCoordBlend.y > 0) $tex_store += texture($tex_name, ${uv_name}1.xy) * texCoordBlend.y;');
  1724. curshader.write('if (texCoordBlend.z > 0) $tex_store += texture($tex_name, ${uv_name}2.xy) * texCoordBlend.z;');
  1725. }
  1726. else {
  1727. if (curshader == frag) {
  1728. textureMap.set(tex_store, 'texture($tex_name, $uv_name.xy)');
  1729. curshader.write('vec4 $tex_store = texture($tex_name, $uv_name.xy);');
  1730. }
  1731. else {
  1732. textureMap.set(tex_store, 'textureLod($tex_name, $uv_name.xy, 0.0)');
  1733. curshader.write('vec4 $tex_store = textureLod($tex_name, $uv_name.xy, 0.0);');
  1734. }
  1735. if (!tex.file.endsWith(".jpg")) { // Pre-mult alpha
  1736. curshader.write('$tex_store.rgb *= $tex_store.a;');
  1737. }
  1738. }
  1739. if (transform_color_space) {
  1740. // Base color socket auto-converts from sRGB to linear
  1741. if (color_space == SpaceLinear && parsing_basecolor) { // Linear to sRGB
  1742. curshader.write('$tex_store.rgb = pow($tex_store.rgb, vec3(2.2, 2.2, 2.2));');
  1743. }
  1744. else if (color_space == SpaceSRGB && !parsing_basecolor) { // sRGB to linear
  1745. curshader.write('$tex_store.rgb = pow($tex_store.rgb, vec3(1.0 / 2.2, 1.0 / 2.2, 1.0 / 2.2));');
  1746. }
  1747. else if (color_space == SpaceDirectXNormalMap) { // DirectX normal map to OpenGL normal map
  1748. curshader.write('$tex_store.y = 1.0 - $tex_store.y;');
  1749. }
  1750. }
  1751. return tex_store;
  1752. }
  1753. public static inline function vec1(v: Float): String {
  1754. #if krom_android
  1755. return 'float($v)';
  1756. #else
  1757. return '$v';
  1758. #end
  1759. }
  1760. public static inline function vec3(v: Array<Float>): String {
  1761. #if krom_android
  1762. return 'vec3(float(${v[0]}), float(${v[1]}), float(${v[2]}))';
  1763. #else
  1764. return 'vec3(${v[0]}, ${v[1]}, ${v[2]})';
  1765. #end
  1766. }
  1767. public static inline function to_vec3(s: String): String {
  1768. #if (kha_direct3d11 || kha_direct3d12)
  1769. return '($s).xxx';
  1770. #else
  1771. return 'vec3($s)';
  1772. #end
  1773. }
  1774. public static function node_by_type(nodes: Array<TNode>, ntype: String): TNode {
  1775. for (n in nodes) if (n.type == ntype) return n;
  1776. return null;
  1777. }
  1778. static function socket_index(node: TNode, socket: TNodeSocket): Int {
  1779. for (i in 0...node.outputs.length) if (node.outputs[i] == socket) return i;
  1780. return -1;
  1781. }
  1782. public static function node_name(node: TNode, _parents: Array<TNode> = null): String {
  1783. if (_parents == null) _parents = parents;
  1784. var s = node.name;
  1785. for (p in _parents) s = p.name + p.id + '_' + s;
  1786. s = safesrc(s) + node.id;
  1787. return s;
  1788. }
  1789. static function safesrc(s: String): String {
  1790. for (i in 0...s.length) {
  1791. var code = s.charCodeAt(i);
  1792. var letter = (code >= 65 && code <= 90) || (code >= 97 && code <= 122);
  1793. var digit = code >= 48 && code <= 57;
  1794. if (!letter && !digit) s = s.replace(s.charAt(i), "_");
  1795. if (i == 0 && digit) s = "_" + s;
  1796. }
  1797. #if kha_opengl
  1798. while (s.indexOf("__") >= 0) s = s.replace("__", "_");
  1799. #end
  1800. return s;
  1801. }
  1802. public static function enumData(s: String): String {
  1803. for (a in Project.assets) if (a.name == s) return a.file;
  1804. return "";
  1805. }
  1806. static function make_texture(image_node: TNode, tex_name: String, matname: String = null): TBindTexture {
  1807. var filepath = enumData(App.enumTexts(image_node.type)[image_node.buttons[0].default_value]);
  1808. if (filepath == "" || filepath.indexOf(".") == -1) {
  1809. return null;
  1810. }
  1811. var tex: TBindTexture = {
  1812. name: tex_name,
  1813. file: filepath
  1814. };
  1815. if (Context.textureFilter) {
  1816. tex.min_filter = "anisotropic";
  1817. tex.mag_filter = "linear";
  1818. tex.mipmap_filter = "linear";
  1819. tex.generate_mipmaps = true;
  1820. }
  1821. else {
  1822. tex.min_filter = "point";
  1823. tex.mag_filter = "point";
  1824. tex.mipmap_filter = "no";
  1825. }
  1826. tex.u_addressing = "repeat";
  1827. tex.v_addressing = "repeat";
  1828. return tex;
  1829. }
  1830. static function is_pow(num: Int): Bool {
  1831. return ((num & (num - 1)) == 0) && num != 0;
  1832. }
  1833. static function asset_path(s: String): String {
  1834. return s;
  1835. }
  1836. static function extract_filename(s: String): String {
  1837. var ar = s.split(".");
  1838. return ar[ar.length - 2] + "." + ar[ar.length - 1];
  1839. }
  1840. static function safestr(s: String): String {
  1841. return s;
  1842. }
  1843. }
  1844. typedef TShaderOut = {
  1845. var out_basecol: String;
  1846. var out_roughness: String;
  1847. var out_metallic: String;
  1848. var out_occlusion: String;
  1849. var out_opacity: String;
  1850. var out_height: String;
  1851. var out_emission: String;
  1852. var out_subsurface: String;
  1853. }
  1854. @:enum abstract ColorSpace(Int) from Int to Int {
  1855. var SpaceAuto = 0; // sRGB for base color, otherwise linear
  1856. var SpaceLinear = 1;
  1857. var SpaceSRGB = 2;
  1858. var SpaceDirectXNormalMap = 3;
  1859. }