Use VAOs for everything.

This commit is contained in:
Quantum 2018-08-29 00:25:32 -04:00
parent 8317201492
commit 4430eb7d75
3 changed files with 58 additions and 68 deletions

View file

@ -80,7 +80,8 @@ class AsteroidManager(object):
__nonzero__ = __bool__
def load(self, file):
self.asteroids.append(WavefrontVBO(load_model(file), 5, 5, 5))
shader = self.world.activate_shader('model')
self.asteroids.append(WavefrontVBO(load_model(file), shader, 5, 5, 5))
def new(self, location, direction):
return Asteroid(self.world, random.choice(self.asteroids), location, direction)
@ -104,12 +105,27 @@ class Belt(Entity):
self.render = gl_info.have_version(3, 3)
if self.render:
shader = world.activate_shader('belt')
if not isinstance(models, list):
models = [models]
self.objects = [WavefrontVBO(load_model(model), info.get('sx', scale), info.get('sy', scale),
info.get('sz', scale)) for model in models]
self.belt = BeltVBO(radius, cross, len(self.objects), count)
self.belt = BeltVBO(radius, cross, len(models), count)
self.objects = [
WavefrontVBO(load_model(model), shader, info.get('sx', scale),
info.get('sy', scale), info.get('sz', scale))
for model in models
]
def callback():
glBindBuffer(GL_ARRAY_BUFFER, vbo)
shader.vertex_attribute('a_translate', self.belt.location_size, self.belt.type, GL_FALSE,
self.belt.stride, self.belt.location_offset, divisor=1)
shader.vertex_attribute('a_scale', self.belt.scale_size, self.belt.type, GL_FALSE,
self.belt.stride, self.belt.scale_offset, divisor=1)
glBindBuffer(GL_ARRAY_BUFFER, 0)
for model, vbo, count in zip(self.objects, self.belt.vbo, self.belt.sizes):
model.additional_attributes(callback)
super(Belt, self).__init__(world, name, (x, y, z), (inclination, longitude, argument))
@ -128,14 +144,7 @@ class Belt(Entity):
shader.uniform_mat4('u_modelMatrix', self.model_matrix)
for object, vbo, count in zip(self.objects, self.belt.vbo, self.belt.sizes):
glBindBuffer(GL_ARRAY_BUFFER, vbo)
shader.vertex_attribute('a_translate', self.belt.location_size, self.belt.type, GL_FALSE,
self.belt.stride, self.belt.location_offset, divisor=1)
shader.vertex_attribute('a_scale', self.belt.scale_size, self.belt.type, GL_FALSE,
self.belt.stride, self.belt.scale_offset, divisor=1)
glBindBuffer(GL_ARRAY_BUFFER, 0)
object.draw(shader, instances=count)
shader.deactivate_all_attributes()
class Sky(Entity):
@ -159,7 +168,6 @@ class Sky(Entity):
shader.vertex_attribute('a_direction', self.cube.direction_size, self.cube.type, GL_FALSE,
self.cube.stride, self.cube.direction_offset)
glBindBuffer(GL_ARRAY_BUFFER, 0)
shader.reset_all_attributes()
def draw(self, options):
cam = self.world.cam
@ -276,7 +284,6 @@ class Body(Entity):
glBindBuffer(GL_ARRAY_BUFFER, self.orbit_vbo.vbo)
shader.vertex_attribute('a_position', self.orbit_vbo.position_size, self.orbit_vbo.type, GL_FALSE,
self.orbit_vbo.stride, self.orbit_vbo.position_offset)
shader.reset_all_attributes()
self.orbit_cache = cache
return self.orbit_vbo, self.orbit_vao
@ -370,7 +377,6 @@ class SphericalBody(Body):
glBindBuffer(GL_ARRAY_BUFFER, 0)
else:
raise ValueError('Invalid type: %s' % self.type)
shader.reset_all_attributes()
self.atmosphere = None
self.clouds = None
@ -403,7 +409,6 @@ class SphericalBody(Body):
shader.vertex_attribute('a_uv', self.clouds.uv_size, self.clouds.type, GL_FALSE,
self.clouds.stride, self.clouds.uv_offset)
glBindBuffer(GL_ARRAY_BUFFER, 0)
shader.reset_all_attributes()
if atm_texture is not None:
self.atm_texture = load_texture_1d(atm_texture, clamp=True)
@ -417,7 +422,6 @@ class SphericalBody(Body):
shader.vertex_attribute('a_u', self.atmosphere.u_size, self.atmosphere.type, GL_FALSE,
self.atmosphere.stride, self.atmosphere.u_offset)
glBindBuffer(GL_ARRAY_BUFFER, 0)
shader.reset_all_attributes()
if 'ring' in info:
distance = world.evaluate(info['ring'].get('distance', self.radius * 1.2))
@ -441,7 +445,6 @@ class SphericalBody(Body):
shader.vertex_attribute('a_u', self.ring.u_size, self.ring.type, GL_FALSE,
self.ring.stride, self.ring.u_offset)
glBindBuffer(GL_ARRAY_BUFFER, 0)
shader.reset_all_attributes()
def _draw_planet(self):
shader = self.world.activate_shader('planet')
@ -584,8 +587,9 @@ class ModelBody(Body):
super(ModelBody, self).__init__(name, world, info, parent)
scale = info.get('scale', 1)
self.vbo = WavefrontVBO(load_model(info['model']), info.get('sx', scale), info.get('sy', scale),
info.get('sz', scale))
shader = world.activate_shader('model')
self.vbo = WavefrontVBO(load_model(info['model']), shader, info.get('sx', scale),
info.get('sy', scale), info.get('sz', scale))
def _draw(self, options):
shader = self.world.activate_shader('model')

View file

@ -9,7 +9,7 @@ from pyglet.gl import *
# noinspection PyUnresolvedReferences
from six.moves import range, zip
from punyverse.glgeom import list_to_gl_buffer
from punyverse.glgeom import list_to_gl_buffer, VAO
from punyverse.texture import load_texture
@ -197,36 +197,41 @@ def load_model(path):
class ModelVBO(object):
__slots__ = ('has_normal', 'has_texture', 'data_buf', 'index_buf', 'offset_type', 'vertex_count')
__slots__ = ('has_normal', 'has_texture', 'data_buf', 'index_buf', 'offset_type', 'vertex_count', 'vao')
def draw(self, shader, instances=None):
def __init__(self):
self.vao = VAO()
def build_vao(self, shader):
stride = (3 + self.has_normal * 3 + self.has_texture * 2) * 4
glBindBuffer(GL_ARRAY_BUFFER, self.data_buf)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.index_buf)
with self.vao:
glBindBuffer(GL_ARRAY_BUFFER, self.data_buf)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.index_buf)
shader.vertex_attribute('a_position', 3, GL_FLOAT, GL_FALSE, stride, 0)
if self.has_normal:
shader.vertex_attribute('a_normal', 3, GL_FLOAT, GL_FALSE, stride, 3 * 4)
else:
shader.vertex_attribute_vec3('a_normal', 0, 0, 0)
if self.has_texture:
shader.vertex_attribute('a_uv', 2, GL_FLOAT, GL_FALSE, stride, (6 if self.has_normal else 3) * 4)
else:
shader.vertex_attribute_vec2('a_uv', 0, 0)
shader.vertex_attribute('a_position', 3, GL_FLOAT, GL_FALSE, stride, 0)
if self.has_normal:
shader.vertex_attribute('a_normal', 3, GL_FLOAT, GL_FALSE, stride, 3 * 4)
if self.has_texture:
shader.vertex_attribute('a_uv', 2, GL_FLOAT, GL_FALSE, stride, (6 if self.has_normal else 3) * 4)
if instances:
glDrawElementsInstanced(GL_TRIANGLES, self.vertex_count, self.offset_type, 0, instances)
else:
glDrawElements(GL_TRIANGLES, self.vertex_count, self.offset_type, 0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
shader.deactivate_attributes('a_position', 'a_normal', 'a_uv')
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
def draw(self, shader, instances=None):
with self.vao:
if not self.has_normal:
shader.vertex_attribute_vec3('a_normal', 0, 0, 0)
if not self.has_texture:
shader.vertex_attribute_vec2('a_uv', 0, 0)
if instances:
glDrawElementsInstanced(GL_TRIANGLES, self.vertex_count, self.offset_type, 0, instances)
else:
glDrawElements(GL_TRIANGLES, self.vertex_count, self.offset_type, 0)
class WavefrontVBO(object):
def __init__(self, model, sx=1, sy=1, sz=1):
def __init__(self, model, shader, sx=1, sy=1, sz=1):
self._tex_cache = {}
self.vbos = []
self.scale = (sx, sy, sz)
@ -240,7 +245,14 @@ class WavefrontVBO(object):
normals = model.normals
for group in self.merge_groups(model):
self.vbos.append((group.material, self.process_group(group, vertices, normals, textures)))
processed = self.process_group(group, vertices, normals, textures)
self.vbos.append((group.material, processed))
processed.build_vao(shader)
def additional_attributes(self, callback):
for _, group in self.vbos:
with group.vao:
callback()
def draw(self, shader, instances=None):
for mat, vbo in self.vbos:

View file

@ -78,8 +78,6 @@ class Program(object):
self.program = program
self.attributes = self._variable_locations(GL_ACTIVE_ATTRIBUTES, glGetActiveAttrib, glGetAttribLocation)
self.uniforms = self._variable_locations(GL_ACTIVE_UNIFORMS, glGetActiveUniform, glGetUniformLocation)
self.active_attributes = set()
self.divisor_attributes = set()
def vertex_attribute(self, name, size, type, normalized, stride, offset, divisor=None):
location = self.attributes[name]
@ -87,30 +85,6 @@ class Program(object):
glEnableVertexAttribArray(location)
if divisor:
glVertexAttribDivisor(location, divisor)
self.divisor_attributes.add(location)
self.active_attributes.add(location)
def deactivate_all_attributes(self):
for location in self.active_attributes:
glDisableVertexAttribArray(location)
for location in self.divisor_attributes:
glVertexAttribDivisor(location, 0)
self.reset_all_attributes()
def deactivate_attributes(self, *attributes):
for attr in attributes:
location = self.attributes[attr]
if location in self.active_attributes:
glDisableVertexAttribArray(location)
if location in self.divisor_attributes:
glVertexAttribDivisor(location, 0)
self.active_attributes.discard(location)
self.divisor_attributes.discard(location)
def reset_all_attributes(self):
# Call this when you bound to a VAO.
self.active_attributes.clear()
self.divisor_attributes.clear()
def vertex_attribute_vec2(self, name, a, b):
glVertexAttrib2f(self.attributes[name], a, b)