Implement mask blending
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user