from OpenGL.GL import * import numpy as np from OpenGL.GL.ARB.vertex_array_object import glDeleteVertexArrays from OpenGL.GL.framebufferobjects import glBindRenderbuffer from OpenGL.GLUT import * import OpenGL.GLUT.freeglut from OpenGL.GLU import * from OpenGL.GL import * from ctypes import sizeof, c_float, c_void_p, c_uint from Lights.Spotlight.Spotlight import Spotlight from WorldProvider.WorldProvider import WorldProvider from MatrixStuff.Transformations import perspectiveMatrix, lookAt, translate, rotate from Objects.Cube.Cube import Cube from Objects.Cuboid.Cuboid import Cuboid from Objects.World import World import json import random import time from scipy.signal import convolve MAX_DISTANCE = 200.0 FRICTION_COEFFICENT = 1 EPSILON = 0.00001 def value_to_color(v, min_value, max_value): r = g = b = 0.0 scope = max_value - min_value normalized = (v - min_value) / (max_value - min_value) if 0.5 * scope + min_value != 0: b = max(0, 1.0 - abs(2.0 * normalized)) g = max(0, 1.0 - abs(2.0 * normalized - 1.0)) r = max(0, 1.0 - abs(2.0 * normalized - 2.0)) l = np.sqrt((r * r + b * b + g * g)) r /= l g /= l b /= l return r, g, b class Client: def __init__(self, test=False, pos=[0, 0, 0]): with open('./config.json', 'r') as f: self.config = json.load(f) glutInit(sys.argv) self.width = 1920 self.height = 1080 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH) glutInitWindowSize(self.width, self.height) glutCreateWindow(b'Voxelengine') with open('passthroughvertex.glsl', 'r') as f: vertex_shader_string = f.read() self.passthrough_vertex_shader_id = glCreateShader(GL_VERTEX_SHADER) glShaderSource(self.passthrough_vertex_shader_id, vertex_shader_string) glCompileShader(self.passthrough_vertex_shader_id) if glGetShaderiv(self.passthrough_vertex_shader_id, GL_COMPILE_STATUS) != GL_TRUE: raise RuntimeError(glGetShaderInfoLog(self.passthrough_vertex_shader_id)) with open('vertex.glsl', 'r') as f: vertex_shader_string = f.read() self.vertex_shader_id = glCreateShader(GL_VERTEX_SHADER) glShaderSource(self.vertex_shader_id, vertex_shader_string) glCompileShader(self.vertex_shader_id) if glGetShaderiv(self.vertex_shader_id, GL_COMPILE_STATUS) != GL_TRUE: raise RuntimeError(glGetShaderInfoLog(self.vertex_shader_id)) with open('fragment.glsl', 'r') as f: fragment_shader_string = f.read() self.fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER) glShaderSource(self.fragment_shader_id, fragment_shader_string) glCompileShader(self.fragment_shader_id) if glGetShaderiv(self.fragment_shader_id, GL_COMPILE_STATUS) != GL_TRUE: raise RuntimeError(glGetShaderInfoLog(self.fragment_shader_id)) Cube.initializeShader() Cuboid.initializeShader() self.geometry_shaders = { Cube: Cube.GeometryShaderId, Cuboid: Cuboid.GeometryShaderId } self.normal_program = {} self.depth_program = {} for key in self.geometry_shaders.keys(): self.normal_program[key] = glCreateProgram() glAttachShader(self.normal_program[key], self.vertex_shader_id) glAttachShader(self.normal_program[key], key.GeometryShaderId) glAttachShader(self.normal_program[key], self.fragment_shader_id) glLinkProgram(self.normal_program[key]) self.depth_program[self.normal_program[key]] = Spotlight.getDepthProgram(self.vertex_shader_id, key.GeometryShaderId) self.world_provider = WorldProvider(self.normal_program) for x_pos in range(0, 100): for y_pos in range(0, 100): for z_pos in range(0, 1): self.world_provider.world.put_object(x_pos, y_pos, z_pos, Cuboid().setColor( random.randint(0, 100) / 100.0, random.randint(0, 100) / 100.0, random.randint(0, 100) / 100.0)) self.projMatrix = perspectiveMatrix(45.0, 400 / 400, 0.01, MAX_DISTANCE) self.rx = self.cx = self.cy = 0 self.opening = 45 glutReshapeFunc(self.resize) glutDisplayFunc(self.display) glutKeyboardFunc(self.keyboardHandler) glutSpecialFunc(self.funcKeydHandler) self.pos = pos self.time = time.time() self.field = (100, 100, 1) self.e_a = np.array([ [0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], [-1, 1, 0], [-1, 0, 0], [-1, -1, 0], [0, -1, 0], [1, -1, 0], ]) self.relaxation_time = 0.55 # 0.55 self.w_a = [ 4.0 / 9.0, 1.0 / 9.0, 1.0 / 36.0, 1.0 / 9.0, 1.0 / 36.0, 1.0 / 9.0, 1.0 / 36.0, 1.0 / 9.0, 1.0 / 36.0 ] self.n_a = np.zeros((len(self.e_a),) + self.field) self.n_a_eq = np.zeros(self.n_a.shape) self.n = np.zeros(self.field) self.n[:, :, :] += 1.0 # self.n /= np.sum(self.n) self.n_a[0] = np.array(self.n) self.u = np.zeros(self.field + (self.e_a.shape[1],)) self.compressible = True self.max_n = self.w_a[0] self.test_pixel = [40, 50, 0] if not test: glutMainLoop() else: self.display() self.resize(100, 100) def display(self): glClearColor(0, 0, 0, 0) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) projMatrix = perspectiveMatrix(45, float(self.width) / float(self.height), 0.01, MAX_DISTANCE) world: World = self.world_provider.world lights = world.get_lights_to_render(self.pos, self.config['render_light_distance']) for light in lights: light.prepareForDepthMapping() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) light_mat = translate(light.pos[0], light.pos[1], light.pos[2]) * \ lookAt(0, 0, 0, -light.pos[0], -light.pos[1], -light.pos[2], 0, 1, 0) * \ perspectiveMatrix(90, float(light.map_size) / float(light.map_size), 0.01, MAX_DISTANCE) for obj_type, program_id in self.depth_program.items(): glUseProgram(program_id) widthid = glGetUniformLocation(program_id, 'width') heightid = glGetUniformLocation(program_id, 'height') nearid = glGetUniformLocation(program_id, 'near') farid = glGetUniformLocation(program_id, 'far') glUniform1f(nearid, 0.01) glUniform1f(farid, 100) glUniform1f(widthid, light.map_size) glUniform1f(heightid, light.map_size) world.render(light_mat, rotate(0, 0, 0), self.depth_program) glFlush() light.finishDepthMapping() glClearColor(0, 0, 0, 0) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glClearColor(0, 0, 0, 0) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) for obj_type, program_id in self.normal_program.items(): glUseProgram(program_id) widthid = glGetUniformLocation(program_id, 'width') heightid = glGetUniformLocation(program_id, 'height') nearid = glGetUniformLocation(program_id, 'near') farid = glGetUniformLocation(program_id, 'far') glUniform1f(nearid, 0.01) glUniform1f(farid, 100) glUniform1f(widthid, self.width) glUniform1f(heightid, self.height) world.render(translate(self.pos[0], self.pos[1], self.pos[2]) * lookAt(0, 0, 0, 0, 0, -self.pos[2], 0, 1, 0) * projMatrix, rotate(0, 0, 0)) glFlush() glutSwapBuffers() min_value = 0 max_value_n = np.max(self.n) # max_value = 1.0 vel = np.sqrt(np.sum(np.square(self.u), axis=3)) max_value_vel = np.max(vel) # max_value_vel = np.sqrt(3) print('round') print(max_value_n) for x_pos in range(0, 100): for y_pos in range(0, 100): for z_pos in range(0, 1): r, g, b = value_to_color(self.n[x_pos, y_pos, z_pos], min_value, max_value_n) # r, g, b = value_to_color(vel[x_pos, y_pos, z_pos], min_value, max_value_vel) self.world_provider.world.set_color(x_pos, y_pos, z_pos, r, g, b) self.world_provider.world.set_color(int(round(self.test_pixel[0])), int(round(self.test_pixel[1])), int(round(self.test_pixel[2])), 1.0, 1.0, 1.0) # self.u *= 0.95 old_n_sum = np.sum(self.n) for a in range(len(self.e_a)): e_au = np.sum(self.e_a[a] * self.u, axis=3) uu = np.sum(self.u * self.u, axis=3) self.n_a_eq[a] = self.w_a[a] * self.n * (1.0 + 3.0 * e_au + 4.5 * np.square(e_au) - 1.5 * uu) print(np.max(self.n_a_eq[0])) if not self.compressible: excess = (self.n_a_eq[0] > self.max_n) * (self.n_a_eq[0] - self.max_n) dir_sum = np.sum(self.n_a_eq[1:], axis=0) self.n_a_eq[1:] += excess * 1/8 #(self.n_a_eq[1:] / dir_sum) self.n_a_eq[0] -= excess n_a_t_1 = np.zeros((len(self.e_a),) + self.field) for a in range(len(self.e_a)): temp = ((-1.0 / self.relaxation_time) * (self.n_a[a] - self.n_a_eq[a]) + self.n_a[a]) n_a_t_1[a, max(self.e_a[a][0], 0): min(self.field[0], self.field[0] + self.e_a[a][0]), max(self.e_a[a][1], 0): min(self.field[1], self.field[1] + self.e_a[a][1]), max(self.e_a[a][2], 0): min(self.field[2], self.field[2] + self.e_a[a][2])] += temp[ max(-self.e_a[a][0], 0): min( self.field[0], self.field[0] - self.e_a[a][0]), max(-self.e_a[a][1], 0): min( self.field[1], self.field[1] - self.e_a[a][1]), max(-self.e_a[a][2], 0): min( self.field[2], self.field[2] - self.e_a[a][2])] for index in range(len(self.e_a[a])): if self.e_a[a][index] != 0: e_a_clipped = -np.array(self.e_a[a]) # e_a_clipped[index] = 0 # e_a_clipped[index] = -self.e_a[a][index] clipped_dir = np.zeros(3) clipped_dir[index] = self.e_a[a][index] e_a_index = np.where(np.all(self.e_a == e_a_clipped, axis=1))[0][0] # e_a_index = 0 if index == 0: if self.e_a[a][index] > 0: slice_index = -1 else: slice_index = 0 n_a_t_1[e_a_index, slice_index, :, :] += temp[slice_index, :, :] temp[slice_index, :, :] *= 0 if index == 1: if self.e_a[a][index] > 0: slice_index = -1 else: slice_index = 0 n_a_t_1[e_a_index, :, slice_index, :] += temp[:, slice_index, :] temp[:, slice_index, :] *= 0 if index == 2: if self.e_a[a][index] > 0: slice_index = -1 else: slice_index = 0 n_a_t_1[e_a_index, :, :, slice_index] += temp[:, :, slice_index] temp[:, :, slice_index] *= 0 self.n_a = n_a_t_1 if np.min(self.n_a) < 0: test = 1 self.n_a = np.maximum(0, self.n_a) self.n_a = old_n_sum * self.n_a / np.sum(self.n_a) self.n = np.sum(self.n_a, axis=0, keepdims=False) # self.n = np.sum(np.abs(n_a_t_1), axis=0, keepdims=False) # stabilise the number because of rounding errors self.n = old_n_sum * self.n / np.sum(self.n) self.u *= 0 for a in range(len(self.e_a)): self.u[:, :, :, 0] += self.n_a[a] * self.e_a[a][0] self.u[:, :, :, 1] += self.n_a[a] * self.e_a[a][1] self.u[:, :, :, 2] += self.n_a[a] * self.e_a[a][2] self.u[:, :, :, 0] /= self.n self.u[:, :, :, 1] /= self.n self.u[:, :, :, 2] /= self.n self.u[self.n == 0] = 0 length = np.sqrt(np.sum(np.square(self.u), axis=3, keepdims=True)) # gravity gravity_applies = self.n < self.w_a[0] gravity_applies[:, :-1, :] = gravity_applies[:, 1:, :] gravity_applies[:, -1, :] = False self.u[gravity_applies, 1] -= 0.01 new_lengths = np.sqrt(np.sum(np.square(self.u), axis=3, keepdims=True)) self.u = self.u / new_lengths * length zero_length = (new_lengths == 0) self.u[zero_length[:, :, :, 0], :] = 0 u = self.u[int(self.test_pixel[0]), int(self.test_pixel[1]), int(self.test_pixel[2])] self.test_pixel[0] = max(0, min(self.field[0] - 1, self.test_pixel[0] + u[0])) self.test_pixel[1] = max(0, min(self.field[1] - 1, self.test_pixel[1] + u[1])) self.test_pixel[2] = max(0, min(self.field[2] - 1, self.test_pixel[2] + u[2])) # print(1.0 / (time.time() - self.time)) self.time = time.time() glutPostRedisplay() def resize(self, w, h): w = max(w, 1) h = max(h, 1) glViewport(0, 0, w, h) self.projMatrix = perspectiveMatrix(45.0, float(w) / float(h), 0.01, MAX_DISTANCE) self.width = w self.height = h def keyboardHandler(self, key: int, x: int, y: int): if key == b'\x1b': exit() if key == b'+': self.rx += 0.25 if key == b'-': self.rx -= 0.25 if key == b'w': self.cy += 0.25 if key == b's': self.cy -= 0.25 if key == b'a': self.cx -= 0.25 if key == b'd': self.cx += 0.25 if key == b'q': self.opening -= 0.25 if key == b'e': self.opening += 0.25 if key == b'r': print(self.cx, self.cy, self.opening) # glutPostRedisplay() # print(key,x,y) def funcKeydHandler(self, key: int, x: int, y: int): if key == 11: glutFullScreenToggle() # print(key) if __name__ == '__main__': client = Client(pos=[-50, -50, -200])