chore(art): 主角像素样例三件留存——美术素材改走 ComfyUI 拍板批产物(第58条收口)
This commit is contained in:
1 parent
131d1047e1
commit
d76a023fa9
3 files changed
+128
No files matched your search
@@ -0,0 +1,128 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
主角站姿像素画样例生成器 — Dungeon Sweeper
|
||||
依据 design/art/art-bible.md:
|
||||
- 小人蓝 #2E6E8E 主色(§4.1) / 亮色描边+落影底盘轮廓通道(§3.1)
|
||||
- 3 头身候选档(§3.1 两档之一;终稿归 §5 角色批)
|
||||
- 窄/直立/对称/凹凸≤2,剑收于剪影内(§3.1/§3.4)
|
||||
- 不用红(危险专属)/金(收益专属)/紫赤 300-345° 禁入带(§4.2)
|
||||
输出: hero-standing-pose.png (1x) + hero-standing-pose-preview.png (8x 四联测试条)
|
||||
"""
|
||||
from PIL import Image, ImageOps
|
||||
|
||||
PAL = {
|
||||
'O': (255, 246, 224, 255), # 亮色描边(暖白)
|
||||
'b': (85, 144, 175, 255), # 蓝高光(小人蓝同族)
|
||||
'B': (46, 110, 142, 255), # 小人蓝 §4.1
|
||||
'd': (31, 74, 96, 255), # 蓝暗部(同族)
|
||||
'S': (242, 199, 156, 255), # 肤色(暖)
|
||||
's': (214, 159, 108, 255), # 肤暗部
|
||||
'E': (51, 38, 27, 255), # 数字墨(眼) §4.1
|
||||
'T': (138, 90, 52, 255), # 皮革(木色族 §4.4)
|
||||
't': (92, 58, 30, 255), # 皮革暗部
|
||||
'W': (183, 195, 203, 255), # 剑-钢
|
||||
'w': (132, 147, 157, 255), # 剑-钢暗部
|
||||
'G': (110, 91, 62, 255), # 落影底盘(暖深)
|
||||
}
|
||||
|
||||
# 左半 16 列(col 0..15),右半水平镜像;-figure 对称剪影
|
||||
LEFT = [
|
||||
"................", # 0
|
||||
"................", # 1
|
||||
"................", # 2
|
||||
".............OOO", # 3 兜帽顶
|
||||
"............OBBB", # 4
|
||||
"...........Obbbb", # 5
|
||||
"...........ObbBB", # 6
|
||||
"...........ObBBB", # 7
|
||||
"...........OSSSS", # 8 额/脸顶(加宽脸窗)
|
||||
"...........OSSES", # 9
|
||||
"...........OSSES", # 10 眼(下移一档更亲和)
|
||||
"...........OSSSS", # 11
|
||||
"...........OSsss", # 12 下巴暗
|
||||
"...........Odddd", # 13 兜帽收底
|
||||
"..........Oddddd", # 14 肩起
|
||||
"..........OdBBBB", # 15 肩
|
||||
"..........OdBbbB", # 16 胸(中高光)
|
||||
".........OBBBbbB", # 17 臂现
|
||||
".........OdTBbbB", # 18 臂+背带
|
||||
".........OdTBbbB", # 19
|
||||
".........OdTBbbB", # 20
|
||||
".........OdTBbbB", # 21
|
||||
".........OdTBbbB", # 22
|
||||
".........OdTBbbB", # 23
|
||||
".........OdTttTW", # 24 腰带+扣(2px 居中)
|
||||
".........OdTttTW", # 25
|
||||
".........OdTTTTt", # 26 双手套握柄
|
||||
".........OddBBBt", # 27 柄下
|
||||
".........OBBOWWW", # 28 剑格
|
||||
".........OBBBBBW", # 29 髋/剑身起
|
||||
"..........OdBddW", # 30 腿+剑
|
||||
"..........OdBddW", # 31
|
||||
"..........OdBddW", # 32
|
||||
"..........OdBddW", # 33
|
||||
"..........OdBddW", # 34
|
||||
"..........OdBddW", # 35
|
||||
"..........OdBddW", # 36
|
||||
"..........OTTttW", # 37 靴
|
||||
"..........OTTttW", # 38
|
||||
"..........OTTttW", # 39
|
||||
"..........OTTttW", # 40
|
||||
"..........OttttW", # 41 靴底
|
||||
"..............OW", # 42 剑尖
|
||||
"................", # 43
|
||||
".........GGGGGGG", # 44 落影底盘
|
||||
"...........GGGGG", # 45
|
||||
"................", # 46
|
||||
"................", # 47
|
||||
]
|
||||
|
||||
W, H = 32, 48
|
||||
grid = [['.'] * W for _ in range(H)]
|
||||
for y, lft in enumerate(LEFT):
|
||||
for x, ch in enumerate(lft):
|
||||
grid[y][x] = ch
|
||||
grid[y][W - 1 - x] = ch
|
||||
|
||||
# 剑身右侧 1px 暗部(col 16),避免完全对称的死平
|
||||
for y in range(29, 42):
|
||||
if grid[y][15] == 'W':
|
||||
grid[y][16] = 'w'
|
||||
|
||||
|
||||
def render(scale=1):
|
||||
img = Image.new('RGBA', (W, H), (0, 0, 0, 0))
|
||||
px = img.load()
|
||||
for y in range(H):
|
||||
for x in range(W):
|
||||
c = PAL.get(grid[y][x])
|
||||
if c:
|
||||
px[x, y] = c
|
||||
return img.resize((W * scale, H * scale), Image.NEAREST)
|
||||
|
||||
|
||||
def on_bg(img, color):
|
||||
bg = Image.new('RGBA', img.size, color + (255,))
|
||||
bg.alpha_composite(img)
|
||||
return bg
|
||||
|
||||
|
||||
one_x = render(1)
|
||||
one_x.save('hero-standing-pose.png')
|
||||
|
||||
# 测试条: 掩尘底 / 裸土底 / 暗底 / 灰度(轮廓通道验证)
|
||||
x8 = render(8)
|
||||
tiles = [
|
||||
on_bg(x8, (201, 175, 131)), # 掩尘 #C9AF83
|
||||
on_bg(x8, (179, 154, 120)), # 裸土 #B39A78
|
||||
on_bg(x8, (46, 42, 38)), # 暗底对照
|
||||
ImageOps.grayscale(on_bg(x8, (201, 175, 131))).convert('RGBA'),
|
||||
]
|
||||
GAP = 24
|
||||
strip = Image.new('RGBA',
|
||||
(len(tiles) * x8.width + (len(tiles) + 1) * GAP, x8.height + 2 * GAP),
|
||||
(250, 244, 230, 255))
|
||||
for i, t in enumerate(tiles):
|
||||
strip.alpha_composite(t, (GAP + i * (x8.width + GAP), GAP))
|
||||
strip.save('hero-standing-pose-preview.png')
|
||||
print('done:', one_x.size, '->', strip.size)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 540 B |
Reference in new issue
Block a user