Brightness/contrast shader didn't make it through migration to 1.14 (SOLVED)

No errors, render_script migrated without any issues.

No changes in shader either..

Script sends vector4 with brightness/contrast to quad#model (gltf now) with material and shader in main collection, as it did before.

What could go wrong?

1 Like

What’s the issue? The brightness/contrast is not affecting the output anymore, right?

Exactly.. there are bars for brightness and contrast and they do nothing after 1.14

Previous version was like 1.10 or 1.11

I think I see the issue (but please, next time copy the code - we have formatting tools here for code snippets and it’s easier to read)

This switches rendering back to the screen:

render.set_render_target(render.RENDER_TARGET_DEFAULT)

But you do so before drawing the scene.

Consequently, the 4 predicates render directly to the screen instead of self.sbuffer. Later, the brightness/contrast shader samples self.sbuffer, which contains only the cleared render target rather than the rendered scene.

You should have something like this: render scene → switch to screen → draw the fullscreen quad with the post-processing shader.

-- Render scene to buffer:
render.set_render_target(self.sbuffer)
render.clear(self.clear_param)

render.draw(self.background_pred)
... (and rest of .draw())

-- NOW switch back to the screen:
render.set_render_target(render.RENDER_TARGET_DEFAULT)

...

P.S.

In the fragment shader you set alpha to zero:

lowp vec4 darken = vec4(time, time, time, 0);
gl_FragColor = color * night * darken;

The multiplication forces gl_FragColor.a to 0. I don’t know if this is intended, but better to check it too.

1 Like

Thanks a lot for your help, Pawel! Tried both. Moving render.set_render_target(render.RENDER_TARGET_DEFAULT) after draws disables all graphics before GUI. Everything goes black and only GUI and cursor are visible.

Here’s a whole render script. Maybe GPT messed up something while replacing old render. functions with graphics. ones and I just don’t see that. Sorry it’s been a while since a last checked render script, and Alex Gulev helped me with that one a lot.

---------------Screen Parameters----------------
window_width = 1920
window_height = 1080
resZoom = 1080 / window_height
resZoomX = 1920 / window_width
resRatio = window_height / window_width
zoom = 1
local dpi_ratio = 1

local RT_SIZE = 2
local helper = {
near = -1,
far = 5000,

win_width = 0,
win_height = 0,
settings_width = 0,
settings_height = 0,
zoom_factor = 0,
RT_proj = vmath.matrix4(),
basic_view = vmath.matrix4(),
zoom = 1,
full_proj = vmath.matrix4(),

}

local function update_projection(self)
helper.win_width = render.get_window_width()
helper.win_height = render.get_window_height()

helper.settings_width = render.get_width()
helper.settings_height = render.get_height()
helper.zoom_factor = math.min(helper.win_width / helper.settings_width, helper.win_height / helper.settings_height)

local projected_width = helper.win_width / helper.zoom / helper.zoom_factor
local projected_height = helper.win_height / helper.zoom / helper.zoom_factor

helper.xoffset = - projected_width / 2
helper.yoffset = - projected_height / 2

helper.full_proj = vmath.matrix4_orthographic(helper.xoffset, helper.xoffset + projected_width,
    helper.yoffset, helper.yoffset + projected_height, helper.near, helper.far)

end

local function update_sbuffer(self)
update_projection(self)

if self.sbuffer then
    render.delete_render_target(self.sbuffer)
end

self.sbuffer_color_params.width = helper.win_width
self.sbuffer_color_params.height = helper.win_height

self.sbuffer_depth_params.width = helper.win_width
self.sbuffer_depth_params.height = helper.win_height

self.sbuffer = render.render_target("sbuffer", {
    [graphics.BUFFER_TYPE_COLOR0_BIT] = self.sbuffer_color_params,
    [graphics.BUFFER_TYPE_DEPTH_BIT] = self.sbuffer_depth_params }
)

end

local function on_steam_event(self, event, data)
if event == "GameOverlayActivated_t" then
print("Overlay is", data.m_bActive)
end
end

function init(self)
msg.post("@render:", "resize", { width = window_width, height = window_height } )

defos.disable_maximize_button() -- Not supported on HTML5
defos.disable_minimize_button() -- Not supported on HTML5
defos.disable_window_resize() -- Not supported on HTML5
defos.set_window_title("Plague Lords Prologue")

--defos.set_cursor_clipped(true)
--mouseIn = defos.is_cursor_clipped()

self.background_pred = render.predicate({"background"})
self.gui_pred = render.predicate({"gui"})
self.text_pred = render.predicate({"text"})
self.tiles_pred = render.predicate({"tiles"})
self.twode_pred = render.predicate({"2d"})
self.mist_pred = render.predicate({"mist"})
self.cursors_pred = render.predicate({"cursors"})
self.quad_pred = render.predicate({"3d"})
self.lights_pred = render.predicate({"lights"})
self.image = render.predicate({"image"})
self.screen_view = vmath.matrix4()


self.clear_color = vmath.vector4(0, 0, 0, 0)
self.clear_color.x = sys.get_config_number("render.clear_color_red", 0)
self.clear_color.y = sys.get_config_number("render.clear_color_green", 0)
self.clear_color.z = sys.get_config_number("render.clear_color_blue", 0)
self.clear_color.w = sys.get_config_number("render.clear_color_alpha", 0)

self.view = vmath.matrix4()

screen_width = render.get_width()
screen_height = render.get_height()

if not develop then
    msg.post("/cur_test", "disable")
    defos.set_cursor_visible(false)
end

self.sbuffer_color_params = {
    format = graphics.TEXTURE_FORMAT_RGBA,
    width = render.get_window_width(),
    height = render.get_window_height(),
    min_filter = graphics.TEXTURE_FILTER_LINEAR,
    mag_filter = graphics.TEXTURE_FILTER_LINEAR,
    u_wrap = graphics.TEXTURE_WRAP_CLAMP_TO_EDGE,
    v_wrap = graphics.TEXTURE_WRAP_CLAMP_TO_EDGE
}
self.sbuffer_depth_params = {
    format = graphics.TEXTURE_FORMAT_DEPTH,
    width = render.get_window_width(),
    height = render.get_window_height(),
    u_wrap = graphics.TEXTURE_WRAP_CLAMP_TO_EDGE,
    v_wrap = graphics.TEXTURE_WRAP_CLAMP_TO_EDGE
}

self.clear_param = {
    [graphics.BUFFER_TYPE_COLOR0_BIT] = self.clear_color,
    [graphics.BUFFER_TYPE_DEPTH_BIT] = 1,
    [graphics.BUFFER_TYPE_STENCIL_BIT] = 1
}

helper.RT_proj = vmath.matrix4_orthographic(-RT_SIZE/2, RT_SIZE/2, -RT_SIZE/2, RT_SIZE/2, - 1, 1)

update_sbuffer(self)

local status, error = pcall(steam.init)
if not status then
    print("Error: " .. error)
    return
end

steam.set_listener(on_steam_event)
-- steam.user_stats_reset_all_stats(true)
--print("RESET STATS")

end

local function resizeWindow()
--print("SCREEN RESOLUTION", helper.win_width, helper.win_height)
defos.disable_maximize_button() -- Not supported on HTML5
defos.disable_minimize_button() -- Not supported on HTML5
defos.disable_window_resize() -- Not supported on HTML5
defos.set_window_title("Plague Lords")
if settings.window_mode == 1 then
defos.set_fullscreen(false)
else
defos.set_fullscreen(true)
end
screen_width = render.get_width()
screen_height = render.get_height()
resZoomX = render.get_width() / settings.resolution.x
resZoom = render.get_height() / settings.resolution.y
--resRatio = window_height / window_width
resRatio = resZoomX / resZoom
window_width = settings.resolution.x
window_height = settings.resolution.y
msg.post("@render:", "resize", { width = window_width, height = window_height } )
--print(render.get_window_width(), render.get_window_height(), render.get_width(), render.get_height())
end

function update(self, dt)
if zoom ~= helper.zoom then
helper.zoom = zoom
update_projection(self)
end
render.clear({[graphics.BUFFER_TYPE_COLOR0_BIT] = vmath.vector4(0,0,0,0), [graphics.BUFFER_TYPE_DEPTH_BIT] = 1, [graphics.BUFFER_TYPE_STENCIL_BIT] = 0})

render.set_depth_mask(true)
render.set_stencil_mask(0xff)

render.set_viewport(0, 0, helper.win_width, helper.win_height)
render.set_view(helper.basic_view)
render.set_view(self.view)

render.set_depth_mask(false)
render.disable_state(graphics.STATE_DEPTH_TEST)
render.disable_state(graphics.STATE_STENCIL_TEST)
render.enable_state(graphics.STATE_BLEND)
render.set_blend_func(graphics.BLEND_FACTOR_SRC_ALPHA, graphics.BLEND_FACTOR_ONE_MINUS_SRC_ALPHA)
render.disable_state(graphics.STATE_CULL_FACE)

--render to buffer
render.set_projection(helper.full_proj)
render.set_viewport(0, 0, helper.win_width, helper.win_height)
render.set_render_target(self.sbuffer)
render.clear(self.clear_param)
render.set_render_target(render.RENDER_TARGET_DEFAULT)

--draw gfx
render.draw(self.background_pred)
render.draw(self.tiles_pred)
render.draw(self.twode_pred)
render.draw(self.mist_pred)

render.set_viewport(0, 0, helper.win_width, helper.win_height)
render.set_view(vmath.matrix4())
render.set_projection(helper.RT_proj)

render.disable_state(graphics.STATE_BLEND)
render.enable_texture(0, self.sbuffer, graphics.BUFFER_TYPE_COLOR0_BIT)
render.draw(self.quad_pred)
render.disable_texture(0)
render.enable_state(graphics.STATE_BLEND)

--render Lights
render.set_projection(helper.full_proj)
render.set_viewport(0, 0, helper.win_width, helper.win_height)
render.set_view(self.view)
render.draw(self.lights_pred)

-- render GUI
render.set_view(helper.basic_view)
render.set_viewport(0, 0, helper.win_width, helper.win_height)
render.set_projection(vmath.matrix4_orthographic(0, helper.win_width, 0, helper.win_height, -5000, 5000))

render.enable_state(graphics.STATE_STENCIL_TEST)
render.draw(self.gui_pred)
render.draw(self.text_pred)
render.disable_state(graphics.STATE_STENCIL_TEST)
render.draw(self.cursors_pred)
render.draw(self.image)
render.set_depth_mask(false)

steam.update()

end

function on_message(self, message_id, message)
if message_id == hash("set_view_projection") then
self.view = message.view
self.projection = message.projection
elseif message_id == hash("zoom") then
helper.zoom = message.zoom
update_projection(self)
elseif message_id == hash("resizeWindow") then
--msg.post("@render:", "resize", { width = 1920, height = 1080 } )
resizeWindow()
-- window_resized - 

elseif message_id == hash("window_resized") then
update_sbuffer(self)
end
end

Tried a lot of combinations in update section. But the one above works fine but disables the shader.

quad_pred is the one where shader is.

1 Like

Put in shader just

gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);

to see if you’ll have single color on screen, maybe something’s wrong with the setup?

1 Like

No changes. It only disables properties I use to send params to shader so gives an error upon trying to adjust settings.

scripts/loader.script:87: 'quad#model' does not have any property called 'bcs'

It seems like shader works but doesn’t affect ingame graphics. So I thought the problem is in “update” of the main render script.

What do you mean? The screen should be in full magenta color - is it?

1 Like

Sry. It shows normal main menu screen without any changes. The shader doesn’t do anything but still receives all parameters.

The shader may work, bt you may still not be able to see it on screen. Something in your post-processing quad setup is not actually working. Or I think I’m lacking some more informations, perhaps a quad setup in your game?
Maybe you could create a repro na share?
Your render script draws the GUI after the post-processing pass. Mayeb could you temporarily disable the GUI draw calls and check if magenta appears?
Do you use built-in quad gltf?
Could you check your quad#model component in the editor?
Make sure the Scene points to the correct glTF file, try leaving the Mesh field empty, and verify that the assigned material has the 3d tag matching self.quad_pred.
Also check the quad’s position, rotation and scale, as these may have changed during the DAE → glTF migration.

1 Like

Yes. Changed to gltf.

Doublechecked that one.

And tags in material?

It seems like I can make a repro with just a main menu. I’ll try to assemble it in a couple of hours.

Didn’t touch them. Everything except render_script is the same as in 1.1. And it worked perfect.

Working on a repro.

1 Like

Solved! Had to move that line with

render.set_render_target(render.RENDER_TARGET_DEFAULT)

after draws and remove mesh from quad#model.

1 Like

Glad we could help!

Remember that also migrating to a built-in GLTF was an issue here, so for anyone migrating a project from DAE to glTF, here are a few things worth checking if some kind of a postprocessing effect that was based on a very common quad approach, suddenly stops working:

  1. Check the model’s Mesh selection.
    Leaving Mesh property empty results in rendering the glTF scene with its imported node transforms. Selecting a specific mesh renders its local geometry without those transforms. If you’re using the built-in quad gltf file - it’s rotation is stored on its scene node. Selecting Plane_001Mesh skipped that rotation, leaving the quad edge-on to the camera, thus invisble. Choosing the empty entry in the Mesh fixed its orientation.

  2. Check the asset’s dimensions against your projection.
    The built-in glTF quad is 1x1, while e.g. in this project’s postprocessing projection was suited for 2x2 quad - so keep it in mind, when using the built-in quad, or use quad_2x2.gltf :wink:

  3. Check render-target switching when updating a render script.
    Yeah, as above - this is the main reason. Here, the switch happened before the scene draw calls, so the shader sampled an empty buffer.

These issues masked each other, so it was a bit more complex, because fixing only the render-target order resulted in a black screen, because the quad was still flipped, so a few issues might overlap each other and it becomes tricky :sweat_smile:

1 Like