Shaders GLSL - Shading Diamonds/Gemstones

Z

Zaid

Guest
ruby_shimmer.png

I'm looking to implement a shader to simulate the light reflection of a gemstone (like the one above) onto a normal-mapped sprite so that it gets a shimmer like in real gemstones.
Currently I've been following this tutorial to get really simple normal mapped lighting and then setting the ambient lighting to pure white light to get an additive effect to add some kind of incandescence type thing to my sprites. My shader code is practically identical to the code in that article. Here's a picture of what I've got so far:

example.png
On the left is the sprite with the current shading, on the right is the normal sprite itself.

Obviously, it's not great at all but I'm unsure how to proceed to get more of the semi-translucent, glittery surface effect like in actual gemstones. This is the closest thing I've been able to find on google about what I'm looking for. But trying out the implementation myself creates just black spots all over the sprites. And everything else I've found on Google has been weird Blender tutorials. Perhaps I just need to play with the normal maps more to give it more hard edges on the surface of the sprite, but I haven't been able to find a way to get it looking right without weird dark spots.

If anyone has a full solution, it would be greatly appreciated but really I'm only looking for a push in the right direction. Maybe the correct search query or link to an article that explains what I'm looking to achieve. Anything to get me going again because right now I'm stuck with what I should be looking for / trying out.
 

sylvain_l

Member
my first concern is scale.

silly question, what happens to your highres gemstone example if you rescale it to the same size as your pixelated one?

pixelating can means blurring details. And at the scale you are (~15px) I'm not even sure you could render a good shimering on a static gem sprite. because at that level of detail the difference between a spherical or faceted gem is slim. (this is also valid for the normal map if you use the same scale for it)

2nd concern
In theory (for my poor knowledge of it) if you can draw the endresult you are looking for; with your starting sprites(&normal map) you could try to rebuild the matrixes needed by your shader...
problem you wouldn't have a perfect solution so you'll need to look for an approximate that would make the algebra hellish!



honestly you could try the other way around; much higher res for your sprite and normal map; do the shadering and scale it down. (but I fear the endreslult would still be meh at 15px scale)
 
Z

Zaid

Guest
Well the top high res example isn't anything I made, it's a picture of a (supposedly) real ruby I just pulled off of Google images to serve as an example of what I'm talking about. I'm not entirely concerned about the finer details as much as I am having surfaces on the gem being partially/entirely white from the light hitting it at certain angles.

I tried to draw a picture to help me explain better:
blah.png

So this is another gem sprite I have kind of shaped like a turtle shell. At the top it shows the original sprite and how it needs to be split up into 9 different surfaces. Then at the bottom, it shows a really rough doodle of what the normals of those 9 surfaces should look like (on the left) and then gives two examples of how the shading should work based on the positioning of the light. For example, if it's hitting the gem from the top than that top surface should be entirely whited out and the surface to the left and right of it should be partially illuminated uniformly (no gradients). Sort of like in the real cut ruby example I posted in the original post.

The normal maps are the same size as the sprites themselves (16x16) but I just can't seem to achieve this effect. The more I looked into it, refraction and dispersion isn't necessary at all, especially since I'm only lighting up surfaces to give it the glimmer effect. The sprites are not transparent at all.
 

sp202

Member
I think you're looking for specular reflection highlights. Fairly easy to do in 3D with a light source and lighting shader, shouldn't be too difficult to adapt it to 2D with a normal map.
 
Last edited:

sylvain_l

Member
I think you're looking for speculation reflection. Fairly easy to do in 3D with a light source and lighting shader, shouldn't be too difficult to adapt it to 2D with a normal map.
IDK, I think in 2D a simple normal map isn't enough.
What give a gem or diamond that particular lightning/shimmering effect is the reflexion AND refraction and the specular/diffraction of the light bouncing multiple times inside the gem. (in 3D you just do the optic math and you got it)
In 2D a single normal map give you mostly a way to do the first reflexion part, which will give the blend mirror effect he already got in the OP example. Perhaps a 2nd normal map could be used to fake the bouncing effect from inside the gem.
 

GMWolf

aka fel666
If you want that specular highlight then a normal map should work fine.
You could use something like the specular component of the blinn-phong shading model.
 
Z

Zaid

Guest
Untitled.png
I tried simplifying the sprite to see if it makes the lighting effect sharper and it worked to a certain extent but there's still a lot to be desired. This is the best results I've gotten so far using specular lighting on a single normal map. Also the simpler sprite (on the left) just looks so gosh awful without any lighting whatsoever. Plus I can never seem to get a surface to entirely white out like you see in the example picture of the real gemstone in the original post. Even if I mess with the falloff settings, best I can get is the green in the sprite turning into a gross bright yellow. (That's with the ambient a light colors being both pure white, of course.)

Perhaps a 2nd normal map could be used to fake the bouncing effect from inside the gem.
Now there's an idea... I'll have to try this out! I wonder what the normal map will have to look like though, I doubt a mirror/flip on the original normal map will prove any good.
 
L

Lycanphoenix

Guest
Probably a bit late to the party, and I might be going about this completely the wrong way, but...
What about using a Signed Distance Field or a simple polygonal mesh to calculate the specular lighting? You could possibly also layer multiple sprites to implement a pseudo-voxel sort of approach.
 

rytan451

Member
best I can get is the green in the sprite turning into a gross bright yellow.
It seems like you're multiplying the channels by the light intensity, and your blue channel is zero. Perhaps, instead, after calculating your lighting:

GML:
gl_FragColor = Matrix4(
    0.9, 0.05, 0.05, 0,
    0.05, 0.9, 0.05, 0,
    0.05, 0.05, 0.9, 0,
    0.0,  0.0,  0.0, 1.0
) * gl_FragColor;
This will desaturate your sprites a bit, but it will also make it such that a bright enough light will make the highlights white.

Or, perhaps, set the fragment to be white if it's sufficiently close to the correct angle for the light to reflect to the camera.
 
L

Lycanphoenix

Guest
That sounds like it could work quite well.

While this won't make actually implementing the original poster's intended effect any easier, if you wish to extend the effect itself even further, then... I think you could probably add to that with an ambient "glow" effect (a translucent, bloom-like overlay) when it's reflecting a lot of light, based on the color of the reflected light and the shape of the surface reflecting said light. There are functions on itch.io for drawing sprites with outlines and color overlays pretty easily which may help here.

Just a thought.
 
Top