MakePaint.hx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. package arm.node;
  2. import iron.data.SceneFormat;
  3. import zui.Nodes;
  4. import arm.ui.UISidebar;
  5. import arm.ui.UINodes;
  6. import arm.shader.MaterialParser;
  7. import arm.shader.NodeShader;
  8. import arm.shader.NodeShaderContext;
  9. import arm.shader.NodeShaderData;
  10. import arm.shader.ShaderFunctions;
  11. import arm.Enums;
  12. class MakePaint {
  13. public static function run(data: NodeShaderData, matcon: TMaterialContext): NodeShaderContext {
  14. var context_id = "paint";
  15. var con_paint:NodeShaderContext = data.add_context({
  16. name: context_id,
  17. depth_write: false,
  18. compare_mode: "always", // TODO: align texcoords winding order
  19. // cull_mode: "counter_clockwise",
  20. cull_mode: "none",
  21. vertex_elements: [{name: "pos", data: "short4norm"}, {name: "nor", data: "short2norm"}, {name: "tex", data: "short2norm"}],
  22. color_attachments:
  23. Context.tool == ToolColorId ? ["RGBA32"] :
  24. (Context.tool == ToolPicker && Context.pickPosNorTex) ? ["RGBA128", "RGBA128"] :
  25. Context.tool == ToolPicker ? ["RGBA32", "RGBA32", "RGBA32"] :
  26. ["RGBA32", "RGBA32", "RGBA32", "R8"]
  27. });
  28. con_paint.data.color_writes_red = [true, true, true, true];
  29. con_paint.data.color_writes_green = [true, true, true, true];
  30. con_paint.data.color_writes_blue = [true, true, true, true];
  31. con_paint.data.color_writes_alpha = [true, true, true, true];
  32. con_paint.allow_vcols = Context.paintObject.data.geom.cols != null;
  33. var vert = con_paint.make_vert();
  34. var frag = con_paint.make_frag();
  35. frag.ins = vert.outs;
  36. #if (kha_direct3d12 || kha_vulkan)
  37. if (Context.tool == ToolBake && Context.bakeType == BakeInit) {
  38. // Init raytraced bake
  39. MakeBake.positionAndNormal(vert, frag);
  40. con_paint.data.shader_from_source = true;
  41. con_paint.data.vertex_shader = vert.get();
  42. con_paint.data.fragment_shader = frag.get();
  43. return con_paint;
  44. }
  45. #end
  46. if (Context.tool == ToolBake) {
  47. MakeBake.setColorWrites(con_paint);
  48. }
  49. if (Context.tool == ToolColorId || Context.tool == ToolPicker) {
  50. MakeColorIdPicker.run(vert, frag);
  51. con_paint.data.shader_from_source = true;
  52. con_paint.data.vertex_shader = vert.get();
  53. con_paint.data.fragment_shader = frag.get();
  54. return con_paint;
  55. }
  56. var faceFill = Context.tool == ToolFill && Context.fillTypeHandle.position == FillFace;
  57. var uvIslandFill = Context.tool == ToolFill && Context.fillTypeHandle.position == FillUVIsland;
  58. var decal = Context.tool == ToolDecal || Context.tool == ToolText;
  59. #if (kha_direct3d11 || kha_direct3d12 || kha_metal || kha_vulkan)
  60. vert.write('vec2 tpos = vec2(tex.x * 2.0 - 1.0, (1.0 - tex.y) * 2.0 - 1.0);');
  61. #else
  62. vert.write('vec2 tpos = vec2(tex.xy * 2.0 - 1.0);');
  63. #end
  64. vert.write('gl_Position = vec4(tpos, 0.0, 1.0);');
  65. var decalLayer = Context.layer.fill_layer != null && Context.layer.uvType == UVProject;
  66. if (decalLayer) {
  67. vert.add_uniform('mat4 WVP', '_decalLayerMatrix');
  68. }
  69. else {
  70. vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrix');
  71. }
  72. vert.add_out('vec4 ndc');
  73. vert.write_attrib('ndc = mul(vec4(pos.xyz, 1.0), WVP);');
  74. frag.write_attrib('vec3 sp = vec3((ndc.xyz / ndc.w) * 0.5 + 0.5);');
  75. frag.write_attrib('sp.y = 1.0 - sp.y;');
  76. frag.write_attrib('sp.z -= 0.0001;'); // small bias
  77. var uvType = Context.layer.fill_layer != null ? Context.layer.uvType : Context.brushPaint;
  78. if (uvType == UVProject) frag.ndcpos = true;
  79. frag.add_uniform('vec4 inp', '_inputBrush');
  80. frag.add_uniform('vec4 inplast', '_inputBrushLast');
  81. frag.add_uniform('float aspectRatio', '_aspectRatioWindowF');
  82. frag.write('vec2 bsp = sp.xy * 2.0 - 1.0;');
  83. frag.write('bsp.x *= aspectRatio;');
  84. frag.write('bsp = bsp * 0.5 + 0.5;');
  85. frag.add_uniform('sampler2D gbufferD');
  86. frag.add_out('vec4 fragColor[4]');
  87. frag.add_uniform('float brushRadius', '_brushRadius');
  88. frag.add_uniform('float brushOpacity', '_brushOpacity');
  89. frag.add_uniform('float brushHardness', '_brushHardness');
  90. if (Context.tool == ToolBrush ||
  91. Context.tool == ToolEraser ||
  92. Context.tool == ToolClone ||
  93. Context.tool == ToolBlur ||
  94. Context.tool == ToolParticle ||
  95. decal) {
  96. var depthReject = !Context.xray;
  97. if (Config.raw.brush_3d && !Config.raw.brush_depth_reject) depthReject = false;
  98. // TODO: sp.z needs to take height channel into account
  99. if (Config.raw.brush_3d && !decal && MakeMaterial.heightUsed) depthReject = false;
  100. if (Context.symX || Context.symY || Context.symZ) depthReject = false;
  101. if (depthReject) {
  102. #if (kha_direct3d11 || kha_direct3d12 || kha_metal || kha_vulkan)
  103. frag.write('if (sp.z > textureLod(gbufferD, sp.xy, 0.0).r + 0.0005) discard;');
  104. #else
  105. frag.write('if (sp.z > textureLod(gbufferD, vec2(sp.x, 1.0 - sp.y), 0.0).r + 0.0005) discard;');
  106. #end
  107. }
  108. MakeBrush.run(vert, frag);
  109. }
  110. else { // Fill, Bake
  111. frag.write('float dist = 0.0;');
  112. var angleFill = Context.tool == ToolFill && Context.fillTypeHandle.position == FillAngle;
  113. if (angleFill) {
  114. frag.add_function(ShaderFunctions.str_octahedronWrap);
  115. frag.add_uniform('sampler2D gbuffer0');
  116. frag.write('vec2 g0 = textureLod(gbuffer0, inp.xy, 0.0).rg;');
  117. frag.write('vec3 wn;');
  118. frag.write('wn.z = 1.0 - abs(g0.x) - abs(g0.y);');
  119. frag.write('wn.xy = wn.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);');
  120. frag.write('wn = normalize(wn);');
  121. frag.n = true;
  122. var angle = Context.brushAngleRejectDot;
  123. frag.write('if (dot(wn, n) < $angle) discard;');
  124. }
  125. var stencilFill = Context.tool == ToolFill && Context.brushStencilImage != null;
  126. if (stencilFill) {
  127. #if (kha_direct3d11 || kha_direct3d12 || kha_metal || kha_vulkan)
  128. frag.write('if (sp.z > textureLod(gbufferD, sp.xy, 0.0).r + 0.0005) discard;');
  129. #else
  130. frag.write('if (sp.z > textureLod(gbufferD, vec2(sp.x, 1.0 - sp.y), 0.0).r + 0.0005) discard;');
  131. #end
  132. }
  133. }
  134. if (Context.colorIdPicked || faceFill || uvIslandFill) {
  135. vert.add_out('vec2 texCoordPick');
  136. vert.write('texCoordPick = tex;');
  137. if (Context.colorIdPicked) {
  138. MakeDiscard.colorId(vert, frag);
  139. }
  140. if (faceFill) {
  141. MakeDiscard.face(vert, frag);
  142. }
  143. else if (uvIslandFill) {
  144. MakeDiscard.uvIsland(vert, frag);
  145. }
  146. }
  147. if (Context.pickerMaskHandle.position == MaskMaterial) {
  148. MakeDiscard.materialId(vert, frag);
  149. }
  150. MakeTexcoord.run(vert, frag);
  151. if (Context.tool == ToolClone || Context.tool == ToolBlur) {
  152. frag.add_uniform('sampler2D gbuffer2');
  153. frag.add_uniform('vec2 gbufferSize', '_gbufferSize');
  154. frag.add_uniform('sampler2D texpaint_undo', '_texpaint_undo');
  155. frag.add_uniform('sampler2D texpaint_nor_undo', '_texpaint_nor_undo');
  156. frag.add_uniform('sampler2D texpaint_pack_undo', '_texpaint_pack_undo');
  157. if (Context.tool == ToolClone) {
  158. MakeClone.run(vert, frag);
  159. }
  160. else { // Blur
  161. MakeBlur.run(vert, frag);
  162. }
  163. }
  164. else {
  165. MaterialParser.parse_emission = Context.material.paintEmis;
  166. MaterialParser.parse_subsurface = Context.material.paintSubs;
  167. MaterialParser.parse_height = Context.material.paintHeight;
  168. MaterialParser.parse_height_as_channel = true;
  169. var uvType = Context.layer.fill_layer != null ? Context.layer.uvType : Context.brushPaint;
  170. MaterialParser.triplanar = uvType == UVTriplanar && !decal;
  171. MaterialParser.sample_keep_aspect = decal;
  172. MaterialParser.sample_uv_scale = 'brushScale';
  173. var sout = MaterialParser.parse(UINodes.inst.getCanvasMaterial(), con_paint, vert, frag, matcon);
  174. MaterialParser.parse_emission = false;
  175. MaterialParser.parse_subsurface = false;
  176. MaterialParser.parse_height_as_channel = false;
  177. MaterialParser.parse_height = false;
  178. var base = sout.out_basecol;
  179. var rough = sout.out_roughness;
  180. var met = sout.out_metallic;
  181. var occ = sout.out_occlusion;
  182. var nortan = MaterialParser.out_normaltan;
  183. var height = sout.out_height;
  184. var opac = sout.out_opacity;
  185. var emis = sout.out_emission;
  186. var subs = sout.out_subsurface;
  187. frag.write('vec3 basecol = $base;');
  188. frag.write('float roughness = $rough;');
  189. frag.write('float metallic = $met;');
  190. frag.write('float occlusion = $occ;');
  191. frag.write('vec3 nortan = $nortan;');
  192. frag.write('float height = $height;');
  193. frag.write('float mat_opacity = $opac;');
  194. #if (kha_direct3d12 || kha_vulkan)
  195. frag.write('float opacity = 1.0;');
  196. #else
  197. frag.write('float opacity = mat_opacity;');
  198. #end
  199. if (Context.layer.fill_layer == null) {
  200. frag.write('opacity *= brushOpacity;');
  201. }
  202. if (Context.material.paintEmis) {
  203. frag.write('float emis = $emis;');
  204. }
  205. if (Context.material.paintSubs) {
  206. frag.write('float subs = $subs;');
  207. }
  208. if (Std.parseFloat(height) != 0.0 && !MakeMaterial.heightUsed) {
  209. MakeMaterial.heightUsed = true;
  210. // Height used for the first time, also rebuild vertex shader
  211. return run(data, matcon);
  212. }
  213. if (Std.parseFloat(emis) != 0.0) MakeMaterial.emisUsed = true;
  214. if (Std.parseFloat(subs) != 0.0) MakeMaterial.subsUsed = true;
  215. }
  216. if (Context.brushMaskImage != null && Context.tool == ToolDecal) {
  217. frag.add_uniform('sampler2D texbrushmask', '_texbrushmask');
  218. frag.write('vec4 mask_sample = textureLod(texbrushmask, uvsp, 0.0);');
  219. if (Context.brushMaskImageIsAlpha) {
  220. frag.write('opacity *= mask_sample.a;');
  221. }
  222. else {
  223. frag.write('opacity *= mask_sample.r * mask_sample.a;');
  224. }
  225. }
  226. else if (Context.tool == ToolText) {
  227. frag.add_uniform('sampler2D textexttool', '_textexttool');
  228. frag.write('opacity *= textureLod(textexttool, uvsp, 0.0).r;');
  229. }
  230. if (Context.brushStencilImage != null && (
  231. Context.tool == ToolBrush ||
  232. Context.tool == ToolEraser ||
  233. Context.tool == ToolFill ||
  234. Context.tool == ToolClone ||
  235. Context.tool == ToolBlur ||
  236. Context.tool == ToolParticle ||
  237. decal)) {
  238. frag.add_uniform('sampler2D texbrushstencil', '_texbrushstencil');
  239. frag.add_uniform('vec4 stencilTransform', '_stencilTransform');
  240. frag.write('vec2 stencil_uv = vec2((sp.xy - stencilTransform.xy) / stencilTransform.z * vec2(aspectRatio, 1.0));');
  241. frag.write('vec2 stencil_size = textureSize(texbrushstencil, 0);');
  242. frag.write('float stencil_ratio = stencil_size.y / stencil_size.x;');
  243. frag.write('stencil_uv -= vec2(0.5 / stencil_ratio, 0.5);');
  244. frag.write('stencil_uv = vec2(stencil_uv.x * cos(stencilTransform.w) - stencil_uv.y * sin(stencilTransform.w),
  245. stencil_uv.x * sin(stencilTransform.w) + stencil_uv.y * cos(stencilTransform.w));');
  246. frag.write('stencil_uv += vec2(0.5 / stencil_ratio, 0.5);');
  247. frag.write('stencil_uv.x *= stencil_ratio;');
  248. frag.write('if (stencil_uv.x < 0 || stencil_uv.x > 1 || stencil_uv.y < 0 || stencil_uv.y > 1) discard;');
  249. frag.write('vec4 texbrushstencil_sample = textureLod(texbrushstencil, stencil_uv, 0.0);');
  250. if (Context.brushStencilImageIsAlpha) {
  251. frag.write('opacity *= texbrushstencil_sample.a;');
  252. }
  253. else {
  254. frag.write('opacity *= texbrushstencil_sample.r * texbrushstencil_sample.a;');
  255. }
  256. }
  257. if (Context.brushMaskImage != null && (Context.tool == ToolBrush || Context.tool == ToolEraser)) {
  258. frag.add_uniform('sampler2D texbrushmask', '_texbrushmask');
  259. frag.write('vec2 binp_mask = inp.xy * 2.0 - 1.0;');
  260. frag.write('binp_mask.x *= aspectRatio;');
  261. frag.write('binp_mask = binp_mask * 0.5 + 0.5;');
  262. frag.write('vec2 pa_mask = bsp.xy - binp_mask.xy;');
  263. if (Context.brushDirectional) {
  264. frag.add_uniform('vec3 brushDirection', '_brushDirection');
  265. frag.write('if (brushDirection.z == 0.0) discard;');
  266. frag.write('pa_mask = vec2(pa_mask.x * brushDirection.x - pa_mask.y * brushDirection.y, pa_mask.x * brushDirection.y + pa_mask.y * brushDirection.x);');
  267. }
  268. var angle = Context.brushAngle + Context.brushNodesAngle;
  269. if (angle != 0.0) {
  270. frag.add_uniform('vec2 brushAngle', '_brushAngle');
  271. frag.write('pa_mask.xy = vec2(pa_mask.x * brushAngle.x - pa_mask.y * brushAngle.y, pa_mask.x * brushAngle.y + pa_mask.y * brushAngle.x);');
  272. }
  273. frag.write('pa_mask /= brushRadius;');
  274. if (Config.raw.brush_3d) {
  275. frag.add_uniform('vec3 eye', '_cameraPosition');
  276. frag.write('pa_mask *= distance(eye, winp.xyz) / 1.5;');
  277. }
  278. frag.write('pa_mask = pa_mask.xy * 0.5 + 0.5;');
  279. frag.write('vec4 mask_sample = textureLod(texbrushmask, pa_mask, 0.0);');
  280. if (Context.brushMaskImageIsAlpha) {
  281. frag.write('opacity *= mask_sample.a;');
  282. }
  283. else {
  284. frag.write('opacity *= mask_sample.r * mask_sample.a;');
  285. }
  286. }
  287. frag.write('if (opacity == 0.0) discard;');
  288. if (Context.tool == ToolParticle) { // Particle mask
  289. frag.add_uniform('sampler2D texparticle', '_texparticle');
  290. #if (kha_direct3d11 || kha_direct3d12 || kha_metal || kha_vulkan)
  291. frag.write('float str = textureLod(texparticle, sp.xy, 0.0).r;');
  292. #else
  293. frag.write('float str = textureLod(texparticle, vec2(sp.x, (1.0 - sp.y)), 0.0).r;');
  294. #end
  295. }
  296. else { // Brush cursor mask
  297. frag.write('float str = clamp((brushRadius - dist) * brushHardness * 400.0, 0.0, 1.0) * opacity;');
  298. }
  299. // Manual blending to preserve memory
  300. frag.wvpposition = true;
  301. frag.write('vec2 sample_tc = vec2(wvpposition.xy / wvpposition.w) * 0.5 + 0.5;');
  302. #if (kha_direct3d11 || kha_direct3d12 || kha_metal || kha_vulkan)
  303. frag.write('sample_tc.y = 1.0 - sample_tc.y;');
  304. #end
  305. frag.add_uniform('sampler2D paintmask');
  306. frag.write('float sample_mask = textureLod(paintmask, sample_tc, 0.0).r;');
  307. frag.write('str = max(str, sample_mask);');
  308. // frag.write('str = clamp(str + sample_mask, 0.0, 1.0);');
  309. frag.add_uniform('sampler2D texpaint_undo', '_texpaint_undo');
  310. frag.write('vec4 sample_undo = textureLod(texpaint_undo, sample_tc, 0.0);');
  311. var matid = Context.material.id / 255;
  312. if (Context.pickerMaskHandle.position == MaskMaterial) {
  313. matid = Context.materialIdPicked / 255; // Keep existing material id in place when mask is set
  314. }
  315. var matidString = MaterialParser.vec1(matid * 3.0);
  316. frag.write('float matid = $matidString;');
  317. // matid % 3 == 0 - normal, 1 - emission, 2 - subsurface
  318. if (Context.material.paintEmis) {
  319. frag.write('if (emis > 0.0) {');
  320. frag.write(' matid += 1.0 / 255.0;');
  321. frag.write(' if (str == 0.0) discard;');
  322. frag.write('}');
  323. }
  324. else if (Context.material.paintSubs) {
  325. frag.write('if (subs > 0.0) {');
  326. frag.write(' matid += 2.0 / 255.0;');
  327. frag.write(' if (str == 0.0) discard;');
  328. frag.write('}');
  329. }
  330. var isMask = Context.layer.isMask();
  331. var layered = Context.layer != Project.layers[0];
  332. if (layered && !isMask) {
  333. if (Context.tool == ToolEraser) {
  334. frag.write('fragColor[0] = vec4(mix(sample_undo.rgb, vec3(0.0, 0.0, 0.0), str), sample_undo.a - str);');
  335. frag.write('nortan = vec3(0.5, 0.5, 1.0);');
  336. frag.write('occlusion = 1.0;');
  337. frag.write('roughness = 0.0;');
  338. frag.write('metallic = 0.0;');
  339. frag.write('matid = 0.0;');
  340. }
  341. else if (Context.tool == ToolParticle || decal || Context.brushMaskImage != null) {
  342. frag.write('fragColor[0] = vec4(' + MakeMaterial.blendMode(frag, Context.brushBlending, 'sample_undo.rgb', 'basecol', 'str') + ', max(str, sample_undo.a));');
  343. }
  344. else {
  345. if (Context.layer.fill_layer != null) {
  346. frag.write('fragColor[0] = vec4(' + MakeMaterial.blendMode(frag, Context.brushBlending, 'sample_undo.rgb', 'basecol', 'opacity') + ', mat_opacity);');
  347. }
  348. else {
  349. frag.write('fragColor[0] = vec4(' + MakeMaterial.blendMode(frag, Context.brushBlending, 'sample_undo.rgb', 'basecol', 'opacity') + ', max(str, sample_undo.a));');
  350. }
  351. }
  352. frag.write('fragColor[1] = vec4(nortan, matid);');
  353. var height = "0.0";
  354. if (Context.material.paintHeight && MakeMaterial.heightUsed) {
  355. height = "height";
  356. }
  357. if (decal) {
  358. frag.add_uniform('sampler2D texpaint_pack_undo', '_texpaint_pack_undo');
  359. frag.write('vec4 sample_pack_undo = textureLod(texpaint_pack_undo, sample_tc, 0.0);');
  360. frag.write('fragColor[2] = mix(sample_pack_undo, vec4(occlusion, roughness, metallic, $height), str);');
  361. }
  362. else {
  363. frag.write('fragColor[2] = vec4(occlusion, roughness, metallic, $height);');
  364. }
  365. }
  366. else {
  367. if (Context.tool == ToolEraser) {
  368. frag.write('fragColor[0] = vec4(mix(sample_undo.rgb, vec3(0.0, 0.0, 0.0), str), sample_undo.a - str);');
  369. frag.write('fragColor[1] = vec4(0.5, 0.5, 1.0, 0.0);');
  370. frag.write('fragColor[2] = vec4(1.0, 0.0, 0.0, 0.0);');
  371. }
  372. else {
  373. frag.add_uniform('sampler2D texpaint_nor_undo', '_texpaint_nor_undo');
  374. frag.add_uniform('sampler2D texpaint_pack_undo', '_texpaint_pack_undo');
  375. frag.write('vec4 sample_nor_undo = textureLod(texpaint_nor_undo, sample_tc, 0.0);');
  376. frag.write('vec4 sample_pack_undo = textureLod(texpaint_pack_undo, sample_tc, 0.0);');
  377. #if (kha_direct3d12 || kha_vulkan)
  378. frag.write('fragColor[0] = vec4(' + MakeMaterial.blendMode(frag, Context.brushBlending, 'sample_undo.rgb', 'basecol', 'str') + ', mat_opacity);');
  379. #else
  380. frag.write('fragColor[0] = vec4(' + MakeMaterial.blendMode(frag, Context.brushBlending, 'sample_undo.rgb', 'basecol', 'str') + ', max(str, sample_undo.a));');
  381. #end
  382. frag.write('fragColor[1] = vec4(mix(sample_nor_undo.rgb, nortan, str), matid);');
  383. if (Context.material.paintHeight && MakeMaterial.heightUsed) {
  384. frag.write('fragColor[2] = mix(sample_pack_undo, vec4(occlusion, roughness, metallic, height), str);');
  385. }
  386. else {
  387. frag.write('fragColor[2] = vec4(mix(sample_pack_undo.rgb, vec3(occlusion, roughness, metallic), str), 0.0);');
  388. }
  389. }
  390. }
  391. frag.write('fragColor[3] = vec4(str, 0.0, 0.0, 1.0);');
  392. if (!Context.material.paintBase) {
  393. con_paint.data.color_writes_red[0] = false;
  394. con_paint.data.color_writes_green[0] = false;
  395. con_paint.data.color_writes_blue[0] = false;
  396. }
  397. if (!Context.material.paintOpac) {
  398. con_paint.data.color_writes_alpha[0] = false;
  399. }
  400. if (!Context.material.paintNor) {
  401. con_paint.data.color_writes_red[1] = false;
  402. con_paint.data.color_writes_green[1] = false;
  403. con_paint.data.color_writes_blue[1] = false;
  404. }
  405. if (!Context.material.paintOcc) {
  406. con_paint.data.color_writes_red[2] = false;
  407. }
  408. if (!Context.material.paintRough) {
  409. con_paint.data.color_writes_green[2] = false;
  410. }
  411. if (!Context.material.paintMet) {
  412. con_paint.data.color_writes_blue[2] = false;
  413. }
  414. if (!Context.material.paintHeight) {
  415. con_paint.data.color_writes_alpha[2] = false;
  416. }
  417. // Base color only as mask
  418. if (isMask) {
  419. // TODO: Apply opacity into base
  420. // frag.write('fragColor[0].rgb *= fragColor[0].a;');
  421. con_paint.data.color_writes_green[0] = false;
  422. con_paint.data.color_writes_blue[0] = false;
  423. con_paint.data.color_writes_alpha[0] = false;
  424. con_paint.data.color_writes_red[1] = false;
  425. con_paint.data.color_writes_green[1] = false;
  426. con_paint.data.color_writes_blue[1] = false;
  427. con_paint.data.color_writes_alpha[1] = false;
  428. con_paint.data.color_writes_red[2] = false;
  429. con_paint.data.color_writes_green[2] = false;
  430. con_paint.data.color_writes_blue[2] = false;
  431. con_paint.data.color_writes_alpha[2] = false;
  432. }
  433. if (Context.tool == ToolBake) {
  434. MakeBake.run(con_paint, vert, frag);
  435. }
  436. MaterialParser.finalize(con_paint);
  437. MaterialParser.triplanar = false;
  438. MaterialParser.sample_keep_aspect = false;
  439. con_paint.data.shader_from_source = true;
  440. con_paint.data.vertex_shader = vert.get();
  441. con_paint.data.fragment_shader = frag.get();
  442. return con_paint;
  443. }
  444. }