I decided to add transparency to the shadow calculations anyway. It's not as slow as I had feared, and it's great for shading the bottom of lakes and oceans. When casting a ray to test for occlusion, it now adds the opacity of all the intersecting blocks. Air has an opacity of zero, rocks and such have 1. Water is 0.2, leaves are 0.4. As soon as the sum of the opacity of the blocks along the ray reaches 1, the loop stops. The sum of all the rays is then used to determine how much light the block receives.
For water, this results in a nice gradient:
And... *peers*... some sort of dark lines along the edges of the chunks. I'll have to look into that.
As for the trees, it does make the shadows a bit softer, but the difference isn't huge:
I've also managed to get rid of that z-ordering problem I had earlier. I no longer use my own custom scene node, I just generate plain SMesh'es. Less code, works better. (So why use a custom scene node in the first place? Eh, I was following a tutorial. :P )
Another cool side-effect is that I can now make things emit light as well, simply by setting their opacity to a negative value:
Light sources will be done in a different way, this is just a little trick I thought of right now.