Jump to content
How to Install Plugins ×

Object Reflections Plugin - Wet Floor Effect


BoltBait

Recommended Posts

Compiled DLL (Thanks to MadJik): <!-- m -->http://jcljay.free.fr/pdn/ReflectionFlat.zip<!-- m -->

I need to make some graphics with reflections similar to the following:

ReflectResults.jpg

What a pain! Well, really only the one on the right turned out to be a pain.

Anyway, I tinkered around in code lab and wrote the following codelab script: (This is the updated script)

void Render(Surface dst, Surface src, Rectangle rect)
{
    int depth = 100;    // maximum distance of the reflection
    int MaxAlpha = 128; // darkest reflection (255-0, default 128)
    int ignore = 0;     // bottom pixels of object to ignore

    PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds);
    Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();
    ColorBgra CurrentPixel;
    for(int y = rect.Top; y < rect.Bottom; y++)
    {
        for (int x = rect.Left; x < rect.Right; x++)
        {
            if (selectionRegion.IsVisible(x, y))
            {
                CurrentPixel = src[x,y]; // Get the current pixel
                if (CurrentPixel.A == 0) // is it transparent?
                {
                    int y1=0;
                    int yd=0;
                    for (y1=y; y1 > 0; y1--)
                    {
                        if ((y1 != selection.Top) && (src[x,y1].A == 0))
                        {
                            yd++;
                        }
                        else
                        {
                            break;
                        }
                    }
                    if (y1+1-yd-ignore >= 0)
                    {
                        CurrentPixel=src[x,y1+1-yd-ignore];
                        if (CurrentPixel.A > 0)
                           if (yd<depth)
                           {
                               // fade the reflection out
                               CurrentPixel.A = (byte)(((double)MaxAlpha/depth)*(depth-yd)*CurrentPixel.A/255);
                           }
                           else
                           {
                               CurrentPixel.A = 0; // totally faded at this point
                           }
                    }
                }
                dst[x,y] = CurrentPixel;
            }
        }
    }
} 

Instructions for use:

1) Create a new layer that is totally transparent.

2) On that layer, place the object that you want to make a reflection for.

3) Select the area where you want the reflection to show.

4) Run the codelab script:

Reflect1.jpg

Sometimes you will want to ignore the bottom of the object like in this example:

Reflect2.jpg

5) Notice how the bottom of the yellow box is showing in the reflection. Just increase the Ignore value to get rid of that. Here it is shown with an Ignore value of 3:

Reflect3.jpg

You'll need to tinker with the depth and MaxAlpha variables to get something workable.

Thanks, MadJik for putting a UI on this one!

Link to comment
Share on other sites

Hmm. Looks like you're mangling alpha values.

CurrentPixel.A = (byte)((MaxAlpha/depth)*(depth-yd));

It's not taking into account the value of CurrentPixel.A. Perhaps if you multiply the right side of the assignment expression by CurrentPixel.A, then divide by 255, then cast to byte, it will be correct.

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

Hmm. Looks like you're mangling alpha values.

Yeah, thanks. I hadn't even thought about that. I only spent about 1/2 hour on this so I knew it would have problems.

The refection is kinda not anti-aliased... maybe because of the alpha values?

Yeah, that's what Rick said. ;)

Hey! I told you it was rough. :D

Just looking at it, I see there is another bug in there too:

if ((y1 == rect.Top) || (src[x,y1].A == 0))

should be:

if ((y1 != selection.Top) && (src[x,y1].A == 0))

I keep forgetting to use selection instead of rect. :D

And then, of course, I need to add the following at the top of the function:

Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt(); 

That will cause the reflection to start at the top of the selection if the selection does not have any non-transparent pixels in it. This eliminates the need to draw a line under text and other odd shapes that I said before. That was my original intent, but I couldn't figure out why it wasn't working. :D

OK, so here's the updated code. The effect is starting to look pretty good...

void Render(Surface dst, Surface src, Rectangle rect) 
{ 
   int depth = 100;    // maximum distance of the reflection 
   int MaxAlpha = 128; // darkest reflection (255-0, default 128) 

   PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds); 
   Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt(); 
   ColorBgra CurrentPixel; 
   for(int y = rect.Top; y     { 
       for (int x = rect.Left; x         { 
           if (selectionRegion.IsVisible(x, y)) 
           { 
               CurrentPixel = src[x,y]; // Get the current pixel 
               if (CurrentPixel.A == 0) // is it transparent? 
               { 
                   int y1=0; 
                   int yd=0; 
                   for (y1=y; y1 > 0; y1--) 
                   { 
                       if ((y1 != selection.Top) && (src[x,y1].A == 0)) 
                       { 
                           yd++; 
                       } 
                       else 
                       { 
                           break; 
                       } 
                   } 
                   if (y1+1-yd >= 0) 
                   { 
                       CurrentPixel=src[x,y1+1-yd];  // look in the mirror 
                       if (CurrentPixel.A > 0) 
                          if (yd                           { 
                              // fade the reflection out 
                              CurrentPixel.A = (byte)((MaxAlpha/depth)*(depth-yd)*CurrentPixel.A/255); 
                          } 
                          else 
                          { 
                              // totally faded at this point 
                              CurrentPixel.A = 0; 
                          } 
                   } 
               } 
               dst[x,y] = CurrentPixel; 
           } 
       } 
   } 
}

DO NOT USE THIS SCRIPT, IT HAS BEEN UPDATED BELOW.

Well, I think one thing left to do is to be able to specify an amount of pixels to ignore before starting the reflection. I'll add that capability on Monday. Then I'll ask Illnab1024 to put a UI on it--that is, if you all think its worth it. Let me know.

Link to comment
Share on other sites

Well, I think one thing left to do is to be able to specify an amount of pixels to ignore before starting the reflection. I'll add that capability on Monday. Then I'll ask Illnab1024 to put a UI on it--that is, if you all think its worth it. Let me know.

OK, that was easy...

void Render(Surface dst, Surface src, Rectangle rect) 
{ 
   int depth = 100;    // maximum distance of the reflection 
   int MaxAlpha = 128; // darkest reflection (255-0, default 128) 
   int ignore = 0;     // bottom pixels of object to ignore

   PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds); 
   Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt(); 
   ColorBgra CurrentPixel; 
   for(int y = rect.Top; y     { 
       for (int x = rect.Left; x         { 
           if (selectionRegion.IsVisible(x, y)) 
           { 
               CurrentPixel = src[x,y]; // Get the current pixel 
               if (CurrentPixel.A == 0) // is it transparent? 
               { 
                   int y1=0; 
                   int yd=0; 
                   for (y1=y; y1 > 0; y1--) 
                   { 
                       if ((y1 != selection.Top) && (src[x,y1].A == 0)) 
                       { 
                           yd++; 
                       } 
                       else 
                       { 
                           break; 
                       } 
                   } 
                   if (y1+1-yd-ignore >= 0) 
                   { 
                       CurrentPixel=src[x,y1+1-yd-ignore];
                       if (CurrentPixel.A > 0) 
                          if (yd                           { 
                              // fade the reflection out 
                              CurrentPixel.A = (byte)((MaxAlpha/depth)*(depth-yd)*CurrentPixel.A/255); 
                          } 
                          else 
                          { 
                              CurrentPixel.A = 0; // totally faded at this point
                          } 
                   } 
               } 
               dst[x,y] = CurrentPixel; 
           } 
       } 
   } 
}

DON'T USE THIS AS THERE IS A BUG IN IT. USE THE ONE IN MY ORIGINAL POST.

Well, I'm done playing with this.

OK, screenshots have been updated (not on this thread though, sorry). Go here for the whole story:

http://boltbait.googlepages.com/reflections

Enjoy. 8)

Link to comment
Share on other sites

It was updated...BAH!

Trust me, the original did.

That actually may be possible. The original script I wrote was not treating alpha values properly.

After Rick pointed that out, I updated the script and published the results on my googlepages. However, I never went back here and updated the screenshots.

Well, today I updated the screenshots on this thread.

Link to comment
Share on other sites

  • 2 weeks later...
:shock: Hey! How did you make the "" effect waves "" ? :shock:

I used the codelab Warp.cs (provided with codelab plugin).

void Render(Surface dst, Surface src, Rectangle rect)
{ 
   float Radius = 2.0f; // Wave Radius
   float XCoef = 0.8f;  // X divider
   float YCoef = 0.3f;  // Y divider

       for(int y = rect.Top; y < rect.Bottom; y++)
   {
       for (int x = rect.Left; x < rect.Right; x++)
       {
           dst[x, y] = src.GetBilinearSample(
x+ Radius  * (float)(
                   Math.Sin((x + y / YCoef ) / (YCoef * 10))-
                   Math.Cos((y - x / XCoef) / (XCoef * 10))),
y- Radius  * (float)(
                   Math.Sin((x + y / YCoef ) / (YCoef * 10))+
                   Math.Cos((y - x / XCoef ) / (XCoef * 10))),
               true
               );
       }
   } 
}

I changed it in order to play with parameters...

float Radius = 2.0f; // Wave Radius

float XCoef = 0.8f; // X divider

float YCoef = 0.3f; // Y divider

Try it with different values.

Link to comment
Share on other sites

What do you think about having a DLL for that :

Here is it !

I took the Glow Effect source to build this once...

MadJik, could you grab the render function out of my original post on this thread and recompile? There was a bug in it that I fixed tonight.

To see the bug, simply set Depth > MaxAlpha. You will see the reflection disappear. This was due to integer math--I was missing a typecast to Double in the alpha calculation.

Link to comment
Share on other sites

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...