marchtoy 初步
This commit is contained in:
4
konabot/docs/user/march.txt
Normal file
4
konabot/docs/user/march.txt
Normal file
@ -0,0 +1,4 @@
|
||||
# 指令介绍
|
||||
简易 Raymarch 小玩具
|
||||
用法:march <scene>
|
||||
例:march sphere(1) cam(4).pos(-5).lookat(0)
|
||||
@ -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())
|
||||
1
konabot/plugins/sksl/marchtoy/__init__.py
Normal file
1
konabot/plugins/sksl/marchtoy/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
import render
|
||||
@ -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
|
||||
|
||||
41
konabot/plugins/sksl/marchtoy/render.py
Normal file
41
konabot/plugins/sksl/marchtoy/render.py
Normal 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
|
||||
@ -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")
|
||||
Reference in New Issue
Block a user