The application is very basic: it renders a quad with two active texture states, which are sampler2D uniforms in the fragment shader. The parameters are all uniforms for simple debugging purposes; although for performance you may not want to do this in practice.

Hmm, when I tested it I thought the effect was a little... subtle? Would it be possible to make it look more bumpy?

Yes, you can set the intensity to a higher value when generating the normal map. You could also lower the lightDir.z for different results -- the higher the value, the more subtle the effect may appear.

A programmatic way of doing the former might look like this in a shader:

And yes it was inspired by a post I saw on /r/gamedev. In terms of performance it should be good; it simply requires one extra texture sample, a little math, and one or two uniforms. The downside is that your sprites need a normal map, so your texture memory will be doubled. Some other ideas for performance:

Use constants instead of uniforms where possible

Use nearest neighbour filtering for textures

If you never use the vertex color, use a custom mesh that only sends {x, y, u, v} to the shader

You could try packing the color and normals into the same texture atlas, but then you would need to send an extra (u, v) texcoord to the shader. Alternatively, you could use half-width texture atlases (e.g. 512x1024) and during initialization pack the color and normals into the same atlas (e.g. 1024x1024); then the normal texcoords would be (u + 0.5, v).

If you really want to save space, you could use a similar technique, but with pure bump instead of normals (i.e. black and white height map). This is closer to the post in /r/gamedev; and you could save the bump as a grayscale PNG and upload it as GL_LUMINANCE. Furthermore, if your color sprites don't need alpha values for some reason, or you have other means of creating alpha, you could store the bump in the sprite sheet's alpha component.

You could also programatically generate normal/bump maps if you were really, really keen to trim down your app size.

There's definitely something weird going on there... Try to set the z-value to 0. Also, no matter where I moved the light, I could not get the leftmost side of the teacup's nozzle (uh, the part where the water comes out from... xD) to become bright.

I think your light direction calculation is really weird. I'd do it like this:

1 2 3 4 5 6 7 8 9 10

uniformvec3lightPos; //3D position, x and y are the pixel coordinates on screen of the light, z is some psuedo-depth value

Reminds me of my English teacher in high school. The best way to prove that someone isn't as good at English as they think is to drag them out in the kitchen, open a drawer and tell them to start talking about those things. That's the kind of stuff you learn from experience, not in school...

But anyway, I thought it was an automatic teapot with a built-in electric pump like we have here in Sweden, in which the spout actually works as a nozzle. Ah, f**k it. Just found out from Wiktionary that the word spout actually comes from Swedish... -_-'

I think you're right that something is off with my light direction. Unfortunately your code does not seem to fix the issue; only makes it all look a little more wonky. Will have to look into it tomorrow...

Note that in my case lightPosition is in eye space. Since my above code assumes that lightPos is the pixel position on screen, you'll have to transform the light position properly on the CPU and upload the transformed position to the lightPos.

Damn, I know how hard it is to get lighting correctly. It's really hard to see when it's right. =S

Ok, after a bit more reading, the issue is:The normal is in tangent space, and the lightPos is not. So eye space wouldn't work, either.

However, if I understand this correctly, my revised code (dividing by resolution) works because the clip space here is the same as tangent space. (Assuming my sprite isn't rotated.)

For some normal maps like the teapot, the lighting only works correctly if I flip the Y value:

1

deltaPos.y = -deltaPos.y;

See the result, which seems more accurate: (attenuation disabled)

The above Y flip does not work with the rock texture, though. See here; the light source is in the bottom right but it appears to be hitting the top left of the rock edges.

Without the Y flip it appears correctly:

Almost there. Not sure why some require this Y flip and others don't... My brain is fried now...

EDIT: Some programs seem to invert the green channel... A better solution may be to invert the green channel of the normal map before doing any calculations. I will fix this up and upload the new version.

Yes!!! The new one's REALLY awesome! The sense of depth is incredible!

EDIT: IT MAKES ME DROOL. Shit.

EDIT2: Do you mind telling me how you solved it? I assume the problem was the way the normals were packed in the image? How did you unpack it correctly?

Thanks!

Regarding the "Y-invert" -- it seems some programs export normal maps with inverted green channels and others don't. For the sake of the example here I'm just sending a simple boolean to the shader (if true => invert green before calculating anything), but presumably in your own engine you will know whether or not the green channel needs to be inverted.

I have tested a bunch of normal maps I've found online (like these) and it seems like some need the green channel inverted, while others don't.

Probably most of these normal map were just auto-generated using a sobel filter...so you could drop the overhead of storage and just generate them at load time...then they'd all be consistent. Surely gimp has a plugin if you don't want to go that route. A websearch of sobel and normal should give a fair number of hits. (Actually some edge detection in addition would probably be a good thing).

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org