Would you like to react to this message? Create an account in a few clicks or log in to continue.
Welcome!!! - Bienvenidos!!! - ( We hope you will get involved in the MMV Community which is dedicated to having fun with Mugen ) - Bienvenidos!!! - Welcome!!!
Subject: Parallax Interpolation June 30th 2018, 8:23 pm
Ok, so I was helping someone to know how parallax works for the Mugen Class section at Mugen Guild. There are some "tutorials" around the internet, I've checked several of them but all they do is just trial & error without showing how to calculate the values, & probably they don't even know what they're doing.
Doing it by trial & error can work when doing very simple stages, although it can get annoying if one wants to make more complex stuff, so I'm copy-pasting the breakdown I made here as well (& in a couple more places).
There are two ways of doing this, Width and Xscale, I'll just cover Width for now. VIB's tutorial covers Xscale (http://mugenguild.com/forum/topics/parallax-tutorial-vib-116138.msg1119796.html#msg1119796), I feel it falls kind of short on explanation, not really hard, although just very few people have made use of it's potential. I may cover Xscale, along with ceiling parallax, scaledelta, animated parallax, vertical parallax & delta that changes (late 2 are workarounds).
For anyone who doesn't know what parallax is, it refers to the effect in which the position of some object appears to change when is viewed from different positions. In mugen, when we refer to parallax we basically refer to this:
^This is an example of a 100% parallax BG (not finished at the time of the video).
A bad parallax will make your characters or any other BG object slide & look weird while scrolling.
---->this is bad parallax.
A good parallax matches with everything and helps to give depth.
---->this is good parallax.
Unlike Xscale (which is used for floors with a given perspective), Width is used mainly for tiled floors, or floors without perspective, the advantage of Width is that it allows a wider distortion without shearing details.
--->this was made using Xscale.
--->this was made using Width & a tiled floor without perspective.
Tutorial starts here.
Calculating Zoffset & Deltas: Deciding a starting & ending delta for the parallax floor, one can calculate the Zoffset of the characters and the delta of any element positioned on the floor. Example used: --->this was made using width & a floor without perspective (not tiled).
This is basically your floor with the values you would set in your piece of code:
For this example I used a floor sprite of 349 pixels of height, top delta is defined by the delta X you decide in the piece of code (0.3), and the bottom delta is proportional to that using the values you set at width, meaning 11000/2000= 5.5 more times.
So 5.5 x 0.3 delta = 1.65 delta, so:
Top moves at 0.3 and bottom moves at 1.65, rest is just linear interpolation.
1.65 – 0.3 = 1.35, means that in 349 pixels your sprite moves 1.35 delta.
Let's say you want to calculate the Zoffset: 349 pixels------->1.35 delta X? ------->0.7 delta
0.7 is taken from 1 - 0.3 = 0.7, because your parallax starts at 0.3, and you need 0.7 to be 1. 1 is always the delta velocity that your characters move standing on your zoffset while scrolling.
Doing the math; (0.7 x 349) / 1.35 = 180.96 pixels This means that in 180.96 pixels, it will move 0.7 delta.
The zoffset 180.96 + 489 pixels = 669.96 pixels = 670, ----> this is the optimal zoffset for the characters, they won't slide. 489 is the Y position of the parallax sprite/floor.
Axis of the sprite must be taken into account (in the sff file), for this example my floor axis was at top.
Let's say you want to get the delta value for a background element sitting on the same parallax floor:
[BG elem] type = normal spriteno = 21,3 start = 100, 590 delta = .690687679,1 mask = 1
349 pixels ---->1.35 delta 101 pixels ----> X?
101 is taken from 590 – 489 = 101 Where 590 is the Y position of your bg element sitting on the floor, and 489 is the Y position of your parallax sprite/floor.
Doing the Math; (101x1.35)/349 = 0.390687679 delta 0.390687679 + 0.3= 0.690687679 ---> this is your optimal delta value for a stage element at the position 590. 0.3 is the delta where your parallax/floor starts at.
Axis of the sprite must be taken into account too (in the sff file), for this one the axis was at bottom.
I'll leave this here for anyone who's familiar with linear interpolation/extrapolation. This is the whole reasoning of these 2 examples, who knows, it may be easier to understand like this.
Mapping with horizontal rows: Let's say I already calculated my Zoffset and want to add one more parallaxed row on top of my bottom parallax, I'd need to calculate the X delta & top width of the parallax behind my first parallax. Example used:
(651.66/860) = 0.7577 0.7577 x 1 = 0.7577 delta X ;----------------------------------
Localcoord is 960x720 I'm using 2 sprites of 1661x412, their position at the sff file is (830,0) for both. Zoffset is 631. The progressive scale reduction (yscalestart) is 1.38, (1133/820), as elements go into the horizon they need to shrink, that's the reason of this. Yscalestart was deprecated in 1.1, and changed for Scalestart because it's more intuitive, I'm just using the deprecated one because I'm doing a little of explanation at guild.
Animated Parallax:
Using Width, once you have calculated your parallax values, you just need to code it like you would code a normal animation, but instead of Spriteno, you use Actionno.
However, this only works with Width & it only was implemented in 1.1, it won't work in 1.0. By using Xscale you need to make use of BG controls (whether you use 1.0 or 1.1).
Reminder: Xscale is used for floors with a given perspective, Width is used mainly for tiled floors, or floors without perspective.
For Xscale (or anything below 1.1), once you have calculated your parallax values you assign an ID to each frame that makes up the parallax. Parallax values are the same except for the Spriteno & the ID.
My animation is formed by 8 sprites, each frame lasts 8 ticks, so the whole animation lasts 64 ticks = looptime 64. Basically you enable & disable each frame in 8 ticks intervals.
The first frame activates at time 0 & disables at time 8. The second frame starts disabled at time 0, enables at time 8 & becomes disabled at time 16. The third frame starts disabled at time 0, enables at time 16 & becomes disabled at time 24. this goes on until loop is completed.
[BGCtrl 2] type = Visible time = 16 value = 0 ;----------------------- [BGCtrlDef 3] ctrlid = 3 looptime = 64
[BGCtrl 3] type = Visible time = 0 value = 0
[BGCtrl 1] type = Visible time = 16 value = 1
[BGCtrl 2] type = Visible time = 24 value = 0 ;----------------------- [BGCtrlDef 4] ctrlid = 4 looptime = 64
[BGCtrl 3] type = Visible time = 0 value = 0
[BGCtrl 1] type = Visible time = 24 value = 1
[BGCtrl 2] type = Visible time = 32 value = 0 ;----------------------- [BGCtrlDef 5] ctrlid = 5 looptime = 64
[BGCtrl 3] type = Visible time = 0 value = 0
[BGCtrl 1] type = Visible time = 32 value = 1
[BGCtrl 2] type = Visible time = 40 value = 0 ;----------------------- [BGCtrlDef 6] ctrlid = 6 looptime = 64
[BGCtrl 3] type = Visible time = 0 value = 0
[BGCtrl 1] type = Visible time = 40 value = 1
[BGCtrl 2] type = Visible time = 48 value = 0 ;----------------------- [BGCtrlDef 7] ctrlid = 7 looptime = 64
[BGCtrl 3] type = Visible time = 0 value = 0
[BGCtrl 1] type = Visible time = 48 value = 1
[BGCtrl 2] type = Visible time = 56 value = 0 ;----------------------- [BGCtrlDef 8] ctrlid = 8 looptime = 64
[BGCtrl 3] type = Visible time = 0 value = 0
[BGCtrl 1] type = Visible time = 56 value = 1
[BGCtrl 2] type = Visible time = 64 value = 0
Here's another way to code it.
Spoiler:
[BGCtrlDef ParallaxAnim] looptime = 64
[BGCtrl 1] type = Visible time = 0 value = 1 ctrlid = 1
[BGCtrl 1] type = Visible time = 0 value = 0 ctrlid = 2,3,4,5,6,7,8 ;--------- [BGCtrl 2] type = Visible time = 8 value = 1 ctrlid = 2
[BGCtrl 2] type = Visible time = 8 value = 0 ctrlid = 1 ;---------- [BGCtrl 3] type = Visible time = 16 value = 1 ctrlid = 3
[BGCtrl 3] type = Visible time = 16 value = 0 ctrlid = 2 ;---------- [BGCtrl 4] type = Visible time = 24 value = 1 ctrlid = 4
[BGCtrl 4] type = Visible time = 24 value = 0 ctrlid = 3 ;---------- [BGCtrl 5] type = Visible time = 32 value = 1 ctrlid = 5
[BGCtrl 5] type = Visible time = 32 value = 0 ctrlid = 4 ;---------- [BGCtrl 6] type = Visible time = 40 value = 1 ctrlid = 6
[BGCtrl 6] type = Visible time = 40 value = 0 ctrlid = 5 ;---------- [BGCtrl 7] type = Visible time = 48 value = 1 ctrlid = 7
[BGCtrl 7] type = Visible time = 48 value = 0 ctrlid = 6 ;---------- [BGCtrl 8] type = Visible time = 56 value = 1 ctrlid = 8
[BGCtrl 8] type = Visible time = 56 value = 0 ctrlid = 7
Scaledelta: Refers to the amount to change the scale of the element for each unit of camera movement, you calculate it dividing the delta range by the sprite width multiplied by the sprite delta.
[BG 0];wall right type=normal spriteno = 12,1 start=130,400 mask = 1 delta= .5,1 scaledelta = -0.002427,0 ;------------Negative when scrolling to the right.
[BG 0];wall left type=normal spriteno = 12,1 start=-130,400 mask = 1 delta= .5,1 scaledelta = 0.002427,0 ;------------Positive when scrolling to the left.
Result:
Note that this method only works in 1.1, the effect is possible for 1.0 but you need to use a workaround, I may cover it in the future. With the addition of scaledelta in 1.1 that method would be obsolete, but I like to use it for stages that have a high-to-the-ground perspective to add vertical parallax (since vertical wall parallax hasn't been implemented in any mugen).
Last edited by Aℓίcℯ on July 18th 2018, 4:26 pm; edited 10 times in total
Doom
Posts : 10512 Join date : 2014-08-22
Subject: Re: Parallax Interpolation July 1st 2018, 2:01 pm
Impressive tutorial ... This will be very useful for the creators of stages in our forum ... Thanks for sharing ...
Aℓίcℯ
Posts : 160 Join date : 2016-09-11
Subject: Re: Parallax Interpolation July 4th 2018, 11:06 pm
Part 2
Mapping with horizontal rows: Let's say I already calculated my Zoffset and want to add one more parallaxed row on top of my bottom parallax, I'd need to calculate the X delta & top width of the parallax behind my first parallax. Example used:
(651.66/860) = 0.7577 0.7577 x 1 = 0.7577 delta X ;----------------------------------
Localcoord is 960x720 I'm using 2 sprites of 1661x412, their position at the sff file is (830,0) for both. Zoffset is 631. The progressive scale reduction (yscalestart) is 1.38, (1133/820), as elements go into the horizon they need to shrink, that's the reason of this. Yscalestart was deprecated in 1.1, and changed for Scalestart because it's more intuitive, I'm just using the deprecated one because I'm doing a little of explanation at guild.
Aℓίcℯ
Posts : 160 Join date : 2016-09-11
Subject: Re: Parallax Interpolation July 11th 2018, 11:17 am
Part 3
Animated Parallax:
Using Width, once you have calculated your parallax values, you just need to code it like you would code a normal animation, but instead of Spriteno, you use Actionno.
However, this only works with Width & it only was implemented in 1.1, it won't work in 1.0. By using Xscale you need to make use of BG controls (whether you use 1.0 or 1.1).
Reminder: Xscale is used for floors with a given perspective, Width is used mainly for tiled floors, or floors without perspective.
For Xscale (or anything below 1.1), once you have calculated your parallax values you assign an ID to each frame that makes up the parallax. Parallax values are the same except for the Spriteno & the ID.
My animation is formed by 8 sprites, each frame lasts 8 ticks, so the whole animation lasts 64 ticks = looptime 64. Basically you enable & disable each frame in 8 ticks intervals.
The first frame activates at time 0 & disables at time 8. The second frame starts disabled at time 0, enables at time 8 & becomes disabled at time 16. The third frame starts disabled at time 0, enables at time 16 & becomes disabled at time 24. this goes on until loop is completed.
[BGCtrl 2] type = Visible time = 16 value = 0 ;----------------------- [BGCtrlDef 3] ctrlid = 3 looptime = 64
[BGCtrl 3] type = Visible time = 0 value = 0
[BGCtrl 1] type = Visible time = 16 value = 1
[BGCtrl 2] type = Visible time = 24 value = 0 ;----------------------- [BGCtrlDef 4] ctrlid = 4 looptime = 64
[BGCtrl 3] type = Visible time = 0 value = 0
[BGCtrl 1] type = Visible time = 24 value = 1
[BGCtrl 2] type = Visible time = 32 value = 0 ;----------------------- [BGCtrlDef 5] ctrlid = 5 looptime = 64
[BGCtrl 3] type = Visible time = 0 value = 0
[BGCtrl 1] type = Visible time = 32 value = 1
[BGCtrl 2] type = Visible time = 40 value = 0 ;----------------------- [BGCtrlDef 6] ctrlid = 6 looptime = 64
[BGCtrl 3] type = Visible time = 0 value = 0
[BGCtrl 1] type = Visible time = 40 value = 1
[BGCtrl 2] type = Visible time = 48 value = 0 ;----------------------- [BGCtrlDef 7] ctrlid = 7 looptime = 64
[BGCtrl 3] type = Visible time = 0 value = 0
[BGCtrl 1] type = Visible time = 48 value = 1
[BGCtrl 2] type = Visible time = 56 value = 0 ;----------------------- [BGCtrlDef 8] ctrlid = 8 looptime = 64
[BGCtrl 3] type = Visible time = 0 value = 0
[BGCtrl 1] type = Visible time = 56 value = 1
[BGCtrl 2] type = Visible time = 64 value = 0
Here's another way to code it.
Spoiler:
[BGCtrlDef ParallaxAnim] looptime = 64
[BGCtrl 1] type = Visible time = 0 value = 1 ctrlid = 1
[BGCtrl 1] type = Visible time = 0 value = 0 ctrlid = 2,3,4,5,6,7,8 ;--------- [BGCtrl 2] type = Visible time = 8 value = 1 ctrlid = 2
[BGCtrl 2] type = Visible time = 8 value = 0 ctrlid = 1 ;---------- [BGCtrl 3] type = Visible time = 16 value = 1 ctrlid = 3
[BGCtrl 3] type = Visible time = 16 value = 0 ctrlid = 2 ;---------- [BGCtrl 4] type = Visible time = 24 value = 1 ctrlid = 4
[BGCtrl 4] type = Visible time = 24 value = 0 ctrlid = 3 ;---------- [BGCtrl 5] type = Visible time = 32 value = 1 ctrlid = 5
[BGCtrl 5] type = Visible time = 32 value = 0 ctrlid = 4 ;---------- [BGCtrl 6] type = Visible time = 40 value = 1 ctrlid = 6
[BGCtrl 6] type = Visible time = 40 value = 0 ctrlid = 5 ;---------- [BGCtrl 7] type = Visible time = 48 value = 1 ctrlid = 7
[BGCtrl 7] type = Visible time = 48 value = 0 ctrlid = 6 ;---------- [BGCtrl 8] type = Visible time = 56 value = 1 ctrlid = 8
[BGCtrl 8] type = Visible time = 56 value = 0 ctrlid = 7
Aℓίcℯ
Posts : 160 Join date : 2016-09-11
Subject: Re: Parallax Interpolation July 18th 2018, 4:28 pm
Part 4
Scaledelta: Refers to the amount to change the scale of the element for each unit of camera movement, you calculate it dividing the delta range by the sprite width multiplied by the sprite delta.
[BG 0];wall right type=normal spriteno = 12,1 start=130,400 mask = 1 delta= .5,1 scaledelta = -0.002427,0 ;------------Negative when scrolling to the right.
[BG 0];wall left type=normal spriteno = 12,1 start=-130,400 mask = 1 delta= .5,1 scaledelta = 0.002427,0 ;------------Positive when scrolling to the left.
Result:
Note that this method only works in 1.1, the effect is possible for 1.0 but you need to use a workaround, I may cover it in the future. With the addition of scaledelta in 1.1 that method would be obsolete, but I like to use it for stages that have a high-to-the-ground perspective to add vertical parallax (since vertical wall parallax hasn't been implemented in any mugen).