diff --git a/konabot/plugins/marchtoy/__init__.py b/konabot/plugins/marchtoy/__init__.py index 903b226..104f611 100644 --- a/konabot/plugins/marchtoy/__init__.py +++ b/konabot/plugins/marchtoy/__init__.py @@ -8,8 +8,11 @@ cmd_marchtoy = on_command("march") @cmd_marchtoy.handle() async def _(args: Message = CommandArg()): if cmd := args.extract_plain_text(): - img = await render.render(cmd, (256, 256)) - buffer = io.BytesIO() - img.save(buffer, format="PNG") - buffer.seek(0) - await cmd_marchtoy.send(await UniMessage().image(raw=buffer).export()) \ No newline at end of file + try: + img = await render.render(cmd, (256, 256)) + buffer = io.BytesIO() + img.save(buffer, format="PNG") + buffer.seek(0) + await cmd_marchtoy.send(await UniMessage().image(raw=buffer).export()) + except Exception as e: + await cmd_marchtoy.send(await Message(message=f"发生了错误: {e}")) \ No newline at end of file diff --git a/konabot/plugins/marchtoy/obj.py b/konabot/plugins/marchtoy/obj.py index ceabaf6..cc6217a 100644 --- a/konabot/plugins/marchtoy/obj.py +++ b/konabot/plugins/marchtoy/obj.py @@ -113,6 +113,55 @@ class Sphere(Object): return f"sdSphere({self.transform.p_expr()}, {self.radius})" +@make_obj("cylinder", "cyl") +class Cylinder(Object): + def __init__(self, _radius: float = 1.0, _height: float = 1.0) -> None: + super().__init__() + self.radius = _radius + self.height = _height + + def parse_args(self, args: list[str]): + param = ArgParser.as_vec2(args) + self.radius = param[0] + self.height = param[1] + + def sdf_block(self) -> str: + return f"sdCappedCylinder({self.transform.p_expr()}, {self.radius}, {self.height})" + + + +@make_obj("torus") +class Torus(Object): + def __init__(self, _r1: float = 0.5, _r2: float = 1.0) -> None: + super().__init__() + self.r1 = _r1 + self.r2 = _r2 + + def parse_args(self, args: list[str]): + param = ArgParser.as_vec2(args) + self.r1 = param[0] + self.r2 = param[1] + + def sdf_block(self) -> str: + return f"sdTorus({self.transform.p_expr()}, vec2({self.r1}, {self.r2}))" + +@make_obj("capsule", "pill") +class Capsule(Object): + def __init__(self, _h: float = 1.0, _r: float = 0.25) -> None: + super().__init__() + self._h = _h + self._r = _r + + def parse_args(self, args: list[str]): + param = ArgParser.as_vec2(args) + self._h = param[0] + self._r = param[1] + + def sdf_block(self) -> str: + return f"sdVerticalCapsule({self.transform.p_expr()}, {self._h}, {self._r})" + + + @make_obj("camera", "cam") class Camera(Object): def __init__(self, _focus: float = 1.0) -> None: diff --git a/konabot/plugins/marchtoy/shaders/frag.glsl b/konabot/plugins/marchtoy/shaders/frag.glsl index 4bc65e8..5dd62b0 100644 --- a/konabot/plugins/marchtoy/shaders/frag.glsl +++ b/konabot/plugins/marchtoy/shaders/frag.glsl @@ -25,6 +25,23 @@ float sdSphere(vec3 p, float r) { return length(p) - r; } +float sdCappedCylinder( vec3 p, float r, float h ) +{ + vec2 d = abs(vec2(length(p.xz),p.y)) - vec2(r,h); + return min(max(d.x,d.y),0.0) + length(max(d,0.0)); +} + +float sdVerticalCapsule( vec3 p, float h, float r ) +{ + p.y -= clamp( p.y, 0.0, h ); + return length( p ) - r; +} +float sdTorus( vec3 p, vec2 t ) +{ + vec2 q = vec2(length(p.xz)-t.x,p.y); + return length(q)-t.y; +} + sdQuery sd(vec3 p) { sdQuery qry; qry.value = 100000000.0; diff --git a/konabot/plugins/marchtoy/utilities.py b/konabot/plugins/marchtoy/utilities.py index 0806c75..7ff1b7e 100644 --- a/konabot/plugins/marchtoy/utilities.py +++ b/konabot/plugins/marchtoy/utilities.py @@ -36,6 +36,22 @@ class ArgParser: raise Exception(f"cannot parse {args}") return default + @staticmethod + def as_vec2( + args: list[str], default: np.ndarray = np.array((0.0, 0.0)) + ) -> np.ndarray: + try: + if len(args) == 1: + x = float(args[0]) + return np.array((x, x)) + elif len(args) == 2: + x = float(args[0]) + y = float(args[1]) + return np.array((x, y)) + except: + raise Exception(f"cannot parse {args}") + return default + @staticmethod def as_vec3( args: list[str], default: np.ndarray = np.array((0.0, 0.0, 0.0))