0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Pyxel】短いプログラムで遊ぶ⑤(高速化追記)

Last updated at Posted at 2024-11-30

20250308追記:描画高速化

描画処理

#描画
def draw():
	pyxel.cls(0)
	_screen_ptr = pyxel.screen.data_ptr()
	for _i in range(SCREEN_HEIGHT*SCREEN_WIDTH):
		_screen_ptr[_i] = pix[_i]

data_ptrに格納する方法をスライスにするとさらに高速化できます。
(「スライス」は今までもなんとなく使ってましたが、最近知りました(^^;)
変更前の描画速度の平均は、約0.007くらい

補足:速度計測方法

import time
...
	start = time.time()
(処理)
	end = time.time()
    time_diff = end - start
    print(time_diff)

一行ずつ格納に変更

#描画
def draw():
	pyxel.cls(0)
	_screen_ptr = pyxel.screen.data_ptr()
	for _i in range(SCREEN_HEIGHT):
		_screen_ptr[_i*SCREEN_WIDTH:_i*SCREEN_WIDTH+(SCREEN_WIDTH)] = pix[_i*SCREEN_WIDTH:_i*SCREEN_WIDTH+(SCREEN_WIDTH)]

変更後の描画速度の平均は、約0.005くらい
で、ここで気づいたことは、全部スライスでいいんじゃ・・・
ということで最終形態

def draw():
	pyxel.cls(0)
	_screen_ptr = pyxel.screen.data_ptr()
	_screen_ptr[0:SCREEN_HEIGHT*SCREEN_WIDTH] = pix[0:SCREEN_HEIGHT*SCREEN_WIDTH]

最終形態の描画速度の平均は、約0.003くらい
変更前から2倍以上の高速化に成功!(とはいえ微々たるものですが・・・計算処理を高速化しないと!)

動作確認はこちら:Pyxel実験室
----------------------------------追記ここまで

「16色を超える色」を使ってマンデルブロート集合を描画します。
深度を上げると表示に時間がかかります。

操作方法:
マウスでカーソル位置を変更して
マウス右クリックで拡大
マウス左クリックで縮小
Cキーでグラデカラーに切り替え
Wキーで別のグラデカラーに切り替え
Gキーでグレーカラーに切り替え
1~9,0キーで深度切り替え
Rキーで初期画面にもどる

前準備として、
内部で作成したパレットファイル my_resource.pyxpalを使用するため、本プログラムの実行前にPyxelエディタを実行("pyxel edit")、ファイル保存して空のリソースファイル:my_resource.pyxresを作成してください。

画像サンプル
mandelzoom1.png
mandelzoom2.png
mandelzoom3.png

import pyxel
import math
import numpy as np

SCREEN_WIDTH = 256
SCREEN_HEIGHT = 256

max_i = 0x100
xmin = -2.0
xmax = 1.2
ymin = -1.2
ymax = 1.2
pix = [0 for tbl in range(SCREEN_WIDTH * SCREEN_HEIGHT)]
#-----------------------------------------------------------------
#計算
def cal_mbrot():
	global max_i
	global xmin
	global xmax
	global ymin
	global ymax
	global pix

	w = SCREEN_WIDTH
	h = SCREEN_HEIGHT
	i = j = k = 0
	x = y = z = x0 = y0 = 0.0
	w1 = 1.0 / w
	h1 = 1.0 / h

	bailout=4.0
	LOG2 = math.log(2)

	p = 0
	for j in range( h ):
		y0 = ymin + (ymax - ymin) * j * h1
		for i in range( w ):
			k = 0
			x0 = xmin + (xmax - xmin) * i * w1
			zx = 0.0
			zy = 0.0
			radius2 = 0.0
			iteration = 0
			while iteration < max_i and radius2 <= bailout:
				zx, zy = zx*zx - zy*zy + x0, 2*zx*zy + y0
				radius2 = zx*zx + zy*zy
				iteration += 1

			alpha = 0
			outside = iteration<max_i
			if outside:
				# smoothing
				log_zn = math.log(radius2) / 2
				nu = math.log(log_zn / LOG2) / LOG2
				alpha = iteration + 1 - nu

				alpha *= 0.05
				alpha = (alpha%1)*255

			k = int(alpha)
			k &= 0xff
			if( k >= 255 ):		#255以上は指定できない
				k = 254
			pix[p] = k
			p+=1
			if( p >= (SCREEN_WIDTH * SCREEN_HEIGHT) ):
				return
#-----------------------------------------------------------------
#マウスで任意の位置を選択(拡大縮小)した時の動作
def zoom_set( isZoom ):
	global xmin
	global xmax
	global ymin
	global ymax

	#マウスカーソル位置をセット
	x = pyxel.mouse_x
	y = pyxel.mouse_y

	xc = xmin + (xmax - xmin) * x / SCREEN_WIDTH
	yc = ymin + (ymax - ymin) * y / SCREEN_HEIGHT

	if( isZoom != 0 ):
		xstep = (xmax - xmin) * 2.0 * 0.5
		ystep = (ymax - ymin) * 2.0 * 0.5
	else:
		xstep = (xmax - xmin) * 0.5 * 0.5
		ystep = (ymax - ymin) * 0.5 * 0.5

	xmin = xc - xstep
	xmax = xc + xstep
	ymin = yc - ystep
	ymax = yc + ystep

	cal_mbrot()
#-----------------------------------------------------------------
#マウスボタン入力
#-----------------------------------------------------------------
def getInputML():
	if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
		return 1
	else:
		return 0

def getInputMR():
	if pyxel.btnp(pyxel.MOUSE_BUTTON_RIGHT):
		return 1
	else:
		return 0
#-----------------------------------------------------------------
#更新
def update():
	global max_i
	global xmin
	global xmax
	global ymin
	global ymax

	#深度変更:キー1,2,3,4,5,6,7,8,9,0
	if pyxel.btnp( pyxel.KEY_1 ):
		max_i = 1<<8
		cal_mbrot()
	elif pyxel.btnp( pyxel.KEY_2 ):
		max_i = 2<<8
		cal_mbrot()
	elif pyxel.btnp( pyxel.KEY_3 ):
		max_i = 3<<8
		cal_mbrot()
	elif pyxel.btnp( pyxel.KEY_4 ):
		max_i = 4<<8
		cal_mbrot()
	elif pyxel.btnp( pyxel.KEY_5 ):
		max_i = 5<<8
		cal_mbrot()
	elif pyxel.btnp( pyxel.KEY_6 ):
		max_i = 6<<8
		cal_mbrot()
	elif pyxel.btnp( pyxel.KEY_7 ):
		max_i = 7<<8
		cal_mbrot()
	elif pyxel.btnp( pyxel.KEY_8 ):
		max_i = 8<<8
		cal_mbrot()
	elif pyxel.btnp( pyxel.KEY_9 ):
		max_i = 9<<8
		cal_mbrot()
	elif pyxel.btnp( pyxel.KEY_0 ):
		max_i = 10<<8
		cal_mbrot()

	#拡大縮小
	if getInputML():
		zoom_set(0)
	elif getInputMR():
		zoom_set(1)

	#C/Gキーでグラデカラー/グレーカラー切り替え
	if pyxel.btnp(pyxel.KEY_C):
		pyxel.load("my_resource.pyxres", excl_images=True, excl_tilemaps=True, excl_sounds=True, excl_musics=True)
		cal_mbrot()
	elif pyxel.btnp(pyxel.KEY_G):
		pyxel.load("glaycolor.pyxres", excl_images=True, excl_tilemaps=True, excl_sounds=True, excl_musics=True)
		cal_mbrot()
	elif pyxel.btnp(pyxel.KEY_W):
		pyxel.load("getcol.pyxres", excl_images=True, excl_tilemaps=True, excl_sounds=True, excl_musics=True)
		cal_mbrot()

	#Rキーで初期画面にもどる
	elif pyxel.btnp(pyxel.KEY_R):
		max_i = 0x100
		xmin = -2.0
		xmax = 1.2
		ymin = -1.2
		ymax = 1.2
		cal_mbrot()
#-----------------------------------------------------------------
#描画
def draw():
	pyxel.cls(0)
	_screen_ptr = pyxel.screen.data_ptr()
	for _i in range(SCREEN_HEIGHT*SCREEN_WIDTH):
		_screen_ptr[_i] = pix[_i]
#-----------------------------------------------------------------
#パレットファイルを作成する
#-----------------------------------------------------------------
def get_color(alpha):
    shift = 0.0
    color = np.empty((3,), np.float32)
    color[0] = (np.cos((alpha*2.0-1.0+shift)*np.pi) + 1.0)
    color[1] = (np.cos((alpha*2.0-0.75+shift)*np.pi) + 1.0)
    color[2] = (np.cos((alpha*2.0-0.5+shift)*np.pi) + 1.0)
    return (color*(0.5*255)).astype(np.float32)
#-----------------------------------------------------------------
def make_palet():
	with open('./my_resource.pyxpal', mode='w') as f:
		#No.0の色を設定
		f.write( str(0)+'\n' )
		density = 0.35
		for y in range(1,255):
			alpha = y * 0.05 * density
			alpha = math.log(alpha+1)
			col = get_color( alpha )
			c0 = int(col[0])
			c1 = int(col[1])
			c2 = int(col[2])
			if(c0 > 255):
				c0 = 255
			if(c1 > 255):
				c1 = 255
			if(c2 > 255):
				c2 = 255
			coldata = c0*0x10000 + c1*0x100 + c2
			f.write( hex(coldata).removeprefix('0x')+'\n' )
#-----------------------------------------------------------------
pyxel.init(SCREEN_WIDTH, SCREEN_HEIGHT)
#パレットファイルを作成する
make_palet()
#255色カラーデータを読み込むためリソース読み込み
pyxel.load("my_resource.pyxres")
#初期画面作成
cal_mbrot()
#マウスカーソル表示
pyxel.mouse( visible = True )
#実行
pyxel.run(update, draw)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?