column major
This commit is contained in:
@ -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()
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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)
|
||||
@ -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__()
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
raise DeprecationWarning
|
||||
from command import Scene
|
||||
import skia
|
||||
import struct
|
||||
@ -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)
|
||||
|
||||
@ -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 情况的单独处理
|
||||
|
||||
17
tests/test_marchtoy_transform.py
Normal file
17
tests/test_marchtoy_transform.py
Normal 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
|
||||
Reference in New Issue
Block a user