尝试 gl backend

This commit is contained in:
bk_office
2026-04-25 14:31:23 +08:00
parent 81e0c05686
commit cc97ca5493
10 changed files with 291 additions and 15 deletions

View File

@ -18,8 +18,8 @@ from dataclasses import dataclass
import re
import numpy as np
from dataclasses import dataclass
from konabot.plugins.marchtoy.obj import Object, Camera, OBJECT_ENTRIES
from konabot.plugins.marchtoy.op import OPERATION_ENTRIES
from obj import Object, Camera, OBJECT_ENTRIES
from op import OPERATION_ENTRIES
from typing import Optional
@dataclass
@ -113,8 +113,8 @@ class Scene:
def __str__(self) -> str:
return ", ".join([str(type(obj)) for obj in self.canvas_objs])
def compile(self) -> str:
PATH = pathlib.Path(__file__).parent / "shaders" / "raymarch.sksl"
def compile(self, fs_src: str = "frag.glsl") -> str:
PATH = pathlib.Path(__file__).parent / "shaders" / fs_src
with PATH.open(encoding="utf-8") as f:
content = f.read()
sdf_block: str = ""

View File

@ -0,0 +1,37 @@
"""
headless moderngl
"""
import pathlib
import moderngl
from command import Scene
import numpy as np
from PIL import Image
def render(vs: str, fs: str, res: tuple[int, int]):
ctx = moderngl.create_context(standalone=True)
try:
program = ctx.program(
vertex_shader=vs,
fragment_shader=fs
)
except Exception as _:
raise Exception("cannot compile glsl")
uniform = program['u_resolution']
uniform.write(np.array(res, dtype=np.float32))
vertices = np.array([-1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0], dtype=np.float32)
indices = np.array([0, 1, 2, 1, 2, 3], dtype=np.int32)
ibo = ctx.buffer(indices)
vbo = ctx.buffer(vertices)
vao = ctx.vertex_array(program, vbo, 'in_position', index_buffer = ibo)
fbo = ctx.simple_framebuffer(res)
fbo.use()
fbo.clear(0.0, 0.0, 0.0, 0.0)
vao.render(moderngl.TRIANGLES)
Image.frombytes('RGB', fbo.size, fbo.read(), 'raw', 'RGB', 0, -1).show()
fs = Scene("cube camera.pos(1).lookat(0)").compile()
PATH = pathlib.Path(__file__).parent / "shaders"
with (PATH / "vert.glsl").open(encoding='utf-8') as f:
vs = f.read()
render(vs, fs, (320, 320))

View File

@ -1,6 +1,6 @@
import numpy as np
from konabot.plugins.marchtoy.texture import Texture
from konabot.plugins.marchtoy.utilities import ArgParser, SkslFormatter
from texture import Texture
from utilities import ArgParser, Formatter
OBJECT_ENTRIES = {}
@ -65,7 +65,6 @@ class Transform:
zaxis = Transform.normalize(q - p)
xaxis = Transform.normalize(np.cross(zaxis, up))
yaxis = Transform.normalize(np.cross(xaxis, zaxis))
# 约定本地 -Z 为“朝前”,这样和 shader 中使用的相机射线方向保持一致。
self.t[:3, 0] = xaxis
self.t[:3, 1] = yaxis
self.t[:3, 2] = -zaxis
@ -73,7 +72,7 @@ class Transform:
def p_expr(self) -> str:
inv = np.linalg.inv(self.t) # + 1e-5 * np.identity(4, dtype=np.float32))
return f"({SkslFormatter.mat4(inv)} * float4(p, 1.0)).xyz"
return f"({Formatter.float4(inv)} * float4(p, 1.0)).xyz"
class Object:

View File

@ -1,6 +1,6 @@
from konabot.plugins.marchtoy.obj import Object
from obj import Object
import numpy as np
from konabot.plugins.marchtoy.utilities import ArgParser
from utilities import ArgParser
OPERATION_ENTRIES = {}

View File

@ -1,4 +1,4 @@
from konabot.plugins.marchtoy.command import Scene
from command import Scene
import skia
import struct
from PIL import Image

View File

@ -0,0 +1,83 @@
#version 330
uniform vec2 u_resolution;
// compatibility
#define float4x4 mat4x4
#define float4 vec4
#define float3 vec3
#define float2 vec2
const float EPS = 0.001;
const int MAX_ITER = 64;
in vec2 fragCoord;
out vec4 fragColor;
struct sdQuery {
float value;
int obj_id;
};
float sdCube(vec3 p, vec3 b) {
p = abs(p) - b;
return length(max(p, 0.0)) + min(max(p.x, max(p.y, p.z)), 0.0);
}
float sdSphere(vec3 p, float r) {
return length(p) - r;
}
sdQuery sd(vec3 p) {
sdQuery qry;
qry.value = 100000000.0;
qry.obj_id = -1;
<SDF_BLOCK>
return qry;
}
vec3 nrm(vec3 p) {
vec2 d = vec2(EPS, 0.0);
return normalize(vec3(
sd(p + d.xyy).value - sd(p - d.xyy).value,
sd(p + d.yxy).value - sd(p - d.yxy).value,
sd(p + d.yyx).value - sd(p - d.yyx).value
));
}
vec4 materialColor(int obj_id) {
<COLOR_BLOCK>
return vec4(1.0);
}
vec4 color(vec3 p, int obj_id) {
vec3 normal = nrm(p);
vec3 light_dir = normalize(vec3(0.5, 0.8, -0.6));
float light = 0.2 + 0.8 * max(dot(normal, light_dir), 0.0);
vec4 base = materialColor(obj_id);
return vec4(base.rgb * light, base.a);
}
vec4 march(vec3 p, vec3 r) {
sdQuery qry;
vec4 col = vec4(0.0);
for(int i = 0; i < MAX_ITER; ++i) {
qry = sd(p);
if(qry.value < EPS){
col = color(p, qry.obj_id);
break;
}
p += qry.value * r;
}
return col;
}
void main() {
vec2 uv = -2. * (fragCoord / u_resolution - .5) * vec2(u_resolution.x / u_resolution.y, 1.);
vec3 c_p = vec3(<CAM_POS>);
vec3 c_z = normalize(vec3(<CAM_DIR>));
vec3 world_up = abs(c_z.y) > 0.999 ? vec3(0., 0., 1.) : vec3(0., 1., 0.);
vec3 c_x = normalize(cross(c_z, world_up));
vec3 c_y = normalize(cross(c_x, c_z));
mat3 view = mat3(c_x, c_y, c_z);
vec3 r = normalize(vec3(uv, <CAM_FOCUS>));
fragColor = march(c_p, view * r);
}

View File

@ -0,0 +1,7 @@
#version 330
in vec2 in_position;
out vec2 fragCoord;
void main() {
gl_Position = vec4(in_position, 0.0, 1.0);
}

View File

@ -1,10 +1,10 @@
import numpy as np
from konabot.plugins.marchtoy.texture import COLORS
from texture import COLORS
class SkslFormatter:
class Formatter:
@staticmethod
def mat4(m: np.ndarray) -> str:
def float4(m: np.ndarray) -> str:
if m.shape != (4, 4):
m = np.identity(4)
v_0 = ", ".join([str(x) for x in m[0]])