I have the following loop in the update function of my render script. Only the last window renders correctly with the other three drawing the ambient light but not the lights themselves.
Is there something that works asynchronously in the render script? Seems like something is being reset by the next run through the loop before being used.
My guess is that you’re clearing the first three on loop. You might want to try clearing only once every four iterations. But that’s just a guess, I could be wrong. I’ve never done something quite like this before.
I’m guessing the "lighting_quad" is fullscreen and not individual quads per player?
What seems to be issue here is that you are clearing the frame with ambient color then drawing the lighting then on the next view/loop iteration the same thing so the one before is removed to ambient color, until all you have is the last player with the correct lighting. One way you can fix this is in the for loop only clear to color for the first view/camera.
Edit* I realize after re-reading that you may be doing this because you are drawing the lighting to the whole quad from each view overlapping the lighting data. I will test for a possible solution.
It’s probably because he’s drawing inside a loop. Wouldn’t it be better to draw to the screen just once, outside the loop? ( Hard to say without actually doing it or knowing how he handles.)
Something like this:
render.clear({[render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0})
...
-- Draw cameras to render target
for k,v in pairs(self.cam) do
render.set_viewport(v.vp.x, v.vp.y, v.vp.z, v.vp.w)
-- draw to render target
render.set_render_target(self.render_target_world)
render.set_view(cam.get(k))
render.set_projection(vmath.matrix4_orthographic(0, v.proj.x, 0, v.proj.y, -1, 1))
set_default_renderer_state()
render.draw(self.tile_pred)
end
-- if it is a single quad ->
render.set_viewport(math.ceil(sx), math.ceil(sy), math.ceil(w), math.ceil(h))
render.set_view(IDENTITY_MATRIX)
render.set_projection(IDENTITY_MATRIX)
-- lighting pass
render.set_render_target(self.render_target_lights)
clear_with_color(ambient_color)
set_default_renderer_state()
render.draw(self.light_pred)
-- draw to screen
render.set_render_target(render.RENDER_TARGET_DEFAULT)
set_default_renderer_state()
render.enable_material(hash("lighting_quad"))
render.enable_texture(0, self.render_target_world, render.BUFFER_COLOR0_BIT)
render.enable_texture(1, self.render_target_lights, render.BUFFER_COLOR0_BIT)
render.draw(self.quad_pred)
render.disable_texture(0)
render.disable_texture(1)
render.disable_material()
Yes! This was key to the answer. I had the same thought last night in bed falling asleep (as you do). Moving the ‘draw to screen’ section after the loop and the two ‘clear render target’ parts before the loop was needed.
@selimanac@MasterMind@Dragosha - thank you all. I’ll be sending you free Steam keys for the game when it’s released first half of June.
Just out of curiosity, I came this far. I’m not happy with the code, but… I had to loop twice (not thrilled about that). I’m pretty sure there’s a better way.
local cameras = camera.get_cameras()
-- World
render.set_render_target(self.render_target_world)
render.clear(state.clear_buffers)
for i, camera_id in ipairs(cameras) do
local view = camera.get_view(camera_id)
local projection = camera.get_projection(camera_id)
local col = (i - 1) % cols
local row = math.floor((i - 1) / cols)
local x = col * rect_width
local y = row * rect_height
render.set_viewport(x, y, rect_width, rect_height)
render.set_view(view)
render.set_projection(projection)
local frustum = projection * view
render.draw(predicates.tile, { frustum = frustum })
end
-- Lights
render.set_render_target(self.render_target_lights)
render.clear(state.clear_buffers)
self.constants.time = vmath.vector4(math.random(90, 100) / 100)
for i, camera_id in ipairs(cameras) do
local view = camera.get_view(camera_id)
local projection = camera.get_projection(camera_id)
local col = (i - 1) % cols
local row = math.floor((i - 1) / cols)
local x = col * rect_width
local y = row * rect_height
render.set_viewport(x, y, rect_width, rect_height)
render.set_view(view)
render.set_projection(projection)
local frustum = projection * view
render.draw(predicates.light, { frustum = frustum, constants = self.constants })
end
-- Render to quad
render.set_viewport(0, 0, state.window_width, state.window_height)
render.set_view(IDENTITY)
render.set_projection(IDENTITY)
render.set_render_target(render.RENDER_TARGET_DEFAULT)
render.enable_state(graphics.STATE_CULL_FACE)
render.enable_material(hash("multiply_quad"))
render.enable_texture("tex0", self.render_target_world, graphics.BUFFER_TYPE_COLOR0_BIT)
render.enable_texture("tex1", self.render_target_lights, graphics.BUFFER_TYPE_COLOR0_BIT)
render.draw(predicates.quad)
render.disable_texture("tex0")
render.disable_texture("tex1")
render.disable_material()
May I ask why you’re not using a frustum? It might help reduce a few draw calls.
Not super important, but I think you don’t need to call render.set_render_target(render.RENDER_TARGET_DEFAULT) in a loop. You can just set it once before the -- draw to screen.
Yeah you’re right, I don’t need to keep calling that - I’m still figuring this stuff out, working from multiple examples, combining them together. There’s probably further refinements that could be made.
edit: I also moved set_default_renderer_state() to just before the loop starts. No need to call that multiple times.