VoxelEngine/Client/Client.py
2020-11-08 10:20:23 +01:00

387 lines
18 KiB
Python

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])