column major

This commit is contained in:
bk_office
2026-04-25 14:58:50 +08:00
parent facd2d0e84
commit 3f3a375dd6
9 changed files with 65 additions and 45 deletions

View File

@ -2,7 +2,7 @@ from nonebot import on_command
from nonebot.adapters import Message
from nonebot_plugin_alconna import UniMessage
from nonebot.params import CommandArg
import render
import konabot.plugins.marchtoy.gl_render as render
import io
cmd_marchtoy = on_command("march", priority=10, block=True)
@cmd_marchtoy.handle()

View File

@ -18,9 +18,9 @@ from dataclasses import dataclass
import re
import numpy as np
from dataclasses import dataclass
from obj import Object, Camera, OBJECT_ENTRIES
from op import OPERATION_ENTRIES
from typing import Optional
from konabot.plugins.marchtoy.obj import Object, Camera, OBJECT_ENTRIES
from konabot.plugins.marchtoy.op import OPERATION_ENTRIES
@dataclass
class Command:

View File

@ -3,11 +3,14 @@ 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]):
from konabot.plugins.marchtoy.command import Scene
async def render(instruction: str, res: tuple[int, int]):
fs = Scene(instruction).compile()
PATH = pathlib.Path(__file__).parent / "shaders"
with (PATH / "vert.glsl").open(encoding='utf-8') as f:
vs = f.read()
ctx = moderngl.create_context(standalone=True)
try:
program = ctx.program(
@ -27,11 +30,4 @@ def render(vs: str, fs: str, res: tuple[int, int]):
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(0.5).pos(1) 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))
return Image.frombytes('RGBA', fbo.size, fbo.read(components=4), 'raw', 'RGBA', 0, -1)

View File

@ -1,14 +1,14 @@
import numpy as np
from texture import Texture
from utilities import ArgParser, Formatter
from konabot.plugins.marchtoy.texture import Texture
from konabot.plugins.marchtoy.utilities import ArgParser, Formatter
OBJECT_ENTRIES = {}
def make_obj(name: str, aliases: list[str] = []):
def make_obj(*name: str):
def decorator(cls):
OBJECT_ENTRIES[name] = cls
for alias in aliases:
# OBJECT_ENTRIES[name] = cls
for alias in [*name]:
OBJECT_ENTRIES[alias] = cls
return cls
@ -29,7 +29,7 @@ class Transform:
self.t = mat @ self.t
return self
# scale 会破坏 sdf 的性质,不应该使用
# scale 会破坏 sdf 的性质 梯度大小会变 导致 overshoot 等问题
def scale(self, x: float, y: float, z: float):
mat = np.identity(4, dtype=np.float32)
mat[0, 0], mat[1, 1], mat[2, 2] = x, y, z
@ -72,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"({Formatter.float4(inv)} * float4(p, 1.0)).xyz"
return f"({Formatter.float4(inv)} * vec4(p, 1.0)).xyz"
class Object:
@ -87,7 +87,7 @@ class Object:
raise NotImplementedError
@make_obj("cube")
@make_obj("cube", "box")
class Cube(Object):
def __init__(self, _size: np.ndarray = np.array([1.0, 1.0, 1.0])) -> None:
super().__init__()
@ -97,10 +97,10 @@ class Cube(Object):
self.size = ArgParser.as_vec3(args)
def sdf_block(self) -> str:
return f"sdCube({self.transform.p_expr()}, float3({self.size[0]}, {self.size[1]}, {self.size[2]}))"
return f"sdCube({self.transform.p_expr()}, vec3({self.size[0]}, {self.size[1]}, {self.size[2]}))"
@make_obj("sphere")
@make_obj("sphere", "ball")
class Sphere(Object):
def __init__(self, _radius: float = 1.0) -> None:
super().__init__()
@ -113,7 +113,7 @@ class Sphere(Object):
return f"sdSphere({self.transform.p_expr()}, {self.radius})"
@make_obj("camera", ["cam"])
@make_obj("camera", "cam")
class Camera(Object):
def __init__(self, _focus: float = 1.0) -> None:
super().__init__()

View File

@ -1,39 +1,37 @@
from obj import Object
import numpy as np
from utilities import ArgParser
from konabot.plugins.marchtoy.obj import Object
from konabot.plugins.marchtoy.utilities import ArgParser
OPERATION_ENTRIES = {}
def make_operation(name: str, aliases: list[str] = []):
def make_operation(*name: str):
def decorator(op):
OPERATION_ENTRIES[name] = op
for alias in aliases:
# OPERATION_ENTRIES[name] = op
for alias in [*name]:
OPERATION_ENTRIES[alias] = op
return op
return decorator
@make_operation("pos", ["translate", "position", "p"])
@make_operation("pos", "translate", "position", "p")
def translate(obj: Object, args: list[str]):
pos = ArgParser.as_vec3(args)
obj.transform.translate(pos[0], pos[1], pos[2])
@make_operation("rot", ["rotate", "r"])
@make_operation("rot", "rotate", "r")
def rotate(obj: Object, args: list[str]):
pos = ArgParser.as_vec3(args)
obj.transform.rotate(pos[0], pos[1], pos[2])
@make_operation("lookat", ["look", "l"])
@make_operation("lookat", "look", "l")
def lookat(obj: Object, args: list[str]):
pos = ArgParser.as_vec3(args)
obj.transform.lookat(pos[0], pos[1], pos[2])
@make_operation("color", ["col", "texture"])
@make_operation("color", "col", "texture")
def color(obj: Object, args: list[str]):
try:
if len(args) == 1:

View File

@ -1,3 +1,4 @@
raise DeprecationWarning
from command import Scene
import skia
import struct

View File

@ -1,3 +1,5 @@
from dataclasses import dataclass
COLORS = {
"red": (1.0, 0.0, 0.0, 1.0),
"green": (0.0, 1.0, 0.0, 1.0),
@ -5,9 +7,6 @@ COLORS = {
"white": (1.0, 1.0, 1.0, 1.0),
}
from dataclasses import dataclass
@dataclass
class Texture:
color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0)

View File

@ -1,17 +1,26 @@
import numpy as np
from texture import COLORS
from konabot.plugins.marchtoy.texture import COLORS
class Formatter:
@staticmethod
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]])
v_1 = ", ".join([str(x) for x in m[1]])
v_2 = ", ".join([str(x) for x in m[2]])
v_3 = ", ".join([str(x) for x in m[3]])
v_0 = ", ".join([str(x) for x in m[:, 0]])
v_1 = ", ".join([str(x) for x in m[:, 1]])
v_2 = ", ".join([str(x) for x in m[:, 2]])
v_3 = ", ".join([str(x) for x in m[:, 3]])
return f"float4x4(float4({v_0}), float4({v_1}), float4({v_2}), float4({v_3}))"
@staticmethod
def vec4(m: np.ndarray) -> str:
if m.shape != (4, 4):
m = np.identity(4)
v_0 = ", ".join([str(x) for x in m[:, 0]])
v_1 = ", ".join([str(x) for x in m[:, 1]])
v_2 = ", ".join([str(x) for x in m[:, 2]])
v_3 = ", ".join([str(x) for x in m[:, 3]])
return f"mat4(vec4({v_0}), vec4({v_1}), vec4({v_2}), vec4({v_3}))"
"""
TODO: 除零出现 nan 情况的单独处理

View File

@ -0,0 +1,17 @@
import sys
from pathlib import Path
PLUGIN_DIR = Path(__file__).resolve().parents[1] / "konabot" / "plugins" / "marchtoy"
if str(PLUGIN_DIR) not in sys.path:
sys.path.insert(0, str(PLUGIN_DIR))
from obj import Transform
def test_translate_expression_puts_offset_in_matrix_column():
transform = Transform().translate(1.0, 2.0, 3.0)
expr = transform.p_expr()
assert "float4(-1.0, -2.0, -3.0, 1.0)" in expr