Godot: Error from get_transform().basis.get_euler() after some play-time

Created on 23 Feb 2018  路  40Comments  路  Source: godotengine/godot

Godot version:
Godot 3.0 Stable Official
Godot 3.0.1 RC1

OS/device including version:
Windows 10 64 bit

Issue description:
When tying an objects rotation to a mouse axis, and calling the rotation euler from get_transform().basis.get_euler.y, the euler will after a while stop sending data and leave errors in the debug window.

Steps to reproduce:
Start project linked below in Godot 3.0, F5 to start the game, use mouse to rotate cube.
After 10-20 seconds errors will appear in the debugger with every frame, ie. the euler stopped working properly

Full Script failing object:

extends Spatial

var cameraAngle = 0.0

func _ready():

    pass

func _input(event):

        var cameraY = -event.relative.y

        $"../".rotate_x(deg2rad(cameraY))
        cameraAngle += cameraY


func _process(delta):

    print($"../".get_global_transform().basis.get_euler().y)

This is the error reported traced to the bottom line:

0:00:35:0027 - Condition ' is_rotation() == false ' is true. returned: euler
----------
Type:Error
Description: 
Time: 0:00:35:0027
C Error: Condition ' is_rotation() == false ' is true. returned: euler
C Source: core\math\matrix3.cpp:462
C Function: Basis::get_euler_yxz

Additional info:
I originally found the issue while developing a character script, this is the very simplified version of the issue.

Minimal reproduction project:
Project can be downloaded from here: https://drive.google.com/open?id=1B18k_mjX2-v-RhD1J-szT1q4nccwavJW

bug core

Most helpful comment

All 40 comments

UPDATE:
I implemented a targeting feature in the original character control-script, making use of look_at() to target an object.
Targeting the object (and removing rotation-control from mouse) resets the issue momentarily until the player is allowed to control the rotation for 10-20 seconds once again.

I was also getting this as well with global_transform.basis.get_euler().

I looked at the is_rotating() function in the error and it checked if it was orthogonal and then I looked at the documentation for get_euler() and it seems it needs an orthonormalized matrix, so global_transform.basis.orthonormalized().get_euler() fixes the problem. So I don't think it's a bug.

But I don't really understand why that works? Is it normal to need that? In all the code/questions I've seen, basis.get_euler() is used / was mentioned. I don't think any of those were official, but maybe this should be mentioned somewhere in the 3d math documentation when it's expanded upon. Some functions (e.g. rotate) also give a similar error when the vector passed to it isn't normalized but in that case it's a bit easier to figure out because the error says p_axis.is_normalized() == false ' is true.

Interestingly, I think the writeup Reduz posted earlier today about transforms in Godot contains the answer to that.

As you're applying rotations to transforms there is always a small degradation in the transform due to floating math error. The matrix vectors will slowly have their lengths and orientation being slightly off. You won't notice this visually until it really gets weird but for certain math functions it is very important that the 3 unit vectors in the transform are normalized and at rightangles to each other.

As orthonormalize is relatively expensive to run it's up to the developer to occasionally apply it.

@BastiaanOlij Thanks, that makes more sense now. Can you link to the writeup?

@volzhs I actually read through that, but it gave me the impression that it should still work (just that it would be slightly off). I think it should be clear that this will cause errors which will cause things to break at some point or another with enough transforms (unless are there any cases were it doesn't?).

Should I file an issue on godot-docs?

Also should the whole transform be orthonormalized like in that tutorial? Is there a difference between calling it on transform vs its basis?

In Godot, Basis is stored as a 3x3 matrix, which has 9 degrees of freedom. A rotation on the other hand has only 3 degrees of freedom (be it polar angles of rotation axes and rotation angle, or 3 Euler angles). So 3x3 matrix is an extravagant representation of rotations and only a subset of all 3x3 matrices correspond to rotations.

get_euler can only extract the Euler angle if the Basis matrix is a rotation matrix. It it's not a rotation matrix, then you can't talk about Euler angles parametrization. This is why it doesn't work and gives you the error.

Even if you start from a rotation matrix, as you modify it with rotate_x, it will drift due to precision errors and your matrix can start going out of that subset of 3x3 matrices which correspond to rotations. This is the downside of using matrix representation.

Regarding the docs, there will be a new one this weekend, and it does cover such downsides of matrix representation.

I tried to push for a quaternion representation of the orientation part in the Transform (which would mostly eliminate that kind of precision errors because it's stored as 4 numbers as opposed to 9, and it's renormalization is just a vector normalization rather than an expensive matrix orthogonolization), but it didn't take off...

@tagcup Godot has quaternions, they are wonderful and they should be used when appropriate.

However if all the rotations where stored in quaternions you'd have to constantly convert them to matrices to do many of the high volume operations and that would just be an incredible performance drain on the engine if it needs to do those conversions for every one of those operations. Especially when child nodes apply their rotation and positioning relative to the rotation and position of its parent, and that to the n-th level, that is far easier to do and far less costly to do when those are stored in (4x4) matrices.

In that way the Transform having basis and origin separated is already an interesting choice, I fully get that from the point of view of making the engine far more accessible to people who aren't fully into the math involved, from a pure mathematical point of view a 4x4 matrix would be better and is what most other engines do, but in this case the 3x3 matrix + origin vector isn't a draw back performance wise as you can still use the same math and making it easier to understand is a bonus. In the end its a 4x4 matrix that gets sent to the shaders though :)

But as far as quaternions go, they shine when used right especially when interpolating between different orientations, and Godot has full support for them when you need them, but it make a lot of sense to leave it up to the developer to assign the quaternion to the transforms basis in order to convert the quaternion to a matrix. That would need to happen in the background anyway, and now it only happens when necessary and in many cases, you don't need the overhead.

I'm well aware that the 3D real vector space is omnipresent, and a conversion all the time is unpractical.

I omitted the details here but what I proposed is to store axis-angle and scale in addition to a baked basis matrix, which requires disabling write access to matrix components. Matrix would need to be rebaked when the axis-angle or scale changed. This comes with a little memory overhead but 1) eliminates and entire class of precision errors 2) makes possible to do polar decomposition (splitting basis into rotation and scale).

2) was the original context I proposed this. Some people get confused when they set a negative scale and get a totally different rotation/scale when they ask for the rotation or scale part

Baking isn't free of course but shouldn't make much of a difference because if for example the axis-angle is stored as a quaternion, performing rotations there is much faster than doing it in the matrix representation, so it should roughly balance out. For scale, it doesn't matter at all

So there is no CPU overhead at all, only a memory overhead, 7 additional floats at most.

This would be totally transparent to the user BTW, the quaternion and scale can be kept as private members. Implementing this would only break direct write access to basis matrix elements which should be super rare anyway.

@tagcup there are many situations where I calculate the matrix for an object and assign the matrix, so if you disable the ability to assign a matrix to an object and force me to always use a quaternion, you'll make me very unhappy indeed because there are various things I can't easily do through quaternions.

Quaternions don't always make sense, I like the current solution. If a quaternion makes sense, I use one. If a quaternion doesn't make sense, I don't. I can add the quaternion to any node where I wish to base my rotations on a quaternion and have it set the matrix.

Anyway, we're going around in circles, and really polluting the OPs thread :)

It's not a circle you totally misunderstood what I was talking about and now you're saying you'd be unhappy because you prefer a matrix representation over a quaternion one.

Basis isn't an arbitrary matrix, it's a rotation scale matrix so even if you assign it by hand it has to come from a rotation. Randomly assigning matrix entries isn't a real use case and makes no sense.

I also nowhere said I'm going to remove matrix constructor (which covers the use case if calculating the rotation matrix elsewhere and assigning it), I was talking about writing to individual components.

FYI you can't also write to matrix elements in Unity and people are just fine. It's no big deal.

And no I'm not changing anything so don't fret over it.

Also if you're thinking quaternions don't always make sense for rotations you're not understanding it correctly. Quaternions and rotation matrices do exactly the same things vice versa, there's no difference between them. If you're thinking you can do one thing with one and can't do in other, that's wrong. Quaternions aren't magical things that make some problems go away and neither are matrices.

If you want to use axis angle parametrization you can do it with both. If you want to use Euler angle parametrization you do it with both. If you want to do SLERP you can do it with both (not implemented for matrix representation in Godot right now but it's trivial to add). There is no difference in mathematics. The only difference is in precision errors, storage and the number if CPU cycles.

Their implementation might not be on par (like SLERP with matrices not implemented yet, or some types of constructors are missing in each class), but that's not a mathematical restriction and can be remedied easily.

We're also not completely off topic but yeah since reduz doesn't want to make any changes toward that direction, it's not fruitful either.

@tagcup, who said anything about random? It's all about math, it's what inputs you start with.

If I want to align an object with a surface it's a simple cross product of vectors. I don't want to first bring that back to a quaternion so that it can calculate the matrix for which I already have all the ingredients.

Btw, what you want is pretty easy to do now just in GDScript by just adding a quaternion variable to your script with a setget, on the get you return the quaternion, on the set you set the quaternion and then assign it to the basis. Godot will nicely calculate the matrix and apply it.

That way you get what you want, and I still have what I want :)

Likewise, who said there won't be a matrix constructor? I'm telling it the second time, if you want to replace the entire basis, you can do it. What you can't do is change some elements which is different from what you want anyway.

And the point of the proposal wasn't to make myself happy but to avoid or alleviate the two problems users typically come across. Like this issue.

You can look at Unity's API if you still have doubts. It's exactly like that. You can't write to individual matrix elements. And people have been just fine without it for years.

@tagcup I guess I'm too old fashioned then, or maybe I've lived on the technical side of things too long :) You are indeed right, I can do what I need to do on a Basis, then assign that to the node, though it also means copying it, then modifying it, then copying it back. It just seems very wasteful just to support one particular use case that you can already do today by just using a quaternion.
I think it also comes from engines I've worked on for years and written myself using 3x4 and 4x4 matrices on this level. Like I said, Godot splitting this into a 3x3 matrix (basis) and translation (origin) instead of this being a single entity feels unnatural to me, but in the background the transform class has all the 3x4 multiplication and xform function you need as you have all the values as you need them, just split into two entities.

So with your remark about Unity up there, lord I'm happy I've chosen Godot over Unity because my RTS game is riddled with access to the elements of the matrix even for some of the most basic functions I need to execute. Same goes for a lot of the VR work I've been doing. That said, a lot of the work I do fits well within core work, maybe less within the type of logic people write for game logic, I give you that :)

I suspect that what Unity ends up doing is similar to what we do with the rotation and scale, those properties are there but they don't actually exist as data, you set the euler values, Godot calculates the 3x3 matrix, then stores that. When you request this information it takes the matrix, determines the euler values, and shows those. This is why the euler angles often change especially when you enter gymbol locked values, Godot may come up with a different combo of values resulting in the same orientation.

Now we could do the same for a quaternion, when you enter a quaternion you calculate the matrix, store that, then calculate the quaternion, euler angles and scale back so those can be displayed. The problem is that you may end up with a different quaternion that result in the same rotation but will screw up what you're actually trying to do with the quaternion. This is something you can easily do in code (albeit a few redraw issues when you change dependent properties):

tool
extends Spatial

export (Quat) var quaternion setget set_quaternion, get_quaternion

func set_quaternion(p_quat):
    var curr_scale = scale
    transform.basis = Basis(p_quat) * curr_scale

func get_quaternion():
    var curr_basis = transform.basis.orthonormalized()
    var quat = Quat(curr_basis)
    return quat

(@reduz actually, putting the C++ equivalent of the above getter and setter functions in to the Spatial Node could be an interesting compromise, I might do a PR for that just to see if its something people like)

Yes, I hear you thinking, there is that orthonormalized function again, but you have to keep in mind WHEN matrices start loosing their precision because this is at the heart of the matter. Also keep in mind that its only called here in the rare case when you're actually obtaining the rotation as a quaternion which really only would happen in the interface.
They start loosing that after multiple matrix multiplications and doing 3x3 matrix multiplications are only a small fraction of the use cases. Many use cases of these multiplications is when you start performing funky stuff on the Transform itself combining scale and translation. Those functions are just nobrainers on 3x4 and 4x4 matrices. They are far harder to do if the rotation is a quaternion, I have a separate vector for scale, and a separate vector for translation.

Regarding the original issue, I think I understand everything a bit better, but while writing something that constantly needs to get the rotation, there doesn't seem to be a way to avoid orthonormalize() on almost every frame. From what I understand Godot doesn't offer a way to catch the error from get_euler(), right? So you'd have to either check before if the transform is orthogonal (which seems redundant and I wouldn't know how) or call it every x calls (which I don't know if it might break earlier). Unless I'm overthinking it or there's some other obvious solution?

Anyways, I'm left wondering, is there any reason for get_euler() not to just auto orthonormalize when it fails the check?

It doesn't necessarily be copied, there's a set() function in Basis and that should allow you to set three basis vectors in a single step.

Regarding

They are far harder to do if the rotation is a quaternion, I have a separate vector for scale, and a separate vector for translation.

This is half the reason I mentioned that whenever the underlying quaternion or scale gets changed, we rebaked the matrix. The other half is because we need to convert it to a matrix for OpenGL anyway.

About you GDScript example, when you use scale, it currently performs a polar decomposition (because scale isn't stored separately) and it's not unique, you may see the scale to 1,-1,1 and you may get -1,-1,1 when you query it. The only way around is to store at least the scale or rotation part separately.

The other part is, your example misses my point. In your example, when I call rotate, it'll do the rotation in matrix representation which leaks errors to a 9D parameter space. Similar for example when I call orthonormalize or any other API function. Why bother storing a quaternion then? It's just waste of cycles.

What I proposed was internal changes to Basis (the API remains the same, apart from element wise write access) such that all updates are made internally using a quaternion and scale vector, which restricts the errors into two smaller and separate subspaces which don't mix, and bakes a 3x3 matrix at the end from that quaternion and scale vector. Since almost always you only change the rotation part in dynamics, the errors are confined to a 4D parameter space.

I'm really curious about the element wise write access that you keep mentioning. Can you give me a practical example?

@AlansCodeLog because it's an expensive operation. Such checks are enabled only in debug builds for performance and their purpose is to make you aware of the issue

BTW I don't know how Unity's Transform works internally. Maybe they're doing something similar indeed, which would explain read-only element-wise access

@tagcup

This is half the reason I mentioned that whenever the underlying quaternion or scale gets changed, we rebaked the matrix. The other half is because we need to convert it to a matrix for OpenGL anyway.

In a way that is already what is happening today, but instead of storing all different ways you can define it, the matrix is what keeps things. Else when you set a quaternion, you have to bake the matrix and then calculate back the euler angles, when you change the euler angles, you'd have to update the quaternion, and if you apply a complete transform, then you need to calculate back quaternion, euler angles, translation and scale.

It makes far more sense to just store the matrix because that is what the entire rendering pipeline needs to have. You can calculate the euler angles from that, you can calculate the quaternion from that, and you only calculate that during design time to show them as properties, or if someone actually needs to access those. That in some conditions you need to orthonormalise that. I actually don't really get why that seems to be such a problem, you need to do a TON of operations on the matrix before it gets enough of a rounding error.

Matrices aren't some magical numbers, the 3 members of the matrix are simply up, right and forward vectors and as such are extremely helpful in many conditions. With a 3x4 matrix you add a translation vector.

The lookat function is one that directly modifies these members by taking a direction vector and an up vector, taking the cross product of those two to get the right vector, and do another cross product to get your spatials up vector, and there you go.

Another that I heavily use is on terrain where you can use the normal vector of the terrain and the current forward vector of your matrix to update the matrix so your object is nicely aligned with your terrain, alot cheaper and more accurate then relying on the physics engine.

This is 3D rendering engine building 101

As I expected, nothing you described requires element wise access, everything you mentioned sets the 3 basis vector at once which I repeatedly say is OK through set(). What you can't do it just to set m[2][1] and leave the rest for example. That not what you're doing.

In a way that is already what is happening today, but instead of storing all different ways you can define it, In a way that is already what is happening today, but instead of storing all different ways you can define it

No it's no and I don't understand why you're not getting it. When you call orthonormalize right now, it will do Gram Schmidt on matrix which mixes scale and rotation errors. When you do it the way I said, it would call normalize on the underlying quaternion and reset the scale to 1,1,1, and rebaked the matrix afterwards. Totally different error characteristics.

If you're not sure how it works you can open up the souce for look at, it calculates 3 vectors, and then assign all 3 at once. That's fine and will always be fine

@tagcup, hmm I did have to access individual members of the matrix yesterday but given that was in a shader :)

Thing that I don't get is, what modifications are you doing to change the matrix to become inaccurate that you can fix with a quaternion given that all modifications you do outside of just setting the matrix, involves matrix multiplications?

While those that purely revolve around rotations can indeed be solved with quaternion multiplications, the moment that a translation is involved, this fall apart.
Take a simple:
node.global_transform = some_transform * node.global_transform
function where some transform is a complex movement you want to apply to the world space location of a node (very common for UI and for the inner workings of the physics engine).
The global_transform of an object is created by multiplying layers of transforms, after which the global transform is multiplied with the inverse of the parents global platform on the assign to get your relative transform for your node. This type of stuff is the bread and butter of how engines work internally and you want to change that by make quaternions leading resulting in constantly updating those quaternions with an operation that potentially requires you to orthonormalise the matrix first?

And for what? One use case where quaternions are superior to matrices, a use case you can solve today by using quaternions where they make sense and baking the matrix only for that use case? Which btw is exactly what Godot does internally where this is the case (skeleton animations for instance are 9 out of 10 times quaternions interpolated between frames and then converted to a rotation matrix)
No instead you ignore all other use cases because you don't see them not to mention that the internals of the engine works with matrices both in reading from it and in updating stuff.

Anyway, we're still revolving in circles and you're trying to convince the wrong person anyway :) I have little say in how Godots internals get changed. I'm just a guy who's been doing this stuff for 25 odd years mostly as a hobby..

Nothing falls apart.

You example is totally irrelevant. You're talking about composing transforms. That itself doesn't introduce any new errors every frame. If those transforms are fixed for example, you'll get the same global transform each time. And no, nobody calls orthonormalize for composing multiple transforms that are already orthonormal.

The problem is the things that introduce new errors every frame. Like rotation.

I'm not trying to convience you as I don't care one bit about what you think. I just don't like nonsense hanging around as truth.

And you keep talking about game engines. This isn't about game engines. This is about math and finite precision math.

Also, the answer to your "for what" is this very issue, which you apparently have forgotten about. Despite all that you write and blather about game engines are like this I'm doing this for this many year buzz, your contribution toward the solution of issues like this so far is 0.

And unlike you, I've been talking toward solving the issue at hand.

Nothing in Godot's Basis currently can solve the OPs problem. Like I said, even if you call orthonormalize every frame (which is apparently your idea of solving the issue), errors will leak into scale (whenever you call rotate, orthonormalize or any Basis function) and you have no way of correcting those scale errors because those aren't stored in different subspaces.

@tagcup that is because I've been reacting on when you went on a tangent of wanting to replace the Basis in a nodes Transform with a Quaternion and went on a whole rampage to why everyone else who may actually be using the stuff that is there today shouldn't be working like that.

I've rarely used orthonormalize, so no, I wouldn't suggest using that every frame. What I would suggest is recognizing we're dealing with an edge case here where a weakness of using matrices as the leading source of rotational and positional information is shown. I don't agree with your suggestion of replacing the rotational part of the transform with something else that may work better in this particular place but IMHO would handicap various other parts of the system especially when you're looking at operations that work off of the orientation vectors you can obtain from a 3x3 matrix or operations that include positional information (i.e. rotations around a secondary point and/or compound transforms that have positional data). I'm sure the transform class can be rewritten to perform those with quaternions but to what end? That is a lot of work with very little gain. If you think its worth it, do the work and submit a PR.

Looking at the OPs original problem, the easy way, but one that I doubt will suffice as it's likely that his example is simplified from what he is really doing, is to prevent applying rotation upon rotation which slowly introduces the error. Instead, use the camera angle he's already maintaining to calculate the matrix for that angle, i.e. transform.basis = Basis(Vector3(1.0, 0.0, 0.0), deg2rad(cameraAngle)).
This however assumes there are no further rotations applied to the camera which is unlikely.

The more complex answer would be to use the suggestion I placed up awhile ago, if in this case a quaternion is the preferred way to store the camera orientation, instead of changing the engine, just use a quaternion when it's needed, Godot has support for them you know!

Excuse any typos cause I'm doing this from memory, there will probably need to be a few tweaks to this code. I'm also placing the script on the camera, instead of a spatial which I guess is a child of that for some reason, if other rotations need to be applied through the quaternion then it makes more sense to have that code on the camera node:

extends Camera

var cameraAngle = 0.0
var myQuaternion = Quat()

func _input(event):
    var cameraY = -event.relative.y

    myQuaternion *= Quat(Vector3(1.0, 0.0, 0.0), deg2rad(cameraY))
    transform.basis = Basis(myQuaternion)

    cameraAngle += cameraY

func _process(delta):
    print(global_transform.basis.get_euler().y)

Applying rotations every frame isn't an obscure use case. Physics engine does it every frame for example. Kinematic characters get rotated every frame by their controllers. I understand you work around but you can do that except for super simplistic cases of isolated objects. This problem needs to be address in Basis.

I fully understand what I proposed magically make everything better. Nothing does. There are of course trade-offs, and I think I mentioned those upfront. But I think the gains in error characteristics outweigh the performance losses.

Otherwise we'll be in this whack-a-mole game in the issue tracker forever where we perpetually get new issues from users about how rotation errors build up and turn the Basis matrix that is not even in R.S form (in which case you can't determine the rotation axes, like in this issue).

I for sure didn't intend to go on a "rampage" though, apologies if anything came out offensive or personal.

@tagcup no apologies needed man, I'm guilty of the same :) That is the problem when you're looking at a problem from two different angles, I see the pro's of sticking with matrices and accept the cons, you see the pro's of using quaternions to store rotational data and accept it's cons. We have a difference of opinion which pro's out way which con's :) Issues will always be raised no matter what solution we go for, there will always be someone who does things in a way that exasperates a problem.

I also feel I need to clarify my remark about my age wasn't to pull seniority, but genuinely a feeling that I might just be too old for this stuff. Habits form, opinions solidify. Matrices have been my bread and butter for decades now so I know how to solve every problem I have (well those related to rendering) with mathematics that use them which is possibly why I rarely run into issues due to precision errors. I've used quaternions many times as well off course, but making them a center piece, it just seems to me to make life more difficult but maybe that is just a lack of learning new tricks.

It's also one of the reasons I made my remark that it still feels weird to me that Godot's transform isn't a 4x4 matrix but split into a 3x3 matrix and position vector.

For me though, I still rarely use quaternions, I dislike euler angles, and I love matrices so I'm pretty happy with how things are :)

There might be an objectively better solution out there of course, which doesn't depend on what either of us think at all.

Maybe switching to double would suppress these errors down to a negligible point. I also haven't checked the literature at all there might be numerically stable algorithms.

Well that I think is why Godot 3 was refactored to have all floating point values be real_t which is typecast to float. Eventually it can just be typecast to double and voila. Right now there is still far to much in the engine that assumes floats are used I guess. It'll also break GDNative which is a bit of pain. I'd love to see the switch to doubles.

That is a funny thing though, I started on an old 286 (well I started programming on a TRS-80 but never did any 3D stuff on that). It didn't have a co-pro I think, or if it had one I didn't know how to use it, so I could only use CPU based 32bit floating point math which was slow as can be. So a lot of math was forced to be 16bit fixed point math just to get some speed out of the thing. Precision issues galore. Luckily I got a 386 fairly quickly afterwards and learned most using 32bit fixed point math as floating point math was still costly. I never did get as crazy as some of my friends figuring out you could do a measure of parallel processing by carefully ordering your instructions so floating point and fixed point math could run side by side.

Anyways, point is, I don't remember running into precision issues after leaving those days behind. GPUs and 64bit CPUs that don't blink at floating point math have made life bliss. What i don't know is if those days schooled me in naturally picking a programming style that avoids precision errors, or whether the problem isn't as big as its made out to be :) What I do know is that those days taught me to value performance over convenience, something that isn't always applicable anymore today and a little convenience can go a long way.

So I'm testing a 3.0 project in master (3.1 alpha). This happens a LOT more. Like, after 10 seconds where with the same code in 3.0 it would never happen even after several minutes of simulation. Calling orthonormalized() makes the errors go away.

I've also noticed that performance is a lot better, not sure if related. Intentional change or bug?

Any updates?

Can anyone still reproduce this bug in Godot 3.2.3 or any later release?

If yes, please ensure that an up-to-date Minimal Reproduction Project (MRP) is included in this report (a MRP is a zipped Godot project with the minimal elements necessary to reliably trigger the bug). You can upload ZIP files in an issue comment with a drag and drop.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

blurymind picture blurymind  路  3Comments

Spooner picture Spooner  路  3Comments

bojidar-bg picture bojidar-bg  路  3Comments

testman42 picture testman42  路  3Comments

n-pigeon picture n-pigeon  路  3Comments