2d Lighting Question. Because there aren't enough of them.

Hello!

I’m having trouble with a lighting problem. I understand the concept of creating a lightmap, and even have a set of pixel blending functions graciously provided by Dx4 in this post: http://www.java-gaming.org/topics/some-new-blendmodes-add-multiply-overlay-etc/24529/view.html.

I’m currently running my prototype in FSEM with a BufferStrategy, Direct3d turned off by runtime options. Now, I’m wondering, given the Graphics I’ve been drawing all my lovely (read: horrifyingly primitive) sprites to, how exactly should I access the pixel data for the blending methods? Keeping a separate BufferedImage and calling out each pixel is EXTREMELY slow (especially in 1080p). Even having that BufferedImage and not applying a lightmap to it, then drawing it with g.drawImage(im, blah) is slow. Is there something I’m missing?

Best,
Munch

[EDIT] the end goal is something akin to this: http://www.youtube.com/watch?v=Xmn6zhDJGLE&feature=fvwp&NR=1 though without the bump mapping.

A good approach would be to draw your game normally and then blend a light map onto it. For the light map just draw each light with additive blending to the light map and finally blend the light map to the screen buffer with multiplicative blending. You’re right about the slowness though. A 1080p framebuffer has almost 2 million pixels, and with a lightmap you’d be filling every one of those at least twice assuming terrain and sprites cover the whole screen + the lightmap blending + any overdraw. As you’ve disabled hardware acceleration all this is done by the CPU, and you’re CPU isn’t a graphics card. Graphics cards exist for a reason. xd

To improve performance you can try to reduce the resolution of the light-map to 1/2th to 1/4th the resolution of the screen. With bilinear interpolation (which is pretty much free if you re-enable hardware acceleration) the difference is completely indistinguishable while light rendering performance shoots through the roof.

The video you posted also has another thing: shadows. If you want shadows, then you’ll have to drop Java2D and use OpenGL. OpenGL can handle hundreds of shadow-casting lights per frame, while unaccelerated Java2D can hardly draw an image covering the whole screen with blending… >_>

I am dissapoint. I’m really not looking forward to learning OpenGl, it’s intimidating…!

Oh also, for some reason FSEM in Java is extremely slow with D3D turned on. With 0 game logic it peaks around 80 fps at 1080p.

theagentd is right, you probably have to switch to an hardware accellerated api for 1080p with “effects”. Take a look at slick2d or libgdx, which should offer enough of a high level api to make transition from java2d easier (especially slick2d, since it kind of mimicks the java2d concepts) and let you dig into the rendering pipeline, when you need to get advanced. libgdx will also offer android support.

For Libgdx I have made light library that allow pretty much those effect that you see on that video out of the box.
http://code.google.com/p/box2dlights/

That work even on mobile devices and you dont have fiddle with opengl bits at all.

:smiley: neat.

Was trying to install it, but it seems to not mesh with the most recent libgdx download. What version of libgdx are you using with it?

Nightlies. 0.92 is bit too old and there is ton of content and bugfixes happened after that point.

For fastest testing there is independed test project builded http://code.google.com/p/box2dlights/downloads/detail?name=box2dLightTestProject.zip

This may belong in the LWJGL board, but it’s an extension of this thread so… yeah.

I’m working on using LWJGL to render a lightmap on top of the 2d scene (using orthographic projection). Would it work to render the lightmap to an FBO, explored in this tutorial?: http://lwjgl.org/wiki/index.php?title=Render_to_Texture_with_Frame_Buffer_Objects_(FBO)

Sincerely,
Knee-deep-in-OpenGL-and-confused

be advised that FBO are pretty advanced, and only available using OpenGL 3.0 and later
if you want a lot of people to be able to play your game, don’t use it. Alternatives include VBO and such

So… create a VBO, render the lightmap to that, then render the VBO on top of the scene?

I have two technique for lights.
Fixed pipeline goes like this:

  1. Render scene.
  2. Clear alpha channel(use color mask for other channels, clear alpha to ambient)
  3. Render Lights with blending, alpha channel as intesity. gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
  4. Render fullscreen black quad with blending. gl.glBlendFunc(GL10.GL_ONE, GL10.GL_DST_ALPHA);
  5. Render UI.

Shaders + FBO’s goes like this.

  1. Render scene.
  2. Render Lights with blending to small size FBO, use alpha channel as intesity. gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
  3. Use gaussian blur to FBO.
  4. Render FBO over to scene with custom shader that draw lights where intesity is high and shadow where intesity is low.
  5. Render UI.

Both techniques are as fast. Shaders give soft lights/shadows but fixed pipeline work everywhere.

Super n00b question: How do I clear the alpha channel?


	private void alphaChannelClear() {
		Gdx.gl10.glClearColor(0f, 0f, 0f, ambientLight);
		Gdx.gl10.glColorMask(false, false, false, true);
		Gdx.gl10.glClear(GL10.GL_COLOR_BUFFER_BIT);
		Gdx.gl10.glColorMask(true, true, true, true);
		Gdx.gl10.glClearColor(0f, 0f, 0f, 0f);
	}

Ok great. But what about this problem: With colored lights rendered over a white background (eg. snow) that blending function just takes it straight to white. Render the black quad first? ???

I seem to have found a workaround by, before clearing the alpha buffer, blending a colored ‘light’ onto the scene in the location (with reduced radius) of the future alpha buffered light.

I am next investigating into this approach: http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/dynamic-2d-soft-shadows-r2032?md=viewrev&rva=1&rvb=1#revisions which seems to take the approach of rendering the light into the alpha buffer FIRST, then for each light, rendering the scene. The emissive pass at the end could be used to render the whole scene in an “ambient” sense under the darkness as well.

Yeah you find the problem. But there is easy fix for that. Just use

glBlendFunc( GL_DST_COLOR,GL_SRC_COLOR);

instead.

You really don’t want to render your scene per light. Instead just draw light to accum buffer and blend that over the scene. For that you dont even need any shaders.

Using that blend function makes it look really bad, you can see the edges of the triangle fan of the lights instead of the smooth dropoff you get with a src_alpha blend.

That blend mode works for me but its not work with current shadow shader that I use but with withoutShadows shader(what is just texture color and nothing more) its work very nicely.

I will commit changes and screenshot later tonight.

Edit: in the trunk.