Skip to content
  • Sponsor matplotlib/matplotlib

  • Notifications You must be signed in to change notification settings
  • Fork 7.9k

[Bug]: Axes3D does not respect distance from camera. #23392

Not planned
@kdbanman

Description

@kdbanman

Bug summary

When plotting a surface and scatter points with Axes3D, either none of the scatter points are occluded by the surface or all of them are occluded. Whether or not they are occluded appears to depend upon a numerical threshold. (Speculation: perhaps the occlusion of a single point?)

Code for reproduction

# On two separate plots, plot a surface and five lines via scatter3D.  
# The five lines are vertically offset by a constant.  
# The two separate plots differ by an imperceptible difference in offset.
# - The rendered difference is significant.
# - Neither is correct.

import numpy as np
import matplotlib.pyplot as plt

def surface(x, y):
  return np.sin(x) + 0.5 * y * np.cos(x)

def plot_surface_and_lines(vertical_line_offset):
  x, y = np.meshgrid(
    np.linspace(-5, 5, 100),
    np.linspace(-5, 5, 100),
  )

  fig = plt.figure(dpi=150)
  ax = fig.add_subplot(projection='3d')
  ax.set(
    xlabel='x',
    ylabel='y',
    zlim=(-3, 3),
    title=f'z offset = {vertical_line_offset}',
  )

  ax.plot_surface(x, y, surface(x, y))

  a, b = np.meshgrid(np.linspace(-5, 5, 5), np.linspace(-5, 5, 100))
  ax.scatter3D(a, b, surface(a, b) + vertical_line_offset, color='red')

  plt.show()


plot_surface_and_lines(0.253)
plot_surface_and_lines(0.254)

Actual outcome

Expected outcome

Both plots should look like this, with occlusion determined point-by-point.

(This was manually composited with an image editing tool, AFAICT this cannot be generated by matplotlib until the bug is fixed.)

image

Additional information

This global occlusion occurs with many combinations of plots, not exclusively .plot_surface and .scatter3D. The occluder or the occluded can be generated by any of

  • .plot_trisurf
  • .plot_surface
  • .scatter3D
  • .plot_wireframe
    and possibly others. I did not test to find the numerical edge of occlusion/non-occlusion with the other combinations.

Perhaps this is related to other github issues related to depth testing or the underlying z-buffer.

Operating system

Ubuntu 18.04.5 LTS, kernel 5.4.188+

Matplotlib Version

3.2.2

Matplotlib Backend

module://ipykernel.pylab.backend_inline

Python version

3.7.13

Jupyter version

5.3.1 (via google colab release 2022/6/10)

Installation

No response

Activity

oscargus

oscargus commented on Jul 6, 2022

@oscargus
Member

FYI, in the current main branch they both look as the 0.253 case, so something has happened although it is still not as expected.

jklymak

jklymak commented on Jul 6, 2022

@jklymak
Member

This is a duplicate of #12260 unfortunately Matplotlib cannot do proper 3D rendering.

kdbanman

kdbanman commented on Jul 6, 2022

@kdbanman
Author

@jklymak #12260 appears to be about some quite unrelated example code. Can you explain the relationship to this issue?

tacaswell

tacaswell commented on Jul 6, 2022

@tacaswell
Member

This is a known issue, I suspect a typo the cross referencing. I'm not sure what issue Jody was aiming for though.

kdbanman

kdbanman commented on Jul 6, 2022

@kdbanman
Author

Thanks for the clarification @tacaswell! Upon further research, I see that the z-order of 3D objects with nontrivial occlusions is indeed a common issue.

Is it possible for me to contribute here? I have some experience with OpenGL. I notice this part of the current docs

3D plotting in Matplotlib is still not as mature as the 2D case. Please report any functions that do not behave as expected as a bug. In addition, help and patches would be greatly appreciated!

and this part as well

This problem will likely not be solved until OpenGL support is added to all of the backends (patches are greatly welcomed).

jklymak

jklymak commented on Jul 6, 2022

@jklymak
Member

Sorry #12620!

It would be great to have proper rendering but that is a big project!

dopplershift

dopplershift commented on Jul 6, 2022

@dopplershift
Contributor

@kdbanman The problem is that Matplotlib doesn't really have a 3D-capable renderer/rasterizer. To do this properly you'd need to do one of:

  1. Wrap OpenGL to handle the rendering to get "true" 3D
  2. Write a full software rasterizer that renders objects into fragments that include a depth component that can be used to draw the correct final fragments in the rendered scene.
kdbanman

kdbanman commented on Jul 6, 2022

@kdbanman
Author

@dopplershift thanks for the context. mplot3d's capabilities are impressive, considering it's not already wrapped OpenGL. I had assumed there was a wrapper in place which might just need patching.

Is there an existing example of wrapped renderer in matplotlib I could refer to?

I'm curious to see a rough example of architecture. Obviously OpenGL is a bit of a different animal - I'm guessing platform and backend portability would be big challenges.

WeatherGod

WeatherGod commented on Jul 7, 2022

@WeatherGod
Member
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      [Bug]: Axes3D does not respect distance from camera. · Issue #23392 · matplotlib/matplotlib