Gambar 3D dalam python dengan (hampir) kinerja normal

Artikel ini dapat dianggap sebagai jawaban untuk yang satu ini , di mana itu adalah pertanyaan untuk menulis hal seperti itu di C ++, yang ditujukan untuk pemula, yaitu, dengan penekanan pada kode yang mudah dibaca dan bukan kinerja tinggi.

Setelah membaca artikel itu, saya punya ide untuk mengulangi program yang ditulis oleh penulis. Saya kenal dengan C ++, tapi saya tidak pernah menulis program yang rumit di atasnya, lebih suka python. Di sini lahir ide untuk menuliskannya. Saya terutama tertarik pada kinerja - saya hampir yakin bahwa beberapa frame per detik adalah batas untuk python. Saya salah.

gambar

gambar

Upaya pertama dapat ditemukan di sini . Di sini kode ditulis secara penuh, tidak termasuk perbedaan bahasa, sesuai dengan yang ada dihaqreu. Dan karena ini, renderingnya adalah O (n ^ 2) - pada dasarnya loop bersarang dalam sudut dan jarak:

         # iterating alpha
        alpha = player.view - player.fov / 2
        mapFB.drawRectangle(player.y - 1, player.x - 1, player.y + 1, player.x + 1, Color(255, 0, 0))
        rayNum = 0
        while alpha < player.fov / 2 + player.view:
            # iterating distance
            dist = 0
            x = player.x
            y = player.y
            while 0 < x < mapFB.w - 1 and 0 < y < mapFB.h - 1:
                  ...

Karena itu, kode ini agak lambat (saya berhasil mendapatkan kurang dari 3-4 frame per detik pada generasi ke-8 intel core i5).

Cara yang jelas untuk mempercepat dan tidak menyulitkan kode adalah mengganti loop dalam dengan operasi kompleksitas linier. Mari kita pertimbangkan segala sesuatu dari sudut pandang matematika: kita perlu menentukan titik perpotongan sinar yang diberikan oleh koordinat pemain dan sudut pandang, dan blok yang ditentukan oleh koordinat dan ukuran (konstan, untuk kesederhanaan). Selanjutnya, Anda harus memilih transfer terdekat dan mengembalikannya. Di bawah ini adalah kode yang sesuai (Kode lengkap ada di sini ):

def block_cross(i, j, k, y_0, alpha, player):
    # cell coordinates
    x_cell = i * H
    y_cell = j * H
    # find collision points
    collisions = []

    if k != 0:
        x = (y_cell - y_0) / k
        y = y_cell
        if x_cell <= x <= x_cell + H and (x - player.x) / cos(alpha) < 0:
            collisions.append((x, y))

    if k != 0:
        x = (y_cell + H - y_0) / k
        y = y_cell + H
        if x_cell <= x <= x_cell + H and (x - player.x) / cos(alpha) < 0:
            collisions.append((x, y))

    x = x_cell
    y = y_0 + x * k
    if y_cell <= y <= y_cell + H and (x - player.x) / cos(alpha) < 0:
        collisions.append((x, y))

    x = x_cell + H
    y = y_0 + (x) * k
    if y_cell <= y <= y_cell + H and (x - player.x) / cos(alpha) < 0:
        collisions.append((x, y))

    # select the closest collision for the block
    dist = 1000 * H
    x = None
    y = None
    for collision in collisions:
        tmp = sqrt((collision[0] - player.x) ** 2 + (collision[1] - player.y) ** 2)
        if tmp < dist:
            dist = tmp;
            x = collision[0]
            y = collision[1]

    return x, y, dist

Perubahan sepele seperti 10 baris memberikan akselerasi lebih dari dua kali lipat, yaitu sekitar 5-6 frame per detik. Ini bukan lagi tersentak, tetapi gambar bergerak, tetapi masih cukup lambat.
Mencari ide tentang mempercepat kode, saya menemukan Cython . Singkatnya, ini adalah proyek yang memungkinkan Anda untuk memberikan akselerasi signifikan kode python tanpa secara serius mengubahnya. Secara singkat tentang dia - di bawah spoiler.

tyts
 cpdef int fun(int num, float val):
    cdef int result
    # do some stuff
    return result

result int( int, , ). , . python-, cdef — python, cython. , python — , :

 cpdef int fun(int num, float val):
    cdef int result
    # do some stuff
    return result

 cdef int fun2(int *arr, float* arr_2):
    cdef int arr_3[10][10]
    # do some stuff
    return result

fun2 python, - fun — .

Cython memberikan beberapa akselerasi, meskipun tidak signifikan - tidak hanya beberapa frame per detik. Namun, dalam jumlah relatif ini tidak begitu kecil - 8-9 gambar per detik, yaitu + 40% untuk opsi terbaik dalam python dan + 200% untuk opsi dengan algoritma naif. Ini masih gambaran yang sangat gugup, tetapi normal untuk tujuan pendidikan. Pada akhirnya, tujuan kami adalah untuk menulisnya sendiri dan menikmati prosesnya, tetapi untuk permainan sebenarnya lebih mudah untuk mengambil perpustakaan seperti pygame, atau umumnya menyisihkan python dan mengambil sesuatu yang lebih cocok.

PS Akan menarik untuk melihat opsi lain untuk mengoptimalkan kode di komentar.

Source: https://habr.com/ru/post/undefined/


All Articles