How to get camera place to see all

Hi,

i’m working on a 3D viewer using the .msh file format. I would like that after opening a file the first time, the optimal position for the camera is calculated. The optimal position for me is: looking at 0,0,0 and moving as long as needed in -z direction to see everything.
Is there a way to calculate that distance??

For those who wanna take a look at the files: MshViewer/Source · master · C-Fu / OpenGL · GitLab

If the camera is at (0,0,Zc) (note that the camera is looking along the negative Z axis in eye space), the Y field-of-view angle is fovy, and the aspect ratio is aspect, then a point (X,Y,Z) will be visible provided that


Z < Zc
|Y|/(Zc-Z) < tan(fovy/2)
|X|/(Zc-Z) < tan(fovy/2)*aspect

Satisfying the first constraint is straightforward; just ensure that Zc is greater than the Z coordinate of any vertex.

The second and third constraints are equivalent to


Zc > Z + |Y|/tan(fovy/2)
Zc > Z + |X|/(tan(fovy/2) * aspect)

This assumes that you’re creating the perspective transformation with gluPerspective() or a work-alike such as glm::perspective. If you’re using glFrustum() or similar, the frustum isn’t forced to be symmetric, so you need to handle the four edges separately.


Zc > Z - Y/(bottom/nearVal)
Zc > Z + Y/(top/nearVal)
Zc > Z - X/(left/nearVal)
Zc > Z + X/(right/nearVal)

Ok so i need to go through the whole mesh, multiply every vertex with it’s model translation matrix and check the things above right??

sounds like a big calculation :smiley:

If you’ve calculated the vertices of the convex hull, you’ll only need to test those, not interior vertices.

If you have a bounding volume, you could use that, although it will tend to over-estimate the distance required.

For a bounding sphere, the requirement is r/(Zc-Z)<sin(fovy/2) => Zc>Z+r/sin(fovy/2)

how would i calculate the hull?? I have only the vertices of each model in a list.

You can find a list of algorithms [b]here[/b].

Note that most of those discuss the 2D case, but most algorithms can be generalised to any number of dimensions.

But I probably wouldn’t bother if you’re only using it to determine the initial camera position. Transforming all of the vertices isn’t going to be that slow; particularly if you offload it to the GPU.

yes i want just the init camera position calculated and it’s done only once.

i’ve also sometimes that problen that a model is much larger than the usual view frustum
so i resize all models to R = 1 beforehand
(that means the whole model fits into a sphere of diameter 2)


float radiusmax_sq = 0;
for (auto& vertex : modelvertices)
{
float radius_sq = dot(vertex.position, vertex.position);
radiusmax_sq = max(radiusmax_sq, radius_sq);
}
float radiusmax = sqrt(radiusmax_sq);

// now divide each vertex position by the max radius
for (auto& vertex : modelvertices)
vertex.position /= radiusmax;

if you have multiple parts / components in you model, you can use “float radiusmax” as a “multiplier”:
– first get all radiusmax
– determine the biggest “radiusmax_biggest”
– later multiply each parts model-to-world matrix with:
—> glm::scale(glm::vec3(radiusmax / radiusmax_biggest))

All right, i just found lot’s of mesh that have the same problem as you descripted. My “virtual world” is smaller then my model.
So i think the best way is to scale everything down and place it at the Center (since now i place everything at the scene root and not the mesh Center)

But hey, i’m learning. So i’m gonna think first and code later XD

My MVPs are calculated here: MshViewer/Source/OpenGlController.cpp · master · C-Fu / OpenGL · GitLab
and at this part i already run through all vertex: MshViewer/Source/OpenGlController.cpp · master · C-Fu / OpenGL · GitLab

So i think it’d be best to calculate the Center and scale factor at that part, so i don’t need to run through everything once more.

My idea:
At this part i can add something like this:
max_x = max(max_x, current_x)
max_y = max(max_y, current_y)
max_z = max(max_z, current_z)
min_x = min(min_x, current_x)
min_y = min(min_y, current_y)
min_z = min(min_z, current_z)

And my Center point is then center_x/y/z = (max_x/y/z + min_x/y/z) / 2

But how do you calculate the scale factor? What does dot()?

==EDIT==

an other idea:
calculate the max/min values while reading in (object class), so i can directly scale the values down at the part i showed you before and get the new Center then. That way i don’t have an other matrix to multiply with (better performance)