make_paint.ts 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. ///if (is_paint || is_forge)
  2. function make_paint_is_raytraced_bake(): bool {
  3. return context_raw.bake_type == bake_type_t.INIT;
  4. }
  5. function make_paint_color_attachments(): string[] {
  6. if (context_raw.tool == workspace_tool_t.COLORID) {
  7. let res: string[] = ["RGBA32"];
  8. return res;
  9. }
  10. if (context_raw.tool == workspace_tool_t.PICKER && context_raw.pick_pos_nor_tex) {
  11. let res: string[] = ["RGBA128", "RGBA128"];
  12. return res;
  13. }
  14. if (context_raw.tool == workspace_tool_t.PICKER || context_raw.tool == workspace_tool_t.MATERIAL) {
  15. let res: string[] = ["RGBA32", "RGBA32", "RGBA32", "RGBA32"];
  16. return res;
  17. }
  18. if (context_raw.tool == workspace_tool_t.BAKE && make_paint_is_raytraced_bake()) {
  19. let res: string[] = ["RGBA64", "RGBA64"];
  20. return res;
  21. }
  22. let format: tex_format_t =
  23. base_bits_handle.position == texture_bits_t.BITS8 ? tex_format_t.RGBA32 :
  24. base_bits_handle.position == texture_bits_t.BITS16 ? tex_format_t.RGBA64 :
  25. tex_format_t.RGBA128;
  26. if (format == tex_format_t.RGBA64) {
  27. let res: string[] = ["RGBA64", "RGBA64", "RGBA64", "R8"];
  28. return res;
  29. }
  30. if (format == tex_format_t.RGBA128) {
  31. let res: string[] = ["RGBA128", "RGBA128", "RGBA128", "R8"];
  32. return res;
  33. }
  34. let res: string[] = ["RGBA32", "RGBA32", "RGBA32", "R8"];
  35. return res;
  36. }
  37. function make_paint_run(data: material_t, matcon: material_context_t): node_shader_context_t {
  38. let context_id: string = "paint";
  39. let props: shader_context_t = {
  40. name: context_id,
  41. depth_write: false,
  42. compare_mode: "always",
  43. cull_mode: "none",
  44. vertex_elements: [
  45. {
  46. name: "pos",
  47. data: "short4norm"
  48. },
  49. {
  50. name: "nor",
  51. data: "short2norm"
  52. },
  53. {
  54. name: "tex",
  55. data: "short2norm"
  56. }
  57. ],
  58. color_attachments: make_paint_color_attachments()
  59. };
  60. let con_paint: node_shader_context_t = node_shader_context_create(data, props);
  61. con_paint.data.color_writes_red = [true, true, true, true];
  62. con_paint.data.color_writes_green = [true, true, true, true];
  63. con_paint.data.color_writes_blue = [true, true, true, true];
  64. con_paint.data.color_writes_alpha = [true, true, true, true];
  65. con_paint.allow_vcols = mesh_data_get_vertex_array(context_raw.paint_object.data, "col") != null;
  66. let kong: node_shader_t = node_shader_context_make_kong(con_paint);
  67. if (context_raw.tool == workspace_tool_t.BAKE && context_raw.bake_type == bake_type_t.INIT) {
  68. // Init raytraced bake
  69. make_bake_position_normal(kong);
  70. con_paint.data.shader_from_source = true;
  71. gpu_create_shaders_from_kong(node_shader_get(kong), ADDRESS(con_paint.data.vertex_shader), ADDRESS(con_paint.data.fragment_shader), ADDRESS(con_paint.data._.vertex_shader_size), ADDRESS(con_paint.data._.fragment_shader_size));
  72. return con_paint;
  73. }
  74. if (context_raw.tool == workspace_tool_t.BAKE) {
  75. make_bake_set_color_writes(con_paint);
  76. }
  77. if (context_raw.tool == workspace_tool_t.COLORID || context_raw.tool == workspace_tool_t.PICKER || context_raw.tool == workspace_tool_t.MATERIAL) {
  78. make_colorid_picker_run(kong);
  79. con_paint.data.shader_from_source = true;
  80. gpu_create_shaders_from_kong(node_shader_get(kong), ADDRESS(con_paint.data.vertex_shader), ADDRESS(con_paint.data.fragment_shader), ADDRESS(con_paint.data._.vertex_shader_size), ADDRESS(con_paint.data._.fragment_shader_size));
  81. return con_paint;
  82. }
  83. let face_fill: bool = context_raw.tool == workspace_tool_t.FILL && context_raw.fill_type_handle.position == fill_type_t.FACE;
  84. let uv_island_fill: bool = context_raw.tool == workspace_tool_t.FILL && context_raw.fill_type_handle.position == fill_type_t.UV_ISLAND;
  85. let decal: bool = context_is_decal();
  86. node_shader_write_vert(kong, "var tpos: float2 = float2(input.tex.x * 2.0 - 1.0, (1.0 - input.tex.y) * 2.0 - 1.0);");
  87. node_shader_write_vert(kong, "output.pos = float4(tpos, 0.0, 1.0);");
  88. let decal_layer: bool = context_raw.layer.fill_layer != null && context_raw.layer.uv_type == uv_type_t.PROJECT;
  89. if (decal_layer) {
  90. node_shader_add_constant(kong, "WVP: float4x4", "_decal_layer_matrix");
  91. }
  92. else {
  93. node_shader_add_constant(kong, "WVP: float4x4", "_world_view_proj_matrix");
  94. }
  95. node_shader_add_out(kong, "ndc: float4");
  96. node_shader_write_attrib_vert(kong, "output.ndc = constants.WVP * float4(input.pos.xyz, 1.0);");
  97. node_shader_write_attrib_frag(kong, "var sp: float3 = (input.ndc.xyz / input.ndc.w) * 0.5 + 0.5;");
  98. node_shader_write_attrib_frag(kong, "sp.y = 1.0 - sp.y;");
  99. node_shader_write_attrib_frag(kong, "sp.z -= 0.0001;"); // small bias
  100. let uv_type: uv_type_t = context_raw.layer.fill_layer != null ? context_raw.layer.uv_type : context_raw.brush_paint;
  101. if (uv_type == uv_type_t.PROJECT) {
  102. kong.frag_ndcpos = true;
  103. }
  104. node_shader_add_constant(kong, "inp: float4", "_input_brush");
  105. node_shader_add_constant(kong, "inplast: float4", "_input_brush_last");
  106. node_shader_add_constant(kong, "aspect_ratio: float", "_aspect_ratio_window");
  107. node_shader_write_frag(kong, "var bsp: float2 = sp.xy * 2.0 - 1.0;");
  108. node_shader_write_frag(kong, "bsp.x *= constants.aspect_ratio;");
  109. node_shader_write_frag(kong, "bsp = bsp * 0.5 + 0.5;");
  110. node_shader_add_texture(kong, "gbufferD");
  111. kong.frag_out = "float4[4]";
  112. node_shader_add_constant(kong, "brush_radius: float", "_brush_radius");
  113. node_shader_add_constant(kong, "brush_opacity: float", "_brush_opacity");
  114. node_shader_add_constant(kong, "brush_hardness: float", "_brush_hardness");
  115. if (context_raw.tool == workspace_tool_t.BRUSH ||
  116. context_raw.tool == workspace_tool_t.ERASER ||
  117. context_raw.tool == workspace_tool_t.CLONE ||
  118. context_raw.tool == workspace_tool_t.BLUR ||
  119. context_raw.tool == workspace_tool_t.SMUDGE ||
  120. context_raw.tool == workspace_tool_t.PARTICLE ||
  121. decal) {
  122. let depth_reject: bool = !context_raw.xray;
  123. if (config_raw.brush_3d && !config_raw.brush_depth_reject) {
  124. depth_reject = false;
  125. }
  126. // TODO: sp.z needs to take height channel into account
  127. let particle: bool = context_raw.tool == workspace_tool_t.PARTICLE;
  128. if (config_raw.brush_3d && !decal && !particle) {
  129. if (make_material_height_used || context_raw.sym_x || context_raw.sym_y || context_raw.sym_z) {
  130. depth_reject = false;
  131. }
  132. }
  133. if (depth_reject) {
  134. node_shader_write_frag(kong, "if (sp.z > sample_lod(gbufferD, sampler_linear, sp.xy, 0.0).r - 0.00005) { discard; }");
  135. }
  136. make_brush_run(kong);
  137. }
  138. else { // Fill, Bake
  139. node_shader_write_frag(kong, "var dist: float = 0.0;");
  140. let angle_fill: bool = context_raw.tool == workspace_tool_t.FILL && context_raw.fill_type_handle.position == fill_type_t.ANGLE;
  141. if (angle_fill) {
  142. node_shader_add_function(kong, str_octahedron_wrap);
  143. node_shader_add_texture(kong, "gbuffer0");
  144. node_shader_write_frag(kong, "var g0: float2 = sample_lod(gbuffer0, sampler_linear, constants.inp.xy, 0.0).rg;");
  145. node_shader_write_frag(kong, "var wn: float3;");
  146. node_shader_write_frag(kong, "wn.z = 1.0 - abs(g0.x) - abs(g0.y);");
  147. // node_shader_write_frag(kong, "wn.xy = wn.z >= 0.0 ? g0.xy : octahedron_wrap(g0.xy);");
  148. node_shader_write_frag(kong, "if (wn.z >= 0.0) { wn.x = g0.x; wn.y = g0.y; } else { var f2: float2 = octahedron_wrap(g0.xy); wn.x = f2.x; wn.y = f2.y; }");
  149. node_shader_write_frag(kong, "wn = normalize(wn);");
  150. kong.frag_n = true;
  151. let angle: f32 = context_raw.brush_angle_reject_dot;
  152. node_shader_write_frag(kong, "if (dot(wn, n) < " + angle + ") { discard; }");
  153. }
  154. let stencil_fill: bool = context_raw.tool == workspace_tool_t.FILL && context_raw.brush_stencil_image != null;
  155. if (stencil_fill) {
  156. node_shader_write_frag(kong, "if (sp.z > sample_lod(gbufferD, sampler_linear, sp.xy, 0.0).r - 0.00005) { discard; }");
  157. }
  158. }
  159. if (context_raw.colorid_picked || face_fill || uv_island_fill) {
  160. node_shader_add_out(kong, "tex_coord_pick: float2");
  161. node_shader_write_vert(kong, "output.tex_coord_pick = input.tex;");
  162. if (context_raw.colorid_picked) {
  163. make_discard_color_id(kong);
  164. }
  165. if (face_fill) {
  166. make_discard_face(kong);
  167. }
  168. else if (uv_island_fill) {
  169. make_discard_uv_island(kong);
  170. }
  171. }
  172. if (context_raw.picker_mask_handle.position == picker_mask_t.MATERIAL) {
  173. make_discard_material_id(kong);
  174. }
  175. make_texcoord_run(kong);
  176. if (context_raw.tool == workspace_tool_t.CLONE || context_raw.tool == workspace_tool_t.BLUR || context_raw.tool == workspace_tool_t.SMUDGE) {
  177. node_shader_add_texture(kong, "gbuffer2");
  178. node_shader_add_constant(kong, "gbuffer_size: float2", "_gbuffer_size");
  179. node_shader_add_texture(kong, "texpaint_undo", "_texpaint_undo");
  180. node_shader_add_texture(kong, "texpaint_nor_undo", "_texpaint_nor_undo");
  181. node_shader_add_texture(kong, "texpaint_pack_undo", "_texpaint_pack_undo");
  182. if (context_raw.tool == workspace_tool_t.CLONE) {
  183. make_clone_run(kong);
  184. }
  185. else { // Blur, Smudge
  186. make_blur_run(kong);
  187. }
  188. }
  189. else {
  190. parser_material_parse_emission = context_raw.material.paint_emis;
  191. parser_material_parse_subsurface = context_raw.material.paint_subs;
  192. parser_material_parse_height = context_raw.material.paint_height;
  193. parser_material_parse_height_as_channel = true;
  194. let uv_type: uv_type_t = context_raw.layer.fill_layer != null ? context_raw.layer.uv_type : context_raw.brush_paint;
  195. parser_material_triplanar = uv_type == uv_type_t.TRIPLANAR && !decal;
  196. parser_material_sample_keep_aspect = decal;
  197. parser_material_sample_uv_scale = "constants.brush_scale";
  198. let sout: shader_out_t = parser_material_parse(ui_nodes_get_canvas_material(), con_paint, kong, matcon);
  199. parser_material_parse_emission = false;
  200. parser_material_parse_subsurface = false;
  201. parser_material_parse_height_as_channel = false;
  202. parser_material_parse_height = false;
  203. let base: string = sout.out_basecol;
  204. let rough: string = sout.out_roughness;
  205. let met: string = sout.out_metallic;
  206. let occ: string = sout.out_occlusion;
  207. let nortan: string = parser_material_out_normaltan;
  208. let height: string = sout.out_height;
  209. let opac: string = sout.out_opacity;
  210. let emis: string = sout.out_emission;
  211. let subs: string = sout.out_subsurface;
  212. node_shader_write_frag(kong, "var basecol: float3 = " + base + ";");
  213. node_shader_write_frag(kong, "var roughness: float = " + rough + ";");
  214. node_shader_write_frag(kong, "var metallic: float = " + met + ";");
  215. node_shader_write_frag(kong, "var occlusion: float = " + occ + ";");
  216. node_shader_write_frag(kong, "var nortan: float3 = " + nortan + ";");
  217. node_shader_write_frag(kong, "var height: float = " + height + ";");
  218. node_shader_write_frag(kong, "var mat_opacity: float = " + opac + ";");
  219. node_shader_write_frag(kong, "var opacity: float = mat_opacity;");
  220. ///if is_forge
  221. node_shader_write_frag(kong, "opacity = 1.0;");
  222. ///else
  223. if (context_raw.layer.fill_layer == null) {
  224. node_shader_write_frag(kong, "opacity *= constants.brush_opacity;");
  225. }
  226. ///end
  227. if (context_raw.material.paint_emis) {
  228. node_shader_write_frag(kong, "var emis: float = " + emis + ";");
  229. }
  230. if (context_raw.material.paint_subs) {
  231. node_shader_write_frag(kong, "var subs: float = " + subs + ";");
  232. }
  233. if (!make_material_height_used && parse_float(height) != 0.0) {
  234. make_material_height_used = true;
  235. // Height used for the first time, also rebuild vertex shader
  236. return make_paint_run(data, matcon);
  237. }
  238. make_material_emis_used = parse_float(emis) != 0.0;
  239. make_material_subs_used = parse_float(subs) != 0.0;
  240. }
  241. if (context_raw.brush_mask_image != null && context_raw.tool == workspace_tool_t.DECAL) {
  242. node_shader_add_texture(kong, "texbrushmask", "_texbrushmask");
  243. node_shader_write_frag(kong, "var mask_sample: float4 = sample_lod(texbrushmask, sampler_linear, uvsp, 0.0);");
  244. if (context_raw.brush_mask_image_is_alpha) {
  245. node_shader_write_frag(kong, "opacity *= mask_sample.a;");
  246. }
  247. else {
  248. node_shader_write_frag(kong, "opacity *= mask_sample.r * mask_sample.a;");
  249. }
  250. }
  251. else if (context_raw.tool == workspace_tool_t.TEXT) {
  252. node_shader_add_texture(kong, "textexttool", "_textexttool");
  253. node_shader_write_frag(kong, "opacity *= sample_lod(textexttool, sampler_linear, uvsp, 0.0).r;");
  254. }
  255. if (context_raw.brush_stencil_image != null && (
  256. context_raw.tool == workspace_tool_t.BRUSH ||
  257. context_raw.tool == workspace_tool_t.ERASER ||
  258. context_raw.tool == workspace_tool_t.FILL ||
  259. context_raw.tool == workspace_tool_t.CLONE ||
  260. context_raw.tool == workspace_tool_t.BLUR ||
  261. context_raw.tool == workspace_tool_t.SMUDGE ||
  262. context_raw.tool == workspace_tool_t.PARTICLE ||
  263. decal)) {
  264. node_shader_add_texture(kong, "texbrushstencil", "_texbrushstencil");
  265. node_shader_add_constant(kong, "texbrushstencil_size: float2", "_size(_texbrushstencil)");
  266. node_shader_add_constant(kong, "stencil_transform: float4", "_stencil_transform");
  267. node_shader_write_frag(kong, "var stencil_uv: float2 = (sp.xy - constants.stencil_transform.xy) / constants.stencil_transform.z * float2(constants.aspect_ratio, 1.0);");
  268. node_shader_write_frag(kong, "var stencil_size: float2 = constants.texbrushstencil_size;");
  269. node_shader_write_frag(kong, "var stencil_ratio: float = stencil_size.y / stencil_size.x;");
  270. node_shader_write_frag(kong, "stencil_uv -= float2(0.5 / stencil_ratio, 0.5);");
  271. node_shader_write_frag(kong, "stencil_uv = float2(stencil_uv.x * cos(constants.stencil_transform.w) - stencil_uv.y * sin(constants.stencil_transform.w),\
  272. stencil_uv.x * sin(constants.stencil_transform.w) + stencil_uv.y * cos(constants.stencil_transform.w));");
  273. node_shader_write_frag(kong, "stencil_uv += float2(0.5 / stencil_ratio, 0.5);");
  274. node_shader_write_frag(kong, "stencil_uv.x *= stencil_ratio;");
  275. node_shader_write_frag(kong, "if (stencil_uv.x < 0.0 || stencil_uv.x > 1.0 || stencil_uv.y < 0.0 || stencil_uv.y > 1.0) { discard; }");
  276. node_shader_write_frag(kong, "var texbrushstencil_sample: float4 = sample_lod(texbrushstencil, sampler_linear, stencil_uv, 0.0);");
  277. if (context_raw.brush_stencil_image_is_alpha) {
  278. node_shader_write_frag(kong, "opacity *= texbrushstencil_sample.a;");
  279. }
  280. else {
  281. node_shader_write_frag(kong, "opacity *= texbrushstencil_sample.r * texbrushstencil_sample.a;");
  282. }
  283. }
  284. if (context_raw.brush_mask_image != null && (context_raw.tool == workspace_tool_t.BRUSH || context_raw.tool == workspace_tool_t.ERASER)) {
  285. node_shader_add_texture(kong, "texbrushmask", "_texbrushmask");
  286. node_shader_write_frag(kong, "var binp_mask: float2 = constants.inp.xy * 2.0 - 1.0;");
  287. node_shader_write_frag(kong, "binp_mask.x *= constants.aspect_ratio;");
  288. node_shader_write_frag(kong, "binp_mask = binp_mask * 0.5 + 0.5;");
  289. node_shader_write_frag(kong, "var pa_mask: float2 = bsp.xy - binp_mask.xy;");
  290. if (context_raw.brush_directional) {
  291. node_shader_add_constant(kong, "brush_direction: float3", "_brush_direction");
  292. node_shader_write_frag(kong, "if (constants.brush_direction.z == 0.0) { discard; }");
  293. node_shader_write_frag(kong, "pa_mask = float2(pa_mask.x * constants.brush_direction.x - pa_mask.y * constants.brush_direction.y, pa_mask.x * constants.brush_direction.y + pa_mask.y * constants.brush_direction.x);");
  294. }
  295. let angle: f32 = context_raw.brush_angle + context_raw.brush_nodes_angle;
  296. if (angle != 0.0) {
  297. node_shader_add_constant(kong, "brush_angle: float2", "_brush_angle");
  298. node_shader_write_frag(kong, "pa_mask.xy = float2(pa_mask.x * constants.brush_angle.x - pa_mask.y * constants.brush_angle.y, pa_mask.x * constants.brush_angle.y + pa_mask.y * constants.brush_angle.x);");
  299. }
  300. node_shader_write_frag(kong, "pa_mask = pa_mask / constants.brush_radius;");
  301. if (config_raw.brush_3d) {
  302. node_shader_add_constant(kong, "eye: float3", "_camera_pos");
  303. node_shader_write_frag(kong, "pa_mask = pa_mask * (distance(constants.eye, winp.xyz) / 1.5);");
  304. }
  305. node_shader_write_frag(kong, "pa_mask = pa_mask.xy * 0.5 + 0.5;");
  306. node_shader_write_frag(kong, "var mask_sample: float4 = sample_lod(texbrushmask, sampler_linear, pa_mask, 0.0);");
  307. if (context_raw.brush_mask_image_is_alpha) {
  308. node_shader_write_frag(kong, "opacity *= mask_sample.a;");
  309. }
  310. else {
  311. node_shader_write_frag(kong, "opacity *= mask_sample.r * mask_sample.a;");
  312. }
  313. }
  314. node_shader_write_frag(kong, "if (opacity == 0.0) { discard; }");
  315. if (context_raw.tool == workspace_tool_t.PARTICLE) { // Particle mask
  316. make_particle_mask(kong);
  317. }
  318. else { // Brush cursor mask
  319. node_shader_write_frag(kong, "var str: float = clamp((constants.brush_radius - dist) * constants.brush_hardness * 400.0, 0.0, 1.0) * opacity;");
  320. // node_shader_write_frag(kong, "var str: float = pow(clamp(1.0 - (dist / constants.brush_radius), 0.0, 1.0), 1.0 - constants.brush_hardness) * opacity;");
  321. // node_shader_write_frag(kong, "var t: float = clamp(dist / constants.brush_radius, 0.0, 1.0); var falloff: float = 1.0 - smoothstep(0.0, 1.0, t); var str: float = pow(falloff, 1.0 / max(constants.brush_hardness, 0.01)) * opacity;");
  322. }
  323. // Manual blending to preserve memory
  324. kong.frag_wvpposition = true;
  325. node_shader_write_frag(kong, "var sample_tc: float2 = float2(input.wvpposition.x / input.wvpposition.w, input.wvpposition.y / input.wvpposition.w) * 0.5 + 0.5;");
  326. node_shader_write_frag(kong, "sample_tc.y = 1.0 - sample_tc.y;");
  327. node_shader_add_texture(kong, "paintmask");
  328. node_shader_write_frag(kong, "var sample_mask: float = sample_lod(paintmask, sampler_linear, sample_tc, 0.0).r;");
  329. node_shader_write_frag(kong, "str = max(str, sample_mask);");
  330. // write(frag, "str = clamp(str + sample_mask, 0.0, 1.0);");
  331. node_shader_add_texture(kong, "texpaint_undo", "_texpaint_undo");
  332. node_shader_write_frag(kong, "var sample_undo: float4 = sample_lod(texpaint_undo, sampler_linear, sample_tc, 0.0);");
  333. let matid: f32 = context_raw.material.id / 255;
  334. if (context_raw.picker_mask_handle.position == picker_mask_t.MATERIAL) {
  335. matid = context_raw.materialid_picked / 255; // Keep existing material id in place when mask is set
  336. }
  337. let matid_string: string = parser_material_vec1(matid * 3.0);
  338. node_shader_write_frag(kong, "var matid: float = " + matid_string + ";");
  339. // matid % 3 == 0 - normal, 1 - emission, 2 - subsurface
  340. if (context_raw.material.paint_emis && make_material_emis_used) {
  341. node_shader_write_frag(kong, "if (emis > 0.0) {");
  342. node_shader_write_frag(kong, " matid += 1.0 / 255.0;");
  343. node_shader_write_frag(kong, " if (str == 0.0) { discard; }");
  344. node_shader_write_frag(kong, "}");
  345. }
  346. else if (context_raw.material.paint_subs && make_material_subs_used) {
  347. node_shader_write_frag(kong, "if (subs > 0.0) {");
  348. node_shader_write_frag(kong, " matid += 2.0 / 255.0;");
  349. node_shader_write_frag(kong, " if (str == 0.0) { discard; }");
  350. node_shader_write_frag(kong, "}");
  351. }
  352. let is_mask: bool = slot_layer_is_mask(context_raw.layer);
  353. let layered: bool = context_raw.layer != project_layers[0];
  354. if (layered && !is_mask) {
  355. if (context_raw.tool == workspace_tool_t.ERASER) {
  356. node_shader_write_frag(kong, "output[0] = float4(lerp3(sample_undo.rgb, float3(0.0, 0.0, 0.0), str), sample_undo.a - str);");
  357. node_shader_write_frag(kong, "nortan = float3(0.5, 0.5, 1.0);");
  358. node_shader_write_frag(kong, "occlusion = 1.0;");
  359. node_shader_write_frag(kong, "roughness = 0.0;");
  360. node_shader_write_frag(kong, "metallic = 0.0;");
  361. node_shader_write_frag(kong, "matid = 0.0;");
  362. }
  363. else if (context_raw.tool == workspace_tool_t.PARTICLE || decal || context_raw.brush_mask_image != null) {
  364. node_shader_write_frag(kong, "output[0] = float4(" + make_material_blend_mode(kong, context_raw.brush_blending, "sample_undo.rgb", "basecol", "str") + ", max(str, sample_undo.a));");
  365. }
  366. else {
  367. if (context_raw.layer.fill_layer != null) {
  368. node_shader_write_frag(kong, "output[0] = float4(" + make_material_blend_mode(kong, context_raw.brush_blending, "sample_undo.rgb", "basecol", "opacity") + ", mat_opacity);");
  369. }
  370. else {
  371. node_shader_write_frag(kong, "output[0] = float4(" + make_material_blend_mode(kong, context_raw.brush_blending, "sample_undo.rgb", "basecol", "opacity") + ", max(str, sample_undo.a));");
  372. }
  373. }
  374. node_shader_write_frag(kong, "output[1] = float4(nortan, matid);");
  375. let height: string = "0.0";
  376. if (context_raw.material.paint_height && make_material_height_used) {
  377. height = "height";
  378. }
  379. if (decal) {
  380. node_shader_add_texture(kong, "texpaint_pack_undo", "_texpaint_pack_undo");
  381. node_shader_write_frag(kong, "var sample_pack_undo: float4 = sample_lod(texpaint_pack_undo, sampler_linear, sample_tc, 0.0);");
  382. node_shader_write_frag(kong, "output[2] = lerp4(sample_pack_undo, float4(occlusion, roughness, metallic, " + height + "), str);");
  383. }
  384. else {
  385. node_shader_write_frag(kong, "output[2] = float4(occlusion, roughness, metallic, " + height + ");");
  386. }
  387. }
  388. else {
  389. if (context_raw.tool == workspace_tool_t.ERASER) {
  390. node_shader_write_frag(kong, "output[0] = float4(lerp3(sample_undo.rgb, float3(0.0, 0.0, 0.0), str), sample_undo.a - str);");
  391. node_shader_write_frag(kong, "output[1] = float4(0.5, 0.5, 1.0, 0.0);");
  392. node_shader_write_frag(kong, "output[2] = float4(1.0, 0.0, 0.0, 0.0);");
  393. }
  394. else {
  395. node_shader_add_texture(kong, "texpaint_nor_undo", "_texpaint_nor_undo");
  396. node_shader_add_texture(kong, "texpaint_pack_undo", "_texpaint_pack_undo");
  397. node_shader_write_frag(kong, "var sample_nor_undo: float4 = sample_lod(texpaint_nor_undo, sampler_linear, sample_tc, 0.0);");
  398. node_shader_write_frag(kong, "var sample_pack_undo: float4 = sample_lod(texpaint_pack_undo, sampler_linear, sample_tc, 0.0);");
  399. ///if is_forge
  400. node_shader_write_frag(kong, "output[0] = float4(" + make_material_blend_mode(kong, context_raw.brush_blending, "sample_undo.rgb", "basecol", "str") + ", mat_opacity);");
  401. ///else
  402. node_shader_write_frag(kong, "output[0] = float4(" + make_material_blend_mode(kong, context_raw.brush_blending, "sample_undo.rgb", "basecol", "str") + ", max(str, sample_undo.a));");
  403. ///end
  404. node_shader_write_frag(kong, "output[1] = float4(lerp3(sample_nor_undo.rgb, nortan, str), matid);");
  405. if (context_raw.material.paint_height && make_material_height_used) {
  406. node_shader_write_frag(kong, "output[2] = lerp4(sample_pack_undo, float4(occlusion, roughness, metallic, height), str);");
  407. }
  408. else {
  409. node_shader_write_frag(kong, "output[2] = float4(lerp3(sample_pack_undo.rgb, float3(occlusion, roughness, metallic), str), 0.0);");
  410. }
  411. }
  412. }
  413. node_shader_write_frag(kong, "output[3] = float4(str, 0.0, 0.0, 1.0);");
  414. if (!context_raw.material.paint_base) {
  415. con_paint.data.color_writes_red[0] = false;
  416. con_paint.data.color_writes_green[0] = false;
  417. con_paint.data.color_writes_blue[0] = false;
  418. }
  419. if (!context_raw.material.paint_opac) {
  420. con_paint.data.color_writes_alpha[0] = false;
  421. }
  422. if (!context_raw.material.paint_nor) {
  423. con_paint.data.color_writes_red[1] = false;
  424. con_paint.data.color_writes_green[1] = false;
  425. con_paint.data.color_writes_blue[1] = false;
  426. }
  427. if (!context_raw.material.paint_occ) {
  428. con_paint.data.color_writes_red[2] = false;
  429. }
  430. if (!context_raw.material.paint_rough) {
  431. con_paint.data.color_writes_green[2] = false;
  432. }
  433. if (!context_raw.material.paint_met) {
  434. con_paint.data.color_writes_blue[2] = false;
  435. }
  436. if (!context_raw.material.paint_height) {
  437. con_paint.data.color_writes_alpha[2] = false;
  438. }
  439. // Base color only as mask
  440. if (is_mask) {
  441. // TODO: Apply opacity into base
  442. // write(frag, "frag_color[0].rgb *= frag_color[0].a;");
  443. con_paint.data.color_writes_green[0] = false;
  444. con_paint.data.color_writes_blue[0] = false;
  445. con_paint.data.color_writes_alpha[0] = false;
  446. con_paint.data.color_writes_red[1] = false;
  447. con_paint.data.color_writes_green[1] = false;
  448. con_paint.data.color_writes_blue[1] = false;
  449. con_paint.data.color_writes_alpha[1] = false;
  450. con_paint.data.color_writes_red[2] = false;
  451. con_paint.data.color_writes_green[2] = false;
  452. con_paint.data.color_writes_blue[2] = false;
  453. con_paint.data.color_writes_alpha[2] = false;
  454. }
  455. if (context_raw.tool == workspace_tool_t.BAKE) {
  456. make_bake_run(con_paint, kong);
  457. }
  458. parser_material_finalize(con_paint);
  459. parser_material_triplanar = false;
  460. parser_material_sample_keep_aspect = false;
  461. con_paint.data.shader_from_source = true;
  462. gpu_create_shaders_from_kong(node_shader_get(kong), ADDRESS(con_paint.data.vertex_shader), ADDRESS(con_paint.data.fragment_shader), ADDRESS(con_paint.data._.vertex_shader_size), ADDRESS(con_paint.data._.fragment_shader_size));
  463. return con_paint;
  464. }
  465. ///end