I wrote a Planet class and use draw_self function to render the sphere, but I didn’t know where I should put the code about lighting.
I try to initial the light before the loop but the planets were not lit.I think maybe it is because I use textures?
I know little about pyopengl and I don’t know if I need shaders.
Here is the code
import math
import numpy as np
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
from PIL import Image
time_scale = 5
G = 12384548 * (time_scale ** 2)
AU = 5859375
def read_texture(planet_name):
texture = glGenTextures(1)
image = Image.open(f"resources/bmp/{planet_name}.bmp")
ix = image.size[0]
iy = image.size[1]
image = image.tobytes("raw", "RGBX", 0, -1)
# Create Texture
glBindTexture(GL_TEXTURE_2D, texture) # 2d texture (x and y size)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_UNSIGNED_BYTE, image)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)
return texture
class Planet:
def __init__(self, planet_name, pos, radius, mass, speed=None):
self.name = planet_name
self.texture = read_texture(planet_name)
self.pos = np.array(pos, dtype="float64") * AU
self.radius = radius
self.mass = mass
self.speed = np.array(speed, dtype="float64") if speed else np.array([0, 0, 0], dtype="float64")
self.speed *= time_scale
self.sphere = gluNewQuadric()
def draw_self(self):
glPushMatrix()
glTranslatef(*self.pos)
glRotatef(90, 1, 0, 0)
gluQuadricTexture(self.sphere, GL_TRUE)
glEnable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, self.texture)
gluSphere(self.sphere, self.radius, 64, 64) # Draw sphere
glPopMatrix()
def move(self):
self.pos += self.speed
def calc(self, mass2, distance):
force = G * mass2 * self.mass / (np.linalg.norm(distance) ** 3) * distance
self.speed += force / self.mass
pygame.init()
width, height = display = (1900, 1060)
scree = pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0] / display[1]), 2, 1e20)
glEnable(GL_DEPTH_TEST)
# here is the light part
light_position = [0.0, 0.0, 0.0, 1.0]
light_ambient_color = [0.0, 0.0, 0.0, 0.0]
light_diffuse_color = [1.0, 1.0, 1.0, 1.0]
glLightfv(GL_LIGHT0, GL_POSITION, light_position)
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient_color)
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse_color)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glColorMaterial(GL_FRONT, GL_DIFFUSE)
glEnable(GL_COLOR_MATERIAL)
glMatrixMode(GL_MODELVIEW)
pygame.mouse.set_visible(False)
pygame.event.set_grab(True)
sun = Planet("sun", (0, 0, 0), 109000, 330000)
mercury = Planet("mercury", (0, 0, -0.37), 575, 0.055, [-1373, 0, 0])
venus = Planet("venus", (0, 0, -0.72), 1423.5, 0.815, [-984, 0, 0])
earth = Planet("earth", (0, 0, -1), 1500, 1, [-835, 0, 0])
moon = Planet("moon", (0, 0, -1.00256), 409, 1 / 81, [-864, 0, 0])
mars = Planet("mars", (0, 0, -1.52), 798, 0.107, [-677, 0, 0])
jupiter = Planet("jupiter", (0, 0, -5.2), 16800, 317.8, [-366, 0, 0])
background = read_texture('venus')
ball = gluNewQuadric()
planets = [mercury, earth, moon, venus, mars, jupiter]
cam = np.array([0, 0, 0], dtype="float64")
target = np.array([0, 0, -1], dtype="float64")
gluLookAt(*cam, *(cam + target), 0, 1, 0)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
camera_yaw = 180
camera_pitch = 0
step = 100
clock = pygame.time.Clock()
running = True
while running:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # Clear the screen
glLoadIdentity()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
elif event.type == pygame.MOUSEMOTION:
dx, dy = pygame.mouse.get_rel()
camera_yaw += dx * 0.1
camera_pitch = min(max(camera_pitch - dy * 0.1, -89.9999), 89.9999)
glPushMatrix()
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
cam += (0, 0, -step)
elif keys[pygame.K_s]:
cam += (0, 0, step)
if keys[pygame.K_a]:
cam += (-step, 0, 0)
elif keys[pygame.K_d]:
cam += (step, 0, 0)
if keys[pygame.K_SPACE]:
cam += (0, step, 0)
elif keys[pygame.K_LSHIFT]:
cam += (0, -step, 0)
for i in planets:
for j in planets:
if i != j:
i.calc(j.mass, j.pos - i.pos)
for i in planets:
i.move()
ah, av = math.radians(camera_yaw), math.radians(camera_pitch)
tmp = cam + earth.pos
target = tmp + [math.sin(ah) * math.cos(av), math.sin(av), -math.cos(ah) * math.cos(av)]
gluLookAt(*tmp, *target, 0, 1, 0)
for i in planets:
i.draw_self()
glPopMatrix()
glMultMatrixf(viewMatrix)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
pygame.display.flip()
clock.tick(60)