Not logged inOpenClonk Forum
Up Topic Development / Developer's Corner / Zoom and Parallax
- - By Günther [de] Date 2010-09-26 00:10
So during the CM ck and I worked out how to properly draw parallax objects when the game is zoomed. We implemented the algorithm in a function in C4Object (C4Object::GetDrawPosition) and made the various drawing functions use it. I also copied that code into the Sky drawing function (C4Sky::Draw), and tried to make it do the same thing. But the result is that the Sky drawing function works nicely, while objects behave strangely. I stared at the code for a while and can't find the problem, so I'm giving up for now and ask for help. The code is in the repos. The good news is that the problem is only apparent while changing the zoom level, so it's not really critical. And the Sky is zooming nicely :-)

Attached is a diagram explaining the formula.
Attachment: ZoomParallax.svgz - The red lines are the sought-after dimensions. (1k)
Reply
Parent - - By Günther [de] Date 2010-09-26 03:54
After deriving the formula from the diagram a second time and validating that it matches the implementation, I finally discovered that the diagram is wrong. The correct version is attached, but testing it has to wait for tomorrow. (Also note that the ResultZoom is not the real zoom, as the objects are scaled with 1/Par - they don't change their size when changing parallaxity with Zoom 1.)
Attachment: ZoomParallax.svgz (1k)
Reply
Parent - By Günther [de] Date 2010-09-26 20:10
And the result is in the repository. There are some bugs with vanishing objects that still need to be fixed, but the positioning math is sound now.
Reply
- - By Günther [de] Date 2010-10-11 21:32
I've written a text intended as a blogpost about this. How do I go about posting it there?

Clonk has supported parallax objects and backgrounds for a while. Parallax scrolling is a method to create a faux 3d effect with only 2d methods by making objects move slower or faster when the imaginary camera moves across the landscape. This approach generally works well, but the effect this had when the zoom level changed was unfortunate. Instead of simply making parallax objects and backgrounds look the same way as the other objects when zoomed, Clonk-Karl and I figured out how they would behave if they really were before or behind the landscape. The first question we had to answer what different zoom levels represented in that virtual world: Does the distance between camera and landscape change, or do the camera optics, like a zoom lens? We eventually came to the conclusion that we needed both: the zoom lens to ensure that every player sees about the same picture independent of the pixel count of their monitor, and the distance change to represent zoom. While real-world zoom uses a zoom lens, real world unmodified humans do not, so changing the virtual distance should feel more natural.

Figuring out how the objects should display on a diagram was straightforward after that. Put a point for the camera, one line for the landscape and screen (the landscape always is on the same plane as the screen, because the screen is what keeps the sky islands from falling down), and one line for the object, and then draw lines from the edges of the object to the camera. The object should be displayed were those lines cross the screen. But we needed several iterations translating that to the formulas used in the engine because we hadn't fully internalized what the given values meant. The position of the object is not where the object is in the virtual world, but where it is displayed on the landscape when the camera is at position 0/0, and the zoomfactor is 1. And the camera is at position 0/0 when the upper left corner of the screen is there. It's as if only the lower right quarter of the camera's view is displayed. The reason is that the parallax math works out rather nice this way: When translating from landscape to screen coordinates, the position of the upper left corner of the screen is simply multiplied by the parallax factor and subtracted from the object's position. But our first diagrams had the camera positions in the middle of the screen, which was confusing because it introduces the screen size into the formulas, which we knew is not there in the engine code.

We finally arrived at what we believed were the correct formulas and put them into the engine. The result was for the most part satisfactory, especially the sky behaved nicely. But objects moved around on the screen when changing the zoom factor while moving as expected when just moving around. I finally discovered why when constructing this diagram a few days later:

(see attachment)

The diagram shows a view from the side on the camera, landscape and one object. Because the formulas for X and Y are independent and identical, only one dimension is shown.

The black distances are given, the red distances are the ones we want to calculate. The green ones are intermediate results. The dashed lines are the lines of sight between camera and object.

At the top left of the diagram is the camera that defines the internal object positions: The position of an object is where this camera would see the object in the landscape. A bit to the right is a camera at position 0/0, but with a different zoom factor (called "Zoom"). Our first version mixed this camera up with the first one. This doesn't matter for objects at position 0/0, which explains why the sky worked correctly: We only tested in a scenario where the sky doesn't move with the wind.

Down from the second camera is the third one, the one for which the calculations are to be done. It has a distance of "TargetX" from the origin, and a zoom factor of "Zoom" like the second camera.

At the right there's the object to be displayed. This one is behind the landscape, but fortunately the formulas work just as well for an object before the landscape. It's distance on the Z axis from the first camera is "1/Par", where "Par" is the parallax factor. Consequently, the distance to the landscape is "1/Par-1", because the first camera has a distance of "1" from the landscape. The position in the virtual world on the X axis is "VX".

Once I had this diagram, calculating the result is a simple application of the http://en.wikipedia.org/wiki/Intercept_theorem. Those interested in the result can take a look at the C4Object::GetDrawPosition() function in the engine.
Attachment: ZoomParallax.png - Diagram (27k)
Reply
Parent - - By Randrian [de] Date 2010-10-11 22:12
A thing which I disliked for the old paralaxity, is that it always had 0,0 as "reference". I think one would expect more the position of the object itself.
E.g. placing multiple objects (form of a circle or so) at one position with different parallaxity should imo make an effect as a bar reaching out of the screen. And you should see it exactly form the front when the object is centered on the screen.
So the old parallaxity wasn't good to use, except for things like stars where the position didn't really matter.
Sorry, but your calculation is a bit complex and I don't know if you have already thought about this aspect.
Reply
Parent - By Günther [de] Date 2010-10-11 23:06
Heh, yeah, that aspect also threw us off initially when revising the math :-)

In terms of the diagram, you're essentially proposing to use the object's position as "VX" instead of "ObjX". The problem is, while VX is an intermediate results, it doesn't appear in the final formula for a good reason: Objects with parallax zero (which have an infinite distance from the viewer) which aren't at 0/0 have an infinite VX. This cancels out with the infinite distance, but storing these values isn't feasible. We could probably special-case parallax zero, I guess.
Reply
Up Topic Development / Developer's Corner / Zoom and Parallax

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill