From f70a725a58eeac0442298a275720d0267d882f2d Mon Sep 17 00:00:00 2001 From: Quantum Date: Tue, 28 Aug 2018 23:10:33 -0400 Subject: [PATCH] Shader for models. Instanced asteroid belt. Removed all instances of legacy pipeline, hopefully. (Except for using VAOs, I guess) --- punyverse/entity.py | 66 +++++++++++++------ punyverse/glgeom.py | 89 +++++++++++-------------- punyverse/loader.py | 62 +++++++++--------- punyverse/model.py | 93 +++++++++++++++------------ punyverse/shader.py | 27 +++++++- punyverse/shaders/belt.vertex.glsl | 28 ++++++++ punyverse/shaders/model.fragment.glsl | 43 +++++++++++++ punyverse/shaders/model.vertex.glsl | 22 +++++++ punyverse/ui.py | 28 +------- punyverse/world.json | 2 +- punyverse/world.py | 15 +++-- 11 files changed, 295 insertions(+), 180 deletions(-) create mode 100644 punyverse/shaders/belt.vertex.glsl create mode 100644 punyverse/shaders/model.fragment.glsl create mode 100644 punyverse/shaders/model.vertex.glsl diff --git a/punyverse/entity.py b/punyverse/entity.py index a5c171a..cee78b1 100644 --- a/punyverse/entity.py +++ b/punyverse/entity.py @@ -63,8 +63,12 @@ class Asteroid(Entity): self.rotation = rx + 1, ry + 1, rz + 1 def draw(self, options): - glLoadMatrixf(self.mv_matrix) - self.model.draw() + shader = self.world.activate_shader('model') + 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): @@ -97,14 +101,16 @@ class Belt(Entity): argument = info.get('argument', 0) rotation = info.get('period', 31536000) models = info['model'] - if not isinstance(models, list): - models = [models] - - objects = [WavefrontVBO(load_model(model), info.get('sx', scale), info.get('sy', scale), - info.get('sz', scale)) for model in models] - - self.belt_id = compile(belt, radius, cross, objects, count) self.rotation_angle = 360.0 / rotation if rotation else 0 + self.render = gl_info.have_version(3, 3) + + if self.render: + 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) super(Belt, self).__init__(world, name, (x, y, z), (inclination, longitude, argument)) @@ -114,8 +120,24 @@ class Belt(Entity): self.rotation = pitch, self.world.tick * self.rotation_angle % 360, roll def draw(self, options): - glLoadMatrixf(self.mv_matrix) - glCallList(self.belt_id) + if not self.render: + return + + shader = self.world.activate_shader('belt') + 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): @@ -155,7 +177,7 @@ class Sky(Entity): glDrawArrays(GL_TRIANGLES, 0, self.cube.vertex_count) - shader.deactivate_attributes() + shader.deactivate_all_attributes() glBindBuffer(GL_ARRAY_BUFFER, 0) self.world.activate_shader(None) @@ -261,7 +283,7 @@ class Body(Entity): shader.vertex_attribute('a_position', orbit.position_size, orbit.type, GL_FALSE, orbit.stride, orbit.position_offset) glDrawArrays(GL_LINE_LOOP, 0, orbit.vertex_count) - shader.deactivate_attributes() + shader.deactivate_all_attributes() glBindBuffer(GL_ARRAY_BUFFER, 0) if not solid: @@ -407,7 +429,7 @@ class SphericalBody(Body): glDrawArrays(GL_TRIANGLE_STRIP, 0, self.sphere.vertex_count) - shader.deactivate_attributes() + shader.deactivate_all_attributes() glBindBuffer(GL_ARRAY_BUFFER, 0) self.world.activate_shader(None) glActiveTexture(GL_TEXTURE0) @@ -429,7 +451,7 @@ class SphericalBody(Body): glDrawArrays(GL_TRIANGLE_STRIP, 0, self.sphere.vertex_count) - shader.deactivate_attributes() + shader.deactivate_all_attributes() glBindBuffer(GL_ARRAY_BUFFER, 0) self.world.activate_shader(None) @@ -462,7 +484,7 @@ class SphericalBody(Body): glDrawArrays(GL_TRIANGLE_STRIP, 0, self.atmosphere.vertex_count) - shader.deactivate_attributes() + shader.deactivate_all_attributes() glBindBuffer(GL_ARRAY_BUFFER, 0) self.world.activate_shader(None) glDisable(GL_BLEND) @@ -489,7 +511,7 @@ class SphericalBody(Body): glDrawArrays(GL_TRIANGLE_STRIP, 0, self.clouds.vertex_count) - shader.deactivate_attributes() + shader.deactivate_all_attributes() glBindBuffer(GL_ARRAY_BUFFER, 0) self.world.activate_shader(None) glDisable(GL_BLEND) @@ -517,7 +539,7 @@ class SphericalBody(Body): glDrawArrays(GL_TRIANGLE_STRIP, 0, self.ring.vertex_count) - shader.deactivate_attributes() + shader.deactivate_all_attributes() glBindBuffer(GL_ARRAY_BUFFER, 0) self.world.activate_shader(None) glDisable(GL_BLEND) @@ -551,5 +573,9 @@ class ModelBody(Body): info.get('sz', scale)) def _draw(self, options): - glLoadMatrixf(self.mv_matrix) - self.vbo.draw() + shader = self.world.activate_shader('model') + 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) diff --git a/punyverse/glgeom.py b/punyverse/glgeom.py index ad23a33..c7b413d 100644 --- a/punyverse/glgeom.py +++ b/punyverse/glgeom.py @@ -11,30 +11,7 @@ from six.moves import range TWOPI = pi * 2 -__all__ = ['compile', 'belt', 'glRestore', 'FontEngine', 'Matrix4f', 'Disk', 'OrbitVBO', - '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() +__all__ = ['FontEngine', 'Matrix4f', 'Disk', 'OrbitVBO', 'SimpleSphere', 'TangentSphere', 'Cube', 'Circle', 'BeltVBO'] def array_to_ctypes(arr): @@ -47,16 +24,19 @@ def array_to_ctypes(arr): }[arr.typecode])) -def array_to_gl_buffer(buffer, array_type='f'): +def array_to_gl_buffer(buffer): 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 list_to_gl_buffer(buffer, array_type='f'): + return array_to_gl_buffer(array(array_type, buffer)) + + class Matrix4f(object): def __init__(self, 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) -def compile(pointer, *args, **kwargs): - display = glGenLists(1) - glNewList(display, GL_COMPILE) - pointer(*args, **kwargs) - glEndList() - return display - - class Circle(object): type = GL_FLOAT stride = 2 * 4 @@ -132,7 +104,7 @@ class Circle(object): for i in range(segs): theta = delta * i 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): @@ -154,7 +126,7 @@ class Disk(object): 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) + self.vbo = list_to_gl_buffer(buffer) class SimpleSphere(object): @@ -190,7 +162,7 @@ class SimpleSphere(object): index += 10 reverse ^= True - self.vbo = array_to_gl_buffer(buffer) + self.vbo = list_to_gl_buffer(buffer) class TangentSphere(object): @@ -231,7 +203,7 @@ class TangentSphere(object): ] index += 14 reverse ^= True - self.vbo = array_to_gl_buffer(buffer) + self.vbo = list_to_gl_buffer(buffer) class Cube(object): @@ -242,7 +214,7 @@ class Cube(object): vertex_count = 36 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, @@ -263,7 +235,7 @@ class OrbitVBO(object): x, z, y = orbit.orbit(theta) 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): if self.vbo is not None: @@ -322,17 +294,28 @@ class FontEngine(object): glBindBuffer(GL_ARRAY_BUFFER, 0) -def belt(radius, cross, object, count): - for i in range(count): - theta = TWOPI * random() - r = gauss(radius, cross) - x, y, z = cos(theta) * r, gauss(0, cross), sin(theta) * r +class BeltVBO(object): + type = GL_FLOAT + stride = 4 * 4 + location_offset = 0 + location_size = 3 + scale_offset = location_size * 4 + scale_size = 1 - glPushMatrix() - glTranslatef(x, y, z) - scale = gauss(1, 0.5) - if scale < 0: - scale = 1 - glScalef(scale, scale, scale) - choice(object).draw() - glPopMatrix() + def __init__(self, radius, cross, objects, count): + arrays = [array('f') for i in range(objects)] + + for i in range(count): + theta = TWOPI * random() + r = gauss(radius, cross) + x, y, z = cos(theta) * r, gauss(0, cross), sin(theta) * r + 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) diff --git a/punyverse/loader.py b/punyverse/loader.py index 4c6d7fd..82fa1b2 100644 --- a/punyverse/loader.py +++ b/punyverse/loader.py @@ -8,7 +8,6 @@ import pyglet from pyglet.gl import * from six.moves import zip_longest -from punyverse.glgeom import glRestore from punyverse.world import World @@ -36,39 +35,40 @@ class glSection(object): def progress_bar(x, y, width, height, filled): - with glRestore(GL_ENABLE_BIT): - glDisable(GL_TEXTURE_2D) - glDisable(GL_BLEND) - x1 = x - x2 = x + width - y1 = y - y2 = y - height - y3 = 0.65 * y1 + 0.35 * y2 - y4 = 0.25 * y1 + 0.75 * y2 + glPushAttrib(GL_ENABLE_BIT) + glDisable(GL_TEXTURE_2D) + glDisable(GL_BLEND) + x1 = x + x2 = x + width + y1 = y + y2 = y - height + y3 = 0.65 * y1 + 0.35 * y2 + y4 = 0.25 * y1 + 0.75 * y2 - glColor3f(0.6, 0.6, 0.6) - with glSection(GL_LINE_LOOP): - glVertex2f(x1, y1) - glVertex2f(x1, y2) - glVertex2f(x2, y2) - glVertex2f(x2, y1) + glColor3f(0.6, 0.6, 0.6) + with glSection(GL_LINE_LOOP): + glVertex2f(x1, y1) + glVertex2f(x1, y2) + glVertex2f(x2, y2) + glVertex2f(x2, y1) - x1 += 1 - y1 -= 1 - x2 = x + width * filled - 1 + x1 += 1 + y1 -= 1 + x2 = x + width * filled - 1 - with glSection(GL_TRIANGLE_STRIP): - glColor3f(0.81, 1, 0.82) - glVertex2f(x1, y1) - glVertex2f(x2, y1) - glColor3f(0, 0.83, 0.16) - glVertex2f(x1, y3) - glVertex2f(x2, y3) - glVertex2f(x1, y4) - glVertex2f(x2, y4) - glColor3f(0.37, 0.92, 0.43) - glVertex2f(x1, y2) - glVertex2f(x2, y2) + with glSection(GL_TRIANGLE_STRIP): + glColor3f(0.81, 1, 0.82) + glVertex2f(x1, y1) + glVertex2f(x2, y1) + glColor3f(0, 0.83, 0.16) + glVertex2f(x1, y3) + glVertex2f(x2, y3) + glVertex2f(x1, y4) + glVertex2f(x2, y4) + glColor3f(0.37, 0.92, 0.43) + glVertex2f(x1, y2) + glVertex2f(x2, y2) + glPopAttrib() def get_context_info(context): diff --git a/punyverse/model.py b/punyverse/model.py index 9465bfa..fd6377e 100644 --- a/punyverse/model.py +++ b/punyverse/model.py @@ -9,7 +9,7 @@ from pyglet.gl import * # noinspection PyUnresolvedReferences 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 @@ -199,25 +199,30 @@ def load_model(path): class ModelVBO(object): __slots__ = ('has_normal', 'has_texture', 'data_buf', 'index_buf', 'offset_type', 'vertex_count') - def draw(self): - with glRestoreClient(GL_CLIENT_VERTEX_ARRAY_BIT): - stride = (3 + self.has_normal * 3 + self.has_texture * 2) * 4 + def draw(self, shader, instances=None): + 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) + glBindBuffer(GL_ARRAY_BUFFER, self.data_buf) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.index_buf) - glEnableClientState(GL_VERTEX_ARRAY) - glVertexPointer(3, GL_FLOAT, stride, 0) - if self.has_normal: - glEnableClientState(GL_NORMAL_ARRAY) - glNormalPointer(GL_FLOAT, stride, 3 * 4) - if self.has_texture: - glEnableClientState(GL_TEXTURE_COORD_ARRAY) - glTexCoordPointer(3, GL_FLOAT, stride, (6 if self.has_normal else 3) * 4) + 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) + 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) - 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): @@ -237,31 +242,39 @@ class WavefrontVBO(object): for group in self.merge_groups(model): self.vbos.append((group.material, self.process_group(group, vertices, normals, textures))) - def draw(self, fv4=GLfloat * 4): - with glRestore(GL_TEXTURE_BIT | GL_ENABLE_BIT): - for mat, vbo in self.vbos: - tex_id = self._tex_cache[mat.texture] if mat and mat.texture else 0 + def draw(self, shader, instances=None): + for mat, vbo in self.vbos: + tex_id = self._tex_cache[mat.texture] if mat and mat.texture else 0 - if tex_id: - glEnable(GL_TEXTURE_2D) - glBindTexture(GL_TEXTURE_2D, tex_id) - else: - glBindTexture(GL_TEXTURE_2D, 0) - glDisable(GL_TEXTURE_2D) + if tex_id: + glActiveTexture(GL_TEXTURE0) + glBindTexture(GL_TEXTURE_2D, tex_id) + shader.uniform_bool('u_material.hasDiffuse', True) + shader.uniform_texture('u_material.diffuseMap', 0) + else: + shader.uniform_bool('u_material.hasDiffuse', False) - if mat: - if mat.Ka: - kx, ky, kz = mat.Ka - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, fv4(kx, ky, kz, 1)) - 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) + if mat and mat.Ka: + shader.uniform_vec3('u_material.ambient', *mat.Ka) + else: + shader.uniform_vec3('u_material.ambient', 0.2, 0.2, 0.2) - 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): by_mat = defaultdict(list) @@ -313,8 +326,8 @@ class WavefrontVBO(object): result.has_normal = has_normal result.has_texture = has_texture result.offset_type = GL_UNSIGNED_SHORT if len(offsets) < 65536 else GL_UNSIGNED_INT - result.data_buf = array_to_gl_buffer(buffer, 'f') - result.index_buf = array_to_gl_buffer(indices, { + result.data_buf = list_to_gl_buffer(buffer, 'f') + result.index_buf = list_to_gl_buffer(indices, { GL_UNSIGNED_SHORT: 'H', GL_UNSIGNED_INT: 'I', }[result.offset_type]) diff --git a/punyverse/shader.py b/punyverse/shader.py index 5f10d41..64b9af8 100644 --- a/punyverse/shader.py +++ b/punyverse/shader.py @@ -79,17 +79,40 @@ class Program(object): 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): + def vertex_attribute(self, name, size, type, normalized, stride, offset, divisor=None): location = self.attributes[name] glVertexAttribPointer(location, size, type, normalized, stride, offset) glEnableVertexAttribArray(location) + if divisor: + glVertexAttribDivisor(location, divisor) + self.divisor_attributes.add(location) self.active_attributes.add(location) - def deactivate_attributes(self): + def deactivate_all_attributes(self): for location in self.active_attributes: glDisableVertexAttribArray(location) + for location in self.divisor_attributes: + glVertexAttribDivisor(location, 0) 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): glUniformMatrix4fv(self.uniforms[name], 1, GL_FALSE, matrix) diff --git a/punyverse/shaders/belt.vertex.glsl b/punyverse/shaders/belt.vertex.glsl new file mode 100644 index 0000000..ae325e0 --- /dev/null +++ b/punyverse/shaders/belt.vertex.glsl @@ -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; +} diff --git a/punyverse/shaders/model.fragment.glsl b/punyverse/shaders/model.fragment.glsl new file mode 100644 index 0000000..fb5dedf --- /dev/null +++ b/punyverse/shaders/model.fragment.glsl @@ -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); +} diff --git a/punyverse/shaders/model.vertex.glsl b/punyverse/shaders/model.vertex.glsl new file mode 100644 index 0000000..a4dc4dc --- /dev/null +++ b/punyverse/shaders/model.vertex.glsl @@ -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; +} diff --git a/punyverse/ui.py b/punyverse/ui.py index 9e40d93..faa55e1 100644 --- a/punyverse/ui.py +++ b/punyverse/ui.py @@ -128,21 +128,6 @@ class Punyverse(pyglet.window.Window): 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.circle = Circle(10, 20) @@ -215,12 +200,8 @@ class Punyverse(pyglet.window.Window): if not width or not height: # Sometimes this happen for no reason? return - glViewport(0, 0, width, height) - glMatrixMode(GL_PROJECTION) self.world.resize(width, height) - glLoadMatrixf(self.world.projection_matrix()) - glMatrixMode(GL_MODELVIEW) def on_mouse_scroll(self, x, y, scroll_x, scroll_y): self.world.cam.speed += scroll_y * 50 + scroll_x * 500 @@ -241,12 +222,9 @@ class Punyverse(pyglet.window.Window): def on_draw(self): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) - glLoadMatrixf(self.world.view_matrix()) - c = self.world.cam x, y, z = c.x, c.y, c.z - glEnable(GL_LIGHTING) world = self.world get_distance = entity_distance(x, y, z) if x != world.x or y != world.y or z != world.z: @@ -257,12 +235,8 @@ class Punyverse(pyglet.window.Window): for entity in world.tracker: entity.draw(self) - glColor4f(1, 1, 1, 1) - glDisable(GL_TEXTURE_2D) - - width, height = self.get_size() - if self.info: + width, height = self.get_size() projection = Matrix4f([ 2 / width, 0, 0, 0, 0, -2 / height, 0, 0, diff --git a/punyverse/world.json b/punyverse/world.json index 5807862..c4e04ae 100644 --- a/punyverse/world.json +++ b/punyverse/world.json @@ -294,7 +294,7 @@ "radius": "2.362 * AU", "cross": 1000, "scale": 30, - "count": 256, + "count": 4096, "rotation": 114536500 } }, diff --git a/punyverse/world.py b/punyverse/world.py index fc600eb..c8558f0 100644 --- a/punyverse/world.py +++ b/punyverse/world.py @@ -26,6 +26,8 @@ class World(object): 'atmosphere': ('atmosphere.vertex.glsl', 'atmosphere.fragment.glsl'), 'text': ('text.vertex.glsl', 'text.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): @@ -51,12 +53,13 @@ class World(object): for entity in self.tracker: entity.update() - shader = self.activate_shader('planet') - shader.uniform_vec3('u_sun.ambient', 0.1, 0.1, 0.1) - shader.uniform_vec3('u_sun.diffuse', 1, 1, 1) - shader.uniform_vec3('u_sun.specular', 0.5, 0.5, 0.5) - shader.uniform_vec3('u_sun.position', 0, 0, 0) - shader.uniform_float('u_sun.intensity', 1) + for name in ('planet', 'model', 'belt'): + shader = self.activate_shader(name) + shader.uniform_vec3('u_sun.ambient', 0.1, 0.1, 0.1) + shader.uniform_vec3('u_sun.diffuse', 1, 1, 1) + shader.uniform_vec3('u_sun.specular', 0.5, 0.5, 0.5) + shader.uniform_vec3('u_sun.position', 0, 0, 0) + shader.uniform_float('u_sun.intensity', 1) shader = self.activate_shader('clouds') shader.uniform_vec3('u_sun', 0, 0, 0)