4
\$\begingroup\$

I'm writing a program that creates animated blobs in 2D, to simulate cells. In order to beautify these objects, I'd like to give them a 3D look by adding a bevel-effect. How can this be achieved?

Program as it looks now (the blobs are animated, move, change shape etc):

Capture of the program in action

And this could be a potential desired outcome:

Program output after desired filter is created

I underscore that I'm not using anything else than GDI+, so I'll have to write the implementation myself. Virtually every graphics program has some kind of beveling filter, but I've looked high and low online to find examples of such code.

Edit:

I was testing a few theories, and this one could work. However, it's not my most optimal solution (even though Gaussian blurs can be made linear using separable kernels) and I have another in the working. Anyway, this could be a first attempt at a fast beveling algorithm:

One possible way to solve the bevel challenge

The result in the picture I created above is the direct outcome of the steps of the algorithm, but I suspect it might run too slow for 25fps.

\$\endgroup\$
  • 1
    \$\begingroup\$ Are you generating these shapes yourself algorithmically? The trick to a good bezel is a good algorithm that generates a larger version of your graphic. But not scaled up. Ideally, you'd just "outset" the shape, which will change its proportions. If you're generating these blobs yourself, as pixels, just draw each pixel as 9 pixels and you have the perfect 1-pixel-outset for the next-larger shape in the algorithm in my answer. \$\endgroup\$ – uliwitness Dec 3 '14 at 9:33
  • \$\begingroup\$ Programatically. See image. \$\endgroup\$ – Pedery Dec 4 '14 at 7:44
4
\$\begingroup\$

What shapes are you using? If your shapes are convex (like circles, squares, rounded rectangles), you can just draw versions of different size and clip them to a triangle whose diagonal goes from upper right to lower left.

I.e., zoomed in, light-to-dark:

light-to-dark version

and dark-to-light:

enter image description here

Then clip that:

clipped upper left

And then combine the two bezels:

two halves combined

and finally draw the original shape on top:

final product, still zoomed in

Now this example is rough and too coarse, but if each of the three rounded rectangles only is visible as a one pixel outline, this will look like a gradient from light to dark in the upper left, and in the opposite direction in the lower right.

Note that in this example the colors are too different, so you can see the various parts. Basically you should take the inner shape's color (in this case white) and lighten it 3 times for the transition to upper left, and darken it for the transition to lower right. The final effect you're going for (again, zoomed in) is something like:

A properly-colored 3-pixel bevel

In theory you could just use one larger shape, clip it, and fill it with a gradient, for each half, but it's quite difficult to get the gradients to line up properly for non-square shapes. Also, this doesn't work for concave shapes (like the letter "C"). The trick to a good bezel is a good algorithm for generating that larger version of your shape. But not scaled up. Ideally, you'd just "outset" the shape, which will change its proportions. If you're generating the shapes yourself, as pixels, just draw each pixel as 9 pixels and you have the perfect 1-pixel-outset for the next-larger shape in the algorithm in my answer.

Update: Another approach would be to first render your shape into a bitmap, and then loop over the pixels. If you find a pixel that is "on", check its surrounding pixels. If it has empty pixels below it or to its right, darken it. If it has empty pixels to its left or above it, lighten it. That would give a proper 1px bezel that lies inside the shape. You could then repeatedly apply this algorithm by mixing the light/dark colors with a percentage of your shape's color, and by looking for pixels you darkened/lightened in the previous iteration instead of transparent pixels. This is probably something that wouldn't be too fast until you manage to implement it e.g. as a shader on the graphics card.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the elaborate suggestion. My shapes are arbitrary, see uploaded image. I do generate them algorithmically though, so I have good control over that part. My idea was rather to give them a nice raised effect, hopefully a bit similar to a gel-like outline. The bevel algorithm should be pretty common so it blows my mind that it's so hard to find... \$\endgroup\$ – Pedery Dec 3 '14 at 11:19
  • \$\begingroup\$ @Pedery I do not see an uploaded image ... ? \$\endgroup\$ – uliwitness Dec 3 '14 at 11:19
  • \$\begingroup\$ @Pedery If you're looking for a "gum drop"-like effect like Mac OS X 10.0 buttons ("Aqua buttons") have it, that's not too hard. Essentially it's a top-to-bottom gradient, and then a second shorter top-to-bottom gradient that is clipped to your shape and the bottom half of an ellipsis that's a bit wider than your shape. There are millions of tutorials for this effect for Photoshop out there which shouldn't be hard to translate to an algorithm. \$\endgroup\$ – uliwitness Dec 3 '14 at 11:23
  • \$\begingroup\$ @Pedery another simple effect would probably be a radial gradient fill, or just doing what I describe above, but instead of making the shape larger, making it smaller. \$\endgroup\$ – uliwitness Dec 3 '14 at 11:25
  • \$\begingroup\$ @Pedery Ah, you added the image. Yeah, either variant of the effect should work with these if you can properly inset/outset the shape, otherwise try the Aqua button effect. \$\endgroup\$ – uliwitness Dec 3 '14 at 11:26
0
\$\begingroup\$

You could get a bevel effect by underlaying the cells with upscaled graduated transparencies of themselves. This can also be used to get a glow effect.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.