Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Voxel to pixel graphics
#1
Hi, new to python here. I'm trying to make a voxel game that has an orthographic camera, in which 1 pixel = 1 voxel. I made a really slow ray marching function that is able to render a Frame every few seconds as a proof of concept (in attached file). What do you think I could do to make this function faster? Or is there a better approach that achieves the same outcome? It needs numpy and pygame to run.

The code for the whole program is below:
import numpy as np
import pygame


pygame.init()
screen = pygame.display.set_mode((640,480), pygame.SCALED)
pixel_array = pygame.PixelArray(screen)
clock = pygame.time.Clock()
running = True

# Configuration Variables
mapsize = [1000,1000,1000]
maxraydistance = 600
cameraoffset = 50

# Materials Loading
matcolors = [
    (0, 0, 0, 0), # 0 air
    (28, 28, 28, 255), # 1 Stone
    (78, 201, 65, 255) #2 Grass
]

# Player Controller Functions
ppos = [500, 500, 10]

# Map Functions
def mapgen_blank(x, y, z):
    map_array = np.zeros((x, y, z), dtype=np.uint8)
    return map_array

def mappreset_singlelayer(map_array):
    mapsize = map_array.shape
    for x in range(mapsize[0]):
        for y in range(mapsize[1]):
            for z in range(1):
                map_array[x][y][z] = 1
    return map_array

def mapstructure_testcubes(px, py, pz, l, w, h):
    for x in range(px, px + l):
        for y in range(py, py + w):
            for z in range(pz, pz + h):
                map_array[x][y][z] = 2
    px += 10
    py += 10
    pz += 10
    for x in range(px, px + l):
        for y in range(py, py + w):
            for z in range(pz, pz + h):
                map_array[x][y][z] = 2

                
map_array = mapgen_blank(1000, 1000, 1000)
map_array = mappreset_singlelayer(map_array)
mapstructure_testcubes(200, 400, 1, 10, 20, 1)
mapstructure_testcubes(240, 440, 1, 20, 10, 2)
mapstructure_testcubes(280, 480, 1, 10, 10, 3)

# Graphics Functions
def raymarch():
    for x in range(640):
        for y in range(480):
            cpos = [ppos[0] - 320 + x, ppos[1] + 240 - y + cameraoffset, ppos[2] + cameraoffset ]  # Adjusted coordinate calculation
            for i in range(maxraydistance):
                cpos[1] -= 1
                cpos[2] -= 1
                if 0 <= cpos[0] < mapsize[0] and 0 <= cpos[1] < mapsize[1] and 0 <= cpos[2] < mapsize[2]:
                    if map_array[cpos[0]][cpos[1]][cpos[2]] != 0:
                        pixel_array[x,y] = matcolors[map_array[cpos[0]][cpos[1]][cpos[2]]]
                        #print(cpos)
                        break
            else:
                continue
        
        pygame.display.flip()  # Update display after all pixels have been processed


# Important Functions
def frame():
    raymarch()


# Mainloop
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    frame()

# Exit
pygame.quit()
deanhystad write Nov-17-2023, 05:54 PM:
Please wrap code in python tags.
buran write Nov-17-2023, 09:47 AM:
Please, post your code in the post, using proper tags, not as attached file. Always use when post code, traceback, output, etc.
See BBcode help for more info.

Attached Files

.py   test1.py (Size: 2.42 KB / Downloads: 41)
Reply
#2
Not doing it in Python would make a big difference. I stripped out everything except the loops and it still almost 5 seconds to run on my laptop.
import time

start = time.time()

for _ in range(640):
    for _ in range(480):
        for _ in range(600):
            pass

print(time.time() - start)
If you could run raymarch in C++, highly optimized C++ that runs on multiple cores of a high power graphics card. it might be possible to get reasonable speed using voxels the size of a pixel. If you want to do it in Python I suggest making much larger voxels.

There are a lot of youtube videos on the subject. Have you watched any of those?
Reply
#3
it's 1,843+ billion iterations.
Reply
#4
you cannot use an interpreted language (Python) as a compiled one (c++ for instance): python remains always slower, but since you're dealing with matrixes, you've to take advantages of Numpy and its functions (and vectorization)!

A basic example based on your code:
import numpy as np
import time

def mappreset_singlelayer(map_array):
    mapsize = map_array.shape
    for x in range(mapsize[0]):
        for y in range(mapsize[1]):
            for z in range(1):
                # map_array[x][y][z] = 1
                map_array[x, y, z] = 1
    return map_array


d, r, c = 2000, 2000, 2000
Mat = np.zeros((d, r, c), dtype = np.uint8)

# with your code
M = np.copy(Mat)
t0 = time.time()
M0 = mappreset_singlelayer(map_array = M)
t1 = time.time()
print(f"Duration with 'mappreset_singlelayer' function: {t1-t0}")
# print(f"M = {M}")

# Using numpy without any loop
M1 = np.copy(Mat)
t2 = time.time()
M1[:, :, 0] = 1
t3 = time.time()
print(f"Duration using Numpy: {t3-t2}")
# print(f"Ratio = X{((t1-t0)/(t3-t2)):.1f} faster for M1")

Check = np.array_equal(M1, M0)
print(f"Are the 2 matrixes equals: {Check}")
Note I need to copy first the Mat matrix, because 'mappreset_singlelayer' changes the matrix in argument (and I do not figure out why)

Without digging in your code which requires to understand exactly what you want to do, let me suggesting you to have a look to the following link if you want to see an example on how to avoid using loops. Nontheless there's at least 1 limitation with the vectorization: your RAM.

https://python-forum.io/thread-40609-page-2.html?highlight=np.kron]topic 'Vectorizing a quadruple for loop in python)'
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Pixel color and action Sartre 4 2,112 Apr-13-2023, 03:26 AM
Last Post: Sartre
  Dynamic pixel display jerryf 2 738 Mar-17-2023, 07:26 PM
Last Post: jerryf
  Python graphics kaltenherz 1 1,730 Sep-05-2021, 05:19 PM
Last Post: jefsummers
  Plotting Pixel Intensity Doev 0 1,734 Oct-21-2020, 10:56 PM
Last Post: Doev
  What is the best way to search for a pixel in a screenshot? TheZadok42 1 2,623 May-15-2020, 12:37 PM
Last Post: scidam
  Fast get pixel and oparate. storzo 7 7,098 Aug-26-2019, 07:36 PM
Last Post: Larz60+
  from graphics import * jmaloney413 2 5,242 Oct-18-2018, 08:22 AM
Last Post: perfringo
  random change of color pixel with PIL louloudevinci 4 8,491 May-31-2018, 03:55 PM
Last Post: louloudevinci
  Why is voxel generated terrain looks better? hsunteik 1 3,236 Apr-13-2017, 11:28 AM
Last Post: SpeedyZapGaming
  Graphics py not found vnc 13 22,899 Apr-05-2017, 05:36 PM
Last Post: wavic

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020