Top-down view, nothing visible with QCamera at (0, 1000, 0), everything visible at (0, 1000, 0.01)
I am working on a 2D top-down game engine where I have a camera defined as follows:
Qt3D::QCamera *cameraEntity = new Qt3D::QCamera(m_worldEntity); cameraEntity->setObjectName(QStringLiteral("cameraEntity")); cameraEntity->lens()->setPerspectiveProjection(60.0f, 16.0f / 9.0f, 0.1f, 1000.0f); cameraEntity->setUpVector(QVector3D(0, 1, 0)); cameraEntity->setViewCenter(QVector3D(0, 0, 0)); cameraEntity->setPosition(QVector3D(0.0f, 1000.0f, 0.01f));
Around (0, 0, 0), there is a 3×3 tile grid based on textured planes, all of them with y=0. When I use the code above, everything works fine :
If I change
0.0fin the last line, however, which is what I would expect to result in the perfect center of the top-down view, none of the planes show up (the screen looks completely black).
0.0fnot work as I expect?
Probably a bug, but bear in mind Qt3D is still a tech preview. My advice is to ask your question on the interest mailing list, usually Sean Harmer (the Qt3D lead) is quite quick to respond. If it's indeed a bug you should file a report, so it can be fixed at some point.
A limitation of vector based camera is that the two vectors that "orient" it in 3D can't be parallel. You defined your "up" vector to be [0,1,0] and your "look" vector to be [0,-1000,0]. That's parallel so it creates an infinite number of possible orientations. Depending on the implementation you might be getting a NaN somewhere in there. When you shift it to [0,-1000,-0.01] the calculations are possible again, but I doubt you're getting very stable (mathematically) result.
An "up" vector is not suppose to point to "up" of the world. It's suppose to point to "up" of the camera in a basic position. Roughly speaking it should point directly up when the camera is looking straight ahead (view and up should be perpendicular). In your case you want a top-down view, so you need to "rotate" your directions 90 degree. So straight for you is down [0,-1000, 0] and up becomes to the side (you can pick which one), for example [0,0,1]:
cameraEntity->setUpVector(QVector3D(0, 0, 1));. Depending which side you pick as an "up" you might get a rotated view of your planes.
Also, you put your planes right at the back side of the frustum. If you use any clipping (which you should anyway) you might get artifacts with that, like things popping in and out, because of floating point precision. Push the far plane a little beyond your geometry to avoid that.
You defined your "up" vector to be [0,1,0] and your "look" vector to be [0,-1000,0]. That's parallel so it creates an infinite number of possible orientations.
I don't quite get what you mean, could you elaborate a bit? (provided you have the time, I'm just curious)
What he means is that the 'look at' and 'look up' vectors for a 'camera' are relative to the 'camera' in 3D space. In other words, if the up vector was an arrow coming out of the top of your head and the look at vector was the arrow coming straight out from your face you're fine.
This means that you cannot have a look vector that points straight down and an up vector that points straight up because these two vectors should be orthogonal to each other. Technically, the math works well as long as they are "sufficiently" perpendicular to each other; otherwise, the math gets 'hinky.' ;)
The reason, primarily has to do with the plane described by the two vectors. This is why they don't have to be perpendicular, but they really can't be parallel.
To be little more technical about it - a view frustum and clipping planes are described using couple of things: a positional vector, a directional "up" vector and a "look at" vector. The other stuff is FOV and near/far distances, but these are of no interest here.
The position is, well, the position of the camera. Nothing fancy.
The "look at" vector is the directional vector from the position of the camera to the center of the near/far planes. It is usually calculated as
normalize(focus point - camera position). The focus point is "ViewCenter" in Qt3D terminology.
The "up vector" is a directional vector pointing where "up" is in the frustum.
In many 3D calculations a "side" vector is also needed. Take a look at this masterpiece of paint brush for a visual aid ;)
The side vector can be calculated as using a cross product between the "look at" and "up" vectors. Now here's a nice animation from wikipedia of what happens with a cross product of two vectors:
As you can see the parallel vectors result in a 0-length cross product, which basically feeds 0 into all kinds of further calculations.
The "up" vector does not have to be pointed in any particular way in general. There are only two rules: 1. it needs to be perpendicular to the bottom/top edge of near/far clipping planes pointing from bottom to top and 2. It can't be parallel to the "look at" vector.
This in particular means it does not have to lie on the clipping plane i.e. it can stick out towards or away from the camera. It is only used to determine the roll of the camera, not the pitch or yaw (which are determined by the "look at" vector).
Well, thanks guys, it's clearer now!
Chris, the visual aids are a real nice touch, much appreciated.
@Chris-Kawa Many thanks! I had read about issues with parallelism somewhere but I never realized it was about this, and I definitely did not realize that the up vector of the camera had so much impact on the camera itself. And thanks for your note about clipping; I am definitely not using it and I should be.