Turned atmosphere and rings into VBOs.

This commit is contained in:
Quantum 2018-08-24 20:57:48 -04:00
parent 825e2ecf6a
commit dde4e1541d
5 changed files with 67 additions and 104 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 640 B

View file

@ -5,7 +5,7 @@ from pyglet.gl import *
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from six.moves import range from six.moves import range
from punyverse.glgeom import compile, flare, disk, glMatrix, glRestore, belt, Sphere from punyverse.glgeom import compile, glMatrix, glRestore, belt, Sphere, Disk
from punyverse.orbit import KeplerOrbit from punyverse.orbit import KeplerOrbit
from punyverse.texture import get_best_texture, load_clouds from punyverse.texture import get_best_texture, load_clouds
@ -266,32 +266,22 @@ class SphericalBody(Body):
self.texture = get_best_texture(info['texture']) self.texture = get_best_texture(info['texture'])
self.sphere = Sphere(self.radius, division, division) self.sphere = Sphere(self.radius, division, division)
self.atmosphere_id = 0 self.atmosphere = None
self.clouds = None self.clouds = None
self.corona_id = 0 self.ring = 0
self.ring_id = 0
if 'atmosphere' in info: if 'atmosphere' in info:
atmosphere_data = info['atmosphere'] atmosphere_data = info['atmosphere']
atm_size = world.evaluate(atmosphere_data.get('diffuse_size', None)) atm_size = world.evaluate(atmosphere_data.get('diffuse_size', None))
atm_texture = atmosphere_data.get('diffuse_texture', None) atm_texture = atmosphere_data.get('diffuse_texture', None)
cloud_texture = atmosphere_data.get('cloud_texture', None) cloud_texture = atmosphere_data.get('cloud_texture', None)
corona_texture = atmosphere_data.get('corona_texture', None)
if cloud_texture is not None: if cloud_texture is not None:
self.cloud_texture = get_best_texture(cloud_texture, loader=load_clouds) self.cloud_texture = get_best_texture(cloud_texture, loader=load_clouds)
self.clouds = Sphere(self.radius + 2, division, division) self.clouds = Sphere(self.radius + 2, division, division)
if corona_texture is not None:
corona = get_best_texture(corona_texture, clamp=True)
corona_size = atmosphere_data.get('corona_size', self.radius / 2)
corona_division = atmosphere_data.get('corona_division', 100)
corona_ratio = atmosphere_data.get('corona_ratio', 0.5)
self.corona_id = compile(flare, self.radius, self.radius + corona_size, corona_division,
corona_ratio, corona)
if atm_texture is not None: if atm_texture is not None:
atm_texture = get_best_texture(atm_texture, clamp=True) self.atm_texture = get_best_texture(atm_texture, clamp=True)
self.atmosphere_id = compile(disk, self.radius, self.radius + atm_size, 30, atm_texture) self.atmosphere = Disk(self.radius, self.radius + atm_size, 30)
if 'ring' in info: if 'ring' in info:
distance = world.evaluate(info['ring'].get('distance', self.radius * 1.2)) distance = world.evaluate(info['ring'].get('distance', self.radius * 1.2))
@ -303,8 +293,8 @@ class SphericalBody(Body):
roll = world.evaluate(info['ring'].get('roll', roll)) roll = world.evaluate(info['ring'].get('roll', roll))
self.ring_rotation = pitch, yaw, roll self.ring_rotation = pitch, yaw, roll
self.ring_id = compile(disk, distance, distance + size, 30, self.ring_texture = get_best_texture(info['ring'].get('texture', None), clamp=True)
get_best_texture(info['ring'].get('texture', None), clamp=True)) self.ring = Disk(distance, distance + size, 30)
def _draw_sphere(self, fv4=GLfloat * 4): def _draw_sphere(self, fv4=GLfloat * 4):
with glMatrix(self.location, self.rotation), glRestore(GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT): with glMatrix(self.location, self.rotation), glRestore(GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT):
@ -325,7 +315,7 @@ class SphericalBody(Body):
self.sphere.draw() self.sphere.draw()
def _draw_atmosphere(self, glMatrixBuffer=GLfloat * 16): def _draw_atmosphere(self, glMatrixBuffer=GLfloat * 16):
with glMatrix(self.location), glRestore(GL_ENABLE_BIT | GL_CURRENT_BIT): with glMatrix(self.location), glRestore(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_TEXTURE_BIT):
matrix = glMatrixBuffer() matrix = glMatrixBuffer()
glGetFloatv(GL_MODELVIEW_MATRIX, matrix) glGetFloatv(GL_MODELVIEW_MATRIX, matrix)
matrix[0: 3] = [1, 0, 0] matrix[0: 3] = [1, 0, 0]
@ -333,14 +323,13 @@ class SphericalBody(Body):
matrix[8:11] = [0, 0, 1] matrix[8:11] = [0, 0, 1]
glLoadMatrixf(matrix) glLoadMatrixf(matrix)
if self.atmosphere_id: glDisable(GL_LIGHTING)
glCallList(self.atmosphere_id) glEnable(GL_TEXTURE_2D)
if self.corona_id:
x, y, z = self.world.cam.direction()
glTranslatef(-x, -y, -z)
glEnable(GL_BLEND) glEnable(GL_BLEND)
glCallList(self.corona_id) glDisable(GL_CULL_FACE)
glBindTexture(GL_TEXTURE_2D, self.atm_texture)
self.atmosphere.draw()
def _draw_clouds(self): def _draw_clouds(self):
with glMatrix(self.location, self.rotation), glRestore(GL_ENABLE_BIT | GL_TEXTURE_BIT): with glMatrix(self.location, self.rotation), glRestore(GL_ENABLE_BIT | GL_TEXTURE_BIT):
@ -355,19 +344,25 @@ class SphericalBody(Body):
self.clouds.draw() self.clouds.draw()
def _draw_rings(self): def _draw_rings(self):
with glMatrix(self.location, self.ring_rotation), glRestore(GL_CURRENT_BIT): with glMatrix(self.location, self.ring_rotation), glRestore(GL_ENABLE_BIT | GL_TEXTURE_BIT):
glCallList(self.ring_id) glDisable(GL_LIGHTING)
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glDisable(GL_CULL_FACE)
glBindTexture(GL_TEXTURE_2D, self.ring_texture)
self.ring.draw()
def _draw(self, options): def _draw(self, options):
self._draw_sphere() self._draw_sphere()
if options.atmosphere and (self.atmosphere_id or self.corona_id): if options.atmosphere and self.atmosphere:
self._draw_atmosphere() self._draw_atmosphere()
if options.cloud and self.clouds: if options.cloud and self.clouds:
self._draw_clouds() self._draw_clouds()
if self.ring_id: if self.ring:
self._draw_rings() self._draw_rings()
def _collides(self, x, y, z): def _collides(self, x, y, z):

View file

@ -9,8 +9,8 @@ from six.moves import range
TWOPI = pi * 2 TWOPI = pi * 2
__all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'disk', 'Sphere', 'belt', __all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'Sphere', 'belt',
'flare', 'glSection', 'glMatrix', 'glRestore', 'progress_bar'] 'glSection', 'glMatrix', 'glRestore', 'progress_bar']
class glContext(object): class glContext(object):
@ -79,6 +79,24 @@ class glMatrix(object):
glPopMatrix() glPopMatrix()
def array_to_ctypes(arr):
return cast(arr.buffer_info()[0], POINTER({
'f': c_float,
'i': c_int,
'I': c_uint,
}[arr.typecode]))
def array_to_gl_buffer(buffer, array_type='f'):
vbo = c_uint()
glGenBuffers(1, byref(vbo))
glBindBuffer(GL_ARRAY_BUFFER, vbo.value)
buffer = array(array_type, buffer)
glBufferData(GL_ARRAY_BUFFER, buffer.itemsize * len(buffer), array_to_ctypes(buffer), GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, 0)
return vbo.value
def compile(pointer, *args, **kwargs): def compile(pointer, *args, **kwargs):
display = glGenLists(1) display = glGenLists(1)
glNewList(display, GL_COMPILE) glNewList(display, GL_COMPILE)
@ -125,69 +143,29 @@ def circle(r, seg, coords):
glVertex2f(cx + cos(theta) * r, cy + sin(theta) * r) glVertex2f(cx + cos(theta) * r, cy + sin(theta) * r)
def disk(rinner, router, segs, tex): class Disk(object):
with glRestore(GL_ENABLE_BIT): def __init__(self, rinner, router, segs):
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glDisable(GL_LIGHTING)
glDisable(GL_CULL_FACE)
glBindTexture(GL_TEXTURE_2D, tex)
res = segs * 5 res = segs * 5
delta = 2 * pi / res
self.vertex_count = (res + 1) * 2
# Need padding to make the last vertex render correctly... why?
buffer = self.vertex_count * 3 * [0]
for i in range(res):
theta = delta * i
x, y = cos(theta), sin(theta)
buffer[6*i:6*i+6] = [rinner * x, rinner * y, 0, router * x, router * y, 1]
buffer[6*res:6*res+6] = buffer[:6]
self.vbo = array_to_gl_buffer(buffer)
with glSection(GL_TRIANGLE_STRIP): def draw(self):
factor = TWOPI / res with glRestoreClient(GL_CLIENT_VERTEX_ARRAY_BIT):
theta = 0 glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
for n in range(res + 1): glEnableClientState(GL_VERTEX_ARRAY)
theta += factor glEnableClientState(GL_TEXTURE_COORD_ARRAY)
x = cos(theta) glVertexPointer(3, GL_FLOAT, 12, 0)
y = sin(theta) glTexCoordPointer(1, GL_FLOAT, 12, 8)
glTexCoord2f(0, 0) glDrawArrays(GL_TRIANGLE_STRIP, 0, self.vertex_count)
glVertex2f(rinner * x, rinner * y) glBindBuffer(GL_ARRAY_BUFFER, 0)
glTexCoord2f(1, 0)
glVertex2f(router * x, router * y)
def flare(rinner, router, res, prob, tex):
with glRestore(GL_ENABLE_BIT):
glEnable(GL_TEXTURE_2D)
glDisable(GL_CULL_FACE)
glDisable(GL_LIGHTING)
glBindTexture(GL_TEXTURE_2D, tex)
last_x = 1
last_y = 0
last_theta = 0
factor = TWOPI / res
rdelta = (router - rinner)
with glSection(GL_QUADS):
for i in range(res + 1):
theta = last_theta + factor
x = cos(theta)
y = sin(theta)
if random() > prob:
distance = rinner + rdelta * random()
avg_theta = (last_theta + theta) / 2
x0, y0 = rinner * last_x, rinner * last_y
x1, y1 = rinner * x, rinner * y
x2, y2 = distance * cos(avg_theta), distance * sin(avg_theta)
glTexCoord2f(0, 0)
glVertex2f(x0, y0)
glTexCoord2f(0, 1)
glVertex2f(x1, y1)
glTexCoord2f(1, 0)
glVertex2f(x2, y2)
glTexCoord2f(1, 1)
glVertex2f(x2, y2)
last_theta = theta
last_x = x
last_y = y
def array_to_ctypes(arr):
return cast(arr.buffer_info()[0], POINTER({
'f': c_float,
'i': c_int,
'I': c_uint,
}[arr.typecode]))
class Sphere(object): class Sphere(object):
@ -214,13 +192,7 @@ class Sphere(object):
r * dx2, r * dy2, r * dz, dx2, dy2, dz, phi1 / tau, t] r * dx2, r * dy2, r * dz, dx2, dy2, dz, phi1 / tau, t]
index += 16 index += 16
vbo = c_uint() self.vbo = array_to_gl_buffer(buffer)
glGenBuffers(1, byref(vbo))
self.vbo = vbo.value
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
buffer = array('f', buffer)
glBufferData(GL_ARRAY_BUFFER, buffer.itemsize * len(buffer), array_to_ctypes(buffer), GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, 0)
def draw(self): def draw(self):
with glRestoreClient(GL_CLIENT_VERTEX_ARRAY_BIT): with glRestoreClient(GL_CLIENT_VERTEX_ARRAY_BIT):

View file

@ -257,5 +257,5 @@ def get_best_texture(info, loader=load_texture, **kwargs):
except ValueError: except ValueError:
pass pass
else: else:
return loader(info) return loader(info, **kwargs)
raise ValueError('No texture found') raise ValueError('No texture found')

View file

@ -23,10 +23,6 @@
"rotation": 2164320, "rotation": 2164320,
"light_source": true, "light_source": true,
"atmosphere": { "atmosphere": {
"corona_texture": "sun_corona.png",
"corona_size": 1500,
"corona_division": 100,
"corona_prob": 0.5,
"diffuse_texture": "sun_diffuse.png", "diffuse_texture": "sun_diffuse.png",
"diffuse_size": 300 "diffuse_size": 300
} }