The approach we used on Hammerwatch Coliseum is very similar to what you suggest. IIRC we have both an add pass and a multiply pass where lights are applied to a render texture that has been cleared with an ambient light color
Il try an implementation and get back to you on how it goes, thank you very much
How do I go about rendering the lights to a separate target
- In your render script, make a separate render target for the lights.
- Also in your render script make a separate predicate for the lights.
- Give your light sprites a new material with a tag matching your predicate.
- In your render script update, for each render target, do:
- enable render target
- clear it
- draw stuff to it
- disable it
In the first thread I linked before, Sicher explains how you use multiple render targets in the material that they are rendered with.
im struggling to get the render target for the light into the shader i know im doing something wrong i just dont know what
could i maybe get a code example of the render script and the shader
Here is my material for the render target quad:
The shader in my project has a ton of extra stuff in it, but I tested this and it should work for you:
varying mediump vec4 var_position;
varying mediump vec3 var_normal;
varying mediump vec2 var_texcoord0;
uniform lowp sampler2D lighting;
uniform lowp sampler2D base;
void main()
{
vec4 light = texture2D(lighting, var_texcoord0.xy);
vec4 b = texture2D(base, var_texcoord0.xy);
gl_FragColor = b * light;
}
And the relevant part of my render script:
-- In render script update()
-- self.base_RT == Render target for base scene
-- self.shadowmap_RT == Render target for lights
--- BASE RENDER
-- Draw normal stuff to render target
render.enable_render_target(self.base_RT)
render.clear({[render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0})
render.draw(self.tile_pred)
render.draw(self.particle_pred)
render.draw_debug2d()
render.draw_debug3d()
render.disable_render_target(self.base_RT)
--- SHADOW MAP
-- Draw lights and Line-of-Sight blockers to render target
render.enable_render_target(self.shadowmap_RT)
render.clear({[render.BUFFER_COLOR_BIT] = self.shadowmap_clear, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0})
render.draw(self.lighting_pred)
render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA)
render.draw(self.los_pred)
render.disable_render_target(self.shadowmap_RT)
-- Draw quad with render target texture on it
render.set_view(zeroMatrix)
render.set_projection(self.RT_proj)
render.enable_texture(0, self.shadowmap_RT, render.BUFFER_COLOR_BIT)
render.enable_texture(1, self.base_RT, render.BUFFER_COLOR_BIT)
render.draw(self.shadowmap_pred)
render.disable_texture(0, self.shadowmap_RT)
render.disable_texture(1, self.base_RT)
Would be awesome, if someone of you would create a tutorial about lighting in 2d games
I could maybe put something together for you
Hey there.
Try to implement 2d lightning. But I dont understand what to do exactly. Tried the code above in a clear project without success.
What about the tutorial or an example project in a clear enviroment? Would be very helpful
Have a look here
It is not that complex although you do need to mess with the render script, a shader and some new materials. The basic idea is this:
STEP 1 - DRAW NORMAL COMPONENTS TO RENDER TARGET
Draw your sprites, tilemaps and any other components you have in your game to a render target (a texture in memory) instead of directly to screen.
You create a render target using render.render_target()
. You enable it in your render script, draw using the normal render calls, then disable it again. Done!
STEP 2 - DRAW LIGHTS TO RENDER TARGET
Draw your lights to another render target. Clear the render target with a semitransparent black color for some ambient light.
In this example the lights are circular sprites of various sizes and with increasing transparency.
They are drawn with a Blend Mode set to Add instead of Alpha.
The sprites have a different material assigned than the normal sprite material. The material uses another tag/predicate so that it doesn’t get drawn with everything else in step 1.
STEP 3 - DRAW A MIX OF BOTH RENDER TARGETS TO A QUAD ON SCREEN
Draw a mix of the two render targets to a model component with a quad (a rectangle) and draw it so that it fills the entire screen.
The quad has a separate material which takes two textures as input parameters and it uses a new tag/predicate so that we can draw it in a separate pass.
Each pixels is a multiplication of the pixel value from the normal graphics and the light. Final result:
I’ve put it all together in an example here:
CODE: https://github.com/britzl/publicexamples/tree/master/examples/simple_lights
DEMO: http://britzl.github.io/publicexamples/simple_lights/index.html
I have some questions about simple_lights example:
- Why create render target with depth, if we not write to depth buffer? And why clear it, if we not write to it?
- quad.vp has varyings var_position and var_normal. They are calculated but not used anywere?
Good points. Parts of the example was copied from another projects and I didn’t consider some of the settings. Pushed some changes. Thanks!
Thanks for the example @britzl.
I dont understand the mechanics at all and the example looks a little bit to complicated to explain
Maybe I have to dive much deeper in it. Never worked with the render and the materials in that way.
Your example works fine and I fooled around a bit to get into it
But do you understand the basic principle behind it? One image with everything fully lit. One image with a semi transparent black/grey (ambient light) with the areas around the lights transparent. Overlay the image with the lights on the normal one to compose the final image with everything dark except around the lights.
This effect is achieved through some renderscript and shader “magic” that might seem very hard to understand in the beginning. But playing around with different examples might help you understand.
Hi.
Sure, its kind of layering / masking.
I started a new project to reproduce it and dupilicated materials etc. but… you use a complete different render-script and an orthographic camera & Script (Helper).
Isnt it possible to “more simpify” the demo? Without any external scripts? Just to have the real bone basics for a better understanding? Maybe some comments or maybe with screenshots or whatever . including - or special - the render-script.
I think there arejust a few changes / additions to the standard-render-script.
Are really 3 materials needed? and a mesh (quad)?
what about the quad scripts (.vp and .fp)? which content?
How can I get this result:
front sprite should not be transparent
he should be black
How can I do it?