VoxelEngine/Client/Client.py
2020-11-30 19:15:08 +01:00

394 lines
16 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 = 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])