【大作业】基于墨戏引擎的绘画程序

作业描述

给之前的墨戏引擎包了个更好的皮,现在可实时调参,保存图片了。基本把 GGUI 的所有组件都用上了。可惜没找到能方便调用笔压的方法。

效果展示



代码链接

Code

参考

墨戏论文

8 Likes

其实感觉交这个作业有点尴尬,毕竟之前是当小作业交,大作业改动不大,但是不交又感觉亏了(虽然已经中奖拿了好多礼品😂)。

2 Likes

或许你第一次提交的moxi代码还有吗?最近在学习格子玻尔兹曼,想参考一下,组件太多,阅读起来不方便!! :grinning:

第一次的代码也挺乱的,不过给你参考吧,要用0.8.5或之前的版本运行,主要是后面的版本不支持taichi_glsl,要把里面对glsl的依赖改了

import taichi as ti
import matplotlib.image as mpig
import taichi_glsl as tg

ti.init(arch=ti.cuda)

res = 512
brushRadius = 0.03

RGB = ti.types.vector(3, float)
RGBA = ti.types.struct(rgb=RGB, a=float)


_Pigment_Surface_c = RGB.field(shape=(res, res))
_Pigment_Surface_a=ti.field(dtype=float,shape=(res,res))
_Pigment_flow_c = RGB.field(shape=(res, res))
_Pigment_flow_a=ti.field(dtype=float,shape=(res,res))
_Pigment_flow_star_c = RGB.field(shape=(res, res))
_Pigment_flow_star_a=ti.field(dtype=float,shape=(res,res))
_Water_Surface = ti.field(float, shape=(res, res))
_Flow = ti.Vector.field(9, dtype=float, shape=(res, res))
_FlowNext = ti.Vector.field(9, dtype=float, shape=(res, res))
_Feq = ti.Vector.field(9, dtype=float, shape=(res, res))
_kapar = ti.Vector.field(9, dtype=float, shape=(res, res))
# _Fixture = ti.Vector.field(4, dtype=float, shape=(res, res))
_BackGroundLayer = ti.Vector.field(3, dtype=float, shape=(res, res))
_FrameBuffer = ti.Vector.field(3, dtype=float, shape=(res, res))
cursor = ti.field(float, shape=2)
currentColor = RGBA.field(shape=2)
currentColor[0] = RGBA(rgb=[0.0, 0.4, 0.25], a=0.5)
currentColor[1] = RGBA(rgb=[1.0, 1.0, 0.2], a=0.5)
_paper = ti.field(dtype=float, shape=(res, res))
_fibers = ti.field(dtype=float, shape=(res, res))
_rou = ti.field(float, shape=(res, res))
_sigma = ti.field(float, shape=(res, res))
_paper.from_numpy(mpig.imread("paper_512_2.png")[:, :, 0])
_fibers.from_numpy(mpig.imread("fibers_512_3.png")[:, :, 0])
_ispinning = ti.field(dtype=int, shape=(res, res))
_kar = ti.field(dtype=float, shape=(res, res))

_FlowVelocity = ti.Vector.field(2, dtype=float, shape=(res, res))

e = ti.Vector.field(2, dtype=int, shape=9)
e[0] = ti.Vector([0, 0])
e[1] = ti.Vector([0, 1])
e[2] = ti.Vector([-1, 0])
e[3] = ti.Vector([0, -1])
e[4] = ti.Vector([1, 0])
e[5] = ti.Vector([1, 1])
e[6] = ti.Vector([-1, 1])
e[7] = ti.Vector([-1, -1])
e[8] = ti.Vector([1, -1])

k = (0, 3, 4, 1, 2, 7, 8, 5, 6)

w = (4.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0 /
     9.0, 1.0/36.0, 1.0/36.0, 1.0/36.0, 1.0/36.0)

# if(True):
#     w = (4.0/9.0, 0.95/9.0, 1.0/9.0, 1.05/9.0, 1.0 /
#          9.0, 1.0/36.0, 1.0/36.0, 1.0/36.0, 1.0/36.0)

q1 = -0.05
q2 = 0.9
q3 = 0.9


@ti.kernel
def ini_sigma():
    for P in ti.grouped(_sigma):
        _sigma[P] = q1+q2*_fibers[P]+q3*_paper[P]


@ti.kernel
def get_ispinning():
    for P in ti.grouped(_ispinning):
        if (_rou[P] == 0 and
            _rou[P+e[1]] < _sigma[P+e[1]] and
            _rou[P+e[2]] < _sigma[P+e[2]] and
            _rou[P+e[3]] < _sigma[P+e[3]] and
            _rou[P+e[4]] < _sigma[P+e[4]] and
            _rou[P+e[5]] < (_sigma[P+e[5]]*1.414213562373095048) and
            _rou[P+e[6]] < (_sigma[P+e[6]]*1.414213562373095048) and
            _rou[P+e[7]] < (_sigma[P+e[7]]*1.414213562373095048) and
                _rou[P+e[8]] < (_sigma[P+e[8]]*1.414213562373095048)):
            _ispinning[P] = 1
        else:
            _ispinning[P] = 0


@ti.kernel
def update_karpa():
    for P in ti.grouped(_kapar):
        for i in ti.static(range(9)):
            P_nebor = P+e[i]
            _kapar[P][i] = 0.5*(_kar[P]+_kar[P_nebor])


@ti.kernel
def ini_k():
    for P in ti.grouped(_kar):
        _kar[P] = _paper[P]


@ti.kernel
def update_k_for_pinning():
    for P in ti.grouped(_kar):
        if(_ispinning[P]):
            _kar[P] = 1


@ti.kernel
def update_rou():
    for P in ti.grouped(_rou):
        _rou[P] = _Flow[P].sum()*(0.995)


omiga = 0.5


@ti.kernel
def update_FlowNext():
    for P in ti.grouped(_FlowNext):
        for i in ti.static(range(9)):
            prePos = P-e[i]
            _FlowNext[P][i] = omiga * \
                (_Feq[prePos][i]-_Flow[prePos][i])+_Feq[prePos][i]


@ti.kernel
def update_flow():
    for P in ti.grouped(_Flow):
        # _Flow[P]=_FlowNext[P]
        for i in ti.static(range(9)):
            prePos = P-e[i]
            _Flow[P][i] = _kapar[P][i] * \
                (_FlowNext[P][k[i]] - _FlowNext[prePos][i]) + \
                _FlowNext[prePos][i]


@ti.kernel
def update_Feq():
    alpha = 0.5
    for P in ti.grouped(_Feq):
        _FlowVelocity[P] = ti.Vector([0.0, 0.0])
        for j in ti.static(range(1, 9)):
            _FlowVelocity[P] += _Flow[P][j]*e[j]
        for i in ti.static(range(9)):
            _Feq[P][i] = w[i]*(_rou[P] + tg.scalar.smoothstep(_rou[P], 0, alpha)*(3 * e[i].dot(_FlowVelocity[P]) +
                               4.5 * (e[i].dot(_FlowVelocity[P]))**2 - 1.5 * _FlowVelocity[P].dot(_FlowVelocity[P])))


@ti.kernel
def fill_BG():
    for p in ti.grouped(_BackGroundLayer):
        _BackGroundLayer[p] = ti.Vector([1,1,1])

# @ti.kernel
# def fill_PL(r: float, g: float, b: float, a: float):
#     for P in ti.grouped(_Pigment_Surface):
#         _Pigment_Surface[P][0] = r
#         _Pigment_Surface[P][1] = g
#         _Pigment_Surface[P][2] = b
#         _Pigment_Surface[P].a = a


@ti.kernel
def render():
    for P in ti.grouped(_FrameBuffer):
        _FrameBuffer[P] = tg.scalar.mix(
            _BackGroundLayer[P], _Pigment_Surface_c[P], _Pigment_Surface_a[P])
        _FrameBuffer[P] = tg.scalar.mix(
            _FrameBuffer[P], _Pigment_flow_c[P], _Pigment_flow_a[P])
        _FrameBuffer[P] = tg.scalar.mix(
            _FrameBuffer[P], ti.Vector([0.0, 0.2, 0.6]), _rou[P]*0.5)


@ti.kernel
def drawStrok(color: ti.template(), i: int, radius: ti.f32):
    center = ti.Vector([cursor[0], cursor[1]])
    for P in ti.grouped(_Pigment_Surface_c):
        dis = (P/res-center).norm()
        if dis < radius:
            # mask = max(1-_rou[P]/0.5,0.1)
            brush_tip = tg.scalar.clamp(1-dis/radius, 0, 1)
            _Water_Surface[P] += max(1-_rou[P]/0.5, 0.7)
            _Water_Surface[P] = tg.scalar.clamp(_Water_Surface[P])
            _Pigment_Surface_c[P] = color[i].rgb
            _Pigment_Surface_a[P] += brush_tip*color[i].a
            # _Pigment_Surface[P]=tg.scalar.clamp(_Pigment_Surface[P],color[i][3])
            _kar[P] = _paper[P]


psy = ti.field(dtype=float, shape=(res, res))


@ti.kernel
def waterSurface_to_flow():
    for P in ti.grouped(_Flow):
        psy[P] = tg.scalar.clamp(_Water_Surface[P], 0, 1.0-_rou[P])
        _Flow[P][0] += psy[P]
        _Water_Surface[P] -= psy[P]


@ti.kernel
def Pigment_S_to_F():
    for P in ti.grouped(psy):
        if (psy[P] > 0):
            denom = (_rou[P]+psy[P])
            _Pigment_flow_c[P] = (_Pigment_flow_c[P]*_rou[P]*_Pigment_flow_a[P] +
                                    _Pigment_Surface_c[P]*psy[P]*_Pigment_Surface_a[P])/  \
                                    (_rou[P]*_Pigment_flow_a[P]+psy[P]*_Pigment_Surface_a[P])
            _Pigment_flow_a[P] = tg.scalar.clamp(
                _Pigment_flow_a[P]+psy[P]*_Pigment_Surface_a[P]/denom, 0, 1)
            _Pigment_Surface_a[P] = tg.scalar.clamp(
                _Pigment_Surface_a[P]-(psy[P]/denom), 0, 1)


@ti.kernel
def update_Pf_star():
    for P in ti.grouped(_Pigment_flow_star_c):
        # _Pigment_flow_star_a[P]=0
        # if (_ispinning[P] and (_rou[P] > 0)):
        #     _Pigment_flow_star_c[P]=_Pigment_flow_c[P-4*_FlowVelocity[P]]
        # else:
        _Pigment_flow_star_c[P]=tg.sampling.bilerp(_Pigment_flow_c,P-4*_FlowVelocity[P])
        _Pigment_flow_star_a[P] = tg.sampling.bilerp(_Pigment_flow_a, P-4*_FlowVelocity[P])


@ti.kernel
def update_Pf():
    for P in ti.grouped(_Pigment_flow_c):
        gama_star = tg.scalar.mix(1, 0.1, tg.scalar.smoothstep(
            _FlowVelocity[P].norm()*4, 0, 0.05))
        _Pigment_flow_a[P] = (_Pigment_flow_a[P]-_Pigment_flow_star_a[P]
                            )*gama_star+_Pigment_flow_star_a[P]
        _Pigment_flow_c[P] = (_Pigment_flow_c[P]-_Pigment_flow_star_c[P]
                            )*gama_star+_Pigment_flow_star_c[P]

_rouPre = ti.field(dtype=float, shape=(res, res))


@ti.kernel
def _update_rouPre():
    for P in ti.grouped(_rouPre):
        _rouPre[P] = _rou[P]


# miu = -0.2
# ksy = 0.5
# niu = 0.0001


# @ti.kernel
# def update_Fixture():
#     for P in ti.grouped(_Fixture):
#         fixFactor = 0.0
#         wLoss = max(_rouPre[P]-_rou[P], 0)
#         if (wLoss > 0):
#             fixFactor = wLoss/_rouPre[P]
#         u_star = tg.scalar.clamp(miu+ksy*_Pigment_flow[P].a, 0, 1)
#         fixFactor = max(
#             fixFactor*(1-tg.scalar.smoothstep(_rou[P], 0, u_star)), niu)
#         tempV = fixFactor*_Pigment_flow[P].a
#         # _Fixture[P]+=tempV
#         _Fixture[P][3] = tg.scalar.clamp(_Fixture[P][3]+tempV)
#         _Pigment_flow[P].a = tg.scalar.clamp(_Pigment_flow[P].a-tempV)


@ti.kernel
def ini_to_1(field: ti.template()):
    for P in ti.grouped(field):
        field[P] = ti.Vector([1.0,1.0,1.0])


gui = ti.ui.Window("ti-ink", (res, res))
canvas=gui.get_canvas()
fill_BG()
ini_k()
ini_sigma()
cursor[0] = 0.5
cursor[1] = 0.5
# ini_to_0(_Pigment_Surface.rgb)
ini_to_1(_Pigment_flow_c)
# ini_to_0(_Fixture)
while gui.running:

    gui.get_event()

    if(gui.is_pressed(ti.GUI.LMB)):
        cursor[0] = gui.get_cursor_pos()[0]
        cursor[1] = gui.get_cursor_pos()[1]
        drawStrok(currentColor, 0, brushRadius)

    if(gui.is_pressed(ti.GUI.RMB)):
        cursor[0] = gui.get_cursor_pos()[0]
        cursor[1] = gui.get_cursor_pos()[1]
        drawStrok(currentColor, 1, brushRadius)
    waterSurface_to_flow()
    Pigment_S_to_F()
    update_rou()
    update_Feq()
    update_FlowNext()
    update_flow()
    update_Pf_star()
    update_Pf()
    # _update_rouPre()
    get_ispinning()
    update_k_for_pinning()
    update_karpa()
   
    # update_Fixture()
    render()
    canvas.set_image(_FrameBuffer)
    gui.show()