Jump to content

Palette Mask plugin request


Recommended Posts

Hi, I don't know if anyone here is taking plugin requests, but if they are, I have one.

 

So... I need a 'Palette Mask' plugin, for textures. I tried learning how to make a plugin, but I couldn't, and I really only want to make this one plugin.

The idea is simple, but the actual creation, I assume not so much.

 

Basically, how it works is:

There's a little UI, you pick two colors, a primary (palette1), and a secondary (palette2).

You open a file browser, and choose a 'Palette Mask' image.

You open another file browser, and choose a 'Palette Map' image

 

If the palette mask is black, then the diffuse texture (base image) is displayed.

If it's red, then the palette1 color mixed with the palette map texture is displayed.

If it's green, then the palette2 color mixed with the palette map texture is displayed.

If it's blue, then this pixel has a metallic specular color

The alpha value of the palette mask is not used.

Any other colors (cyan, purple etc.) are just combinations of these cases.

 

If you are interested in how the palette1/palette2 colors are mixed with the palette map, I posted some HLSL shader code here: http://pastebin.com/EVja22sK

 

 

I am willing to pay for this plugin, if it works correctly.

If you're interested in my request, please reply, and I will give you a few sample textures to work with.

 

 

 

Thank you,

-Nen

Edited by Nengalore
Link to comment
Share on other sites

If I understand you correctly, that shouldn't be too hard. Go ahead and post the samples, and I and/or one of the other plugin developers will look into it.

 

That code snippet that you linked to is Java, but converting Java to C# is pretty straightforward as they are mostly the same.

Edit: Read your post too fast. I see it's HLSL, not Java. Can you blame a guy, they look much alike.

Edited by toe_head2001

(September 25th, 2023)  Sorry about any broken images in my posts. I am aware of the issue.

bp-sig.png
My Gallery  |  My Plugin Pack

Layman's Guide to CodeLab

Link to comment
Share on other sites

If I understand you correctly, that shouldn't be too hard. Go ahead and post the samples, and I and/or one of the other plugin developers will look into it.

 

That code snippet that you linked to is Java, but converting Java to C# is pretty straightforward as they are mostly the same.

 

These are small textures, just as an example, if you want different textures, just ask.

 

For this texture, if you want to show me that your plugin worked, take a snip of your screen after using your plugin with these colors:

 

palette1:

RGB: 65, 64, 73

 

palette2:

RGB: 172, 27, 44

PluginSamples.zip

Edited by Nengalore
Link to comment
Share on other sites

I got about 20 lines into converting that code snippet to C#, and then I realized it is missing some code in a few places.

 

For example:

if (paletteMaskMapValue.x < paletteMaskMapValue.y)
{
    palette = palette2;
The 'palette2' variable is not declared anywhere in the file.

(September 25th, 2023)  Sorry about any broken images in my posts. I am aware of the issue.

bp-sig.png
My Gallery  |  My Plugin Pack

Layman's Guide to CodeLab

Link to comment
Share on other sites

I got about 20 lines into converting that code snippet to C#, and then I realized it is missing some code in a few places.

 

For example:

if (paletteMaskMapValue.x < paletteMaskMapValue.y)
{
    palette = palette2;
The 'palette2' variable is not declared anywhere in the file.

 

Well I mentioned that 'palette1' (primary) and 'palette2' (secondary) refer to the two color selections on the UI.

Edited by Nengalore
Link to comment
Share on other sites

This morning I spent some more time on this. I was able to recreate some of the needed HLSL functions (frac, saturate, ect.) in C# based on info from MSDN, but there are places in the code I have no idea what the outcome of the line of code should be.

 

I simply don't know enough about HLSL to continue. I've heard HLSL can be used directly in .Net via WPF, but I'm not too familiar with that either.

 

Here's my work-in-progress of that file(about half). I can't be sure if my changes are correct.

 

Hidden Content:
using System;

namespace MapMask
{
    internal struct Float3
    {
        public float R;
        public float G;
        public float B;

        public Float3(float first, float second, float third)
        {
            R = first;
            G = second;
            B = third;
        }
    }

    public class Class1
    {
        float frac(float n)
        {
            float number = n - (float)Math.Truncate(n);
            return number;
        }

        float saturate(float n)
        {
            float number;

            if (n < 0)
                number = 0;
            else if (n > 1)
                number = 1;
            else
                number = n;

            return number;
        }

        float lerp(float x, float y, float s)
        {
            float number = x + s * (y - x);
            return number;
        }

        // ===================================================================================
        // HUEING
        // ===================================================================================
        //Utility Functions
        Float3 ExpandHSL(Float3 HSL)
        {
            //float3 outputVal = inVal * (maxVal - minVal) + minVal;
            Float3 expanded = HSL;
            expanded.R = (HSL.R * (.706f - .3137f)) + .3137f; //reexpand hue
            expanded.R -= .41176f; //offset hue
            expanded.G = (HSL.G * .5882f);
            expanded.B = (HSL.B * .70588f);
            return expanded;
        }

        Float3 AdjustLightness(Float3 HSL, float brightness, float contrast) //Adjust the lightness of the HSL
        {
            HSL.B = (float)(Math.Pow(HSL.B, contrast) * contrast);
            HSL.B = brightness + ((1 - brightness) * HSL.;
            return HSL;
        }

        float OffsetHue(float hue, float hueOffset)
        {
            float H = frac(hue + hueOffset);
            return H;
        }
        float OffsetSaturation(float saturation, float satOffset)
        {
            float S = saturation;
            S = (float)Math.Pow(S, satOffset);
            S = S * (1 - satOffset);
            S = saturate(S);
            return S;
        }

        Float3 OffsetHSL(Float3 HSL, float hueOffset, float satOffset)
        {
            float H = OffsetHue(HSL.X, hueOffset);
            float S = OffsetSaturation(HSL.Y, satOffset);

            return new Float3(H, S, HSL.Z);
        }

        Float3 ConvertHSLToRGB(Float3 HSL)
        {
            const float fOneThird = 0.333333333f;
            const float fTwoThirds = 0.666666666f;
            Float3 color;

            float temp1, temp2;
            float H = HSL.R;
            float S = HSL.G;
            float L = HSL.B;

            //if (S == 0)
            //  return float3(L, L, L);

            float LtimesS = L * S;

            if (L < 0.5f)
                temp2 = L + LtimesS;
            else
                temp2 = L + S - LtimesS;

            temp1 = 2.0f * L - temp2;

            Float3 temp3 = frac(new Float3(H + fOneThird, H, H - fOneThird));

            Float3 temp3Times6 = 6.0f * temp3;
            Float3 temp3Times2 = 2.0f * temp3;
            Float3 temp3Times1point5 = 1.5f * temp3;
            Float3 firstEquation = temp1 + (temp2 - temp1) * 6.0f * temp3;
            Float3 secondEquation = temp1 + (temp2 - temp1) * (fTwoThirds - temp3) * 6.0f;

            if (temp3Times6.R < 1.0f)
                color.R = firstEquation.R;
            else if (temp3Times2.R < 1.0f)
                color.R = temp2;
            else if (temp3Times1point5.R < 1.0f)
                color.R = secondEquation.R;
            else
                color.R = temp1;

            if (temp3Times6.G < 1.0f)
                color.G = firstEquation.G;
            else if (temp3Times2.G < 1.0f)
                color.G = temp2;
            else if (temp3Times1point5.G < 1.0f)
                color.G = secondEquation.G;
            else
                color.G = temp1;

            if (temp3Times6.B < 1.0f)
                color.B = firstEquation.B;
            else if (temp3Times2.B < 1.0f)
                color.B = temp2;
            else if (temp3Times1point5.B < 1.0f)
                color.B = secondEquation.B;
            else
                color.B = temp1;

            return color;
        }



        Float3 ManipulateHSL(in Float3 HSL, float4 palette)
        {
            HSL = ExpandHSL(HSL);
            HSL = AdjustLightness(HSL, palette.z, palette.w);
            HSL = OffsetHSL(HSL.rgb, palette.x, palette.y);
            return HSL;
        }

        float ManipulateAO(in float ao, float brightness, float contrast)
        {
            brightness += 1;
            //brightness + ((1 - brightness) * HSL.;
            float ret = ao * (brightness + (1 - brightness) * ao);
            return saturate(ret);
        }


        void HuePixel(
    in float4 diffuseMapValue,
            in float4 specularMapValue,
            float4 paletteMaskMapValue,
            float4 paletteMapValue,
            out Float3 fragmentDiffuseColor,
            out float4 fragmentSpecularColor
            )
        {
            fragmentDiffuseColor = diffuseMapValue.rgb;
            fragmentSpecularColor = specularMapValue;

            float paletteMaskSum = paletteMaskMapValue.x + paletteMaskMapValue.y;


            // Only use the palette that applies
            float4 palette;
            Float3 chosenSpecColor, chosenMetallicSpecColor;

            if (paletteMaskMapValue.x < paletteMaskMapValue.y)
            {
                palette = palette2;
                chosenSpecColor = palette2Specular.rgb;
                chosenMetallicSpecColor = palette2MetallicSpecular.rgb;
            }
            else
            {
                palette = palette1;
                chosenSpecColor = palette1Specular.rgb;
                chosenMetallicSpecColor = palette1MetallicSpecular.rgb;
            }

            // Get the palette map, apply the deltas, and convert it to RGB
            Float3 HSL = ManipulateHSL(new Float3(paletteMapValue.g, paletteMapValue.b, paletteMapValue.a), palette);
            float ambientOcclusion = ManipulateAO(paletteMapValue.r, palette.z, palette.w);
            HSL.z *= ambientOcclusion;
            Float3 RGB = ConvertHSLToRGB(HSL);

            //Blend the result into the original diffuse
            fragmentDiffuseColor = lerp(diffuseMapValue.rgb, RGB.rgb, paletteMaskSum);

            // Determine the hue specular color
            Float3 hueSpecColor;
            const Float3 white = new Float3(1, 1, 1);
            float metallicMask = paletteMaskMapValue.b;
            //1.0 uses chosenMetallicSpecColor, .5 uses white, 0.0 uses chosenSpecColor      
            if (metallicMask > .5)
            {
                hueSpecColor = lerp(white, chosenMetallicSpecColor, (metallicMask - 0.5) * 2);
            }
            else
            {
                hueSpecColor = lerp(chosenSpecColor, white, metallicMask * 2);
            }
            hueSpecColor *= specularMapValue.r;
            fragmentSpecularColor.rgb = lerp(fragmentSpecularColor.rgb, hueSpecColor, paletteMaskSum);

        }
    }
}

(September 25th, 2023)  Sorry about any broken images in my posts. I am aware of the issue.

bp-sig.png
My Gallery  |  My Plugin Pack

Layman's Guide to CodeLab

Link to comment
Share on other sites

This morning I spent some more time on this. I was able to recreate some of the needed HLSL functions (frac, saturate, ect.) in C# based on info from MSDN, but there are places in the code I have no idea what the outcome of the line of code should be.

 

I simply don't know enough about HLSL to continue. I've heard HLSL can be used directly in .Net via WPF, but I'm not too familiar with that either.

 

Here's my work-in-progress of that file(about half). I can't be sure if my changes are correct.

 

Hidden Content:
using System;

namespace MapMask
{
    internal struct Float3
    {
        public float R;
        public float G;
        public float B;

        public Float3(float first, float second, float third)
        {
            R = first;
            G = second;
            B = third;
        }
    }

    public class Class1
    {
        float frac(float n)
        {
            float number = n - (float)Math.Truncate(n);
            return number;
        }

        float saturate(float n)
        {
            float number;

            if (n < 0)
                number = 0;
            else if (n > 1)
                number = 1;
            else
                number = n;

            return number;
        }

        float lerp(float x, float y, float s)
        {
            float number = x + s * (y - x);
            return number;
        }

        // ===================================================================================
        // HUEING
        // ===================================================================================
        //Utility Functions
        Float3 ExpandHSL(Float3 HSL)
        {
            //float3 outputVal = inVal * (maxVal - minVal) + minVal;
            Float3 expanded = HSL;
            expanded.R = (HSL.R * (.706f - .3137f)) + .3137f; //reexpand hue
            expanded.R -= .41176f; //offset hue
            expanded.G = (HSL.G * .5882f);
            expanded.B = (HSL.B * .70588f);
            return expanded;
        }

        Float3 AdjustLightness(Float3 HSL, float brightness, float contrast) //Adjust the lightness of the HSL
        {
            HSL.B = (float)(Math.Pow(HSL.B, contrast) * contrast);
            HSL.B = brightness + ((1 - brightness) * HSL.;
            return HSL;
        }

        float OffsetHue(float hue, float hueOffset)
        {
            float H = frac(hue + hueOffset);
            return H;
        }
        float OffsetSaturation(float saturation, float satOffset)
        {
            float S = saturation;
            S = (float)Math.Pow(S, satOffset);
            S = S * (1 - satOffset);
            S = saturate(S);
            return S;
        }

        Float3 OffsetHSL(Float3 HSL, float hueOffset, float satOffset)
        {
            float H = OffsetHue(HSL.X, hueOffset);
            float S = OffsetSaturation(HSL.Y, satOffset);

            return new Float3(H, S, HSL.Z);
        }

        Float3 ConvertHSLToRGB(Float3 HSL)
        {
            const float fOneThird = 0.333333333f;
            const float fTwoThirds = 0.666666666f;
            Float3 color;

            float temp1, temp2;
            float H = HSL.R;
            float S = HSL.G;
            float L = HSL.B;

            //if (S == 0)
            //  return float3(L, L, L);

            float LtimesS = L * S;

            if (L < 0.5f)
                temp2 = L + LtimesS;
            else
                temp2 = L + S - LtimesS;

            temp1 = 2.0f * L - temp2;

            Float3 temp3 = frac(new Float3(H + fOneThird, H, H - fOneThird));

            Float3 temp3Times6 = 6.0f * temp3;
            Float3 temp3Times2 = 2.0f * temp3;
            Float3 temp3Times1point5 = 1.5f * temp3;
            Float3 firstEquation = temp1 + (temp2 - temp1) * 6.0f * temp3;
            Float3 secondEquation = temp1 + (temp2 - temp1) * (fTwoThirds - temp3) * 6.0f;

            if (temp3Times6.R < 1.0f)
                color.R = firstEquation.R;
            else if (temp3Times2.R < 1.0f)
                color.R = temp2;
            else if (temp3Times1point5.R < 1.0f)
                color.R = secondEquation.R;
            else
                color.R = temp1;

            if (temp3Times6.G < 1.0f)
                color.G = firstEquation.G;
            else if (temp3Times2.G < 1.0f)
                color.G = temp2;
            else if (temp3Times1point5.G < 1.0f)
                color.G = secondEquation.G;
            else
                color.G = temp1;

            if (temp3Times6.B < 1.0f)
                color.B = firstEquation.B;
            else if (temp3Times2.B < 1.0f)
                color.B = temp2;
            else if (temp3Times1point5.B < 1.0f)
                color.B = secondEquation.B;
            else
                color.B = temp1;

            return color;
        }



        Float3 ManipulateHSL(in Float3 HSL, float4 palette)
        {
            HSL = ExpandHSL(HSL);
            HSL = AdjustLightness(HSL, palette.z, palette.w);
            HSL = OffsetHSL(HSL.rgb, palette.x, palette.y);
            return HSL;
        }

        float ManipulateAO(in float ao, float brightness, float contrast)
        {
            brightness += 1;
            //brightness + ((1 - brightness) * HSL.;
            float ret = ao * (brightness + (1 - brightness) * ao);
            return saturate(ret);
        }


        void HuePixel(
    in float4 diffuseMapValue,
            in float4 specularMapValue,
            float4 paletteMaskMapValue,
            float4 paletteMapValue,
            out Float3 fragmentDiffuseColor,
            out float4 fragmentSpecularColor
            )
        {
            fragmentDiffuseColor = diffuseMapValue.rgb;
            fragmentSpecularColor = specularMapValue;

            float paletteMaskSum = paletteMaskMapValue.x + paletteMaskMapValue.y;


            // Only use the palette that applies
            float4 palette;
            Float3 chosenSpecColor, chosenMetallicSpecColor;

            if (paletteMaskMapValue.x < paletteMaskMapValue.y)
            {
                palette = palette2;
                chosenSpecColor = palette2Specular.rgb;
                chosenMetallicSpecColor = palette2MetallicSpecular.rgb;
            }
            else
            {
                palette = palette1;
                chosenSpecColor = palette1Specular.rgb;
                chosenMetallicSpecColor = palette1MetallicSpecular.rgb;
            }

            // Get the palette map, apply the deltas, and convert it to RGB
            Float3 HSL = ManipulateHSL(new Float3(paletteMapValue.g, paletteMapValue.b, paletteMapValue.a), palette);
            float ambientOcclusion = ManipulateAO(paletteMapValue.r, palette.z, palette.w);
            HSL.z *= ambientOcclusion;
            Float3 RGB = ConvertHSLToRGB(HSL);

            //Blend the result into the original diffuse
            fragmentDiffuseColor = lerp(diffuseMapValue.rgb, RGB.rgb, paletteMaskSum);

            // Determine the hue specular color
            Float3 hueSpecColor;
            const Float3 white = new Float3(1, 1, 1);
            float metallicMask = paletteMaskMapValue.b;
            //1.0 uses chosenMetallicSpecColor, .5 uses white, 0.0 uses chosenSpecColor      
            if (metallicMask > .5)
            {
                hueSpecColor = lerp(white, chosenMetallicSpecColor, (metallicMask - 0.5) * 2);
            }
            else
            {
                hueSpecColor = lerp(chosenSpecColor, white, metallicMask * 2);
            }
            hueSpecColor *= specularMapValue.r;
            fragmentSpecularColor.rgb = lerp(fragmentSpecularColor.rgb, hueSpecColor, paletteMaskSum);

        }
    }
}

 

Great work! And please do not give up, this plugin is not just for me, there's a community of people who would really like this plugin as well.

Thank you for doing this.

Edited by Nengalore
Link to comment
Share on other sites

I've found some relevant information on using HLSL in .NET via WPF. I look into it in the coming days when I have some time.

 

http://mrpfister.com/journal/writing-hlsl-pixel-shaders-for-wpf/

https://msdn.microsoft.com/en-us/library/system.windows.media.effects.pixelshader%28v=vs.110%29.aspx

(September 25th, 2023)  Sorry about any broken images in my posts. I am aware of the issue.

bp-sig.png
My Gallery  |  My Plugin Pack

Layman's Guide to CodeLab

Link to comment
Share on other sites

  • 4 weeks later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...