-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
[ENH]: Specify a custom focal length / FOV for the 3d camera #22035
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I think the best path forward here is a to open a PR to modify You can then write a class like class FocalProject:
def __init__(self, focal_length):
self.fl = focal_length
def get_projection(self, zfront, zback):
return ...(self.fl)
fp = FocalProject(5)
...
ax3d.set_proj_type(fp.get_projection) and now you have an object that lets you control how the projection matrix is created that will be consulted by the rest of the machinery at draw time. Modifying |
This sounds like you are planning to do advanced 3d plots in Matplotlib. You should be aware that Matplotlib does only pseudo-3d rendering by projecting the objects in the right way and drawing them in the right order. For example, this will fail for mutually overlapping objects where parts of one objects are in front of and other parts are behind another object. So before diving deep here, make sure that Matplotlib is good enough for your application. |
@tacaswell that works, though I'm not sure how much sense it makes to fully generalize the API when afaik there's only one canonical perspective matrix used in computer graphics (plus its simplified forms). More complex nonlinear transformations (ie a fisheye lens) can't be implemented via a simple matrix multiplication, so they wouldn't be able to slot in here anyways. A small note, the matrix in the original post is actually a simplification of the most general form, with the assumption of a symmetric viewing volume. Which I believe is pretty much the only use case, and so it's not worth fully generalizing right now. Any yeah, I only want to use this for wireframes / points / convex objects, so matplotlib works well with me. Can minimize my dependencies, embed these in notebooks, and don't have to train myself/others on different frameworks. |
It seems to me that if there is a more general matrix, and it reduces to the same matrix that we are now doing for focal_length=1, is there any harm to using the more general matrix, and coming up with a simple API to pass the more general parameters? |
I'll draft something up next week and see what you guys think. |
Fair! I do not know enough about 3D graphics to be sure about that one way or the other. Taking a callable is is likely powerful enough, makes sure we do not lock our selves into bad API choices, and is a common pattern (it is used throughout scipy and for our color maps) so I suggested it as the most conservative path forward ;) If there is only one reasonable paramatarization of this matrix, then I agree with @jklymak . One API suggestion would be to extend |
Problem
I'd like to be able to recreate the perspective-warping effects of changing focal length / FOV of a physical camera in matplotlib, for more fine-tuned camera control and for replicating real-world cameras in software.
Proposed solution
From this slide deck, we see how to generate a projection matrix:

This page has a nice derivation of the matrix.
The persp_transformation function in /lib/mpl_toolkits/mplot3d/proj3d.py implements this for a fixed focal distance of 1 (equivalent to a FOV of 90 deg):
It should not be too hard to update this function to take in a focal length. I think the biggest question is the user interface.
Thefocal_length
can be taken as fundamental and the currentproj_type
arguments to the Axes3D constructor can be mapped tofocal_length = 1
forproj_type == 'persp'
. To specify a custom focal length however, what should the user input?Edit: I think the easiest thing would be a default
focal_length = None
argument, which can be set by the user but otherwise gets set to 1 ifproj_type == 'persp'
.The text was updated successfully, but these errors were encountered: