PDA

View Full Version : How to get camera place to see all



3DPrgmer
11-12-2016, 04:36 AM
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: https://git.rwth-aachen.de/carstenf/OpenGL/tree/master/MshViewer/Source

GClements
11-12-2016, 06:37 AM
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)

3DPrgmer
11-12-2016, 08:09 AM
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 :D

GClements
11-12-2016, 09:46 AM
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??
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)

3DPrgmer
11-13-2016, 02:43 AM
how would i calculate the hull?? I have only the vertices of each model in a list.

GClements
11-13-2016, 03:18 AM
how would i calculate the hull?? I have only the vertices of each model in a list.

You can find a list of algorithms here (https://en.wikipedia.org/wiki/Convex_hull_algorithms).

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.

3DPrgmer
11-13-2016, 04:04 AM
yes i want just the init camera position calculated and it's done only once.

john_connor
11-13-2016, 09:09 AM
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))

3DPrgmer
11-27-2016, 07:14 AM
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: https://git.rwth-aachen.de/carstenf/OpenGL/blob/master/MshViewer/Source/OpenGlController.cpp#L227
and at this part i already run through all vertex: https://git.rwth-aachen.de/carstenf/OpenGL/blob/master/MshViewer/Source/OpenGlController.cpp#L390

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 (https://git.rwth-aachen.de/carstenf/OpenGL/blob/master/MshViewer/Source/OpenGlController.cpp#L407) 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)