Shader for models. Instanced asteroid belt.

Removed all instances of legacy pipeline, hopefully. (Except for using VAOs, I guess)
This commit is contained in:
Quantum 2018-08-28 23:10:33 -04:00
parent 510dcb46a6
commit a46d5a9ff7
11 changed files with 286 additions and 177 deletions

View file

@ -63,8 +63,12 @@ class Asteroid(Entity):
self.rotation = rx + 1, ry + 1, rz + 1 self.rotation = rx + 1, ry + 1, rz + 1
def draw(self, options): def draw(self, options):
glLoadMatrixf(self.mv_matrix) shader = self.world.activate_shader('model')
self.model.draw() shader.uniform_mat4('u_mvpMatrix', self.mvp_matrix)
shader.uniform_mat4('u_mvMatrix', self.mv_matrix)
shader.uniform_mat4('u_modelMatrix', self.model_matrix)
self.model.draw(shader)
self.world.activate_shader(None)
class AsteroidManager(object): class AsteroidManager(object):
@ -100,10 +104,9 @@ class Belt(Entity):
if not isinstance(models, list): if not isinstance(models, list):
models = [models] models = [models]
objects = [WavefrontVBO(load_model(model), info.get('sx', scale), info.get('sy', scale), self.objects = [WavefrontVBO(load_model(model), info.get('sx', scale), info.get('sy', scale),
info.get('sz', scale)) for model in models] info.get('sz', scale)) for model in models]
self.belt = BeltVBO(radius, cross, len(self.objects), count)
self.belt_id = compile(belt, radius, cross, objects, count)
self.rotation_angle = 360.0 / rotation if rotation else 0 self.rotation_angle = 360.0 / rotation if rotation else 0
super(Belt, self).__init__(world, name, (x, y, z), (inclination, longitude, argument)) super(Belt, self).__init__(world, name, (x, y, z), (inclination, longitude, argument))
@ -114,8 +117,21 @@ class Belt(Entity):
self.rotation = pitch, self.world.tick * self.rotation_angle % 360, roll self.rotation = pitch, self.world.tick * self.rotation_angle % 360, roll
def draw(self, options): def draw(self, options):
glLoadMatrixf(self.mv_matrix) shader = self.world.activate_shader('belt')
glCallList(self.belt_id) shader.uniform_mat4('u_mvpMatrix', self.mvp_matrix)
shader.uniform_mat4('u_mvMatrix', self.mv_matrix)
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()
self.world.activate_shader(None)
class Sky(Entity): class Sky(Entity):
@ -155,7 +171,7 @@ class Sky(Entity):
glDrawArrays(GL_TRIANGLES, 0, self.cube.vertex_count) glDrawArrays(GL_TRIANGLES, 0, self.cube.vertex_count)
shader.deactivate_attributes() shader.deactivate_all_attributes()
glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ARRAY_BUFFER, 0)
self.world.activate_shader(None) self.world.activate_shader(None)
@ -261,7 +277,7 @@ class Body(Entity):
shader.vertex_attribute('a_position', orbit.position_size, orbit.type, GL_FALSE, shader.vertex_attribute('a_position', orbit.position_size, orbit.type, GL_FALSE,
orbit.stride, orbit.position_offset) orbit.stride, orbit.position_offset)
glDrawArrays(GL_LINE_LOOP, 0, orbit.vertex_count) glDrawArrays(GL_LINE_LOOP, 0, orbit.vertex_count)
shader.deactivate_attributes() shader.deactivate_all_attributes()
glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ARRAY_BUFFER, 0)
if not solid: if not solid:
@ -407,7 +423,7 @@ class SphericalBody(Body):
glDrawArrays(GL_TRIANGLE_STRIP, 0, self.sphere.vertex_count) glDrawArrays(GL_TRIANGLE_STRIP, 0, self.sphere.vertex_count)
shader.deactivate_attributes() shader.deactivate_all_attributes()
glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ARRAY_BUFFER, 0)
self.world.activate_shader(None) self.world.activate_shader(None)
glActiveTexture(GL_TEXTURE0) glActiveTexture(GL_TEXTURE0)
@ -429,7 +445,7 @@ class SphericalBody(Body):
glDrawArrays(GL_TRIANGLE_STRIP, 0, self.sphere.vertex_count) glDrawArrays(GL_TRIANGLE_STRIP, 0, self.sphere.vertex_count)
shader.deactivate_attributes() shader.deactivate_all_attributes()
glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ARRAY_BUFFER, 0)
self.world.activate_shader(None) self.world.activate_shader(None)
@ -462,7 +478,7 @@ class SphericalBody(Body):
glDrawArrays(GL_TRIANGLE_STRIP, 0, self.atmosphere.vertex_count) glDrawArrays(GL_TRIANGLE_STRIP, 0, self.atmosphere.vertex_count)
shader.deactivate_attributes() shader.deactivate_all_attributes()
glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ARRAY_BUFFER, 0)
self.world.activate_shader(None) self.world.activate_shader(None)
glDisable(GL_BLEND) glDisable(GL_BLEND)
@ -489,7 +505,7 @@ class SphericalBody(Body):
glDrawArrays(GL_TRIANGLE_STRIP, 0, self.clouds.vertex_count) glDrawArrays(GL_TRIANGLE_STRIP, 0, self.clouds.vertex_count)
shader.deactivate_attributes() shader.deactivate_all_attributes()
glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ARRAY_BUFFER, 0)
self.world.activate_shader(None) self.world.activate_shader(None)
glDisable(GL_BLEND) glDisable(GL_BLEND)
@ -517,7 +533,7 @@ class SphericalBody(Body):
glDrawArrays(GL_TRIANGLE_STRIP, 0, self.ring.vertex_count) glDrawArrays(GL_TRIANGLE_STRIP, 0, self.ring.vertex_count)
shader.deactivate_attributes() shader.deactivate_all_attributes()
glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ARRAY_BUFFER, 0)
self.world.activate_shader(None) self.world.activate_shader(None)
glDisable(GL_BLEND) glDisable(GL_BLEND)
@ -551,5 +567,9 @@ class ModelBody(Body):
info.get('sz', scale)) info.get('sz', scale))
def _draw(self, options): def _draw(self, options):
glLoadMatrixf(self.mv_matrix) shader = self.world.activate_shader('model')
self.vbo.draw() shader.uniform_mat4('u_mvpMatrix', self.mvp_matrix)
shader.uniform_mat4('u_mvMatrix', self.mv_matrix)
shader.uniform_mat4('u_modelMatrix', self.model_matrix)
self.vbo.draw(shader)
self.world.activate_shader(None)

View file

@ -11,30 +11,7 @@ from six.moves import range
TWOPI = pi * 2 TWOPI = pi * 2
__all__ = ['compile', 'belt', 'glRestore', 'FontEngine', 'Matrix4f', 'Disk', 'OrbitVBO', __all__ = ['FontEngine', 'Matrix4f', 'Disk', 'OrbitVBO', 'SimpleSphere', 'TangentSphere', 'Cube', 'Circle', 'BeltVBO']
'SimpleSphere', 'TangentSphere', 'Cube', 'Circle']
class glRestore(object):
def __init__(self, flags):
self.flags = flags
def __enter__(self):
glPushAttrib(self.flags)
def __exit__(self, exc_type, exc_val, exc_tb):
glPopAttrib()
class glRestoreClient(object):
def __init__(self, flags):
self.flags = flags
def __enter__(self):
glPushClientAttrib(self.flags)
def __exit__(self, exc_type, exc_val, exc_tb):
glPopClientAttrib()
def array_to_ctypes(arr): def array_to_ctypes(arr):
@ -47,16 +24,19 @@ def array_to_ctypes(arr):
}[arr.typecode])) }[arr.typecode]))
def array_to_gl_buffer(buffer, array_type='f'): def array_to_gl_buffer(buffer):
vbo = c_uint() vbo = c_uint()
glGenBuffers(1, byref(vbo)) glGenBuffers(1, byref(vbo))
glBindBuffer(GL_ARRAY_BUFFER, vbo.value) 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) glBufferData(GL_ARRAY_BUFFER, buffer.itemsize * len(buffer), array_to_ctypes(buffer), GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ARRAY_BUFFER, 0)
return vbo.value return vbo.value
def list_to_gl_buffer(buffer, array_type='f'):
return array_to_gl_buffer(array(array_type, buffer))
class Matrix4f(object): class Matrix4f(object):
def __init__(self, matrix): def __init__(self, matrix):
self.matrix = array('f', matrix) self.matrix = array('f', matrix)
@ -111,14 +91,6 @@ class Matrix4f(object):
return type(self)(sum(a[i] * b[j] for i, j in zip(r, c)) for c in cols for r in rows) return type(self)(sum(a[i] * b[j] for i, j in zip(r, c)) for c in cols for r in rows)
def compile(pointer, *args, **kwargs):
display = glGenLists(1)
glNewList(display, GL_COMPILE)
pointer(*args, **kwargs)
glEndList()
return display
class Circle(object): class Circle(object):
type = GL_FLOAT type = GL_FLOAT
stride = 2 * 4 stride = 2 * 4
@ -132,7 +104,7 @@ class Circle(object):
for i in range(segs): for i in range(segs):
theta = delta * i theta = delta * i
buffer[2*i:2*i+2] = [cos(theta) * r, sin(theta) * r] buffer[2*i:2*i+2] = [cos(theta) * r, sin(theta) * r]
self.vbo = array_to_gl_buffer(buffer) self.vbo = list_to_gl_buffer(buffer)
class Disk(object): class Disk(object):
@ -154,7 +126,7 @@ class Disk(object):
x, y = cos(theta), sin(theta) x, y = cos(theta), sin(theta)
buffer[6*i:6*i+6] = [rinner * x, rinner * y, 0, router * x, router * y, 1] buffer[6*i:6*i+6] = [rinner * x, rinner * y, 0, router * x, router * y, 1]
buffer[6*res:6*res+6] = buffer[:6] buffer[6*res:6*res+6] = buffer[:6]
self.vbo = array_to_gl_buffer(buffer) self.vbo = list_to_gl_buffer(buffer)
class SimpleSphere(object): class SimpleSphere(object):
@ -190,7 +162,7 @@ class SimpleSphere(object):
index += 10 index += 10
reverse ^= True reverse ^= True
self.vbo = array_to_gl_buffer(buffer) self.vbo = list_to_gl_buffer(buffer)
class TangentSphere(object): class TangentSphere(object):
@ -231,7 +203,7 @@ class TangentSphere(object):
] ]
index += 14 index += 14
reverse ^= True reverse ^= True
self.vbo = array_to_gl_buffer(buffer) self.vbo = list_to_gl_buffer(buffer)
class Cube(object): class Cube(object):
@ -242,7 +214,7 @@ class Cube(object):
vertex_count = 36 vertex_count = 36
def __init__(self): def __init__(self):
self.vbo = array_to_gl_buffer([ self.vbo = list_to_gl_buffer([
-1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1,
-1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1,
1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1,
@ -263,7 +235,7 @@ class OrbitVBO(object):
x, z, y = orbit.orbit(theta) x, z, y = orbit.orbit(theta)
buffer[3*theta:3*theta+3] = [x, y, z] buffer[3*theta:3*theta+3] = [x, y, z]
self.vbo = array_to_gl_buffer(buffer) self.vbo = list_to_gl_buffer(buffer)
def close(self): def close(self):
if self.vbo is not None: if self.vbo is not None:
@ -322,17 +294,28 @@ class FontEngine(object):
glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ARRAY_BUFFER, 0)
def belt(radius, cross, object, count): class BeltVBO(object):
for i in range(count): type = GL_FLOAT
theta = TWOPI * random() stride = 4 * 4
r = gauss(radius, cross) location_offset = 0
x, y, z = cos(theta) * r, gauss(0, cross), sin(theta) * r location_size = 3
scale_offset = location_size * 4
scale_size = 1
glPushMatrix() def __init__(self, radius, cross, objects, count):
glTranslatef(x, y, z) arrays = [array('f') for i in range(objects)]
scale = gauss(1, 0.5)
if scale < 0: for i in range(count):
scale = 1 theta = TWOPI * random()
glScalef(scale, scale, scale) r = gauss(radius, cross)
choice(object).draw() x, y, z = cos(theta) * r, gauss(0, cross), sin(theta) * r
glPopMatrix() scale = gauss(1, 0.5)
if scale < 0:
scale = 1
choice(arrays).extend((x, y, z, scale))
self.vbo = []
self.sizes = []
for a in arrays:
self.vbo.append(array_to_gl_buffer(a))
self.sizes.append(len(a) // 4)

View file

@ -8,7 +8,6 @@ import pyglet
from pyglet.gl import * from pyglet.gl import *
from six.moves import zip_longest from six.moves import zip_longest
from punyverse.glgeom import glRestore
from punyverse.world import World from punyverse.world import World
@ -36,39 +35,40 @@ class glSection(object):
def progress_bar(x, y, width, height, filled): def progress_bar(x, y, width, height, filled):
with glRestore(GL_ENABLE_BIT): glPushAttrib(GL_ENABLE_BIT)
glDisable(GL_TEXTURE_2D) glDisable(GL_TEXTURE_2D)
glDisable(GL_BLEND) glDisable(GL_BLEND)
x1 = x x1 = x
x2 = x + width x2 = x + width
y1 = y y1 = y
y2 = y - height y2 = y - height
y3 = 0.65 * y1 + 0.35 * y2 y3 = 0.65 * y1 + 0.35 * y2
y4 = 0.25 * y1 + 0.75 * y2 y4 = 0.25 * y1 + 0.75 * y2
glColor3f(0.6, 0.6, 0.6) glColor3f(0.6, 0.6, 0.6)
with glSection(GL_LINE_LOOP): with glSection(GL_LINE_LOOP):
glVertex2f(x1, y1) glVertex2f(x1, y1)
glVertex2f(x1, y2) glVertex2f(x1, y2)
glVertex2f(x2, y2) glVertex2f(x2, y2)
glVertex2f(x2, y1) glVertex2f(x2, y1)
x1 += 1 x1 += 1
y1 -= 1 y1 -= 1
x2 = x + width * filled - 1 x2 = x + width * filled - 1
with glSection(GL_TRIANGLE_STRIP): with glSection(GL_TRIANGLE_STRIP):
glColor3f(0.81, 1, 0.82) glColor3f(0.81, 1, 0.82)
glVertex2f(x1, y1) glVertex2f(x1, y1)
glVertex2f(x2, y1) glVertex2f(x2, y1)
glColor3f(0, 0.83, 0.16) glColor3f(0, 0.83, 0.16)
glVertex2f(x1, y3) glVertex2f(x1, y3)
glVertex2f(x2, y3) glVertex2f(x2, y3)
glVertex2f(x1, y4) glVertex2f(x1, y4)
glVertex2f(x2, y4) glVertex2f(x2, y4)
glColor3f(0.37, 0.92, 0.43) glColor3f(0.37, 0.92, 0.43)
glVertex2f(x1, y2) glVertex2f(x1, y2)
glVertex2f(x2, y2) glVertex2f(x2, y2)
glPopAttrib()
def get_context_info(context): def get_context_info(context):

View file

@ -9,7 +9,7 @@ from pyglet.gl import *
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from six.moves import range, zip from six.moves import range, zip
from punyverse.glgeom import array_to_gl_buffer, glRestoreClient, glRestore from punyverse.glgeom import list_to_gl_buffer
from punyverse.texture import load_texture from punyverse.texture import load_texture
@ -199,25 +199,30 @@ def load_model(path):
class ModelVBO(object): 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')
def draw(self): def draw(self, shader, instances=None):
with glRestoreClient(GL_CLIENT_VERTEX_ARRAY_BIT): stride = (3 + self.has_normal * 3 + self.has_texture * 2) * 4
stride = (3 + self.has_normal * 3 + self.has_texture * 2) * 4
glBindBuffer(GL_ARRAY_BUFFER, self.data_buf) glBindBuffer(GL_ARRAY_BUFFER, self.data_buf)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.index_buf) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.index_buf)
glEnableClientState(GL_VERTEX_ARRAY) shader.vertex_attribute('a_position', 3, GL_FLOAT, GL_FALSE, stride, 0)
glVertexPointer(3, GL_FLOAT, stride, 0) if self.has_normal:
if self.has_normal: shader.vertex_attribute('a_normal', 3, GL_FLOAT, GL_FALSE, stride, 3 * 4)
glEnableClientState(GL_NORMAL_ARRAY) else:
glNormalPointer(GL_FLOAT, stride, 3 * 4) shader.vertex_attribute_vec3('a_normal', 0, 0, 0)
if self.has_texture: if self.has_texture:
glEnableClientState(GL_TEXTURE_COORD_ARRAY) shader.vertex_attribute('a_uv', 2, GL_FLOAT, GL_FALSE, stride, (6 if self.has_normal else 3) * 4)
glTexCoordPointer(3, GL_FLOAT, stride, (6 if self.has_normal else 3) * 4) else:
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) glDrawElements(GL_TRIANGLES, self.vertex_count, self.offset_type, 0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) shader.deactivate_attributes('a_position', 'a_normal', 'a_uv')
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
class WavefrontVBO(object): class WavefrontVBO(object):
@ -237,31 +242,39 @@ class WavefrontVBO(object):
for group in self.merge_groups(model): for group in self.merge_groups(model):
self.vbos.append((group.material, self.process_group(group, vertices, normals, textures))) self.vbos.append((group.material, self.process_group(group, vertices, normals, textures)))
def draw(self, fv4=GLfloat * 4): def draw(self, shader, instances=None):
with glRestore(GL_TEXTURE_BIT | GL_ENABLE_BIT): for mat, vbo in self.vbos:
for mat, vbo in self.vbos: tex_id = self._tex_cache[mat.texture] if mat and mat.texture else 0
tex_id = self._tex_cache[mat.texture] if mat and mat.texture else 0
if tex_id: if tex_id:
glEnable(GL_TEXTURE_2D) glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, tex_id) glBindTexture(GL_TEXTURE_2D, tex_id)
else: shader.uniform_bool('u_material.hasDiffuse', True)
glBindTexture(GL_TEXTURE_2D, 0) shader.uniform_texture('u_material.diffuseMap', 0)
glDisable(GL_TEXTURE_2D) else:
shader.uniform_bool('u_material.hasDiffuse', False)
if mat: if mat and mat.Ka:
if mat.Ka: shader.uniform_vec3('u_material.ambient', *mat.Ka)
kx, ky, kz = mat.Ka else:
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, fv4(kx, ky, kz, 1)) shader.uniform_vec3('u_material.ambient', 0.2, 0.2, 0.2)
if mat.Kd:
kx, ky, kz = mat.Kd
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fv4(kx, ky, kz, 1))
if mat.Ks:
kx, ky, kz = mat.Ks
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, fv4(kx, ky, kz, 1))
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mat.shininess)
vbo.draw() if mat and mat.Kd:
shader.uniform_vec3('u_material.diffuse', *mat.Kd)
else:
shader.uniform_vec3('u_material.diffuse', 0.8, 0.8, 0.8)
if mat and mat.Ks:
shader.uniform_vec3('u_material.specular', *mat.Ks)
else:
shader.uniform_vec3('u_material.specular', 0, 0, 0)
if mat:
shader.uniform_float('u_material.shininess', mat.shininess)
else:
shader.uniform_float('u_material.shininess', 0)
vbo.draw(shader, instances=instances)
def merge_groups(self, model): def merge_groups(self, model):
by_mat = defaultdict(list) by_mat = defaultdict(list)
@ -313,8 +326,8 @@ class WavefrontVBO(object):
result.has_normal = has_normal result.has_normal = has_normal
result.has_texture = has_texture result.has_texture = has_texture
result.offset_type = GL_UNSIGNED_SHORT if len(offsets) < 65536 else GL_UNSIGNED_INT result.offset_type = GL_UNSIGNED_SHORT if len(offsets) < 65536 else GL_UNSIGNED_INT
result.data_buf = array_to_gl_buffer(buffer, 'f') result.data_buf = list_to_gl_buffer(buffer, 'f')
result.index_buf = array_to_gl_buffer(indices, { result.index_buf = list_to_gl_buffer(indices, {
GL_UNSIGNED_SHORT: 'H', GL_UNSIGNED_SHORT: 'H',
GL_UNSIGNED_INT: 'I', GL_UNSIGNED_INT: 'I',
}[result.offset_type]) }[result.offset_type])

View file

@ -79,17 +79,40 @@ class Program(object):
self.attributes = self._variable_locations(GL_ACTIVE_ATTRIBUTES, glGetActiveAttrib, glGetAttribLocation) self.attributes = self._variable_locations(GL_ACTIVE_ATTRIBUTES, glGetActiveAttrib, glGetAttribLocation)
self.uniforms = self._variable_locations(GL_ACTIVE_UNIFORMS, glGetActiveUniform, glGetUniformLocation) self.uniforms = self._variable_locations(GL_ACTIVE_UNIFORMS, glGetActiveUniform, glGetUniformLocation)
self.active_attributes = set() self.active_attributes = set()
self.divisor_attributes = set()
def vertex_attribute(self, name, size, type, normalized, stride, offset): def vertex_attribute(self, name, size, type, normalized, stride, offset, divisor=None):
location = self.attributes[name] location = self.attributes[name]
glVertexAttribPointer(location, size, type, normalized, stride, offset) glVertexAttribPointer(location, size, type, normalized, stride, offset)
glEnableVertexAttribArray(location) glEnableVertexAttribArray(location)
if divisor:
glVertexAttribDivisor(location, divisor)
self.divisor_attributes.add(location)
self.active_attributes.add(location) self.active_attributes.add(location)
def deactivate_attributes(self): def deactivate_all_attributes(self):
for location in self.active_attributes: for location in self.active_attributes:
glDisableVertexAttribArray(location) glDisableVertexAttribArray(location)
for location in self.divisor_attributes:
glVertexAttribDivisor(location, 0)
self.active_attributes.clear() self.active_attributes.clear()
self.divisor_attributes.clear()
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 vertex_attribute_vec2(self, name, a, b):
glVertexAttrib2f(self.attributes[name], a, b)
def vertex_attribute_vec3(self, name, a, b, c):
glVertexAttrib3f(self.attributes[name], a, b, c)
def uniform_mat4(self, name, matrix): def uniform_mat4(self, name, matrix):
glUniformMatrix4fv(self.uniforms[name], 1, GL_FALSE, matrix) glUniformMatrix4fv(self.uniforms[name], 1, GL_FALSE, matrix)

View file

@ -0,0 +1,28 @@
#version 130
in vec3 a_position;
in vec3 a_normal;
in vec2 a_uv;
in vec3 a_translate;
in float a_scale;
out vec2 v_uv;
out vec3 v_normal;
out vec3 v_position;
out vec3 v_camDirection;
uniform mat4 u_mvpMatrix;
uniform mat4 u_mvMatrix;
uniform mat4 u_modelMatrix;
void main() {
mat4 matrix = mat4(mat3(a_scale));
matrix[3].xyz = a_translate;
mat4 modelMatrix = u_modelMatrix * matrix;
gl_Position = u_mvpMatrix * matrix * vec4(a_position, 1);
v_normal = normalize(vec3(modelMatrix * vec4(a_normal, 0)));
v_uv = a_uv;
v_position = (modelMatrix * vec4(a_position, 1)).xyz;
v_camDirection = (u_mvMatrix * matrix * vec4(a_position, 1)).xyz;
}

View file

@ -0,0 +1,43 @@
#version 130
in vec2 v_uv;
in vec3 v_normal;
in vec3 v_position;
in vec3 v_camDirection;
out vec4 o_fragColor;
struct Material {
bool hasDiffuse;
sampler2D diffuseMap;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
struct Sun {
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 position;
float intensity;
};
uniform Sun u_sun;
uniform Material u_material;
void main() {
vec3 incident = normalize(u_sun.position - v_position);
vec3 reflected = normalize(reflect(-incident, v_normal));
float diffuseIntensity = max(dot(v_normal, incident), 0.0);
float shininess = pow(max(dot(normalize(v_camDirection), reflected), 0), u_material.shininess);
vec3 diffuse = u_material.hasDiffuse ? texture2D(u_material.diffuseMap, v_uv).rgb : vec3(1);
vec3 ambient = u_material.ambient * u_sun.ambient * diffuse;
vec3 specular = u_material.specular * u_sun.specular * max(shininess, 0) * diffuseIntensity;
diffuse *= u_material.diffuse * u_sun.diffuse * diffuseIntensity;
o_fragColor = vec4((ambient + diffuse + specular) * u_sun.intensity, 1);
}

View file

@ -0,0 +1,22 @@
#version 130
in vec3 a_position;
in vec3 a_normal;
in vec2 a_uv;
out vec2 v_uv;
out vec3 v_normal;
out vec3 v_position;
out vec3 v_camDirection;
uniform mat4 u_mvpMatrix;
uniform mat4 u_mvMatrix;
uniform mat4 u_modelMatrix;
void main() {
gl_Position = u_mvpMatrix * vec4(a_position, 1);
v_normal = normalize(vec3(u_modelMatrix * vec4(a_normal, 0)));
v_uv = a_uv;
v_position = (u_modelMatrix * vec4(a_position, 1)).xyz;
v_camDirection = (u_mvMatrix * vec4(a_position, 1)).xyz;
}

View file

@ -127,21 +127,6 @@ class Punyverse(pyglet.window.Window):
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glMatrixMode(GL_MODELVIEW)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_LIGHT1)
fv4 = GLfloat * 4
glLightfv(GL_LIGHT0, GL_POSITION, fv4(.5, .5, 1, 0))
glLightfv(GL_LIGHT0, GL_SPECULAR, fv4(.5, .5, 1, 1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, fv4(1, 1, 1, 1))
glLightfv(GL_LIGHT1, GL_POSITION, fv4(1, 0, .5, 0))
glLightfv(GL_LIGHT1, GL_DIFFUSE, fv4(.5, .5, .5, 1))
glLightfv(GL_LIGHT1, GL_SPECULAR, fv4(1, 1, 1, 1))
self.info_engine = FontEngine() self.info_engine = FontEngine()
self.circle = Circle(10, 20) self.circle = Circle(10, 20)
@ -214,12 +199,8 @@ class Punyverse(pyglet.window.Window):
if not width or not height: if not width or not height:
# Sometimes this happen for no reason? # Sometimes this happen for no reason?
return return
glViewport(0, 0, width, height) glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
self.world.resize(width, height) self.world.resize(width, height)
glLoadMatrixf(self.world.projection_matrix())
glMatrixMode(GL_MODELVIEW)
def on_mouse_scroll(self, x, y, scroll_x, scroll_y): def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
self.world.cam.speed += scroll_y * 50 + scroll_x * 500 self.world.cam.speed += scroll_y * 50 + scroll_x * 500
@ -240,12 +221,9 @@ class Punyverse(pyglet.window.Window):
def on_draw(self): def on_draw(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadMatrixf(self.world.view_matrix())
c = self.world.cam c = self.world.cam
x, y, z = c.x, c.y, c.z x, y, z = c.x, c.y, c.z
glEnable(GL_LIGHTING)
world = self.world world = self.world
get_distance = entity_distance(x, y, z) get_distance = entity_distance(x, y, z)
if x != world.x or y != world.y or z != world.z: if x != world.x or y != world.y or z != world.z:
@ -256,12 +234,8 @@ class Punyverse(pyglet.window.Window):
for entity in world.tracker: for entity in world.tracker:
entity.draw(self) entity.draw(self)
glColor4f(1, 1, 1, 1)
glDisable(GL_TEXTURE_2D)
width, height = self.get_size()
if self.info: if self.info:
width, height = self.get_size()
projection = Matrix4f([ projection = Matrix4f([
2 / width, 0, 0, 0, 2 / width, 0, 0, 0,
0, -2 / height, 0, 0, 0, -2 / height, 0, 0,

View file

@ -294,7 +294,7 @@
"radius": "2.362 * AU", "radius": "2.362 * AU",
"cross": 1000, "cross": 1000,
"scale": 30, "scale": 30,
"count": 256, "count": 4096,
"rotation": 114536500 "rotation": 114536500
} }
}, },

View file

@ -26,6 +26,8 @@ class World(object):
'atmosphere': ('atmosphere.vertex.glsl', 'atmosphere.fragment.glsl'), 'atmosphere': ('atmosphere.vertex.glsl', 'atmosphere.fragment.glsl'),
'text': ('text.vertex.glsl', 'text.fragment.glsl'), 'text': ('text.vertex.glsl', 'text.fragment.glsl'),
'line': ('line.vertex.glsl', 'line.fragment.glsl'), 'line': ('line.vertex.glsl', 'line.fragment.glsl'),
'model': ('model.vertex.glsl', 'model.fragment.glsl'),
'belt': ('belt.vertex.glsl', 'model.fragment.glsl'),
} }
def __init__(self, file, callback): def __init__(self, file, callback):
@ -51,12 +53,13 @@ class World(object):
for entity in self.tracker: for entity in self.tracker:
entity.update() entity.update()
shader = self.activate_shader('planet') for name in ('planet', 'model', 'belt'):
shader.uniform_vec3('u_sun.ambient', 0.1, 0.1, 0.1) shader = self.activate_shader(name)
shader.uniform_vec3('u_sun.diffuse', 1, 1, 1) shader.uniform_vec3('u_sun.ambient', 0.1, 0.1, 0.1)
shader.uniform_vec3('u_sun.specular', 0.5, 0.5, 0.5) shader.uniform_vec3('u_sun.diffuse', 1, 1, 1)
shader.uniform_vec3('u_sun.position', 0, 0, 0) shader.uniform_vec3('u_sun.specular', 0.5, 0.5, 0.5)
shader.uniform_float('u_sun.intensity', 1) shader.uniform_vec3('u_sun.position', 0, 0, 0)
shader.uniform_float('u_sun.intensity', 1)
shader = self.activate_shader('clouds') shader = self.activate_shader('clouds')
shader.uniform_vec3('u_sun', 0, 0, 0) shader.uniform_vec3('u_sun', 0, 0, 0)