Spaces:
Runtime error
Runtime error
import pygame | |
from pygame.locals import * | |
from OpenGL.GL import * | |
from OpenGL.GLU import * | |
import numpy as np | |
from scipy import ndimage | |
import random | |
# Simple 3D Earth Viewer with atmosphere, clouds, terrain, and stars | |
# Uses PyOpenGL and pygame for rendering | |
def create_sphere(radius, slices, stacks): | |
vertices = [] | |
normals = [] | |
texcoords = [] | |
indices = [] | |
for i in range(stacks + 1): | |
V = i / stacks | |
phi = V * np.pi | |
for j in range(slices + 1): | |
U = j / slices | |
theta = U * 2 * np.pi | |
x = radius * np.sin(phi) * np.cos(theta) | |
y = radius * np.cos(phi) | |
z = radius * np.sin(phi) * np.sin(theta) | |
vertices.append([x, y, z]) | |
nx, ny, nz = x/radius, y/radius, z/radius | |
normals.append([nx, ny, nz]) | |
texcoords.append([U, V]) | |
for i in range(stacks): | |
for j in range(slices): | |
first = i * (slices + 1) + j | |
second = first + slices + 1 | |
indices.append(first) | |
indices.append(second) | |
indices.append(first + 1) | |
indices.append(second) | |
indices.append(second + 1) | |
indices.append(first + 1) | |
return np.array(vertices), np.array(normals), np.array(texcoords), np.array(indices) | |
def create_terrain_noise(resolution=64): | |
# Generate procedural terrain (heightmap) | |
noise = np.random.randn(resolution, resolution) * 0.01 | |
noise = ndimage.gaussian_filter(noise, sigma=2) | |
return noise | |
def create_starfield(num_stars=1000): | |
stars = [] | |
for _ in range(num_stars): | |
theta = np.random.uniform(0, 2*np.pi) | |
phi = np.arccos(1 - np.random.uniform(0, 1)) | |
r = 100 + np.random.uniform(0, 10) | |
x = r * np.sin(phi) * np.cos(theta) | |
y = r * np.cos(phi) | |
z = r * np.sin(phi) * np.sin(theta) | |
stars.append([x, y, z]) | |
return np.array(stars) | |
def load_texture_from_solid_color(color, width=64, height=64): | |
texture_data = np.zeros((height, width, 3), dtype=np.uint8) | |
texture_data[:, :] = color | |
texture_data = texture_data.tobytes() | |
texture_id = glGenTextures(1) | |
glBindTexture(GL_TEXTURE_2D, texture_id) | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_data) | |
return texture_id | |
def load_simple_earth_texture(): | |
# Create a simple blue marble-like texture | |
width, height = 1024, 512 | |
texture_data = np.zeros((height, width, 3), dtype=np.uint8) | |
for y in range(height): | |
for x in range(width): | |
# Simple Earth approximation with blue oceans and green/brown continents | |
u, v = x / width, y / height | |
if np.sin(2*np.pi*u) * np.sin(np.pi*v) > 0.5 or (u-0.3)**2 + (v-0.5)**2 < 0.02: | |
texture_data[y, x] = [30, 100, 200] # Ocean | |
elif np.random.rand() < 0.3: | |
texture_data[y, x] = [100, 180, 80] # Land | |
else: | |
texture_data[y, x] = [30, 100, 200] | |
texture_data = texture_data.tobytes() | |
texture_id = glGenTextures(1) | |
glBindTexture(GL_TEXTURE_2D, texture_id) | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_data) | |
return texture_id | |
class Earth3DViewer: | |
def __init__(self): | |
pygame.init() | |
self.display = (800, 600) | |
pygame.display.set_mode(self.display, DOUBLEBUF | OPENGL) | |
pygame.display.set_caption("3D Earth Viewer") | |
gluPerspective(45, (self.display[0]/self.display[1]), 0.1, 100.0) | |
glTranslatef(0.0, 0.0, -15) | |
# Create Earth | |
self.vertices, self.normals, self.texcoords, self.indices = create_sphere(6.0, 32, 32) | |
self.cloud_vertices, _, _, _ = create_sphere(6.05, 32, 32) # Slightly bigger for cloud layer | |
self.atmosphere_vertices, _, _, _ = create_sphere(6.2, 32, 32) # Atmosphere glow | |
# Load textures | |
self.earth_texture = load_simple_earth_texture() | |
self.cloud_texture = load_texture_from_solid_color([200, 200, 255], 64, 64) | |
self.atmosphere_texture = load_texture_from_solid_color([150, 200, 255, 100], 64, 64) | |
# Create procedural terrain displacement (conceptual) | |
self.terrain_noise = create_terrain_noise(32) | |
# Stars | |
self.stars = create_starfield(500) | |
self.rotation = 0 | |
self.cloud_rotation = 0 | |
def draw_sphere(self, vertices, texture_id, blend=False, alpha=1.0): | |
if blend: | |
glEnable(GL_BLEND) | |
glBlendFunc(GL_SRC_ALPHA, GL_ONE) | |
glDepthMask(GL_FALSE) | |
glBindTexture(GL_TEXTURE_2D, texture_id) | |
glEnable(GL_TEXTURE_2D) | |
glBegin(GL_TRIANGLES) | |
for i in range(0, len(self.indices), 3): | |
for j in range(3): | |
idx = self.indices[i + j] | |
glTexCoord2fv(self.texcoords[idx]) | |
glVertex3fv(vertices[idx]) | |
glEnd() | |
glDisable(GL_TEXTURE_2D) | |
if blend: | |
glDisable(GL_BLEND) | |
glDepthMask(GL_TRUE) | |
def draw_stars(self): | |
glEnable(GL_POINT_SMOOTH) | |
glPointSize(1.0) | |
glColor3f(1, 1, 1) | |
glBegin(GL_POINTS) | |
for star in self.stars: | |
glVertex3fv(star) | |
glEnd() | |
def render(self): | |
while True: | |
for event in pygame.event.get(): | |
if event.type == pygame.QUIT: | |
pygame.quit() | |
return | |
# Handle rotation | |
self.rotation += 0.5 | |
self.cloud_rotation += 0.6 | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) | |
glEnable(GL_DEPTH_TEST) | |
# Draw stars (background) | |
glPushMatrix() | |
glRotatef(self.rotation * 0.01, 0, 1, 0) | |
self.draw_stars() | |
glPopMatrix() | |
# Draw Earth | |
glPushMatrix() | |
glRotatef(self.rotation, 0, 1, 0) | |
self.draw_sphere(self.vertices, self.earth_texture) | |
glPopMatrix() | |
# Draw clouds | |
glPushMatrix() | |
glRotatef(self.cloud_rotation, 0, 1, 0) | |
self.draw_sphere(self.cloud_vertices, self.cloud_texture, blend=True, alpha=0.3) | |
glPopMatrix() | |
# Draw atmosphere glow | |
glPushMatrix() | |
glRotatef(self.rotation, 0, 1, 0) | |
glColor4f(0.5, 0.8, 1.0, 0.1) | |
self.draw_sphere(self.atmosphere_vertices, self.atmosphere_texture, blend=True, alpha=0.1) | |
glPopMatrix() | |
pygame.display.flip() | |
pygame.time.wait(30) | |
if __name__ == "__main__": | |
app = Earth3DViewer() | |
app.render() |