marchtoy 初步

This commit is contained in:
alcoholicgirl
2026-04-25 01:13:32 +08:00
parent b73d020b67
commit 3bf0735af4
6 changed files with 76 additions and 62 deletions

View File

@ -0,0 +1,4 @@
# 指令介绍
简易 Raymarch 小玩具
用法march <scene>
march sphere(1) cam(4).pos(-5).lookat(0)

View File

@ -2,16 +2,23 @@ from nonebot_plugin_alconna import Alconna, Args, Option, UniMessage, on_alconna
from konabot.common.nb.exc import BotExceptionMessage
from konabot.plugins.sksl.run_sksl import render_sksl_shader_to_gif
from nonebot import on_command
from nonebot.adapters import Bot, Event, Message
from nonebot.params import CommandArg
import marchtoy
import io
cmd_run_sksl = on_alconna(
Alconna(
"shadertool",
Option("--width", Args["width_", int]),
Option("--height", Args["height_", int]),
Option("--duration", Args["duration_", float]),
Option("--fps", Args["fps_", float]),
Args["code", str],
)
)
cmd_run_sksl = on_alconna(Alconna(
"shadertool",
Option("--width", Args["width_", int]),
Option("--height", Args["height_", int]),
Option("--duration", Args["duration_", float]),
Option("--fps", Args["fps_", float]),
Args["code", str],
))
@cmd_run_sksl.handle()
async def _(
@ -34,10 +41,23 @@ async def _(
if width_ > 640 or height_ > 640:
raise BotExceptionMessage("最大支持 640x640 啦!不要太大啦!")
code = code.strip("\"").strip("'")
code = code.strip('"').strip("'")
try:
res = await render_sksl_shader_to_gif(code, width_, height_, duration_, fps_)
await cmd_run_sksl.send(await UniMessage().image(raw=res).export())
except (ValueError, RuntimeError) as e:
await cmd_run_sksl.send(await UniMessage().text(f"渲染时遇到了问题:\n\n{e}").export())
await cmd_run_sksl.send(
await UniMessage().text(f"渲染时遇到了问题:\n\n{e}").export()
)
cmd_marchtoy = on_command("march", priority=10, block=True)
@cmd_marchtoy.handle()
async def _(args: Message = CommandArg()):
if cmd := args.extract_plain_text():
img = await marchtoy.render.render(cmd, 256, 256)
buffer = io.BytesIO()
img.save(buffer, format="PNG")
buffer.seek(0)
await cmd_run_sksl.send(await UniMessage().image(raw=buffer).export())

View File

@ -0,0 +1 @@
import render

View File

@ -22,19 +22,6 @@ from obj import Object, Camera, OBJECT_ENTRIES
from op import OPERATION_ENTRIES
from typing import Optional
"""
# cmd = on_command("march", priority=10, block=True)
# @cmd.handle()
# async def _(args: Message = CommandArg()):
# if inst_text := args.extract_plain_text():
# instructions = inst_text.split(' ')
# for instruction in instructions:
# if instruction == '': continue
# if parsed_inst := parse_instruction(instruction):
# pass
"""
@dataclass
class Command:
id: str

View File

@ -0,0 +1,41 @@
from command import Scene
import skia
import struct
from PIL import Image
import numpy as np
# 暂时先照抄小帕的了,之后有空再单独封装一下
async def render(cmd: str, width: int, height: int):
scene = Scene(cmd)
surface = skia.Surface(width, height)
sksl_code = scene.compile()
runtime_effect = skia.RuntimeEffect.MakeForShader(scene.compile())
if runtime_effect is None:
raise Exception("cannot compile sksl shader")
uv_uniform = struct.pack("ff", float(width), float(height))
uniform_data = skia.Data.MakeWithCopy(uv_uniform)
shader = runtime_effect.makeShader(uniform_data, None, 0)
canvas = surface.getCanvas()
canvas.clear(skia.Color(0, 0, 0, 0))
paint = skia.Paint()
paint.setShader(shader)
canvas.drawRect(skia.Rect.MakeWH(width, height), paint)
image = surface.makeImageSnapshot()
target_info = skia.ImageInfo.Make(
image.width(),
image.height(),
skia.ColorType.kBGRA_8888_ColorType,
skia.AlphaType.kPremul_AlphaType,
)
pixel_data = bytearray(
image.width() * image.height() * 4
) # 4 bytes per pixel (BGRA)
success = image.readPixels(target_info, pixel_data, target_info.minRowBytes())
img_array = np.frombuffer(pixel_data, dtype=np.uint8).reshape((height, width, 4))
rgb_array = img_array[:, :, [2, 1, 0]]
pil_img = Image.fromarray(rgb_array)
return pil_img

View File

@ -1,39 +0,0 @@
from command import Scene
import skia
import struct
from PIL import Image
import numpy as np
# 暂时先照抄小帕的了,之后有空再单独封装一下
width = 480
height = 480
scene = Scene("sphere(1).pos(0, 0, 0) camera(4.0).pos(1).lookat(0.0)")
surface = skia.Surface(width, height)
sksl_code = scene.compile()
runtime_effect = skia.RuntimeEffect.MakeForShader(scene.compile())
if runtime_effect is None:
raise Exception("cannot compile sksl shader")
uv_uniform = struct.pack("ff", float(width), float(height))
uniform_data = skia.Data.MakeWithCopy(uv_uniform)
shader = runtime_effect.makeShader(uniform_data, None, 0)
canvas = surface.getCanvas()
canvas.clear(skia.Color(0, 0, 0, 0))
paint = skia.Paint()
paint.setShader(shader)
canvas.drawRect(skia.Rect.MakeWH(width, height), paint)
image = surface.makeImageSnapshot()
target_info = skia.ImageInfo.Make(
image.width(),
image.height(),
skia.ColorType.kBGRA_8888_ColorType,
skia.AlphaType.kPremul_AlphaType,
)
pixel_data = bytearray(image.width() * image.height() * 4) # 4 bytes per pixel (BGRA)
success = image.readPixels(target_info, pixel_data, target_info.minRowBytes())
img_array = np.frombuffer(pixel_data, dtype=np.uint8).reshape((height, width, 4))
rgb_array = img_array[:, :, [2, 1, 0]]
pil_img = Image.fromarray(rgb_array)
pil_img.save("1.png")