Creating complex alpha masks in real-time?
Ren’Py has advanced a lot since I last tackled this, and I was hoping someone here might be able to put me on the path towards a reasonably optimized way of doing this:
I’ve been using a paper-doll system for the player character in my game where the character tans based on the swimsuit(s) they’ve been wearing.
So far, to accomplish the effect, I basically have two main images of the character—one pale and one with maximum tan. The tanned image is laid on top of the pale one with an alpha mask to essentially “apply” the tan effect.
So far, my biggest problem is how to create this alpha mask in-game.
I have a convoluted method that’s been working, but it’s probably a performance nightmare, so I was hopping someone could suggest a method that might be more appropriate.
Currently I have 3 grayscale images/alpha masks to represent each of the tanline possibilities (technically 2, as the 3rd is just a solid color).
In-game, there is a value of 0-100 representing how much each of each type of tan the player character has (essentially an alpha value of 0.0 - 1.0). Those three variables are updated on a regular basis throughout the game.
What I’d like to be able to do is layer those three images on top of each other (at their current opacity levels) and create a single alpha mask that will be applied to the tan image. It has to be able to update on a regular basis as the values change.
(Technically, there will be more than one of these, as I’ll need a set for each image of the character.)
Any thoughts/suggestions on efficient ways of pulling this off?
Creating complex alpha masks in real-time?
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
-
- Regular
- Posts: 34
- Joined: Wed Dec 26, 2018 10:45 am
- Contact:
- m_from_space
- Miko-Class Veteran
- Posts: 975
- Joined: Sun Feb 21, 2021 3:36 am
- Contact:
Re: Creating complex alpha masks in real-time?
How about you share your code, so we can see what method you are using? Do you experience a performance issue?
Sounds like you want to create a DynamicDisplayable using a Composite image and AlphaMask.
https://www.renpy.org/doc/html/displayables.html
Something I would do, but I have no clue how your images really apply here:
edit: Changed order of some lines, since you seem to want to apply the alphamask to the tanned image, not the final one. I'm not sure you realize what AlphaMask means, maybe you only mean opacity. Let me know.
Sounds like you want to create a DynamicDisplayable using a Composite image and AlphaMask.
https://www.renpy.org/doc/html/displayables.html
Something I would do, but I have no clue how your images really apply here:
Code: Select all
default tan_amount = 0.0
init python:
def tannedImage(st, at):
global tan_amount
# load a base image
img_base = Image(PATH_TO_BASE_IMAGE)
# load a second image, applying an opacity
img_tan = im.MatrixColor(PATH_TO_TAN_IMAGE, im.matrix.opacity(tan_amount))
# apply alpha mask to tan image
img_tan = AlphaMask(img_tan, PATH_TO_MASK)
# put both images together
img = Composite((IMG_WIDTH, IMG_HEIGHT), (0,0), img_base, (0,0), img_tan)
# return the image, None means that we won't call the function until the next interaction
return img, None
image tannedperson = DynamicDisplayable(tannedImage)
label start:
show tannedperson
"Look, I have no tan. Let's change that..."
$ tan_amount = 0.5
"That was fast."
-
- Regular
- Posts: 34
- Joined: Wed Dec 26, 2018 10:45 am
- Contact:
Re: Creating complex alpha masks in real-time?
I know what I'm trying to do is difficult to convey in text. I've got some images that I help will clear it up a bit more.
I'm starting with the pale and tan images:
I've got three mask images that I'm using for the tan-lines (though the third is technically just a solid color):
I'm setting an opacity level for each of those three images separately (values from 0-100), based on in-game stats. To get the final mask that will be used on the tan image, I merge those three together into a combined mask:
I'll have to go through the game code later to see if I can find the relevant sections from my working version. It's really convoluted, as there's far more to it than just the tan section (there are sections for hair and clothing, etc.).
I'm starting with the pale and tan images:
I've got three mask images that I'm using for the tan-lines (though the third is technically just a solid color):
I'm setting an opacity level for each of those three images separately (values from 0-100), based on in-game stats. To get the final mask that will be used on the tan image, I merge those three together into a combined mask:
I'll have to go through the game code later to see if I can find the relevant sections from my working version. It's really convoluted, as there's far more to it than just the tan section (there are sections for hair and clothing, etc.).
- m_from_space
- Miko-Class Veteran
- Posts: 975
- Joined: Sun Feb 21, 2021 3:36 am
- Contact:
Re: Creating complex alpha masks in real-time?
Okay that's helpful. And it's possible with the suggestion I gave you. I would try the following:
Code: Select all
# renpy will normally load those images automatically, and you can use their file names, but let's do it manually for clarity
image body_pale = "/images/..."
image body_tan = "/images/..."
image mask_one = ...
image mask_two = ...
image mask_nosuit = ...
# your opacity levels (0 to 100), better would be 0.0 to 1.0 to not have to divide by 100 later on
default mask_one_value = 0
default mask_two_value = 0
default mask_nosuit_value = 0
init python:
def tannedImage(st, at):
# apply current opacity levels to masks (maybe there is a better way to apply opacity I don't know about)
img_one = im.MatrixColor(mask_one, im.matrix.opacity(mask_one_value/100.0))
img_two = im.MatrixColor(mask_two, im.matrix.opacity(mask_two_value/100.0))
img_nosuit = im.MatrixColor(mask_nosuit, im.matrix.opacity(mask_nosuit_value/100.0))
# combine the masks
img_mask = Composite((IMG_WIDTH, IMG_HEIGHT), (0,0), img_one, (0,0), img_two, (0,0), img_nosuit)
# apply mask to tanned body
img_tan = AlphaMask(body_tan, img_mask)
# put tanned parts on top of pale body
img_final = Composite((IMG_WIDTH, IMG_HEIGHT), (0,0), body_pale, (0,0), img_tan)
# return the image
return img_final, None
image tannedperson = DynamicDisplayable(tannedImage)
label start:
show tannedperson
"Look, I have no tan. Let's change that..."
$ mask_one_value = 50
"That was fast."
-
- Regular
- Posts: 34
- Joined: Wed Dec 26, 2018 10:45 am
- Contact:
Re: Creating complex alpha masks in real-time?
Thanks for the suggestion! I'm going to have to spend a little time with it and see how it works for me.m_from_space wrote: ↑Thu Aug 18, 2022 3:20 am Okay that's helpful. And it's possible with the suggestion I gave you. I would try the following:
Yes, I was wondering about the im.MatrixColor part, too, as I'm pretty sure that's what I've been using in places.m_from_space wrote: ↑Thu Aug 18, 2022 3:20 amCode: Select all
# apply current opacity levels to masks (maybe there is a better way to apply opacity I don't know about) img_one = im.MatrixColor(mask_one, im.matrix.opacity(mask_one_value/100.0))
I wasn't sure if Renpy has a more efficient way of handling oppacity now, or if that's still the best method.
-
- Regular
- Posts: 34
- Joined: Wed Dec 26, 2018 10:45 am
- Contact:
Re: Creating complex alpha masks in real-time?
I tried it like this:
But I get this error:
If I change the Images to string variables...
...then it works. I think you can't pass a displayable to an image modifier?
Code: Select all
# renpy will normally load those images automatically, and you can use their file names, but let's do it manually for clarity
image body_pale = "images/avatar/pale.webp"
image body_tan = "images/avatar/tanned.webp"
image mask_one = "images/avatar/1p_msk.webp"
image mask_two = "images/avatar/2p_msk.webp"
image mask_nosuit = "images/avatar/no_msk.webp"
# your opacity levels (0 to 100), better would be 0.0 to 1.0 to not have to divide by 100 later on
default mask_one_value = 0
default mask_two_value = 0
default mask_nosuit_value = 0
init python:
def tannedImage(st, at):
# apply current opacity levels to masks (maybe there is a better way to apply opacity I don't know about)
img_one = im.MatrixColor(mask_one, im.matrix.opacity(mask_one_value/100.0))
img_two = im.MatrixColor(mask_two, im.matrix.opacity(mask_two_value/100.0))
img_nosuit = im.MatrixColor(mask_nosuit, im.matrix.opacity(mask_nosuit_value/100.0))
# combine the masks
img_mask = Composite((909, 720), (0,0), img_one, (0,0), img_two, (0,0), img_nosuit)
# apply mask to tanned body
img_tan = AlphaMask(body_tan, img_mask)
# put tanned parts on top of pale body
img_final = Composite((909, 720), (0,0), body_pale, (0,0), img_tan)
# return the image
return img_final, None
image tannedperson = DynamicDisplayable(tannedImage)
Code: Select all
I'm sorry, but an uncaught exception occurred.
While running game code:
File "game/script.rpy", line 19, in script
show tannedperson
File "game/systems/avatar_x/avatar_x2.rpy", line 19, in tannedImage
img_one = im.MatrixColor(mask_one, im.matrix.opacity(mask_one_value/100.0))
NameError: name 'mask_one' is not defined
Code: Select all
default body_pale = "images/avatar/pale.webp"
default body_tan = "images/avatar/tanned.webp"
default mask_one = "images/avatar/1p_msk.webp"
default mask_two = "images/avatar/2p_msk.webp"
default mask_nosuit = "images/avatar/no_msk.webp"
Who is online
Users browsing this forum: LuckyT