Implement mask blending

This commit is contained in:
Lubos Lenco
2021-06-02 13:32:23 +02:00
parent 0c2382b578
commit 9979bf091b
7 changed files with 182 additions and 32 deletions
+10
View File
@@ -0,0 +1,10 @@
#version 330
uniform sampler2D tex0;
uniform sampler2D texa;
in vec2 texCoord;
out vec4 FragColor;
void main() {
vec4 col0 = textureLod(tex0, texCoord, 0);
float mask = textureLod(texa, texCoord, 0).r;
FragColor = vec4(col0.rgb, col0.a * mask);
}
+52 -3
View File
@@ -1,10 +1,59 @@
#version 330
uniform sampler2D tex0;
uniform sampler2D texa;
uniform float opac;
uniform int blending;
in vec2 texCoord;
out vec4 FragColor;
void main() {
vec4 col0 = textureLod(tex0, texCoord, 0);
float mask = textureLod(texa, texCoord, 0).r;
FragColor = vec4(col0.rgb, col0.a * mask);
float col0 = textureLod(tex0, texCoord, 0).r;
float cola = textureLod(texa, texCoord, 0).r;
float str = opac;
float outColor = 0.0;
if (blending == 0) { // Mix
outColor = mix(cola, col0, str);
}
else if (blending == 1) { // Darken
outColor = mix(cola, min(cola, col0), str);
}
else if (blending == 2) { // Multiply
outColor = mix(cola, cola * col0, str);
}
else if (blending == 3) { // Burn
outColor = mix(cola, 1.0 - (1.0 - cola) / col0, str);
}
else if (blending == 4) { // Lighten
outColor = max(cola, col0 * str);
}
else if (blending == 5) { // Screen
outColor = (1.0 - ((1.0 - str) + str * (1.0 - col0)) * (1.0 - cola));
}
else if (blending == 6) { // Dodge
outColor = mix(cola, cola / (1.0 - col0), str);
}
else if (blending == 7) { // Add
outColor = mix(cola, cola + col0, str);
}
else if (blending == 8) { // Overlay
outColor = mix(cola, cola < 0.5 ? 2.0 * cola * col0 : 1.0 - 2.0 * (1.0 - cola) * (1.0 - col0), str);
}
else if (blending == 9) { // Soft Light
outColor = ((1.0 - str) * cola + str * ((1.0 - cola) * col0 * cola + cola * (1.0 - (1.0 - col0) * (1.0 - cola))));
}
else if (blending == 10) { // Linear Light
outColor = (cola + str * (2.0 * (col0 - 0.5)));
}
else if (blending == 11) { // Difference
outColor = mix(cola, abs(cola - col0), str);
}
else if (blending == 12) { // Subtract
outColor = mix(cola, cola - col0, str);
}
else if (blending == 13) { // Divide
outColor = (1.0 - str) * cola + str * cola / col0;
}
else { // Hue, Saturation, Color, Value
outColor = mix(cola, col0, str);
}
FragColor = vec4(outColor, outColor, outColor, 1.0);
}
+53 -19
View File
@@ -34,7 +34,8 @@ class Layers {
public static var pipeCopyBGRA: PipelineState;
public static var pipeCopyRGB: PipelineState = null;
public static var pipeInvert8: PipelineState;
public static var pipeMask: PipelineState;
public static var pipeApplyMask: PipelineState;
public static var pipeMergeMask: PipelineState;
public static var tex0: TextureUnit;
public static var tex1: TextureUnit;
public static var texmask: TextureUnit;
@@ -43,6 +44,10 @@ class Layers {
public static var blending: ConstantLocation;
public static var tex0Mask: TextureUnit;
public static var texaMask: TextureUnit;
public static var tex0MergeMask: TextureUnit;
public static var texaMergeMask: TextureUnit;
public static var opacMergeMask: ConstantLocation;
public static var blendingMergeMask: ConstantLocation;
public static var tempImage: Image = null;
public static var tempMaskImage: Image = null;
public static var expa: Image = null;
@@ -210,15 +215,27 @@ class Layers {
pipeCopy8.colorAttachments[0] = TextureFormat.L8;
pipeInvert8.compile();
pipeMask = new PipelineState();
pipeMask.vertexShader = kha.Shaders.getVertex("layer_merge.vert");
pipeMask.fragmentShader = kha.Shaders.getFragment("mask_merge.frag");
pipeApplyMask = new PipelineState();
pipeApplyMask.vertexShader = kha.Shaders.getVertex("layer_merge.vert");
pipeApplyMask.fragmentShader = kha.Shaders.getFragment("mask_apply.frag");
var vs = new VertexStructure();
vs.add("pos", VertexData.Float2);
pipeMask.inputLayout = [vs];
pipeMask.compile();
tex0Mask = pipeMask.getTextureUnit("tex0");
texaMask = pipeMask.getTextureUnit("texa");
pipeApplyMask.inputLayout = [vs];
pipeApplyMask.compile();
tex0Mask = pipeApplyMask.getTextureUnit("tex0");
texaMask = pipeApplyMask.getTextureUnit("texa");
pipeMergeMask = new PipelineState();
pipeMergeMask.vertexShader = kha.Shaders.getVertex("layer_merge.vert");
pipeMergeMask.fragmentShader = kha.Shaders.getFragment("mask_merge.frag");
var vs = new VertexStructure();
vs.add("pos", VertexData.Float2);
pipeMergeMask.inputLayout = [vs];
pipeMergeMask.compile();
tex0MergeMask = pipeMergeMask.getTextureUnit("tex0");
texaMergeMask = pipeMergeMask.getTextureUnit("texa");
opacMergeMask = pipeMergeMask.getConstantLocation("opac");
blendingMergeMask = pipeMergeMask.getConstantLocation("blending");
}
public static function makePipeCopyRGB() {
@@ -354,7 +371,11 @@ class Layers {
// Apply masks
var masks = l1.getMasks();
if (masks != null) {
for (m in masks) m.applyMask();
for (i in 0...masks.length - 1) {
mergeLayer(masks[i + 1], masks[i]);
masks[i].delete();
}
masks[masks.length - 1].applyMask();
Context.setLayer(l1);
}
@@ -389,15 +410,13 @@ class Layers {
mask = l1masks[0].texpaint;
}
if (l1.isMask() || l1.paintBase) {
if (l1.isMask()) {
l0.texpaint.g4.begin();
l0.texpaint.g4.setPipeline(pipeMerge);
l0.texpaint.g4.setTexture(tex0, l1.texpaint);
l0.texpaint.g4.setTexture(tex1, empty);
l0.texpaint.g4.setTexture(texmask, mask);
l0.texpaint.g4.setTexture(texa, tempImage);
l0.texpaint.g4.setFloat(opac, l1.getOpacity());
l0.texpaint.g4.setInt(blending, l1.blending);
l0.texpaint.g4.setPipeline(pipeMergeMask);
l0.texpaint.g4.setTexture(Layers.tex0MergeMask, l1.texpaint);
l0.texpaint.g4.setTexture(Layers.texaMergeMask, tempImage);
l0.texpaint.g4.setFloat(opacMergeMask, l1.getOpacity());
l0.texpaint.g4.setInt(blendingMergeMask, l1.blending);
l0.texpaint.g4.setVertexBuffer(iron.data.ConstData.screenAlignedVB);
l0.texpaint.g4.setIndexBuffer(iron.data.ConstData.screenAlignedIB);
l0.texpaint.g4.drawIndexedVertices();
@@ -405,6 +424,21 @@ class Layers {
}
if (l1.isLayer()) {
if (l1.paintBase) {
l0.texpaint.g4.begin();
l0.texpaint.g4.setPipeline(pipeMerge);
l0.texpaint.g4.setTexture(tex0, l1.texpaint);
l0.texpaint.g4.setTexture(tex1, empty);
l0.texpaint.g4.setTexture(texmask, mask);
l0.texpaint.g4.setTexture(texa, tempImage);
l0.texpaint.g4.setFloat(opac, l1.getOpacity());
l0.texpaint.g4.setInt(blending, l1.blending);
l0.texpaint.g4.setVertexBuffer(iron.data.ConstData.screenAlignedVB);
l0.texpaint.g4.setIndexBuffer(iron.data.ConstData.screenAlignedIB);
l0.texpaint.g4.drawIndexedVertices();
l0.texpaint.g4.end();
}
tempImage.g2.begin(false);
tempImage.g2.pipeline = pipeCopy;
tempImage.g2.drawImage(l0.texpaint_nor, 0, 0);
@@ -513,10 +547,10 @@ class Layers {
tempImage.g2.pipeline = null;
tempImage.g2.end();
// Merge mask
// Apply mask
if (iron.data.ConstData.screenAlignedVB == null) iron.data.ConstData.createScreenAlignedData();
l.texpaint.g4.begin();
l.texpaint.g4.setPipeline(Layers.pipeMask);
l.texpaint.g4.setPipeline(Layers.pipeApplyMask);
l.texpaint.g4.setTexture(Layers.tex0Mask, tempImage);
l.texpaint.g4.setTexture(Layers.texaMask, m.texpaint);
l.texpaint.g4.setVertexBuffer(iron.data.ConstData.screenAlignedVB);
+1 -1
View File
@@ -90,7 +90,7 @@ class LayerSlot {
else { // Mask
name = "Mask " + (id + 1);
var format = "RGBA32"; // Full bits for undo support, R8 is used
blending = BlendDarken;
blending = BlendAdd;
{
var t = new RenderTargetRaw();
+2 -3
View File
@@ -174,11 +174,10 @@ class ExportTexture {
if (l1masks != null && !bakeMaterial) {
if (l1masks.length > 1) {
Layers.makeTempMaskImg();
Layers.tempMaskImage.g2.begin(false);
Layers.tempMaskImage.g2.drawImage(l1masks[0].texpaint, 0, 0);
Layers.tempMaskImage.g2.begin(true, 0x00000000);
Layers.tempMaskImage.g2.end();
var l1 = { texpaint: Layers.tempMaskImage };
for (i in 1...l1masks.length) {
for (i in 0...l1masks.length) {
Layers.mergeLayer(untyped l1, l1masks[i]);
}
mask = Layers.tempMaskImage;
+48
View File
@@ -440,6 +440,54 @@ class MakeMaterial {
}
}
public static function blendModeMask(frag: NodeShader, blending: Int, cola: String, colb: String, opac: String): String {
if (blending == BlendMix) {
return 'mix($cola, $colb, $opac)';
}
else if (blending == BlendDarken) {
return 'mix($cola, min($cola, $colb), $opac)';
}
else if (blending == BlendMultiply) {
return 'mix($cola, $cola * $colb, $opac)';
}
else if (blending == BlendBurn) {
return 'mix($cola, 1.0 - (1.0 - $cola) / $colb, $opac)';
}
else if (blending == BlendLighten) {
return 'max($cola, $colb * $opac)';
}
else if (blending == BlendScreen) {
return '(1.0 - ((1.0 - $opac) + $opac * (1.0 - $colb)) * (1.0 - $cola))';
}
else if (blending == BlendDodge) {
return 'mix($cola, $cola / (1.0 - $colb), $opac)';
}
else if (blending == BlendAdd) {
return 'mix($cola, $cola + $colb, $opac)';
}
else if (blending == BlendOverlay) {
return 'mix($cola, $cola < 0.5 ? 2.0 * $cola * $colb : 1.0 - 2.0 * (1.0 - $cola) * (1.0 - $colb), $opac)';
}
else if (blending == BlendSoftLight) {
return '((1.0 - $opac) * $cola + $opac * ((1.0 - $cola) * $colb * $cola + $cola * (1.0 - (1.0 - $colb) * (1.0 - $cola))))';
}
else if (blending == BlendLinearLight) {
return '($cola + $opac * (2.0 * ($colb - 0.5)))';
}
else if (blending == BlendDifference) {
return 'mix($cola, abs($cola - $colb), $opac)';
}
else if (blending == BlendSubtract) {
return 'mix($cola, $cola - $colb, $opac)';
}
else if (blending == BlendDivide) {
return '(1.0 - $opac) * $cola + $opac * $cola / $colb';
}
else { // BlendHue, BlendSaturation, BlendColor, BlendValue
return 'mix($cola, $colb, $opac)';
}
}
public static inline function getDisplaceStrength():Float {
var sc = Context.mainObject().transform.scale.x;
return Config.raw.displace_strength * 0.02 * sc;
+16 -6
View File
@@ -202,14 +202,24 @@ class MakeMesh {
var masks = l.getMasks();
if (masks != null) {
var texpaint_mask = 'texpaint_mask' + l.id;
frag.write('float $texpaint_mask = 1.0;');
var hasVisible = false;
for (m in masks) {
if (!m.isVisible()) continue;
frag.add_shared_sampler('sampler2D texpaint' + m.id);
frag.write('$texpaint_mask -= 1.0 - textureLodShared(texpaint' + m.id + ', texCoord, 0.0).r;');
if (m.isVisible()) {
hasVisible = true;
break;
}
}
if (hasVisible) {
var texpaint_mask = 'texpaint_mask' + l.id;
frag.write('float $texpaint_mask = 0.0;');
for (m in masks) {
if (!m.isVisible()) continue;
frag.add_shared_sampler('sampler2D texpaint' + m.id);
frag.write('float texpaint_mask_sample' + m.id + ' = textureLodShared(texpaint' + m.id + ', texCoord, 0.0).r;');
frag.write('$texpaint_mask = ' + MakeMaterial.blendModeMask(frag, m.blending, '$texpaint_mask', 'texpaint_mask_sample' + m.id, m.getOpacity() + "") + ';');
}
frag.write('texpaint_opac *= clamp($texpaint_mask, 0.0, 1.0);');
}
frag.write('texpaint_opac *= max($texpaint_mask, 0.0);');
}
if (l.getOpacity() < 1) {