I definitely am losing my mind a bit here trying to render my game to a custom target so I can implement full screen effects. I have followed a few tutorials and checked everywhere, but I can’t seem to grasp what I’m doing wrong exactly
I have this render script and a render target correctly setup with a quad and a custom material, the projection seems to work fine except it doesn’t look good
--
-- projection that centers content with maintained aspect ratio and optional zoom
--
local function fixed_projection(near, far, zoom)
local projected_width = render.get_window_width() / (zoom or 1)
local projected_height = render.get_window_height() / (zoom or 1)
local xoffset = -(projected_width - render.get_width()) / 2
local yoffset = -(projected_height - render.get_height()) / 2
return vmath.matrix4_orthographic(xoffset, xoffset + projected_width, yoffset, yoffset + projected_height, near, far)
end
--
-- projection that centers and fits content with maintained aspect ratio
--
local function fixed_fit_projection(near, far)
local width = render.get_width()
local height = render.get_height()
local window_width = render.get_window_width()
local window_height = render.get_window_height()
local zoom = math.min(window_width / width, window_height / height)
return fixed_projection(near, far, zoom)
end
--
-- projection that stretches content
--
local function stretch_projection(near, far)
return vmath.matrix4_orthographic(0, render.get_width(), 0, render.get_height(), near, far)
end
local function get_projection(self)
return self.projection_fn(self.near, self.far, self.zoom)
end
function init(self)
self.tile_pred = render.predicate({ "tile" })
self.gui_pred = render.predicate({ "gui" })
self.text_pred = render.predicate({ "text" })
self.particle_pred = render.predicate({ "particle" })
self.clear_color = vmath.vector4(0, 0, 0, 0)
self.clear_color.x = sys.get_config("render.clear_color_red", 0)
self.clear_color.y = sys.get_config("render.clear_color_green", 0)
self.clear_color.z = sys.get_config("render.clear_color_blue", 0)
self.clear_color.w = sys.get_config("render.clear_color_alpha", 0)
self.view = vmath.matrix4()
-- default is stretch projection. copy from builtins and change for different projection
-- or send a message to the render script to change projection:
-- msg.post("@render:", "use_stretch_projection", { near = -1, far = 1 })
-- msg.post("@render:", "use_fixed_projection", { near = -1, far = 1, zoom = 2 })
-- msg.post("@render:", "use_fixed_fit_projection", { near = -1, far = 1 })
self.near = -1
self.far = 1
self.projection_fn = fixed_projection
-- Create a new render target.
local color_params = { format = render.FORMAT_RGBA, width = render.get_window_width(), height = render.get_window_height() }
local target_params = { [render.BUFFER_COLOR_BIT] = color_params }
self.target = render.render_target("target", target_params)
self.window_pred = render.predicate({ "postprocess" })
end
function update(self)
local window_width = render.get_window_width()
local window_height = render.get_window_height()
if window_width == 0 or window_height == 0 then
return
end
-- clear screen buffers
--
render.set_depth_mask(true)
render.set_stencil_mask(0xff)
render.clear({ [render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0 })
-- render world (sprites, tilemaps, particles etc)
--
local proj = get_projection(self)
local frustum = proj * self.view
render.set_viewport(0, 0, window_width, window_height)
render.set_view(self.view)
render.set_projection(proj)
render.set_depth_mask(false)
render.disable_state(render.STATE_DEPTH_TEST)
render.disable_state(render.STATE_STENCIL_TEST)
render.enable_state(render.STATE_BLEND)
render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA)
render.disable_state(render.STATE_CULL_FACE)
render.draw(self.tile_pred, { frustum = frustum })
render.draw(self.particle_pred, { frustum = frustum })
render.draw_debug3d()
-- Set the render target to our target.
render.set_render_target(self.target)
-- Clear the render target with the games clear color.
render.clear({ [render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0 })
-- Draw all objects with the "tile" tag in their material.
render.draw(self.tile_pred, { frustum = frustum })
-- Reset the render target.
render.set_render_target(render.RENDER_TARGET_DEFAULT)
-- Set the texture in slot 0 of the material to our render target.
render.enable_texture(0, self.target, render.BUFFER_COLOR_BIT)
-- Draw the window quad.
render.draw(self.window_pred)
-- Unset the texture slot.
render.disable_texture(0, self.target)
-- render GUI
--
local view_gui = vmath.matrix4()
local proj_gui = vmath.matrix4_orthographic(0, window_width, 0, window_height, -1, 1)
local frustum_gui = proj_gui * view_gui
render.set_view(view_gui)
render.set_projection(proj_gui)
render.enable_state(render.STATE_STENCIL_TEST)
render.draw(self.gui_pred, { frustum = frustum_gui })
render.draw(self.text_pred, { frustum = frustum_gui })
render.disable_state(render.STATE_STENCIL_TEST)
end
function on_message(self, message_id, message)
if message_id == hash("clear_color") then
self.clear_color = message.color
elseif message_id == hash("set_view_projection") then
self.view = message.view
self.projection = message.projection
elseif message_id == hash("use_camera_projection") then
self.projection_fn = function() return self.projection or vmath.matrix4() end
elseif message_id == hash("use_stretch_projection") then
self.near = message.near or -1
self.far = message.far or 1
self.projection_fn = stretch_projection
elseif message_id == hash("use_fixed_projection") then
self.near = message.near or -1
self.far = message.far or 1
self.zoom = message.zoom or 1
self.projection_fn = fixed_projection
elseif message_id == hash("use_fixed_fit_projection") then
self.near = message.near or -1
self.far = message.far or 1
self.projection_fn = fixed_fit_projection
end
end
This is how it looks in the engine vs running on the game
I don’t even know what “version” of the render_script this is at this point but every version I’ve made I got the same issue, it renders in this weird way almost like my GPU is dying


