Hello, While i was trying to do a psx style shader, i noticed every texture turns black, except the skybox, which is a cubemap
i don’t know much about shaders, but someone knows what could be causing this?, the platform is just a shape
Render.render_script :
local MSG_CLEAR_COLOR = hash("clear_color")
local MSG_WINDOW_RESIZED = hash("window_resized")
local MSG_SET_VIEW_PROJ = hash("set_view_projection")
local MSG_SET_CAMERA_PROJ = hash("use_camera_projection")
local MSG_USE_STRETCH_PROJ = hash("use_stretch_projection")
local MSG_USE_FIXED_PROJ = hash("use_fixed_projection")
local MSG_USE_FIXED_FIT_PROJ = hash("use_fixed_fit_projection")
local DEFAULT_NEAR = -1
local DEFAULT_FAR = 1
local DEFAULT_ZOOM = 1
--
-- projection that centers content with maintained aspect ratio and optional zoom
--
local function get_fixed_projection(camera, state)
camera.zoom = camera.zoom or DEFAULT_ZOOM
local projected_width = state.window_width / camera.zoom
local projected_height = state.window_height / camera.zoom
local left = -(projected_width - state.width) / 2
local bottom = -(projected_height - state.height) / 2
local right = left + projected_width
local top = bottom + projected_height
return vmath.matrix4_orthographic(left, right, bottom, top, camera.near, camera.far)
end
--
-- projection that centers and fits content with maintained aspect ratio
--
local function get_fixed_fit_projection(camera, state)
camera.zoom = math.min(state.window_width / state.width, state.window_height / state.height)
return get_fixed_projection(camera, state)
end
--
-- projection that stretches content
--
local function get_stretch_projection(camera, state)
return vmath.matrix4_orthographic(0, state.width, 0, state.height, camera.near, camera.far)
end
--
-- projection for gui
--
local function get_gui_projection(camera, state)
return vmath.matrix4_orthographic(0, state.window_width, 0, state.window_height, camera.near, camera.far)
end
local function update_clear_color(state, color)
if color then
state.clear_buffers[graphics.BUFFER_TYPE_COLOR0_BIT] = color
end
end
local function update_camera(camera, state)
if camera.projection_fn then
camera.proj = camera.projection_fn(camera, state)
camera.options.frustum = camera.proj * camera.view
end
end
local function update_state(state)
state.window_width = render.get_window_width()
state.window_height = render.get_window_height()
state.valid = state.window_width > 0 and state.window_height > 0
if not state.valid then
return false
end
if state.window_width == state.prev_window_width and state.window_height == state.prev_window_height then
return true
end
state.prev_window_width = state.window_width
state.prev_window_height = state.window_height
state.width = render.get_width()
state.height = render.get_height()
for _, camera in pairs(state.cameras) do
update_camera(camera, state)
end
return true
end
local function init_camera(camera, projection_fn, near, far, zoom)
camera.view = vmath.matrix4()
camera.near = near == nil and DEFAULT_NEAR or near
camera.far = far == nil and DEFAULT_FAR or far
camera.zoom = zoom == nil and DEFAULT_ZOOM or zoom
camera.projection_fn = projection_fn
end
local function create_predicates(...)
local arg = {...}
local predicates = {}
for _, predicate_name in pairs(arg) do
predicates[predicate_name] = render.predicate({predicate_name})
end
return predicates
end
local function create_camera(state, name, is_main_camera)
local camera = {}
camera.options = {}
state.cameras[name] = camera
if is_main_camera then
state.main_camera = camera
end
return camera
end
local function create_state()
local state = {}
local color = vmath.vector4(0, 0, 0, 0)
color.x = sys.get_config_number("render.clear_color_red", 0)
color.y = sys.get_config_number("render.clear_color_green", 0)
color.z = sys.get_config_number("render.clear_color_blue", 0)
color.w = sys.get_config_number("render.clear_color_alpha", 0)
state.clear_buffers = {
[graphics.BUFFER_TYPE_COLOR0_BIT] = color,
[graphics.BUFFER_TYPE_DEPTH_BIT] = 1,
[graphics.BUFFER_TYPE_STENCIL_BIT] = 0
}
state.cameras = {}
return state
end
local function set_camera_world(state)
local camera_components = camera.get_cameras()
if #camera_components > 0 then
for i = #camera_components, 1, -1 do
if camera.get_enabled(camera_components[i]) then
local camera_component = state.cameras.camera_component
camera_component.camera = camera_components[i]
render.set_camera(camera_component.camera, { use_frustum = true })
return camera_component.options
end
end
end
local camera_world = state.cameras.camera_world
render.set_view(camera_world.view)
render.set_projection(camera_world.proj)
return camera_world.options
end
local function reset_camera_world(state)
if state.cameras.camera_component.camera then
state.cameras.camera_component.camera = nil
render.set_camera()
end
end
function init(self)
-- 1. ADDED "post_process" TO PREDICATES
self.predicates = create_predicates("tile", "gui", "particle", "model", "skybox", "debug_text", "post_process")
local state = create_state()
self.state = state
local camera_world = create_camera(state, "camera_world", true)
init_camera(camera_world, get_stretch_projection)
local camera_gui = create_camera(state, "camera_gui")
init_camera(camera_gui, get_gui_projection)
local camera_component = create_camera(state, "camera_component")
update_state(state)
self.rt_width = 0
self.rt_height = 0
end
function update(self)
local state = self.state
if not state.valid then
if not update_state(state) then
return
end
end
if self.rt_width ~= state.window_width or self.rt_height ~= state.window_height then
self.rt_width = state.window_width
self.rt_height = state.window_height
if self.render_target then
render.delete_render_target(self.render_target)
end
local color_params = {
format = graphics.TEXTURE_FORMAT_RGBA,
width = self.rt_width,
height = self.rt_height,
min_filter = render.FILTER_NEAREST,
mag_filter = render.FILTER_NEAREST,
u_wrap = render.WRAP_CLAMP_TO_EDGE,
v_wrap = render.WRAP_CLAMP_TO_EDGE
}
local depth_params = {
format = graphics.TEXTURE_FORMAT_DEPTH,
width = self.rt_width,
height = self.rt_height,
u_wrap = render.WRAP_CLAMP_TO_EDGE,
v_wrap = render.WRAP_CLAMP_TO_EDGE
}
self.render_target = render.render_target("psx_rt", {
[graphics.BUFFER_TYPE_COLOR0_BIT] = color_params,
[graphics.BUFFER_TYPE_DEPTH_BIT] = depth_params
})
end
local predicates = self.predicates
local draw_options_world = set_camera_world(state)
local constants_model = render.constant_buffer()
constants_model.light = vmath.vector4(0.0, 50.0, 50.0, 1.0)
constants_model.tint = vmath.vector4(1.0, 1.0, 1.0, 1.0)
local opts_model = { frustum = draw_options_world.frustum, constants = constants_model }
local constants_2d = render.constant_buffer()
constants_2d.tint = vmath.vector4(1.0, 1.0, 1.0, 1.0)
local opts_2d = { frustum = draw_options_world.frustum, constants = constants_2d }
render.set_render_target(self.render_target)
render.set_viewport(0, 0, state.window_width, state.window_height)
render.set_depth_mask(true)
render.set_stencil_mask(0xff)
render.clear(state.clear_buffers)
render.set_blend_func(graphics.BLEND_FACTOR_SRC_ALPHA, graphics.BLEND_FACTOR_ONE_MINUS_SRC_ALPHA)
render.enable_state(graphics.STATE_DEPTH_TEST)
render.enable_state(graphics.STATE_CULL_FACE)
render.draw(predicates.model, opts_model)
render.set_depth_mask(false)
render.disable_state(graphics.STATE_CULL_FACE)
render.enable_state(graphics.STATE_CULL_FACE)
render.set_cull_face(graphics.FACE_TYPE_FRONT)
render.set_depth_func(graphics.COMPARE_FUNC_LEQUAL)
render.draw(predicates.skybox, draw_options_world)
render.set_depth_mask(false)
render.set_depth_func(graphics.COMPARE_FUNC_LESS)
render.set_cull_face(graphics.FACE_TYPE_BACK)
render.disable_state(graphics.STATE_CULL_FACE)
-- render components: sprites, tilemaps, particles etc (Uses opts_2d)
render.enable_state(graphics.STATE_BLEND)
render.draw(predicates.tile, opts_2d)
render.draw(predicates.particle, opts_2d)
render.disable_state(graphics.STATE_DEPTH_TEST)
render.draw_debug3d()
render.set_render_target(render.RENDER_TARGET_DEFAULT)
-- =========================================================
-- PASS 2: DRAW THE RENDER TARGET TO THE SCREEN (PSX SHADER)
-- =========================================================
render.set_depth_mask(true)
render.clear(state.clear_buffers)
render.enable_texture(0, self.render_target, graphics.BUFFER_TYPE_COLOR0_BIT)
render.enable_state(graphics.STATE_BLEND)
render.draw(predicates.post_process, draw_options_world)
render.disable_state(graphics.STATE_BLEND)
render.disable_texture("tex0")
reset_camera_world(state)
local camera_gui = state.cameras.camera_gui
render.set_view(camera_gui.view)
render.set_projection(camera_gui.proj)
render.enable_state(graphics.STATE_STENCIL_TEST)
render.draw(predicates.gui, camera_gui.options)
render.draw(predicates.debug_text, camera_gui.options)
render.disable_state(graphics.STATE_STENCIL_TEST)
render.disable_state(graphics.STATE_BLEND)
end
function on_message(self, message_id, message)
local state = self.state
local camera = state.main_camera
if message_id == MSG_CLEAR_COLOR then
update_clear_color(state, message.color)
elseif message_id == MSG_WINDOW_RESIZED then
update_state(state)
elseif message_id == MSG_SET_VIEW_PROJ then
camera.view = message.view
self.camera_projection = message.projection or vmath.matrix4()
update_camera(camera, state)
elseif message_id == MSG_SET_CAMERA_PROJ then
camera.projection_fn = function() return self.camera_projection end
elseif message_id == MSG_USE_STRETCH_PROJ then
init_camera(camera, get_stretch_projection, message.near, message.far)
update_camera(camera, state)
elseif message_id == MSG_USE_FIXED_PROJ then
init_camera(camera, get_fixed_projection, message.near, message.far, message.zoom)
update_camera(camera, state)
elseif message_id == MSG_USE_FIXED_FIT_PROJ then
init_camera(camera, get_fixed_fit_projection, message.near, message.far)
update_camera(camera, state)
end
end
psx.fp :
varying mediump vec2 var_texcoord0;
uniform lowp sampler2D tex0;
uniform mediump vec4 time;
uniform mediump vec4 res_bit_dither;
mediump float hash(mediump vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
}
void main() {
mediump float res_x = res_bit_dither.x > 0.0 ? res_bit_dither.x : 320.0;
mediump float res_y = res_bit_dither.y > 0.0 ? res_bit_dither.y : 240.0;
mediump float bit_depth = res_bit_dither.z > 0.0 ? res_bit_dither.z : 5.0; // 5-bit color (32 levels)
mediump float dither_strength = res_bit_dither.w > 0.0 ? res_bit_dither.w : 0.03;
mediump vec2 grid = vec2(res_x, res_y);
mediump vec2 uv = floor(var_texcoord0 * grid) / grid;
lowp vec3 col = texture2D(tex0, uv).rgb;
mediump float levels = pow(2.0, bit_depth);
col = floor(col * levels) / levels;
mediump float noise = hash(uv * grid + mod(time.x, 10.0));
col += (noise - 0.5) * dither_strength;
gl_FragColor = vec4(col, 1.0);
}
psx.vp :
attribute mediump vec4 position;
attribute mediump vec2 texcoord0;
uniform mediump mat4 view_proj;
varying mediump vec2 var_texcoord0;
void main() {
gl_Position = view_proj * vec4(position.xyz, 1.0);
var_texcoord0 = texcoord0;
}


