EDIT: I made massive progress in the 2nd post of this thread. I've got it 95% working, it looks just like photoshop Soft Light blending. Go to the 2nd post of this thread for the code. It just needs to be cleaned up, and this could possibly be a new blending mode for Ren'py one day. I'm making some rookie mistakes the veterans could easily help me fix.
Renpy has add, min, max, normal and multiply blend modes. I'd like to add Soft Light blend mode. This means you'd have two images shown, overlaid over each other, then the second image on top would be set to Soft Light blend mode.
Hypothetically, it'd work like this:
Code: Select all
transform soft_light_blending:
blend "softlight"
label start:
show image1 at center
show image2 at center, soft_light_blending
image special_fancy_overlay_soft_light = Transform("special_fancy_overlay_soft_light .png", blend="softlight")
Outside Sources
https://www.npmjs.com/package/glsl-blend-soft-light
Code: Select all
void main() {
vec4 bgColor = texture2D(bg, vUv);
vec4 fgColor = texture2D(foreground, vUv);
vec3 color = blend(bgColor.rgb, fgColor.rgb);
gl_FragColor = vec4(color, 1.0);
}
(blend < 0.5) ? (2.0 * base * blend + base * base * (1.0 - 2.0 * blend)) : (sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend))
This code was made by Remix and shared in Discord. It's a means of allowing two textures to be passed to a shader?
Code: Select all
init python:
class ShaderDisplayable(renpy.Displayable):
def __init__(self, *args, **kwargs):
self.shader_kws, kwargs = renpy.split_properties(kwargs, "u_", "")
self.shader = kwargs.pop("shader")
self.mipmap = kwargs.pop("mipmap", None)
# Pass additional properties on to the constructor.
super(ShaderDisplayable, self).__init__(**kwargs)
self.shader_textures = [renpy.easy.displayable(k) for k in args]
def render(self, width, height, st, at):
mr = renpy.display.render.render(
self.shader_textures[0], width, height, st, at)
w, h = mr.get_size()
rv = renpy.display.render.Render(w, h, opaque=False)
rv.blit(mr, (0,0))
for k in self.shader_textures[1:]:
cr = renpy.display.render.render(k, w, h, st, at)
rv.blit(cr, (0,0), focus=False, main=False)
rv.mesh = True
rv.add_shader(self.shader)
for k,v in self.shader_kws.items():
rv.add_uniform("u_{}".format(k), v)
rv.add_property("mipmap",
renpy.config.mipmap_dissolves if (self.mipmap is None)
else self.mipmap)
return rv
def event(self, ev, x, y, st):
return None
def visit(self):
return self.shader_textures
Based on the above code by Remix, we'd be able to specify Soft Light blend shader between the two given textures:
Code: Select all
image hello Tom = ShaderDisplayable("bg tom", "fg tom", u_keyword=1.0, shader="....")
Someone already made a soft light blend mode for Ren'py, but it doesn't actually blend one image over another, instead it applies a single color as a soft light over the base image which isn't very useful IMO.
https://github.com/CrossCouloir/renpy-b ... s/base.rpy
https://github.com/CrossCouloir/renpy-b ... _light.rpy
Code: Select all
soft_light_blend_mode = BlendMode("crosscouloir.soft_light")
soft_light_blend_mode.vars = """
uniform float u_lod_bias;
uniform sampler2D tex0;
uniform vec4 u_light_color;
attribute vec2 a_tex_coord;
varying vec2 v_tex_coord;
"""
soft_light_blend_mode.fragment_functions = """
float blendSoftLight(float base, float blend) {
return (blend<0.5)?(2.0*base*blend+base*base*(1.0-2.0*blend)):(sqrt(base)*(2.0*blend-1.0)+2.0*base*(1.0-blend));
}
vec3 blendSoftLight(vec3 base, vec3 blend) {
return vec3(blendSoftLight(base.r,blend.r),blendSoftLight(base.g,blend.g),blendSoftLight(base.b,blend.b));
}
vec3 blendSoftLight(vec3 base, vec3 blend, float opacity) {
return (blendSoftLight(base, blend) * opacity + base * (1.0 - opacity));
}
"""
soft_light_blend_mode.vertex_shader = """
v_tex_coord = a_tex_coord;
"""
soft_light_blend_mode.fragment_shader = """
vec4 bgcolor = texture2D(tex0, v_tex_coord.st, u_lod_bias);
vec3 blended = blendSoftLight(bgcolor.xyz, u_light_color.xyz, u_light_color.w);
gl_FragColor = vec4(blended, bgcolor.w);
"""
soft_light_blend_mode.register()
Here is more code that might be useful. It's supposed to be a Darken blend mode shader. This was written by user EviteGames from Discord:
https://discord.com/channels/2866338985 ... 8019353652
Code: Select all
float blendDarken(float base, float blend) {
return min(blend,base);
}
vec3 blendDarken(vec3 base, vec3 blend) {
return vec3(blendDarken(base.r,blend.r),blendDarken(base.g,blend.g),blendDarken(base.b,blend.b));
}
vec3 blendDarken(vec3 base, vec3 blend, float opacity) {
return (blendDarken(base, blend) * opacity + base * (1.0 - opacity));
}
gl_FragColor = vec4(min(baseColor.r,blendColor.r), min(baseColor.g, blendColor.g), min(baseColor.b, blendColor.b), 1.0)
renpy.register_shader("evitegames.darkenblend", variables="""
uniform sampler2D tex0; // this should be the 'background' texture or the image/render itself
uniform sampler2D tex1; // this should be the 'blend' texture or the video we're trying to darken the image with
uniform float u_lod_bias;
attribute vec2 a_tex_coord;
varying vec2 v_tex_coord;
""", vertex_300="""
v_tex_coord = a_tex_coord;
""", fragment_300="""
vec4 baseColor = texture2D(tex0, v_tex_coord.st, u_lod_bias);
vec4 blendColor = texture2D(tex1, v_tex_coord.st, u_lod_bias);
gl_FragColor = vec4(min(baseColor.r,blendColor.r), min(baseColor.g, blendColor.g), min(baseColor.b, blendColor.b), 1.0);
""")
https://zhuanlan-zhihu-com.translate.go ... r_pto=wapp
Code: Select all
PS_BLEND_SOFTLIGHT = """
VARYING vec2 varUv;
UNIFORM sampler2D tex0;
UNIFORM sampler2D tex1;
void main()
{
vec4 color0 = texture2D(tex0, varUv);
vec4 color1 = texture2D(tex1, varUv);
for(int i=0; i<4; i++)
{
if(color1[i] >= 0.5)
{
gl_FragColor[i] = 2.0 * color0[i] * color1[i] + color0[i] * color0[i] - 2.0 * color0[i] * color0[i] * color1[i] ;
}
else
{
gl_FragColor[i] = 2.0 * sqrt(color0[i]) * color1[i] - sqrt(color0[i]) + 2.0 * color0[i] - 2.0 * color0[i] * color1[i];
}
}
}
"""
https://www.renpy.org/doc/html/model.ht ... iority-200
Code: Select all
uniform float u_lod_bias;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform float u_renpy_dissolve_offset;
uniform float u_renpy_dissolve_multiplier;
attribute vec2 a_tex_coord;
varying vec2 v_tex_coord;
v_tex_coord = a_tex_coord;
vec4 color0 = texture2D(tex0, v_tex_coord.st, u_lod_bias);
vec4 color1 = texture2D(tex1, v_tex_coord.st, u_lod_bias);
vec4 color2 = texture2D(tex2, v_tex_coord.st, u_lod_bias);
float a = clamp((color0.a + u_renpy_dissolve_offset) * u_renpy_dissolve_multiplier, 0.0, 1.0);
gl_FragColor = mix(color1, color2, a);