This commit is contained in:
Crizomb 2022-08-19 19:28:22 +02:00 committed by GitHub
commit 541c8cb42e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 1410 additions and 0 deletions

Binary file not shown.

Binary file not shown.

60
mandelbulb/camera.py Normal file
View file

@ -0,0 +1,60 @@
from dataclasses import dataclass
from tools import *
import numpy as np
class Camera:
def __init__(self, r1 : np.array, phi : float, theta : float):
assert r1.shape == (3,)
self.r1 = r1
self.r1_temp = 0, 0, 0
self.camThetaBase = 0
self.camPhiBase = 0
self.camTheta = theta
self.camPhi = phi
r1_temp = self.rotateCam()
self.camMat = self.getCam(r1_temp)
def getCam(self, r1):
camF = normalize(r1)
camR = normalize(cross(vec3(0, 1, 0), camF))
camU = cross(camF, camR)
mat_ = mat3(camR, camU, camF)
return mat_
def rotateCam(self):
yz = vec2(self.r1[1], self.r1[2])
new_yz = pR(yz, self.camTheta + self.camThetaBase)
xz = vec2(self.r1[0], new_yz[1])
new_xz = pR(xz, self.camPhi + self.camPhiBase)
vec = vec3(new_xz[0], new_yz[0], new_xz[1])
return vec
@staticmethod
def mouseToAngle(u_mouse, u_resolution):
m = (u_mouse - u_resolution / 2) / u_resolution
return m
def update(self):
self.r1_temp = self.rotateCam()
self.camMat = self.getCam(self.r1_temp)

1
mandelbulb/controls.py Normal file
View file

@ -0,0 +1 @@

109
mandelbulb/main.py Normal file
View file

@ -0,0 +1,109 @@
import moderngl_window as mglw
from tools import *
from camera import Camera
from time import sleep
print(__name__)
class App(mglw.WindowConfig):
window_size = 1600, 900
ro = 0, -0.5, -1.5
ro = mult_ext_tuples(1, ro)
rc = 0, -1, 2
u_mouse = 0, 0
forward = False
backward = False
resource_dir = 'resources/programs'
cam = Camera(vec3(*rc), 0, 0)
mouse_pressed = False
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.quad = mglw.geometry.quad_fs()
self.program = self.load_program(vertex_shader='vertex.glsl', fragment_shader='fragment.glsl')
# uniforms
self.set_uniform('u_resolution', self.window_size)
self.set_uniform('ro', self.ro)
self.set_uniform('rc', self.rc)
#self.set_uniform('u_mouse', self.u_mouse)
self.set_uniform('cam', mat3ToTuple(np.eye(3)))
def set_uniform(self, u_name, u_value):
try:
self.program[u_name] = u_value
except KeyError:
None
print(f'{u_name} not used in shader')
def moove(self):
x, y, z = tuple(self.cam.r1_temp)
x = -x
y = -y
if self.forward:
self.ro = add_tuples(self.ro, mult_ext_tuples(0.1, (x, y, z)))
if self.backward:
self.ro = add_tuples(self.ro, mult_ext_tuples(-0.1, (x, y, z)))
def cam_render(self):
angles = self.cam.mouseToAngle(vec2(*self.u_mouse), vec2(*self.window_size))
self.cam.camPhi, self.cam.camTheta = -angles[0]*4, angles[1]*2
self.cam.update()
def render(self, time, frame_time):
self.ctx.clear()
#self.program['u_time'] = time
self.quad.render(self.program)
self.set_uniform('cam', mat3ToTuple(self.cam.camMat))
if self.mouse_pressed:
self.cam_render()
if self.forward or self.backward:
self.moove()
self.set_uniform('ro', self.ro)
sleep(0)
def mouse_drag_event(self, x: int, y: int, dx: int, dy: int):
self.u_mouse = x, y
self.mouse_pressed = True
def mouse_release_event(self, x: int, y: int, button: int):
self.mouse_pressed = False
self.cam.camThetaBase += self.cam.camTheta
self.cam.camPhiBase += self.cam.camPhi
def key_event(self, key, action, modifiers):
match key:
case self.wnd.keys.UP:
if action == self.wnd.keys.ACTION_PRESS:
self.forward = True
elif action == self.wnd.keys.ACTION_RELEASE:
self.forward = False
case self.wnd.keys.DOWN:
if action == self.wnd.keys.ACTION_PRESS:
self.backward = True
elif action == self.wnd.keys.ACTION_RELEASE:
self.backward = False
if __name__ == '__main__':
mglw.run_window_config(App)

View file

@ -0,0 +1,175 @@
#version 330 core
#include hg_sdf.glsl
layout (location = 0) out vec4 fragColor;
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
uniform vec3 ro;
uniform mat3 cam;
const float FOV = 2;
const int MAX_STEPS = 256;
const float MAX_DIST = 500;
const float EPSILON = 0.0005;
const float DIST_CAM = 2;
float packColor(vec3 color) {
return color.r + color.g * 256.0 + color.b * 256.0 * 256.0;
}
vec3 unpackColor(float f) {
vec3 color;
color.b = floor(f / 256.0 / 256.0);
color.g = floor((f - color.b * 256.0 * 256.0) / 256.0);
color.r = floor(f - color.b * 256.0 * 256.0 - color.g * 256.0);
// now we have a vec3 with the 3 components in range [0..255]. Let's normalize it!
return color / 255.0;
}
vec3 fOpUnionChamferId(vec3 res1, vec3 res2, float r) {
float a = res1.x;
float b = res2.x;
return vec3(min(min(a, b), (a - r + b)*sqrt(0.5)), res1.yz);
}
vec3 fOpDifferenceId(vec3 res1, vec3 res2) {
return (res1.x > -res2.x) ? res1 : vec3(-res2.x, res2.yz);
}
vec3 fOpUnionId(in vec3 res1, in vec3 res2){
return (res1.x < res2.x) ? res1 : res2;
}
vec3 map(in vec3 p){
//pMod3(p, vec3(10.0));
float planeId = 1;
float planeColor = packColor(vec3(50, 50, 50));
float planeDist = fPlane(p, vec3(0, 1, 0), 1.0);
vec3 plane = vec3(planeDist, planeColor, planeId);
float sphereId = 2;
float sphereColor = packColor(vec3(200, 0, 0));
vec3 spherePos = vec3(2.0, 0.0, 0.0);
float sphereDist = fSphere(p-spherePos, 1);
vec3 sphere = vec3(sphereDist, sphereColor, sphereId);
float playerId = 3;
float playerColor = packColor(vec3(0, 200, 0));;
vec3 playerPos = ro+vec3(0, -1, DIST_CAM);
float playerDist = fCapsule(p-playerPos, 0.2, 0.2);
vec3 player = vec3(playerDist, playerColor, playerId);
float mandelBulbId = 3;
float mandelBulbColor = packColor(vec3(50, 50, 50));;
float mandelBulbDist = fmandelBulbe(p);;
vec3 mandelBulb = vec3(mandelBulbDist, mandelBulbColor, mandelBulbId);;
//vec3 res = fOpUnionId(plane, sphere);
vec3 res = mandelBulb;
//res = fOpUnionId(res, mandelBulb);
return res;
}
vec4 rayMarch(vec3 ro, vec3 rd) {
vec3 hit = vec3(0.0);
vec3 object = vec3(0.0);
vec3 p = vec3(0.0);
float compt = 0;
for (float i = 0; i < MAX_STEPS; i++) {
p = ro + object.x * rd;
hit = map(p);
object.x += hit.x;
object.yz = hit.yz;
if (hit.z == 2 || hit.z == 3) compt += 1;
if (abs(hit.x) < EPSILON || object.x > MAX_DIST){
if (hit.z != 2) return vec4(object, compt);
return vec4(object, 0);
}
}
return vec4(object, compt);
}
vec3 getNormal(vec3 p) {
vec2 e = vec2(EPSILON, 0.0);
vec3 n = vec3(map(p).x) - vec3(map(p - e.xyy).x, map(p - e.yxy).x, map(p - e.yyx).x);
return normalize(n);
}
vec3 getLight(vec3 p, vec3 rd, vec3 color) {
vec3 lightPos = vec3(10.0, 55.0, -20.0);
vec3 L = normalize(lightPos - p);
vec3 N = getNormal(p);
vec3 V = -rd;
vec3 R = reflect(-L, N);
vec3 specColor = vec3(0.5);
vec3 specular = specColor * pow(clamp(dot(R, V), 0.0, 1.0), 10.0);
vec3 diffuse = color * clamp(dot(L, N), 0.0, 1.0);
vec3 ambient = color * 0.05;
vec3 fresnel = 0.25 * color * pow(1.0 + dot(rd, N), 3.0);
// shadows
float d = rayMarch(p + N * 0.02, normalize(lightPos)).x;
if (d < length(lightPos - p)) return ambient + fresnel;
return diffuse + ambient + specular + fresnel;
}
vec3 getMaterial(vec3 p, float color_pack, float id) {
vec3 m = vec3(0.0);
vec3 color = unpackColor(color_pack);
switch (int(id)) {
case 1:
m = vec3(0.2 + 0.4 * mod(floor(p.x) + floor(p.z), 2.0)); break;
}
return color+m;
return color;
}
void render(inout vec3 col, in vec3 ro, in mat3 cam, in vec2 uv) {
vec3 r1 = vec3(0, 0, 1);
vec3 lookAt = ro + r1;
vec3 rd = cam*normalize(vec3(uv, FOV));
vec4 result = rayMarch(ro, rd);
vec3 object = result.xyz;
vec3 glowing_color = vec3(0.5, 0, 0);
float nb_itter = result.w;
vec3 background = vec3(0, 0, 0);
if (object.x < MAX_DIST) {
vec3 p = ro + object.x * rd;
vec3 material = getMaterial(p, object.y, object.z);
col += getLight(p, rd, material);
// fog
col = mix(col, background, 1.0 - exp(-0.00002 * object.x * object.x));
} else {
// col += background - max(0.9 * rd.y, 0.0);
col = col;
}
float glow_fact = smoothstep(0, MAX_STEPS, nb_itter);
col += glowing_color*glow_fact;
}
void main() {
vec2 uv = (2.0 * gl_FragCoord.xy - u_resolution.xy) / u_resolution.y;
vec3 col;
render(col, ro, cam, uv);
// gamma correction
col = pow(col, vec3(0.4545));
fragColor = vec4(col, 1.0);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,8 @@
#version 440 core
in vec3 in_position;
void main() {
gl_Position = vec4(in_position, 1);
}

View file

View file

View file

5
mandelbulb/test.py Normal file
View file

@ -0,0 +1,5 @@
import numpy as np
import tools
m = np.array(((1, 2, 3), (4, 5, 6), (7, 8, 9)))
print(tools.mat3ToTuple(m))

48
mandelbulb/tools.py Normal file
View file

@ -0,0 +1,48 @@
import numpy as np
from numpy import cos, sin, tan, exp
from numpy.linalg import norm, det
from numpy import cross
import numba
from dataclasses import dataclass
PI = np.pi
TAU = 2*np.pi
def vec2(x, y, dtype=float):
return np.array((x, y), dtype=dtype)
def vec3(x, y, z, dtype=float):
return np.array((x, y, z), dtype=dtype)
def mat3(a : np.array, b : np.array, c : np.array):
return np.array((a, b, c)).T
def mat3ToTuple(m):
return m[0, 0], m[0, 1], m[0, 2], m[1, 0], m[1, 1], m[1, 2], m[2, 0], m[2, 1], m[2, 2]
#return m[0, 0], m[1, 0], m[2, 0], m[0, 1], m[1, 1], m[2, 1], m[0, 2], m[1, 2], m[2, 2]
def getRot2D(theta):
return np.array( [( cos(theta), -sin(theta) ), (sin(theta), cos(theta))] )
def pR(p, a):
return cos(a)*p + sin(a)*vec2(p[1], -p[0])
def add_tuples(t1, t2):
assert len(t1) == len(t2)
temp = [0]*len(t1)
for i in range(len(t1)):
temp[i] += t1[i] + t2[i]
return tuple(temp)
def mult_ext_tuples(a, t1):
return tuple([a*t for t in t1])
def normalize(vec):
return vec/norm(vec)