make_paint.ts 22 KB

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