Motiviert durch meine incomplete answer zu this Frage, ich bin ein einfaches Skybox in PyOpenGL gemäß this Tutorial Implementierung, so dass kleinere Verbesserungen wie für OpenGL 2.1/GLSL 120 und python2.7 benötigt -isms. In den meisten Fällen funktioniert es erfolgreich, aber je nachdem, welche sechs Bilder ich an meine Cubemap weitergebe, werden die Bilder entweder zwischen einem einzelnen Paar gegenüberliegender Gesichter ausgetauscht oder zufällig rotiert! Im Folgenden finden Sie die Hauptklasse dieser Demo:Uneinheitliche Skybox Rendering verschiedene Texturen in Pygame + mit PyOpenGL
import pygame
import sys
import time
import glob
import numpy as np
from ctypes import *
from OpenGL.GL import *
from OpenGL.GL import shaders
from OpenGL.GLU import *
def load_shaders(vert_url, frag_url):
vert_str = "\n".join(open(vert_url).readlines())
frag_str = "\n".join(open(frag_url).readlines())
vert_shader = shaders.compileShader(vert_str, GL_VERTEX_SHADER)
frag_shader = shaders.compileShader(frag_str, GL_FRAGMENT_SHADER)
program = shaders.compileProgram(vert_shader, frag_shader)
return program
def load_cubemap(folder_url):
tex_id = glGenTextures(1)
face_order = ["right", "left", "top", "bottom", "back", "front"]
"""
#hack that fixes issues for ./images1/
face_order = ["right", "left", "top", "bottom", "front", "back"]
"""
face_urls = sorted(glob.glob(folder_url + "*"))
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_CUBE_MAP, tex_id)
for i, face in enumerate(face_order):
face_url = [face_url for face_url in face_urls if face in face_url.lower()][0]
face_image = pygame.image.load(face_url).convert()
"""
#hack that fixes issues for ./images2/
if face == "bottom":
face_image = pygame.transform.rotate(face_image, 270)
if face == "top":
face_image = pygame.transform.rotate(face_image, 90)
"""
"""
#hack that fixes issues for ./images3/
if face == "bottom" or face == "top":
face_image = pygame.transform.rotate(face_image, 180)
"""
face_surface = pygame.image.tostring(face_image, 'RGB')
face_width, face_height = face_image.get_size()
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, face_width, face_height, 0, GL_RGB, GL_UNSIGNED_BYTE, face_surface)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)
glBindTexture(GL_TEXTURE_CUBE_MAP, 0)
return tex_id
def render():
global width, height, program
global rotation, cubemap
glEnable(GL_DEPTH_TEST)
glEnable(GL_TEXTURE_2D)
glEnable(GL_TEXTURE_CUBE_MAP)
skybox_right = [1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1]
skybox_left = [-1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1]
skybox_top = [-1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1]
skybox_bottom = [-1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1]
skybox_back = [-1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1]
skybox_front = [-1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1]
skybox_vertices = np.array([skybox_right, skybox_left, skybox_top, skybox_bottom, skybox_back, skybox_front], dtype=np.float32).flatten()
skybox_vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, skybox_vbo)
glBufferData(GL_ARRAY_BUFFER, skybox_vertices.nbytes, skybox_vertices, GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glClear(GL_COLOR_BUFFER_BIT)
glClear(GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60, float(width)/height, 0.1, 1000)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
#glRotate(rotation, 0, 1, 0)#spin around y axis
#glRotate(rotation, 1, 0, 0)#spin around x axis
glRotate(rotation, 1, 1, 1)#rotate around x, y, and z axes
glUseProgram(program)
glDepthMask(GL_FALSE)
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap)
glEnableClientState(GL_VERTEX_ARRAY)
glBindBuffer(GL_ARRAY_BUFFER, skybox_vbo)
glVertexPointer(3, GL_FLOAT, 0, None)
glDrawArrays(GL_TRIANGLES, 0, 36)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glDisableClientState(GL_VERTEX_ARRAY)
glBindTexture(GL_TEXTURE_CUBE_MAP, 0)
glDepthMask(GL_TRUE)
glUseProgram(0)
pygame.display.flip()
if __name__ == "__main__":
title = "Skybox"
target_fps = 60
(width, height) = (800, 600)
flags = pygame.DOUBLEBUF|pygame.OPENGL
screen = pygame.display.set_mode((width, height), flags)
prev_time = time.time()
rotation = 0
cubemap = load_cubemap("./images1/")#front and back images appear swapped
#cubemap = load_cubemap("./images2/")#top and bottom images appear rotated by 90 and 270 degrees respectively
#cubemap = load_cubemap("./images3/")#top and bottom images appear rotated by 180 degrees
program = load_shaders("./shaders/skybox.vert", "./shaders/skybox.frag")
pause = False
while True:
#Handle the events
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
pause = not pause
#Do computations and render stuff on screen
if not pause:
rotation += 1
render()
#Handle timing code for desired FPS
curr_time = time.time()
diff = curr_time - prev_time
delay = max(1.0/target_fps - diff, 0)
time.sleep(delay)
fps = 1.0/(delay + diff)
prev_time = curr_time
pygame.display.set_caption("{0}: {1:.2f}".format(title, fps))
ich die Cubemaps für die Skybox folgende Vertex- und Fragment-Shader verwenden für die Anzeige:
./shaders/skybox.vert
#version 120
varying vec3 tex_coords;
void main()
{
gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
tex_coords = vec3(gl_Vertex);
}
./shaders/skybox.frag
#version 120
varying vec3 tex_coords;
uniform samplerCube skybox;
void main()
{
gl_FragColor = textureCube(skybox, tex_coords);
}
Ich glaube nach viel herumspielen, dass die e rror ist in pygames Laden der Skybox Bilder. Ich habe drei Sets von Skybox-Bildern getestet. Jeder hat einen anderen visuellen Fehler und Hack, um sie zu beheben, die ich in dem obigen Code notiert habe. Hier sind die Quellen für die drei Skyboxen zum Testen (vergesse nicht, die Bilder so umzubenennen, dass sie right
, left
, top
, , back
oder front
in ihren jeweiligen Dateinamen enthalten).
Alle diese drei Skyboxes verwenden unterschiedliche Bildformate (BMP (die "Strahlen" Bilder in diesem zip verwenden), tga bzw. png). Wie kann ich all diese und zukünftige Bildbearbeitungen zuverlässig und robust handhaben, ohne auf scheinbar zufällige Rotationen oder Image-Swaps angewiesen zu sein? Jede Hilfe oder Einsicht würde sehr geschätzt werden.
Update: Ich habe erstellt ein github repository wo Sie den Code testen können, ohne eine main.py und Shadern erstellen zu müssen, die Bilder herunterzuladen und zu umbenennen und die Inhalte selbst zu organisieren. Dies sollte den Code viel einfacher zu laufen, wenn Sie daran interessiert sind, es zu testen.
Hier sind die Versionen von allem, was ich verwende:
- Python 2.7.12
- pygame 1.9.2b1
- PyOpenGL 3.1.0 (unter Verwendung von OpenGL 2.1 und GLSL 120)
Lassen Sie mich wissen, wenn Sie weitere Informationen benötigen!