Homework0 texture

使用双线性插值 加载纹理贴图(实现的很粗糙 效果 有点差orz…

生成的图片:

原图:

import numpy as np
import taichi as ti
import torch
import math
import cv2

ti.init(arch=ti.gpu)

eps = 1e-5

_t = ti.imread('images/yui.jpg').astype(np.float32) / 255.0
_c = np.array([[-0.5, -0.5, 0.0, 0.0, 0.0],
               [0.5, -0.5, 0.0, 1.0, 0.0],
               [0.5, 0.5, 0.0, 1.0, 1.0],
               [0.5, 0.5, 0.0, 1.0, 1.0],
               [-0.5, 0.5, 0.0, 0.0, 1.0],
               [-0.5, -0.5, 0.0, 0.0, 0.0]]).astype(np.float32)

texture = ti.var(ti.f32, shape=_t.shape)
t_s = ti.var(ti.i32, shape=(2,))
cube = ti.var(ti.f32, shape=_c.shape)
item_t = ti.var(ti.i32, shape=())
item_c = ti.var(ti.i32, shape=())

mat_model = ti.Matrix(4, 4, dt=ti.f32, shape=())
mat_view = ti.Matrix(4, 4, dt=ti.f32, shape=())
mat_proj = ti.Matrix(4, 4, dt=ti.f32, shape=())

tri = ti.Vector(4, dt=ti.f32, shape=(3,))

n = 512
pixels = ti.var(ti.f32, shape=(n, n, 3))
z_buffer = ti.var(ti.f32, shape=(n, n))

dv = ti.var(ti.f32, shape=(3, 3))
rot = ti.var(ti.f32, shape=(3, 2))
c_p = ti.var(ti.f32, shape=(3,))


@ti.func
def clip(x, a, b):
    return max(a, min(x, b))


@ti.func
def init_mat_model():
    it = item_c[None]
    rot_x = ti.Matrix([[1.0, 0.0, 0.0, 0.0],
                       [0.0, ti.cos(rot[it, 0]), -ti.sin(rot[it, 0]), 0.0],
                       [0.0, ti.sin(rot[it, 0]), ti.cos(rot[it, 0]), 0.0],
                       [0.0, 0.0, 0.0, 1.0]])
    rot_y = ti.Matrix([[ti.cos(rot[it, 1]), 0.0, ti.sin(rot[it, 1]), 0.0],
                       [0.0, 1.0, 0.0, 0.0],
                       [-ti.sin(rot[it, 1]), 0.0, ti.cos(rot[it, 1]), 0.0],
                       [0.0, 0.0, 0.0, 1.0]])
    T = ti.Matrix([[1.0, 0.0, 0.0, dv[it, 0]],
                   [0.0, 1.0, 0.0, dv[it, 1]],
                   [0.0, 0.0, 1.0, dv[it, 2]],
                   [0.0, 0.0, 0.0, 1.0]])
    mat_model[None] = T @ rot_y @ rot_x


@ti.func
def init_mat_view():
    T = ti.Matrix([[1.0, 0.0, 0.0, -c_p[0]],
                   [0.0, 1.0, 0.0, -c_p[1]],
                   [0.0, 0.0, 1.0, -c_p[2]],
                   [0.0, 0.0, 0.0, 1.0]])
    g = -ti.Vector([c_p[0], c_p[1], c_p[2]]).normalized()
    h = ti.Vector([0.0, 1.0, 0.0])
    gxt = g.cross(h).normalized()
    t = gxt.cross(g).normalized()
    R = ti.Matrix([[gxt[0], gxt[1], gxt[2], 0.0],
                   [t[0], t[1], t[2], 0.0],
                   [-g[0], -g[1], -g[2], 0.0],
                   [0.0, 0.0, 0.0, 1.0]])
    mat_view[None] = R @ T


@ti.func
def init_mat_proj():
    zn, zf = 0.1, 50.0
    t, b = 1.0 * zn, -1.0 * zn
    l, r = -1.0 * zn, 1.0 * zn
    zn *= -1
    zf *= -1
    Mp = ti.Matrix([[zn, 0.0, 0.0, 0.0],
                    [0.0, zn, 0.0, 0.0],
                    [0.0, 0.0, zn + zf, -zn * zf],
                    [0.0, 0.0, 1.0, 0.0]])
    Mot = ti.Matrix([[1.0, 0.0, 0.0, 0.0],
                     [0.0, 1.0, 0.0, 0.0],
                     [0.0, 0.0, 1.0, -(zn + zf) / 2.0],
                     [0.0, 0.0, 0.0, 1.0]])
    Mos = ti.Matrix([[2.0 / (r - l), 0.0, 0.0, 0.0],
                     [0.0, 2.0 / (t - b), 0.0, 0.0],
                     [0.0, 0.0, 2.0 / (zn - zf), 0.0],
                     [0.0, 0.0, 0.0, 1.0]])
    mat_proj[None] = Mos @ Mot @ Mp


@ti.func
def init_range(tri):
    l = int(ti.floor(clip(min(tri[0][0], tri[1][0], tri[2][0]), 0, n - 1)))
    r = int(ti.ceil(clip(max(tri[0][0], tri[1][0], tri[2][0]), 0, n - 1)))
    b = int(ti.floor(clip(min(tri[0][1], tri[1][1], tri[2][1]), 0, n - 1)))
    t = int(ti.ceil(clip(max(tri[0][1], tri[1][1], tri[2][1]), 0, n - 1)))
    return l, r, b, t


@ti.func
def det(a, b):
    return a[0] * b[1] - a[1] * b[0]


@ti.func
def area(a, b):
    return ti.abs(det(a, b))


@ti.func
def in_tri(x, y, tri):
    m = ti.Matrix([[0., 0.], [0., 0.], [0., 0.]])
    s = ti.Vector([0., 0., 0.])
    for k in ti.static(range(3)):
        m[k, 0], m[k, 1] = tri[k][0] - x, tri[k][1] - y
    for k in ti.static(range(3)):
        s[k] = det(ti.Vector([m[k, 0], m[k, 1]]),
                   ti.Vector([m[(k + 1) % 3, 0], m[(k + 1) % 3, 1]]))
    return s[0] * s[1] >= 0 and s[1] * s[2] >= 0 and s[2] * s[0] >= 0


@ti.func
def bary(x, y, tri):
    m = ti.Matrix([[0., 0.], [0., 0.], [0., 0.]])
    s = ti.Vector([0., 0., 0.])
    for k in ti.static(range(3)):
        m[k, 0], m[k, 1] = tri[k][0] - x, tri[k][1] - y
    for k in ti.static(range(3)):
        s[k] = det(ti.Vector([m[k, 0], m[k, 1]]),
                   ti.Vector([m[(k + 1) % 3, 0], m[(k + 1) % 3, 1]]))
    s = ti.abs(s)
    u, v, w = s[1], s[2], s[0]
    sa = u + v + w
    return u / sa, v / sa, w / sa


@ti.func
def interpolation(x, y):  # bilinear
    th, tw = t_s[0], t_s[1]
    c = ti.Vector([clip(x * tw, 0., th - 1 - eps),
                   clip(y * th, 0., tw - 1 - eps)])
    p = ti.ti_int(ti.floor(c))
    color = ti.Vector([0., 0., 0.])
    for i in ti.static(range(2)):
        for j in ti.static(range(2)):
            v = ti.Vector([p[0] + i, p[1] + j], dt=ti.f32) - c
            w = abs(v[0]) * abs(v[1])
            for k in ti.static(range(3)):
                color[k] += w * texture[p[0] + i, p[1] + j, k]
    return color


@ti.func
def set_pixel(x, y, z, c):
    if 1 > z > -1 and z > z_buffer[x, y]:
        for k in ti.static(range(3)):
            pixels[x, y, k] = c[k]
        z_buffer[x, y] = z


@ti.kernel
def render_tri():
    it = item_t[None]
    init_mat_model()
    init_mat_view()
    init_mat_proj()
    for i in ti.static(range(3)):
        tri[i] = ti.Vector([cube[3 * it + i, 0],
                            cube[3 * it + i, 1],
                            cube[3 * it + i, 2],
                            1.0])
        tri[i] = mat_proj @ mat_view @ mat_model @ tri[i]
        tri[i] /= tri[i][3]
        tri[i][0] = 0.5 * n * (1.0 + tri[i][0])
        tri[i][1] = 0.5 * n * (1.0 + tri[i][1])
    cd = ti.Matrix([[0.0, 0.0], [0.0, 0.0], [0.0, 0.0]])
    for k in ti.static(range(3)):
        cd[k, 0], cd[k, 1] = cube[3 * it + k, 3], cube[3 * it + k, 4]
    l, r, b, t = init_range(tri)
    # print(l, r, b, t)
    for x, y in ti.ndrange((l, r + 1), (b, t + 1)):
        if in_tri(x + 0.5, y + 0.5, tri):
            u, v, w = bary(x + 0.5, y + 0.5, tri)
            z = u * tri[0][2] + v * tri[1][2] + w * tri[2][2]
            tx = u * cd[0, 0] + v * cd[1, 0] + w * cd[2, 0]
            ty = u * cd[0, 1] + v * cd[1, 1] + w * cd[2, 1]
            tx = clip(tx, 0., 1.)
            ty = clip(ty, 0., 1.)
            color = interpolation(tx, ty)
            set_pixel(x, y, z, color)

@ti.kernel
def init():
    for i, j in z_buffer:
        z_buffer[i, j] = -100
        pixels[i, j, 0] = 202 / 255
        pixels[i, j, 1] = 235 / 255
        pixels[i, j, 2] = 216 / 255

texture.from_numpy(_t)
cube.from_numpy(_c)
c_p.from_numpy(np.array([1.0, 1.0, 1.0]).astype(np.float32))
t_s[0], t_s[1] = _t.shape[0], _t.shape[1]
dv.from_numpy(np.array([[0.0, 0.0, 0.5],
                        [0.0, 0.5, 0.0],
                        [0.5, 0.0, 0.0]]).astype(np.float32))

rot.from_numpy(np.array([[0.0, 0.0],
                         [-math.pi / 2, 0.0],
                         [0.0, math.pi / 2]]).astype(np.float32))

gui = ti.GUI('Yui')
init()
for i in range(3):
    for j in range(2):
        item_c[None] = i
        item_t[None] = j
        render_tri()
img = np.round(pixels.to_numpy() * 255).astype(np.uint8)
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
cv2.imwrite('images/yui_draw.jpg', img)
for t in range(10000):
    gui.set_image(pixels)
    gui.show()
4 Likes

Cool homework! Btw, you can use ti.imwrite(img, 'images/yui_draw.jpg') to save images, and ti.imshow(img) to show images without a loop.

1 Like

ok! thank you!!!

编译代码后报错
Traceback (most recent call last):
File “C:\Users\recZ\anaconda3\lib\runpy.py”, line 193, in _run_module_as_main
main”, mod_spec)
File “C:\Users\recZ\anaconda3\lib\runpy.py”, line 85, in _run_code
exec(code, run_globals)
File “C:\Users\recZ\anaconda3\lib\cProfile.py”, line 185, in
main()
File “C:\Users\recZ\anaconda3\lib\cProfile.py”, line 178, in main
runctx(code, globs, None, options.outfile, options.sort)
File “C:\Users\recZ\anaconda3\lib\cProfile.py”, line 20, in runctx
filename, sort)
File “C:\Users\recZ\anaconda3\lib\profile.py”, line 62, in runctx
prof.runctx(statement, globals, locals)
File “C:\Users\recZ\anaconda3\lib\cProfile.py”, line 100, in runctx
exec(cmd, globals, locals)
File “C:/Users/recZ/.spyder-py3/xx.py”, line 9, in
import torch
ModuleNotFoundError: No module named ‘torch’