Turned atmosphere and rings into VBOs.

This commit is contained in:
Quantum 2018-08-24 20:57:48 -04:00
parent 825e2ecf6a
commit f7b6e9a977
5 changed files with 68 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
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.texture import get_best_texture, load_clouds
@ -266,32 +266,22 @@ class SphericalBody(Body):
self.texture = get_best_texture(info['texture'])
self.sphere = Sphere(self.radius, division, division)
self.atmosphere_id = 0
self.atmosphere = None
self.clouds = None
self.corona_id = 0
self.ring_id = 0
self.ring = 0
if 'atmosphere' in info:
atmosphere_data = info['atmosphere']
atm_size = world.evaluate(atmosphere_data.get('diffuse_size', None))
atm_texture = atmosphere_data.get('diffuse_texture', None)
cloud_texture = atmosphere_data.get('cloud_texture', None)
corona_texture = atmosphere_data.get('corona_texture', None)
if cloud_texture is not None:
self.cloud_texture = get_best_texture(cloud_texture, loader=load_clouds)
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:
atm_texture = get_best_texture(atm_texture, clamp=True)
self.atmosphere_id = compile(disk, self.radius, self.radius + atm_size, 30, atm_texture)
self.atm_texture = get_best_texture(atm_texture, clamp=True)
self.atmosphere = Disk(self.radius, self.radius + atm_size, 30)
if 'ring' in info:
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))
self.ring_rotation = pitch, yaw, roll
self.ring_id = compile(disk, distance, distance + size, 30,
get_best_texture(info['ring'].get('texture', None), clamp=True))
self.ring_texture = get_best_texture(info['ring'].get('texture', None), clamp=True)
self.ring = Disk(distance, distance + size, 30)
def _draw_sphere(self, fv4=GLfloat * 4):
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()
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()
glGetFloatv(GL_MODELVIEW_MATRIX, matrix)
matrix[0: 3] = [1, 0, 0]
@ -333,14 +323,13 @@ class SphericalBody(Body):
matrix[8:11] = [0, 0, 1]
glLoadMatrixf(matrix)
if self.atmosphere_id:
glCallList(self.atmosphere_id)
glDisable(GL_LIGHTING)
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glDisable(GL_CULL_FACE)
if self.corona_id:
x, y, z = self.world.cam.direction()
glTranslatef(-x, -y, -z)
glEnable(GL_BLEND)
glCallList(self.corona_id)
glBindTexture(GL_TEXTURE_2D, self.atm_texture)
self.atmosphere.draw()
def _draw_clouds(self):
with glMatrix(self.location, self.rotation), glRestore(GL_ENABLE_BIT | GL_TEXTURE_BIT):
@ -355,19 +344,25 @@ class SphericalBody(Body):
self.clouds.draw()
def _draw_rings(self):
with glMatrix(self.location, self.ring_rotation), glRestore(GL_CURRENT_BIT):
glCallList(self.ring_id)
with glMatrix(self.location, self.ring_rotation), glRestore(GL_ENABLE_BIT | GL_TEXTURE_BIT):
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):
self._draw_sphere()
if options.atmosphere and (self.atmosphere_id or self.corona_id):
if options.atmosphere and self.atmosphere:
self._draw_atmosphere()
if options.cloud and self.clouds:
self._draw_clouds()
if self.ring_id:
if self.ring:
self._draw_rings()
def _collides(self, x, y, z):

View file

@ -9,8 +9,8 @@ from six.moves import range
TWOPI = pi * 2
__all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'disk', 'Sphere', 'belt',
'flare', 'glSection', 'glMatrix', 'glRestore', 'progress_bar']
__all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'Sphere', 'belt',
'glSection', 'glMatrix', 'glRestore', 'progress_bar']
class glContext(object):
@ -79,6 +79,24 @@ class glMatrix(object):
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):
display = glGenLists(1)
glNewList(display, GL_COMPILE)
@ -125,69 +143,29 @@ def circle(r, seg, coords):
glVertex2f(cx + cos(theta) * r, cy + sin(theta) * r)
def disk(rinner, router, segs, tex):
with glRestore(GL_ENABLE_BIT):
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glDisable(GL_LIGHTING)
glDisable(GL_CULL_FACE)
glBindTexture(GL_TEXTURE_2D, tex)
class Disk(object):
def __init__(self, rinner, router, segs):
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 + 2) * [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):
factor = TWOPI / res
theta = 0
for n in range(res + 1):
theta += factor
x = cos(theta)
y = sin(theta)
glTexCoord2f(0, 0)
glVertex2f(rinner * x, rinner * y)
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]))
def draw(self):
with glRestoreClient(GL_CLIENT_VERTEX_ARRAY_BIT):
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glVertexPointer(3, GL_FLOAT, 12, 0)
glTexCoordPointer(3, GL_FLOAT, 12, 8)
glDrawArrays(GL_TRIANGLE_STRIP, 0, self.vertex_count)
glBindBuffer(GL_ARRAY_BUFFER, 0)
class Sphere(object):
@ -214,13 +192,7 @@ class Sphere(object):
r * dx2, r * dy2, r * dz, dx2, dy2, dz, phi1 / tau, t]
index += 16
vbo = c_uint()
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)
self.vbo = array_to_gl_buffer(buffer)
def draw(self):
with glRestoreClient(GL_CLIENT_VERTEX_ARRAY_BIT):

View file

@ -207,6 +207,7 @@ def load_texture(file, clamp=False):
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
if clamp:
print('Clamped')
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
@ -257,5 +258,5 @@ def get_best_texture(info, loader=load_texture, **kwargs):
except ValueError:
pass
else:
return loader(info)
return loader(info, **kwargs)
raise ValueError('No texture found')

View file

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