I too think there is a serious language issue here. What do we mean by "used"? I am not nitpicking at all, because it really is very important. Let me elaborate.
In practice, current applications, games, and simulators that produce 3D visuals, tend to have the following parts. (Note that this is as general as possible, so others will definitely disagree on how the different parts are
best separated. For this discussion, however, I believe this kind of separation is most useful.)
- Graphics Engine
This constructs and manipulates the data structures that describe the objects and environments visualized.
- Physics Engine, including Game Logic (optional, relevant only to games and simulators)
This handles the interactions between the objects and environments manipulated by the Graphics Engine.
Typically, the Physics Engine works in small time steps, often much shorter time steps than the visual update rate.
In Games, where you have independent actors (non-player characters, monsters, etc.) that implement their own logic – even if as simple as the ghosts in PacMan –, Game Logic is implemented either as part of the Physics Engine, or more commonly as a separate part; in many games implemented using a domain-specific scripting language like Lua or Python. Then, story developers don't have to write low-level code, and instead use that high-level scripting language with nice interfaces for telling the Physics Engine what that monster/NPC is doing. This too usually runs in time steps shorter (or at most as long time steps) as display updates.
In some cases, like the numerous monsters in e.g. Gauntlet, the Game Logic may actually implement flocking, or treating large groups of enemies as units, or as "limbs" of a single enemy. There's a lot of related research and discovery on this front, but as it is relevant to games in general and 3D, I'll not expand further on that.
- Rendering Engine
This takes a subset of the data structures maintained by the Graphics Engine – the small fraction that is necessary for displaying the current visual –, and renders (draws) it.
Typically the rendering is not directly to a visible display, but to a backing store or texture in the graphics display device memory (as opposed to generic RAM).
In the context of this post, Rendering Engine includes the mathematics of 3D projection, as well as mapping textures to surfaces, pixel shaders (that apply programmatic effects to textured surfaces), and so on.
- User interface
This is the part that responds to user actions, like mouse movement, keypresses, and so on, and acts upon them by notifying the Physics Engine, Graphics Engine, or Rendering Engine, depending on how simple the application is.
For local applications, it tends to be extremely simple. For a networked game, things become more complicated, because both the local instance of the game and the remote server must stay in agreement on what this particular player is doing, and what other players are doing. So, simple local applications can implement this part in whatever programming language they want, but real-time networked applications have this part usually written in C or C++.
If the application supports scripting on behalf of the user – often called extensions or plug-ins –, let's put that part into this section also. It is common to provide such an interface for modules to be written in a scripting language; Python is very commonly supported.
- Windowing Toolkit (optional, relevant only for when non-fullscreen)
The windowing toolkit uses the backing store or texture, and maps it to a standard window in the graphical user interface.
Usually, the Windowing Toolkit provides an event-based interface used to implement the User Interface also. However, there is no actual requirement that they are the same. For example, VLC and other media players support multiple User Interfaces in parallel (for controlling playback), not just the one provided by the graphical environment itself.
Sometimes the Rendering Engine is tightly coupled to the Windowing Toolkit (anything based on DirectX and Windows), or sometimes they are completely separate (any rendering engines based on OpenGL). So, do consider this separation model shown here as an abstract example, not anything directly applicable as-is to real life.
As of 2020, the Rendering Engine is almost always implemented in a separate, accelerated GPU unit, which may be integrated to the same chip as the CPU. OpenGL ES is probably the most widely used (because it is used on tablets and most mobile phones) standard for accessing these GPU units. On desktop machines, there is DirectX, OpenGL, Quartz. The support libraries that implement a programming interface to these – format the data structures, query capabilities, et cetera – are usually written in C or C++, with bindings (access by) other programming languages.
The Graphics Engines used in games are hot stuff, and also written in C or C++. For applications that show a single 3D object with simple lighting and texturing models, there might not be a graphics engine (or a physics engine) at all, since all data is used all the time, and the library interfaces' view transformation support suffices.
The Physics Engine is often a separate library written in a low level language, implementing all sorts of collision and damage stuff, so that moving objects don't just pass through each other – very interesting for games, and perhaps simulators, but you'll almost never find anything like it in a plain 3D viewer or editor. It can also be an integral part of the Graphics Engine. You can write a simple Physics Engine – say like Crayon Physics – in a scripting language, but for anything more complicated, C or C++ is used. Many newer graphics card support some sort of physics calculation acceleration, say via Nvidia CUDA or OpenCL, so that the fast vector math available on GPUs can handle most of this load (especially collision calculations).
Windowing Toolkit (or more commonly,
widget toolkit) is the programming interface to the Graphical User Interface. There are many of these, as each operating system tends to have their own; but for portable applications, GTK+ written in C, and Qt, FLTK, and wxWidgets written in C++, are commonly used.
The toolkit itself is basically a library written in a low-level programming language, that exposes the capabilities of the graphical user interface used.
In this context, the windowing toolkit also provides the "surface" or "backing store" for the rendered visuals, and shows it inside the GUI window.
While written in a low level language, these commonly have high-level bindings to scripting languages like Python.
To recap, some parts and some types of 3D applications can be written in Python, but they'll rely on interfacing to libraries and hardware definitely not running Python.
Consider
PyMOL, a 3D molecular visualization application written in Python (
sources at GitHub). Its
user interface is written in Python, and it chooses the graphics backend (written in C++, corresponding to the Graphics Engine, Physics Engine, Rendering Engine, and interface to Windowing Toolkit) at runtime, based on what the Python code detects on the OS and availability at runtime.
I personally like to write the User Interface (and interface to Windowing Toolkit) in Python, because then the end users can adjust and modify that as they like, without having to have any development tools themselves. However, the logic on manipulating 3D objects (or even 2D ones) is typically implemented as a library (or libraries) written in C or C++, that the Python user interface code invokes. Thus, most of the time the processor is actually running code compiled from C or C++, and only when the user makes a change – say, at most 60 times a second – a little bit of Python code gets executed by the CPython interpreter.
If you've read this far, you'll now see why "used" is such a poor word here. Yes, Python can be used effectively to implement certain specific parts of 3D software, and is pretty often used for that. Games tend to use Lua more, though. Are there 3D applications that are written purely in Python? Well, yes, for simple viewers and such, because the non-application-specific stuff that does the most work, is written in a lower-level language like C or C++, but these tend to be very simple. Anything that can manipulate the 3D object or environment visualized will either use libraries written in a more efficient language, or be too slow to be enjoyable.
Similarly, you often see suggestions of using Python for scientific calculation, yet Python itself is not that efficient in handling large amounts of data. The reason is that there are libraries written in C and C++ and Python modules interfacing to those libraries, like
SciPy: while the Python code describes the operations done on matrices, arrays, etc., the actual machine code that
implements those operations is written in C or C++. Because Python provides higher-level abstractions and garbage collection et cetera, it is easier for non-computer-scientists to implement calculations in Python, but still effectively leverage the speed of C/C++.
At the very core of this is the Python
ctypes module. Simply put, Python has a built-in mechanism for interfacing to libraries written in C/C++. (The other way around, embedding a Python interpreter in a game or application is also possible; but Lua is even easier for that.)