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 = 0.9 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.heat_map = np.zeros((100, 100, 1)) self.v_map_x = np.zeros((100, 100, 1)) self.v_map_y = np.zeros((100, 100, 1)) self.v_map_z = np.zeros((100, 100, 1)) 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() max_value = np.max(self.heat_map) # min_value = np.min(self.heat_map) min_value = 0 vel = np.sqrt(np.square(self.v_map_x) + np.square(self.v_map_y) + np.square(self.v_map_z)) max_value = np.max(vel) min_value = np.min(vel) 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.heat_map[x_pos, y_pos, z_pos], min_value, max_value) r, g, b = value_to_color(vel[x_pos, y_pos, z_pos], min_value, max_value) self.world_provider.world.set_color(x_pos, y_pos, z_pos, r, g, b) # friction # self.heat_map += np.sqrt(np.square(self.v_map_x * (1.0 - FRICTION_COEFFICENT)) + # np.square(self.v_map_y * (1.0 - FRICTION_COEFFICENT)) + # np.square(self.v_map_z * (1.0 - FRICTION_COEFFICENT))) self.v_map_x *= FRICTION_COEFFICENT self.v_map_y *= FRICTION_COEFFICENT self.v_map_z *= FRICTION_COEFFICENT # hot stuff rises / cool stuff sinks rise = self.heat_map[:, :-1, :] > (self.heat_map[:, 1:, :] + EPSILON) self.v_map_y[:, :-1, :] += 1.0 * rise sink = self.heat_map[:, :-1, :] < (self.heat_map[:, 1:, :] - EPSILON) self.v_map_y[:, 1:, :] -= 1.0 * sink #flow new_v_map_x = np.zeros(self.v_map_x.shape) new_v_map_y = np.zeros(self.v_map_x.shape) new_v_map_z = np.zeros(self.v_map_x.shape) for x_pos in range(self.v_map_x.shape[0]): for y_pos in range(self.v_map_x.shape[1]): for z_pos in range(self.v_map_x.shape[2]): target_x = min(self.v_map_x.shape[0] - 1, max(0, int(round(x_pos + self.v_map_x[x_pos, y_pos, z_pos])))) target_y = min(self.v_map_x.shape[1] - 1, max(0, int(round(y_pos + self.v_map_y[x_pos, y_pos, z_pos])))) target_z = min(self.v_map_x.shape[2] - 1, max(0, int(round(z_pos + self.v_map_z[x_pos, y_pos, z_pos])))) friction_dispersion = (1.0 -FRICTION_COEFFICENT) / 4 # velocity dispersion # x new_v_map_x[target_x, target_y, target_z] += self.v_map_x[x_pos, y_pos, z_pos] * FRICTION_COEFFICENT if target_y + 1 < self.v_map_x.shape[1] - 1: new_v_map_y[target_x, target_y + 1, target_z] += self.v_map_x[x_pos, y_pos, z_pos] * friction_dispersion else: new_v_map_x[target_x, target_y, target_z] += self.v_map_x[x_pos, y_pos, z_pos] * friction_dispersion if target_y - 1 > 0: new_v_map_y[target_x, target_y - 1, target_z] -= self.v_map_x[x_pos, y_pos, z_pos] * friction_dispersion else: new_v_map_x[target_x, target_y, target_z] += self.v_map_x[x_pos, y_pos, z_pos] * friction_dispersion if target_z + 1 < self.v_map_x.shape[2] - 1: new_v_map_z[target_x, target_y, target_z + 1] += self.v_map_x[x_pos, y_pos, z_pos] * friction_dispersion else: new_v_map_x[target_x, target_y, target_z] += self.v_map_x[x_pos, y_pos, z_pos] * friction_dispersion if target_z - 1 > 0: new_v_map_z[target_x, target_y, target_z - 1] -= self.v_map_x[x_pos, y_pos, z_pos] * friction_dispersion else: new_v_map_x[target_x, target_y, target_z] += self.v_map_x[x_pos, y_pos, z_pos] * friction_dispersion # y new_v_map_y[target_x, target_y, target_z] += self.v_map_y[x_pos, y_pos, z_pos] * FRICTION_COEFFICENT if target_x + 1 < self.v_map_x.shape[0] - 1: new_v_map_x[target_x + 1, target_y, target_z] += self.v_map_y[x_pos, y_pos, z_pos] * friction_dispersion else: new_v_map_y[target_x, target_y, target_z] += self.v_map_y[x_pos, y_pos, z_pos] * friction_dispersion if target_x - 1 > 0: new_v_map_x[target_x - 1, target_y, target_z] -= self.v_map_y[x_pos, y_pos, z_pos] * friction_dispersion else: new_v_map_y[target_x, target_y, target_z] += self.v_map_y[x_pos, y_pos, z_pos] * friction_dispersion if target_z + 1 < self.v_map_x.shape[2] - 1: new_v_map_z[target_x, target_y, target_z + 1] += self.v_map_y[x_pos, y_pos, z_pos] * friction_dispersion else: new_v_map_y[target_x, target_y, target_z] += self.v_map_y[x_pos, y_pos, z_pos] * friction_dispersion if target_z - 1 > 0: new_v_map_z[target_x, target_y, target_z - 1] -= self.v_map_y[x_pos, y_pos, z_pos] * friction_dispersion else: new_v_map_y[target_x, target_y, target_z] += self.v_map_y[x_pos, y_pos, z_pos] * friction_dispersion # z new_v_map_z[target_x, target_y, target_z] += self.v_map_z[x_pos, y_pos, z_pos] * FRICTION_COEFFICENT if target_x + 1 < self.v_map_x.shape[0] - 1: new_v_map_x[target_x + 1, target_y, target_z] += self.v_map_z[x_pos, y_pos, z_pos] * friction_dispersion else: new_v_map_z[target_x, target_y, target_z] += self.v_map_z[x_pos, y_pos, z_pos] * friction_dispersion if target_x - 1 > 0: new_v_map_x[target_x - 1, target_y, target_z] -= self.v_map_z[x_pos, y_pos, z_pos] * friction_dispersion else: new_v_map_z[target_x, target_y, target_z] += self.v_map_z[x_pos, y_pos, z_pos] * friction_dispersion if target_y + 1 < self.v_map_x.shape[1] - 1: new_v_map_y[target_x, target_y + 1, target_z] += self.v_map_z[x_pos, y_pos, z_pos] * friction_dispersion else: new_v_map_z[target_x, target_y, target_z] += self.v_map_z[x_pos, y_pos, z_pos] * friction_dispersion if target_y - 1 > 0: new_v_map_y[target_x, target_y - 1, target_z] -= self.v_map_z[x_pos, y_pos, z_pos] * friction_dispersion else: new_v_map_z[target_x, target_y, target_z] += self.v_map_z[x_pos, y_pos, z_pos] * friction_dispersion # handle boundaries filter_mat = np.array([[-1.0], [0], [1.0]]) / 2.0 new_v_map_y[0, :, :] += convolve(new_v_map_x[0, :, :], filter_mat, 'same') new_v_map_x[0, :, :] = 0 new_v_map_y[new_v_map_x.shape[0] - 1, :, :] +=\ convolve(new_v_map_x[new_v_map_x.shape[0] - 1, :, :], filter_mat, 'same') new_v_map_x[new_v_map_x.shape[0] - 1, :, :] = 0 filter_mat = np.array([[-1.0], [0], [1.0]]) / 2.0 new_v_map_x[:, 0, :] += convolve(new_v_map_y[:, 0, :], filter_mat, 'same') new_v_map_y[:, 0, :] = 0 new_v_map_x[:, new_v_map_x.shape[1] - 1, :] +=\ convolve(new_v_map_y[:, new_v_map_x.shape[1] - 1, :], filter_mat, 'same') new_v_map_y[:, new_v_map_x.shape[1] - 1, :] = 0 # corners new_v_map_x[0, 0, 0] = new_v_map_y[0, 0, 0] = new_v_map_z[0, 0, 0] = 0 new_v_map_x[-1, 0, 0] = new_v_map_y[-1, 0, 0] = new_v_map_z[-1, 0, 0] = 0 new_v_map_x[-1, -1, 0] = new_v_map_y[-1, -1, 0] = new_v_map_z[-1, -1, 0] = 0 new_v_map_x[-1, -1, -1] = new_v_map_y[-1, -1, -1] = new_v_map_z[-1, -1, -1] = 0 new_v_map_x[0, -1, -1] = new_v_map_y[0, -1, -1] = new_v_map_z[0, -1, -1] = 0 new_v_map_x[0, -1, 0] = new_v_map_y[0, -1, 0] = new_v_map_z[0, -1, 0] = 0 new_v_map_x[-1, -1, 0] = new_v_map_y[-1, -1, 0] = new_v_map_z[-1, -1, 0] = 0 new_v_map_x[-1, 0, -1] = new_v_map_y[-1, 0, -1] = new_v_map_z[-1, 0, -1] = 0 self.v_map_x = new_v_map_x self.v_map_y = new_v_map_y self.v_map_z = new_v_map_z filter_mat = (np.zeros((3, 3, 1)) + 1.0) / 9.0 v_map = np.pad(self.v_map_x, 1, 'edge') self.v_map_x = convolve(v_map, filter_mat, mode='same')[1:-1, 1:-1, 1:2] v_map = np.pad(self.v_map_y, 1, 'edge') self.v_map_y = convolve(v_map, filter_mat, mode='same')[1:-1, 1:-1, 1:2] v_map = np.pad(self.v_map_z, 1, 'edge') self.v_map_z = convolve(v_map, filter_mat, mode='same')[1:-1, 1:-1, 1:2] # moving heat heat_map = np.zeros(self.heat_map.shape) for x_pos in range(self.v_map_x.shape[0]): for y_pos in range(self.v_map_x.shape[1]): for z_pos in range(self.v_map_x.shape[2]): target_x = min(self.v_map_x.shape[0] - 1, max(0, int(round(x_pos + self.v_map_x[x_pos, y_pos, z_pos])))) target_y = min(self.v_map_x.shape[1] - 1, max(0, int(round(y_pos + self.v_map_y[x_pos, y_pos, z_pos])))) target_z = min(self.v_map_x.shape[2] - 1, max(0, int(round(z_pos + self.v_map_z[x_pos, y_pos, z_pos])))) heat_map[target_x, target_y, target_z] += self.heat_map[x_pos, y_pos, z_pos] self.heat_map = heat_map # dispersing heat heat_map = np.pad(self.heat_map, 1, 'edge') self.heat_map = convolve(heat_map, filter_mat, mode='same')[1:-1, 1:-1, 1:2] # heat source keeps source block on constant heat self.heat_map[50-5:50+5, 0, 0] = 100.0 # roof gets cooled off to min temp self.heat_map[:, 99, :] = np.maximum(self.heat_map[:, 99, :] * 0.8, 0.0) 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])