This project is a 3D Solar System simulation developed in Python using OpenGL with the programmable pipeline.
The graphical user interface is implemented with PyQt, and rendering is performed inside a QOpenGLWidget.
- ☀️ Sun positioned at the center of world space
- 🪐 All planets orbiting around the Sun
- 🌙 Moon orbiting around the Earth
- 🪐 Saturn's rings with shadow projection
- 💡 Lambert shading for realistic light diffusion from the Sun
- 🔵 Orbit rings rendered for every planet
- 🌌 Space background texture
- 🎮 Scene exploration with flexible camera controls
- Change between 3 visualization modes with
Pkey: - Select a planet anytime by clicking on it
- Click anywhere else to discard planet selection
- Move freely around the scene
- Pitch and Yaw movement with
WASDkeys - Zoom in and out using left and right click or mouse wheel
- Fix camera orientation with
Fkey
- Pitch and Yaw movement with
- The camera follows the movement of the planet
- Zoom in and out using mouse wheel
- Up-close visualization of a planet
- Pivot around the planet with
WASDkeys - Zoom in and out using mouse wheel
- Pivot around the planet with
- Compile all shader programs
- Create scene objects
- Generate Vertex Array Objects (VAO), Vertex Buffers, and Element Buffers
- Store planets in an array
- Load textures
- Create View and Projection matrices
- Upload matrices to shader programs
Each frame performs:
- Render space background using:
GL_TRIANGLE_FAN(2 triangles forming a quad)
- Iterate through planet array:
- Render planets using
GL_TRIANGLE_STRIP - Render orbit rings using
GL_LINE_STRIP - Render saturn's rings using
GL_TRIANGLE_STRIP
- Render planets using
- Write text on the screen with QPainter()
Spheres are constructed using GL_TRIANGLE_STRIP for efficient rendering and reduced vertex duplication.
Lambert's cosine law is used to simulate diffuse lighting from the Sun.
- For a sphere, vertex coordinates equal the surface normals
- Normals are transformed into world space using:
- Result is passed to the fragment shader for lighting calculations
Ray casting system was implemented to select planets directly from the 3D scene whenever Focus mode or Follow mode are active.
When the user clicks on the screen, a ray is generated from the camera position through the mouse coordinates into world space. The screen coordinates are converted into Normalized Device Coordinates and then transformed using the inverse Projection and View matrices to obtain the ray direction.
Each planet is represented with a bounding sphere using its world position and radius. A ray–sphere intersection test is performed against all planets, and the closest intersected object becomes the selected element.
- Limb Darkening
- Rim Glow
- Procedural Noise
- Smoothstep Edge Fading
The shader performs a ray–sphere intersection test between each ring fragment and the planet’s bounding sphere.
If the fragment is behind the planet relative to the Sun, a smooth shadow is applied using the penetration depth and the discriminant of the intersection.
This creates a soft, physically accurate shadow on the rings, enhancing visual realism.
- Perspective projection
- Resolution: 800 × 600
- Near plane: 0.1
- Far plane: 800
- Field of view: 45°
Defines the viewing frustum and maps points into normalized device coordinates.
- Look-at matrix is used for flexibility between view modes
- Constructed using camera position, target and up vectors
- Unique for each object
- Updated every frame based on transformations
The Earth uses an Equirectangular Projection Texture obtained from:
NASA / Goddard Space Flight Center Scientific Visualization Studio
https://svs.gsfc.nasa.gov/3615/
- Python
- OpenGL (Programmable Pipeline)
- PyQt
- GLSL Shaders



