MJW Posted July 30, 2017 Share Posted July 30, 2017 This is a CodeLab port of @harold's NormalMapPlus plugin. It's functionally identical, except for some fixes, the slider controls having an extra decimal place (due to the way CodeLab works), and the addition of a brief Help menu. Though the code is functionally the same, it was somewhat rewritten. It's in the Stylize submenu. The fixes are: 1) The ROI boundary pixels are handled correctly. 2) The normals are computed at the correct positions, rather than being shifted one pixel left. 3) The JIT compiler optimization crash doesn't occur. (The crash is almost certainly not due to a bug in the original plugin code, and will probably be fixed in the JIT compiler soon.) Here is the DLL (Version 1.4): NormalMapPlus.zip Here is the code: Spoiler // Name: NormalMapPlus // Submenu: Stylize // Author: harold, Simon Brown, MJW // Title: NormalMapPlus // Version: 1.4 // Desc: CodeLab port of NormalMapPlus // Keywords: normal map // URL: https://forums.getpaint.net/index.php?/topic/17010-normalmapplus-v10/ // Help: #region UICode DoubleSliderControl Amount1 = 0.3; // [0,1] X DoubleSliderControl Amount2 = 0.5; // [0,1] Y DoubleSliderControl Amount3 = 0.11; // [0,1] Z #endregion void Render(Surface dst, Surface src, Rectangle rect) { // Delete any of these lines you don't need Rectangle selection = EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt(); int top = rect.Top, bottom = rect.Bottom, left = rect.Left, right = rect.Right; float lightX = (float)Amount1; float lightY = (float)Amount2; float lightZ = (float)Amount3; Float4 lightDir = new Float4(lightX, lightY, lightZ, 0.0f); if (IsCancelRequested) return; // Handle the boundary conditions. int prevY = (top == 0) ? top : top - 1; int leftPrevX = (left == 0) ? left : left - 1; int srcMaxY = src.Height - 1; int srcMaxX = src.Width - 1; for (int y = top; y < bottom; y++) { int nextY = (y != srcMaxY) ? y + 1 : y; Float4 UL = (Float4)src[leftPrevX, prevY]; Float4 UM = (Float4)src[left, prevY]; Float4 ML = (Float4)src[leftPrevX, y]; Float4 MM = (Float4)src[left, y]; Float4 LL = (Float4)src[leftPrevX, nextY]; Float4 LM = (Float4)src[left, nextY]; for (int x = left; x < right; x++) { // Get the rightward height values. int nextX = (x != srcMaxX) ? x + 1 : x; Float4 UR = (Float4)src[nextX, prevY]; Float4 MR = (Float4)src[nextX, y]; Float4 LR = (Float4)src[nextX, nextY]; Float4 dx = (UL - UR) + 2.0f * (ML - MR) + (LL - LR); Float4 dy = (UL - LL) + 2.0f * (UM - LM) + (UR - LR); float u = Float4.Dot(dx, lightDir); float v = Float4.Dot(dy, lightDir); Float4 normal = new Float4(u, v, 1.0f, 0.0f); normal.Normalize(); normal = 0.5f * normal + 0.5f; normal.W = 1.0f; dst[x, y] = (ColorBgra)normal; // Shift the height values left. UL = UM; UM = UR; ML = MM; MM = MR; LL = LM; LM = LR; } prevY = y; } } public struct Float4 { public float A; public float R; public float G; public float B; public float X { get { return this.R; } set { this.R = value; } } public float Y { get { return this.G; } set { this.G = value; } } public float Z { get { return this.B; } set { this.B = value; } } public float W { get { return this.A; } set { this.A = value; } } public static explicit operator ColorBgra(Float4 c) { return ColorBgra.FromBgra((byte)(255f * c.B), (byte)(255f * c.G), (byte)(255f * c.R), (byte)(255f * c.A)); } public static explicit operator Float4(ColorBgra c) { return FromBgra(((float)c.B) / 255f, ((float)c.G) / 255f, ((float)c.R) / 255f, ((float)c.A) / 255f); } public static Float4 operator +(Float4 c, float s) { c.A += s; c.R += s; c.G += s; c.B += s; return c; } public static Float4 operator *(Float4 c, float s) { c.A *= s; c.R *= s; c.G *= s; c.B *= s; return c; } public static Float4 operator *(float s, Float4 c) { c.A *= s; c.R *= s; c.G *= s; c.B *= s; return c; } public static Float4 operator +(Float4 c0, Float4 c1) { c0.A += c1.A; c0.R += c1.R; c0.G += c1.G; c0.B += c1.B; return c0; } public static float Dot(Float4 c0, Float4 c1) { return ((((c0.A * c1.A) + (c0.R * c1.R)) + (c0.G * c1.G)) + (c0.B * c1.B)); } public static Float4 operator -(Float4 c0, Float4 c1) { c0.A -= c1.A; c0.R -= c1.R; c0.G -= c1.G; c0.B -= c1.B; return c0; } public void Normalize() { float num = 1f / ((float)Math.Sqrt((double)((((this.A * this.A) + (this.R * this.R)) + (this.G * this.G)) + (this.B * this.B)))); this = (Float4)(this * num); } public Float4(float x, float y, float z, float w) { this.A = w; this.R = x; this.G = y; this.B = z; } public static Float4 FromBgra(float b, float g, float r, float a) { Float4 num = new Float4(); num.A = a; num.R = r; num.G = g; num.B = b; return num; } } EDIT 01 AUG 1017: Moved to Stylize window. Changed version to 1.4. 1 6 Quote Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted August 2, 2017 Share Posted August 2, 2017 Thanks for the update MJW! And a special thanks for uploading the source What, no submenu? There are many to choose from... Effects > Stylize (Simon's version was in this submenu) Effects > The Normal Tools (gOUJOSAMMA's Normal Tools) I'd even prefer Effects > Advanced over leaving this in Effects > 1 Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
MJW Posted August 2, 2017 Author Share Posted August 2, 2017 I agree it should be in a submenu. I incorrectly thought the original wasn't, and was just trying to preserve that. I'll probably put in in Stylize. I hope to create a version that also supports 24-bit height maps, and put that in my Height Map submenu. I'll create a new submenu-ed version in a day or so. (As far as Advanced, I know others disagree, but I think that submenu should be reserved for "meta" plugins such as CodeLab and ScriptLab.) 1 Quote Link to comment Share on other sites More sharing options...
MJW Posted August 2, 2017 Author Share Posted August 2, 2017 'Tis done. The plugin is now in the Stylize submenu. 2 Quote Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted August 2, 2017 Share Posted August 2, 2017 Thank you. I'll flag that change for the next Plugin Index. 1 Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
VolvobmT24 Posted March 13, 2018 Share Posted March 13, 2018 hi i have tried to get this plugin to work but im only getting an error when i try to use the plugin, first i found a very old version, some way google thinks an article that are over 4 years old should be in the top, tried that version but that was many errors then i found this now but it still wont work, maybe im are doing it wrong but i have redone it several times as i was instructed to install it., this is my error log, strangely i have my language set to English but it still writes some words on Swedish, File: C:\Program Files\Paint.NET\Effects\NormalMapPlus.dll Name: NormalMapPlusEffect.NormalMapPlusEffectPlugin Version: 1.4.6422.43071 Author: Copyright © harold, Simon Brown, MJW Copyright: CodeLab port of NormalMapPlus Website: https://forums.getpaint.net/index.php?/topic/17010-normalmapplus-v10/ Full error message: System.TypeLoadException: Det gick inte att läsa in typen PaintDotNet.IndirectUI.WindowHelpContentType från sammansättningen PaintDotNet.Core, Version=4.5.5454.39504, Culture=neutral, PublicKeyToken=null. vid NormalMapPlusEffect.NormalMapPlusEffectPlugin.OnCustomizeConfigUIWindowProperties(PropertyCollection props) vid PaintDotNet.Effects.PropertyBasedEffect.CreateConfigDialog() i d:\src\pdn\paintdotnet\src\Effects\PropertyBasedEffect.cs:rad 86 vid PaintDotNet.Menus.EffectMenuBase.RunEffectImpl(Type effectType) i d:\src\pdn\paintdotnet\src\PaintDotNet\Menus\EffectMenuBase.cs:rad 910 if i dont restart paint when prompted to do it then it looks like it maybe are working but then when i try to use it i gives one bigger error log File: C:\Program Files\Paint.NET\Effects\NormalMapPlus.dll Name: NormalMapPlusEffect.NormalMapPlusEffectPlugin Version: 1.4.6422.43071 Author: Copyright © harold, Simon Brown, MJW Copyright: CodeLab port of NormalMapPlus Website: https://forums.getpaint.net/index.php?/topic/17010-normalmapplus-v10/ Full error message: PaintDotNet.WorkerThreadException: Worker thread threw an exception ---> System.NullReferenceException: Objektreferensen har inte angetts till en instans av ett objekt. vid NormalMapPlusEffect.NormalMapPlusEffectPlugin.OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs) vid PaintDotNet.Effects.Effect`1.OnSetRenderInfo(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs) i d:\src\pdn\paintdotnet\src\Effects\Effect`1.cs:rad 67 vid PaintDotNet.Effects.BackgroundEffectRenderer.ThreadFunction() i d:\src\pdn\paintdotnet\src\PaintDotNet\Effects\BackgroundEffectRenderer.cs:rad 218 --- Slut på stackspårning för interna undantag --- vid PaintDotNet.Effects.BackgroundEffectRenderer.DrainExceptions() i d:\src\pdn\paintdotnet\src\PaintDotNet\Effects\BackgroundEffectRenderer.cs:rad 431 vid PaintDotNet.Menus.EffectMenuBase.DoEffect(Effect effect, EffectConfigToken token, PdnRegion selectedRegion, PdnRegion regionToRender, IRenderer`1 clipMaskRenderer, Surface originalSurface, Exception& exception) i d:\src\pdn\paintdotnet\src\PaintDotNet\Menus\EffectMenuBase.cs:rad 1527 Quote Link to comment Share on other sites More sharing options...
VolvobmT24 Posted March 13, 2018 Share Posted March 13, 2018 so sorry i had missed a program needed for it to work, it was not mentioned in the first post i did read that codelab was needed, tried it for another program and now this work sorry to bother you this program now works like i had hoped so big thanks for this pluging anyway , tried to delete my first post but dont know how to do it Quote Link to comment Share on other sites More sharing options...
MJW Posted March 13, 2018 Author Share Posted March 13, 2018 @VolvobmT24, CodeLab isn't needed to make the plugin work. You can just download and unzip the DLL. I included the code, so if someone wants to, they can paste it into CodeLab and build the plugin, but that's not what most people would do. I think you need to use a newer version of Paint.Net. Quote Link to comment Share on other sites More sharing options...
Hypure Posted May 27, 2020 Share Posted May 27, 2020 Cool! just what I was looking for. Quote Link to comment Share on other sites More sharing options...
LoudSilence Posted September 22, 2020 Share Posted September 22, 2020 I put the dll in effects but its not there..?? Quote PDN Discord Server Link to comment Share on other sites More sharing options...
ReMake Posted September 22, 2020 Share Posted September 22, 2020 See above Quote Link to comment Share on other sites More sharing options...
toe_head2001 Posted September 22, 2020 Share Posted September 22, 2020 @LoudSilence, you've made a few of these 'plugin installation issue' posts. You should know the troubleshooting steps by now. You are turning into The Boy Who Cried Wolf, and it's obnoxious. 3 Quote (September 25th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
ReMake Posted September 22, 2020 Share Posted September 22, 2020 9 minutes ago, toe_head2001 said: ... The Boy Who Cried Wolf ... I just found out what it means. Subtly noted. Sorry for off topic. Quote Link to comment Share on other sites More sharing options...
YoJeff Posted November 10, 2020 Share Posted November 10, 2020 I am trying to use this tool for textures for Fallout 3. The "3D effect" seems all right, but the suit is too glossy. Do the X, Y and Z parameters refer to something specific? (Height, transparency, ...) Thanks! Quote Link to comment Share on other sites More sharing options...
MJW Posted November 10, 2020 Author Share Posted November 10, 2020 (Keep in mind I only ported some existing code, so I take no responsibility for the philosophy behind it.) The X, Y, Z values are really just RGB weights used to convert a color image to an intensity image. The intensity image is what's used to as the height map, for which the partial derivatives in each direction are computed. The default values for the weights are (0.3, 0.5, 0.11), which are sort of close to the usual color-to-intensity weights, giving most weight to green and least to blue. EDIT: I should mention that the way the code is written, along with the names of the variables, makes me question whether the original author fully understood that's what he was doing. Specifically, the differences used to approximate the differentials are computed first, then the weights applied. However, the results are the same. 1 Quote Link to comment Share on other sites More sharing options...
null54 Posted November 10, 2020 Share Posted November 10, 2020 2 hours ago, YoJeff said: I am trying to use this tool for textures for Fallout 3. The "3D effect" seems all right, but the suit is too glossy. Many games use the alpha channel to control glossiness (specularity) of a normal map. Quote Plugin Pack | PSFilterPdn | Content Aware Fill | G'MIC | Paint Shop Pro Filetype | RAW Filetype | WebP Filetype The small increase in performance you get coding in C++ over C# is hardly enough to offset the headache of coding in the C++ language. ~BoltBait Link to comment Share on other sites More sharing options...
MJW Posted November 10, 2020 Author Share Posted November 10, 2020 27 minutes ago, null54 said: Many games use the alpha channel to control glossiness (specularity) of a normal map. It appears to me that this plugin completely ignores the alpha channel. In the computations, it uses a zero weight for W (which is alpha), then in the end, sets it to 1.0, which gets re-scaled to 255 upon conversion to ColorBgra. As far as I can see, no matter what alpha is in the original image, it ignores it, and replaces it by 255 in the final image. (Keep in mind I'm merely looking at the code, so perhaps I'm missing something.) It would be easy to add the option of preserving alpha, if that would be useful. Quote Link to comment Share on other sites More sharing options...
YoJeff Posted November 12, 2020 Share Posted November 12, 2020 Thanks for the answers. I found another plugin on the Skyrim Nexus. The initial texture files in Fallout 3 have an alpha of 255, so preserving the alpha wouldn't change anything (in my case). Quote Link to comment Share on other sites More sharing options...
Punk'n Posted January 21, 2021 Share Posted January 21, 2021 On 11/10/2020 at 10:56 PM, null54 said: Many games use the alpha channel to control glossiness (specularity) of a normal map. Adjust the specular color in the BSLightingShader with Nifskope. It's a quick-fix for that problem and depending on the material that I'm adjusting the shine on, depends on how dark I adjust the color. Wood --- especially aged/damaged --- I often change it to charcoal or black. I adjusted the specular color to black and the strength from 81.0000 to 20.0000 which gave me the results seen above... Hope that helps. (Skyrim modder lol) For my textures I rely heavily on this plugin and Normalizer for sure! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.