Switch clouds to shaders.

This commit is contained in:
Quantum 2018-08-26 18:11:18 -04:00
parent 3770ec617b
commit f7797949d9
9 changed files with 107 additions and 32 deletions

View file

@ -5,7 +5,7 @@ from pyglet.gl import *
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from six.moves import range from six.moves import range
from punyverse.glgeom import compile, glRestore, belt, Sphere, Disk, OrbitVBO, Matrix4f, SimpleSphere, TangentSphere from punyverse.glgeom import compile, glRestore, belt, Disk, OrbitVBO, Matrix4f, SimpleSphere, TangentSphere
from punyverse.model import load_model, WavefrontVBO from punyverse.model import load_model, WavefrontVBO
from punyverse.orbit import KeplerOrbit from punyverse.orbit import KeplerOrbit
from punyverse.texture import get_best_texture, load_clouds from punyverse.texture import get_best_texture, load_clouds
@ -32,9 +32,14 @@ class Entity(object):
def mv_matrix(self): def mv_matrix(self):
return self.world.view_matrix() * self.model_matrix return self.world.view_matrix() * self.model_matrix
@cached_property
def mvp_matrix(self):
return self.world.vp_matrix * self.model_matrix
def update(self): def update(self):
self.model_matrix = None self.model_matrix = None
self.mv_matrix = None self.mv_matrix = None
self.mvp_matrix = None
x, y, z = self.location x, y, z = self.location
dx, dy, dz = self.direction dx, dy, dz = self.direction
self.location = x + dx, y + dy, z + dz self.location = x + dx, y + dy, z + dz
@ -316,8 +321,9 @@ class SphericalBody(Body):
atm_texture = atmosphere_data.get('diffuse_texture', None) atm_texture = atmosphere_data.get('diffuse_texture', None)
cloud_texture = atmosphere_data.get('cloud_texture', None) cloud_texture = atmosphere_data.get('cloud_texture', None)
if cloud_texture is not None: if cloud_texture is not None:
self.cloud_texture = get_best_texture(cloud_texture, loader=load_clouds) self.cloud_transparency = get_best_texture(cloud_texture, loader=load_clouds)
self.clouds = Sphere(self.radius + 2, division, division) self.cloud_radius = self.radius + 2
self.clouds = self._get_sphere(division, tangent=False)
if atm_texture is not None: if atm_texture is not None:
self.atm_texture = get_best_texture(atm_texture, clamp=True) self.atm_texture = get_best_texture(atm_texture, clamp=True)
@ -341,7 +347,7 @@ class SphericalBody(Body):
shader.uniform_float('u_radius', self.radius) shader.uniform_float('u_radius', self.radius)
shader.uniform_mat4('u_modelMatrix', self.model_matrix) shader.uniform_mat4('u_modelMatrix', self.model_matrix)
shader.uniform_mat4('u_mvMatrix', self.mv_matrix) shader.uniform_mat4('u_mvMatrix', self.mv_matrix)
shader.uniform_mat4('u_mvpMatrix', self.world.vp_matrix * self.model_matrix) shader.uniform_mat4('u_mvpMatrix', self.mvp_matrix)
glActiveTexture(GL_TEXTURE0) glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, self.texture) glBindTexture(GL_TEXTURE_2D, self.texture)
@ -395,7 +401,7 @@ class SphericalBody(Body):
def _draw_star(self): def _draw_star(self):
shader = self.world.activate_shader('star') shader = self.world.activate_shader('star')
shader.uniform_float('u_radius', self.radius) shader.uniform_float('u_radius', self.radius)
shader.uniform_mat4('u_mvpMatrix', self.world.vp_matrix * self.model_matrix) shader.uniform_mat4('u_mvpMatrix', self.mvp_matrix)
glActiveTexture(GL_TEXTURE0) glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, self.texture) glBindTexture(GL_TEXTURE_2D, self.texture)
@ -436,17 +442,30 @@ class SphericalBody(Body):
self.atmosphere.draw() self.atmosphere.draw()
def _draw_clouds(self): def _draw_clouds(self):
with glRestore(GL_ENABLE_BIT | GL_TEXTURE_BIT): glEnable(GL_BLEND)
glLoadMatrixf(self.mv_matrix) shader = self.world.activate_shader('clouds')
glEnable(GL_BLEND) shader.uniform_float('u_radius', self.cloud_radius)
glEnable(GL_ALPHA_TEST) shader.uniform_mat4('u_modelMatrix', self.model_matrix)
glEnable(GL_CULL_FACE) shader.uniform_mat4('u_mvpMatrix', self.mvp_matrix)
glDisable(GL_LIGHTING)
glEnable(GL_TEXTURE_2D)
glCullFace(GL_BACK) glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, self.cloud_texture) glBindTexture(GL_TEXTURE_2D, self.cloud_transparency)
self.clouds.draw() shader.uniform_texture('u_transparency', 0)
shader.uniform_vec3('u_diffuse', 1, 1, 1)
shader.uniform_vec3('u_ambient', 0.1, 0.1, 0.1)
glBindBuffer(GL_ARRAY_BUFFER, self.clouds.vbo)
shader.vertex_attribute('a_normal', self.clouds.direction_size, self.clouds.type, GL_FALSE,
self.clouds.stride, self.clouds.direction_offset)
shader.vertex_attribute('a_uv', self.clouds.uv_size, self.clouds.type, GL_FALSE,
self.clouds.stride, self.clouds.uv_offset)
glDrawArrays(GL_TRIANGLE_STRIP, 0, self.clouds.vertex_count)
shader.deactivate_attributes()
glBindBuffer(GL_ARRAY_BUFFER, 0)
self.world.activate_shader(None)
glDisable(GL_BLEND)
def _draw_rings(self): def _draw_rings(self):
with glRestore(GL_ENABLE_BIT | GL_TEXTURE_BIT): with glRestore(GL_ENABLE_BIT | GL_TEXTURE_BIT):

View file

@ -1,4 +1,5 @@
import os import os
import sys
from ctypes import pointer, byref, create_string_buffer, POINTER, cast from ctypes import pointer, byref, create_string_buffer, POINTER, cast
from pyglet.gl import * from pyglet.gl import *
@ -39,11 +40,15 @@ class Program(object):
succeeded = GLint() succeeded = GLint()
log_length = GLint() log_length = GLint()
glGetShaderiv(shader, GL_COMPILE_STATUS, byref(succeeded)) glGetShaderiv(shader, GL_COMPILE_STATUS, byref(succeeded))
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, byref(log_length))
buffer = create_string_buffer(log_length.value + 1)
glGetShaderInfoLog(shader, log_length.value, None, buffer)
if not succeeded: if not succeeded:
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, byref(log_length)) raise CompileError(buffer.value.decode('utf-8'))
buffer = create_string_buffer(log_length.value + 1) elif log_length.value:
glGetShaderInfoLog(shader, log_length.value, None, buffer) print('Warning:', file=sys.stderr)
raise CompileError(buffer.value) print(buffer.value.decode('utf-8'), file=sys.stderr)
def __init__(self, vertex_file, fragment_file): def __init__(self, vertex_file, fragment_file):
with glShader(GL_VERTEX_SHADER) as vertex_shader, glShader(GL_FRAGMENT_SHADER) as fragment_shader: with glShader(GL_VERTEX_SHADER) as vertex_shader, glShader(GL_FRAGMENT_SHADER) as fragment_shader:

View file

@ -0,0 +1,19 @@
#version 130
in vec2 v_uv;
in vec3 v_normal;
in vec3 v_position;
out vec4 o_fragColor;
uniform vec3 u_ambient;
uniform vec3 u_diffuse;
uniform vec3 u_sun;
uniform sampler2D u_transparency;
void main() {
vec3 incident = normalize(u_sun - v_position);
vec3 diffuse = u_diffuse * clamp(dot(v_normal, incident) + 0.2, 0.0, 1.0);
o_fragColor = vec4(u_ambient + diffuse, texture(u_transparency, v_uv).r);
}

View file

@ -0,0 +1,20 @@
#version 130
in vec3 a_normal;
in vec2 a_uv;
out vec2 v_uv;
out vec3 v_normal;
out vec3 v_position;
uniform float u_radius;
uniform mat4 u_mvpMatrix;
uniform mat4 u_modelMatrix;
void main() {
vec3 position = u_radius * a_normal;
v_uv = a_uv;
v_normal = (u_modelMatrix * vec4(a_normal, 0)).xyz;
v_position = (u_modelMatrix * vec4(position, 1)).xyz;
gl_Position = u_mvpMatrix * vec4(position, 1);
}

View file

@ -6,6 +6,8 @@ in vec3 v_position;
in vec3 v_camDirection; in vec3 v_camDirection;
in mat3 v_TBN; in mat3 v_TBN;
out vec4 o_fragColor;
struct Surface { struct Surface {
sampler2D diffuseMap; sampler2D diffuseMap;
bool hasNormal; bool hasNormal;
@ -49,5 +51,5 @@ void main() {
emission *= u_planet.emission * (1 - min(diffuseIntensity * 2, 1)); emission *= u_planet.emission * (1 - min(diffuseIntensity * 2, 1));
specular *= u_planet.specular * u_sun.specular * max(shininess, 0) * diffuseIntensity; specular *= u_planet.specular * u_sun.specular * max(shininess, 0) * diffuseIntensity;
gl_FragColor = vec4((ambient + diffuse + emission + specular) * u_sun.intensity, 1); o_fragColor = vec4((ambient + diffuse + emission + specular) * u_sun.intensity, 1);
} }

View file

@ -1,8 +1,9 @@
#version 130 #version 130
in vec2 v_uv; in vec2 v_uv;
out vec4 o_fragColor;
uniform sampler2D u_skysphere; uniform sampler2D u_skysphere;
void main() { void main() {
gl_FragColor = vec4(texture(u_skysphere, v_uv).rgb, 1); o_fragColor = vec4(texture(u_skysphere, v_uv).rgb, 1);
} }

View file

@ -1,8 +1,9 @@
#version 130 #version 130
in vec2 v_uv; in vec2 v_uv;
out vec4 o_fragColor;
uniform sampler2D u_emission; uniform sampler2D u_emission;
void main() { void main() {
gl_FragColor = vec4(texture(u_emission, v_uv).rgb, 1); o_fragColor = vec4(texture(u_emission, v_uv).rgb, 1);
} }

View file

@ -1,6 +1,5 @@
from __future__ import print_function from __future__ import print_function
import itertools
import os.path import os.path
import struct import struct
from ctypes import c_int, byref, c_uint from ctypes import c_int, byref, c_uint
@ -9,7 +8,7 @@ from io import BytesIO
import six import six
from pyglet import image from pyglet import image
from pyglet.gl import * from pyglet.gl import *
from six.moves import zip, range from six.moves import range
try: try:
from ._glgeom import bgr_to_rgb, flip_vertical from ._glgeom import bgr_to_rgb, flip_vertical
@ -229,21 +228,26 @@ def load_clouds(file):
path, width, height, depth, mode, texture = load_image(file, path) path, width, height, depth, mode, texture = load_image(file, path)
if depth != 1:
texture = texture[::depth]
buffer = c_uint() buffer = c_uint()
glGenTextures(1, byref(buffer)) glGenTextures(1, byref(buffer))
id = buffer.value id = buffer.value
pixels = bytearray(len(texture) * 4)
white = b'\xff'[0]
pixels[:] = itertools.chain.from_iterable(zip(itertools.repeat(white), itertools.repeat(white),
itertools.repeat(white),
itertools.islice(texture, 0, None, depth)))
glBindTexture(GL_TEXTURE_2D, id) glBindTexture(GL_TEXTURE_2D, id)
if gl_info.have_version(3) or gl_info.have_extension('GL_ARB_framebuffer_object'):
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, texture)
glGenerateMipmap(GL_TEXTURE_2D)
else:
gluBuild2DMipmaps(GL_TEXTURE_2D, 1, width, height, GL_RED, GL_UNSIGNED_BYTE, texture)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, six.binary_type(pixels))
if gl_info.have_extension('GL_EXT_texture_filter_anisotropic'):
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, glGetInteger(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT))
cache[path] = id cache[path] = id
return id return id

View file

@ -20,6 +20,7 @@ class World(object):
PROGRAMS = { PROGRAMS = {
'sky': ('sky.vertex.glsl', 'sky.fragment.glsl'), 'sky': ('sky.vertex.glsl', 'sky.fragment.glsl'),
'planet': ('planet.vertex.glsl', 'planet.fragment.glsl'), 'planet': ('planet.vertex.glsl', 'planet.fragment.glsl'),
'clouds': ('clouds.vertex.glsl', 'clouds.fragment.glsl'),
'star': ('star.vertex.glsl', 'star.fragment.glsl'), 'star': ('star.vertex.glsl', 'star.fragment.glsl'),
} }
@ -52,6 +53,9 @@ class World(object):
shader.uniform_vec3('u_sun.specular', 0.5, 0.5, 0.5) shader.uniform_vec3('u_sun.specular', 0.5, 0.5, 0.5)
shader.uniform_vec3('u_sun.position', 0, 0, 0) shader.uniform_vec3('u_sun.position', 0, 0, 0)
shader.uniform_float('u_sun.intensity', 1) shader.uniform_float('u_sun.intensity', 1)
shader = self.activate_shader('clouds')
shader.uniform_vec3('u_sun', 0, 0, 0)
self.activate_shader(None) self.activate_shader(None)
def _load_programs(self): def _load_programs(self):