From 896d9d88b790066902cb8b9c88650ce33da80465 Mon Sep 17 00:00:00 2001 From: Quantum Date: Mon, 27 Aug 2018 19:28:17 -0400 Subject: [PATCH] Convert rings to shaders. Also add planet shadows onto rings. --- punyverse/entity.py | 32 ++++++++++++++----- punyverse/glgeom.py | 48 +++++----------------------- punyverse/shaders/ring.fragment.glsl | 22 +++++++++++++ punyverse/shaders/ring.vertex.glsl | 16 ++++++++++ punyverse/world.py | 1 + 5 files changed, 71 insertions(+), 48 deletions(-) create mode 100644 punyverse/shaders/ring.fragment.glsl create mode 100644 punyverse/shaders/ring.vertex.glsl diff --git a/punyverse/entity.py b/punyverse/entity.py index 7ccc49e..02e566e 100644 --- a/punyverse/entity.py +++ b/punyverse/entity.py @@ -468,15 +468,31 @@ class SphericalBody(Body): glDisable(GL_BLEND) def _draw_rings(self): - with glRestore(GL_ENABLE_BIT | GL_TEXTURE_BIT): - glLoadMatrixf(self.mv_matrix) - glDisable(GL_LIGHTING) - glEnable(GL_TEXTURE_2D) - glEnable(GL_BLEND) - glDisable(GL_CULL_FACE) + glEnable(GL_BLEND) + shader = self.world.activate_shader('ring') + shader.uniform_mat4('u_modelMatrix', self.model_matrix) + shader.uniform_mat4('u_mvpMatrix', self.mvp_matrix) + shader.uniform_vec3('u_planet', *self.location) + shader.uniform_vec3('u_sun', 0, 0, 0) + shader.uniform_float('u_planetRadius', self.radius) + shader.uniform_float('u_ambient', 0.1) - glBindTexture(GL_TEXTURE_2D, self.ring_texture) - self.ring.draw() + glActiveTexture(GL_TEXTURE0) + glBindTexture(GL_TEXTURE_2D, self.ring_texture) + shader.uniform_texture('u_texture', 0) + + glBindBuffer(GL_ARRAY_BUFFER, self.ring.vbo) + shader.vertex_attribute('a_position', self.ring.position_size, self.ring.type, GL_FALSE, + self.ring.stride, self.ring.position_offset) + shader.vertex_attribute('a_u', self.ring.u_size, self.ring.type, GL_FALSE, + self.ring.stride, self.ring.u_offset) + + glDrawArrays(GL_TRIANGLE_STRIP, 0, self.ring.vertex_count) + + shader.deactivate_attributes() + glBindBuffer(GL_ARRAY_BUFFER, 0) + self.world.activate_shader(None) + glDisable(GL_BLEND) def _draw(self, options): self._draw_sphere() diff --git a/punyverse/glgeom.py b/punyverse/glgeom.py index 74cce39..952e10b 100644 --- a/punyverse/glgeom.py +++ b/punyverse/glgeom.py @@ -9,7 +9,7 @@ from six.moves import range TWOPI = pi * 2 -__all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'Sphere', 'belt', +__all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'belt', 'glSection', 'glRestore', 'progress_bar'] @@ -179,6 +179,13 @@ def circle(r, seg, coords): class Disk(object): + type = GL_FLOAT + stride = 3 * 4 + position_offset = 0 + position_size = 2 + u_offset = position_size * 4 + u_size = 1 + def __init__(self, rinner, router, segs): res = segs * 5 delta = 2 * pi / res @@ -276,45 +283,6 @@ class TangentSphere(object): self.vbo = array_to_gl_buffer(buffer) -class Sphere(object): - def __init__(self, r, lats, longs): - tau = pi * 2 - phi_div = tau / longs - theta_div = pi / lats - - self.vertex_count = (lats + 1) * (longs + 1) * 2 - buffer = self.vertex_count * 8 * [0] - index = 0 - for i in range(longs + 1): - phi1, phi2 = i * phi_div, (i + 1) * phi_div - for j in range(lats + 1): - theta = j * theta_div - sine = sin(theta) - dz = cos(theta) - t = 1 - theta / pi - dx1 = sine * cos(phi2) - dy1 = sine * sin(phi2) - dx2 = sine * cos(phi1) - dy2 = sine * sin(phi1) - buffer[index:index + 16] = [r * dx1, r * dy1, r * dz, dx1, dy1, dz, phi2 / tau, t, - r * dx2, r * dy2, r * dz, dx2, dy2, dz, phi1 / tau, t] - index += 16 - - self.vbo = array_to_gl_buffer(buffer) - - def draw(self): - with glRestoreClient(GL_CLIENT_VERTEX_ARRAY_BIT): - glBindBuffer(GL_ARRAY_BUFFER, self.vbo) - glEnableClientState(GL_VERTEX_ARRAY) - glEnableClientState(GL_NORMAL_ARRAY) - glEnableClientState(GL_TEXTURE_COORD_ARRAY) - glVertexPointer(3, GL_FLOAT, 32, 0) - glNormalPointer(GL_FLOAT, 32, 3 * 4) - glTexCoordPointer(3, GL_FLOAT, 32, 6 * 4) - glDrawArrays(GL_TRIANGLE_STRIP, 0, self.vertex_count) - glBindBuffer(GL_ARRAY_BUFFER, 0) - - class OrbitVBO(object): def __init__(self, orbit): buffer = 360 * 3 * [0] diff --git a/punyverse/shaders/ring.fragment.glsl b/punyverse/shaders/ring.fragment.glsl new file mode 100644 index 0000000..af07020 --- /dev/null +++ b/punyverse/shaders/ring.fragment.glsl @@ -0,0 +1,22 @@ +#version 130 + +in vec3 v_position; +in float v_u; + +out vec4 o_fragColor; + +uniform vec3 u_sun; +uniform vec3 u_planet; +uniform float u_planetRadius; +uniform float u_ambient; +uniform sampler2D u_texture; + +void main() { + vec3 incident = v_position - u_sun; + vec3 plane_normal = u_planet - u_sun; + vec3 plane_intersect = dot(plane_normal, plane_normal) / dot(incident, plane_normal) * incident; + o_fragColor = texture(u_texture, vec2(v_u, 0)); + if (length(plane_intersect) < length(incident) && + distance(plane_intersect, plane_normal) <= u_planetRadius) + o_fragColor.rgb *= u_ambient; +} diff --git a/punyverse/shaders/ring.vertex.glsl b/punyverse/shaders/ring.vertex.glsl new file mode 100644 index 0000000..cb5ab79 --- /dev/null +++ b/punyverse/shaders/ring.vertex.glsl @@ -0,0 +1,16 @@ +#version 130 + +in vec2 a_position; +in float a_u; + +out vec3 v_position; +out float v_u; + +uniform mat4 u_mvpMatrix; +uniform mat4 u_modelMatrix; + +void main() { + gl_Position = u_mvpMatrix * vec4(a_position, 0, 1); + v_position = (u_modelMatrix * vec4(a_position, 0, 1)).xyz; + v_u = a_u; +} diff --git a/punyverse/world.py b/punyverse/world.py index 7ab3464..8a1efd1 100644 --- a/punyverse/world.py +++ b/punyverse/world.py @@ -22,6 +22,7 @@ class World(object): 'planet': ('planet.vertex.glsl', 'planet.fragment.glsl'), 'clouds': ('clouds.vertex.glsl', 'clouds.fragment.glsl'), 'star': ('star.vertex.glsl', 'star.fragment.glsl'), + 'ring': ('ring.vertex.glsl', 'ring.fragment.glsl'), } def __init__(self, file, callback):