米MITメディアラボ開発
ビジュアル・プログラミング環境「Scratch」Web版version3
描画の高速化処理
令和6年9月18日
茂出木敏雄
ホームページ http://www.bekkoame.ne.jp/~modegi/
掲載プログラムの全データは上記サイトよりダウンロードできます。
Scratch_example.zip内の¥Scratch¥adv_h¥フォルダ

１２．拡張機能「ペン(２次元グラフィックス)」の高速化（１）：サインカーブ(1)第９章で紹介したサインカーブ”Scratch3_sine.sb3”につき、並列処理に対応できるように書き直したものが、次ページに示す”Scratch3_sine_single.sb3” である。
定義ブロック「波形表示」は、[X1,X2]の範囲でサインカーブの一部を描画し、描画範囲を複数個所設定して同時描画が可能になるように、マルチスレッドをサポートさせた。
また、処理時間を秒単位で計測できる「時間計測」ブロックも追加した（変数：Time）。
本プログラムで使用する変数として、幅、振幅、Time、X、Yの５点を定義しているが、「波形表示」ブロック内で使用する変数Xと変数Yは、マルチスレッドで動いている場合、各スレッド（スプライト）ごとに異なる値になるため、変数を定義する際、以下のようにローカル変数（このスプライトのみ）に変更設定する必要がある。他の３つの変数はプログラム内で共通して使用するため、デフォルトのグローバル変数（すべてのスプライト用）にする。

2

１２．拡張機能「ペン」の高速化（１）：サインカーブ(2)”Scratch3_sine_single.sb3”
3

１２．拡張機能「ペン」の高速化（１）：サインカーブ(3) プログラム部拡大”Scratch3_sine_single.sb3”

4

１２．拡張機能「ペン」の高速化（１）：サインカーブ(4) 実行部

ローカル変数（各スプライト内）”Scratch3_sine_single.sb3”

グローバル変数（プログラム全体で共有）
5

１２．拡張機能「ペン」の高速化（１）：サインカーブ(5) 描画処理の高速化
本章ではマルチスレッドを用いた高速化手法を紹介するのが主であるが、描画処理の高速化は、後述する並列処理（マルチスレッド）を用いるより、画面更新タイミングの設定変更を行う方が圧倒的に効果的である。デフォルトでは描画コマンドを実行する度に画面更新が行われ、描画経過が可視化される設定になっているが、以下のように、定義ブロック「波形表示」を右クリックして、編集メニューで「画面を再描画せずに実行する」を設定する。その設定を行ったのが、”Scratch3_sine_singleh.sb3” である。

6

１２．拡張機能「ペン」の高速化（１）：サインカーブ(6) マルチスレッド１
本節では４スレッド（スプライト）を並列実行させて描画を高速化する手法を紹介する。自分自身のクローン（スプライト）を３種生成して、自分自身をクローンIDを0として、クローンID:0～3の４種のクローンの各々に以下の設定で定義ブロック「波形表示」を並列実行させる。
クローン０： ０～幅／２
クローン１： 幅／２～幅
クローン２： 幅～幅×３／２
クローン３： 幅×３／２～幅×２本プログラムで使用するローカル変数として、IDとXSの２点を追加定義し、IDはローカル変数（このスプライトのみ）に変更設定する必要があるが、XSはデフォルトのグローバル変数（すべてのスプライト用）でもよい。
これらの設定を行ったのが、”Scratch3_sine_4clone.sb3” である。

7

１２．拡張機能「ペン」の高速化（１）：サインカーブ(7) マルチスレッド２”Scratch3_sine_4clone.sb3”

8

１２．拡張機能「ペン」の高速化（２）：シェーディング球(1)
陰影をつけた球体のイメージをピクセル単位に算出して描画する処理を、並列実行できるように作成したものが、次ページに示す”Scratch3_Sphere_single.sb3” である。
定義ブロック「球描画」は、(Xs,Ys)から(Xe,Ye)の矩形領域（Xs<Xe, Ys<Ye）で球体の一部を描画し、描画範囲を複数個所設定して同時描画が可能になるように、マルチスレッドをサポートさせた。
球体の原点を(0,0)、半径をSizeとして、ピクセル(X,Y)における球体の陰影V（明るさ）は、
R=(X2+Y2)1/2を算出し、R<Sizeの場合、V=100・(Size2－R2)1/2／Sizeで与える。
本プログラムで使用する変数として、Size、X、Y、R、Vの５点を定義しているが、「球描画」
ブロック内で使用する変数X、Y、R、Vは、マルチスレッドで動いている場合、各スレッド（スプライト）ごとに異なる値になるため、変数を定義する際、ローカル変数（このスプライトのみ）に変更設定する必要がある。変数Sizeはプログラム内で共通して使用するため、デフォルトのグローバル変数（すべてのスプライト用）にする。

9

１２．拡張機能「ペン」の高速化（２）：シェーディング球(2)”Scratch3_Sphere_single.sb3”

10

１２．拡張機能「ペン」の高速化（２）：シェーディング球(3) プログラム部拡大球の半径を設定”Scratch3_Sphere_single.sb3”
11

１２．拡張機能「ペン」の高速化（２）：シェーディング球(4) 実行部

ローカル変数（各スプライト内）

グローバル変数（プログラム全体で共有）”Scratch3_Sphere_single.sb3”

12

１２．拡張機能「ペン」の高速化（２）：シェーディング球(5) 描画処理の高速化
本章ではマルチスレッドを用いた高速化手法を紹介するのが主であるが、描画処理の高速化は、後述する並列処理（マルチスレッド）を用いるより、画面更新タイミングの設定変更を行う方が圧倒的に効果的である。デフォルトでは描画コマンドを実行する度に画面更新が行われ、描画経過が可視化される設定になっているが、以下のように、定義ブ
ロック「球描画」を右クリックして、編集メニューで「画面を再描画せずに実行する」を設定する。その設定を行ったのが、”Scratch3_Sphere_singleh.sb3” である。

13

１２．拡張機能「ペン」の高速化（２）：シェーディング球(6) マルチスレッド１
本節では４スレッド（スプライト）を並列実行させて描画を高速化する手法を紹介する。自分自身のクローン（スプライト）を３種生成して、自分自身をクローンIDを0として、クローン
ID:0～3の４種のクローンの各々に以下の矩形範囲の設定で定義ブロック「球描画」を並列実行させる。
クローン０： (-Size, -Size)～ (0, 0)
クローン１： (0, -Size)～ (Size, 0)
クローン２： (-Size, 0)～ (0, Size)
クローン３： (0, 0)～ (Size, Size)
本プログラムで使用するローカル変数として、IDを追加定義し、IDはローカル変数（このスプライトのみ）に変更設定する必要がある。
これらの設定を行ったのが、”Scratch3_Sphere_4clone.sb3” である。

14

１２．拡張機能「ペン」の高速化（２）：シェーディング球(7) マルチスレッド２”Scratch3_Sphere_4clone.sb3”

15

１２．拡張機能「ペン」の高速化（３）：市松模様球(1)
前ページまでの例題では、マルチスレッドによる並列処理の効果が、定義ブロックにおける画面更新タイミングの設定変更に比べて弱く、わかりにくかった。
本例題では描画負荷の大きい動画表示にて、マルチスレッドの効果を確認する。
市松模様のテクスチャを貼り付けた球体のイメージをピクセル単位に算出して描画する処理を、次ページ”Scratch3_SphereTex_single.sb3”に示す。
P.13と同様に、描画処理は、シングルスレッドで実行させ、定義ブロック「球描画」を右クリックして、編集メニューで「画面を再描画せずに実行する」を設定している。
グローバル変数Bs（変数BhはBs/2）で、市松模様テクスチャの格子ピッチ（単位：角度）を設定できるようにしている。
球体の半径Size内に含まれる描画する画素(X,Y)ごとに、球体におけるX方向の角度AxとY方向の角度Ayを360度単位で算出する。
各々Bsで割った余りをAx%Bs, Ay%Bsとすると、
Ax%Bs>Bs/2-1かつAy%Bs>Bs/2-1、またはAx%Bs<Bs/2かつAy%Bs<Bs/2の場合、画素(X,Y)を黒色で塗りつぶすようにした。

16

１２．拡張機能「ペン」の高速化（３）：市松模様球(2)”Scratch3_SphereTex_single.sb3”

17

１２．拡張機能「ペン」の高速化（３）：市松模様球(3) プログラム部拡大1”Scratch3_SphereTex_single.sb3”

18

１２．拡張機能「ペン」の高速化（３）：市松模様球(4) プログラム部拡大2球の半径を設定

格子ピッチを設定”Scratch3_SphereTex_single.sb3”

19

１２．拡張機能「ペン」の高速化（３）：市松模様球(5) 実行部”Scratch3_SphereTex_single.sb3”

20

１２．拡張機能「ペン」の高速化（４）：市松模様球の回転(1)
市松模様のテクスチャを貼り付けた球体のイメージで、テクスチャの格子を移動させながら複数回上書き描画させることにより、回転させた球体を描画させる処理を次ページ”Scratch3_SphereTexMovie_single.sb3”に示す。
P.13と同様に、描画処理は、シングルスレッドで実行させ、定義ブロック「球描画」を右クリックして、編集メニューで「画面を再描画せずに実行する」を設定している。
グローバル変数Bs（変数BhはBs/2）で、市松模様テクスチャの格子ピッチ（単位：角度）を設定するとともに、定義ブロック「球描画」のパラメータ(Bx,By)で、X方向のテクスチャの位相BxとY方向のテクスチャの位相Byを指定できるようにしている。
球体の半径Size内に含まれる描画する画素(X,Y)ごとに、球体におけるX方向の角度AxとY方向の角度Ayを360度単位で算出する。
テクスチャの位相(Bx,By)を考慮して、各方向の角度(Ax,Ay)をBsで割った余りを(Ax+Bx)%Bs, (Ay+By)%Bsとすると、(Ax+Bx)%Bs>Bs/2-1かつ(Ay+By)%Bs>Bs/2-1、または(Ax+By)%Bs<Bs/2かつ(Ay+By)%Bs<Bs/2の場合、画素(X,Y)を黒色で塗りつぶすように、これに該当しない場合、画素(X,Y)を背景色（白色）で塗りつぶすようにした。
テクスチャの位相(Bx,By)の各々を0～Bs-1の範囲で１づつ変化させて球体をBs回再描画させると、球体が45度方向に回転するアニメーションを表現できる。

21

１２．拡張機能「ペン」の高速化（４）：市松模様球の回転(2)”Scratch3_SphereTexMovie_single.sb3”

22

１２．拡張機能「ペン」の高速化（４）：市松模様球の回転(3)プログラム部拡大”Scratch3_SphereTexMovie_single.sb3”

23

１２．拡張機能「ペン」の高速化（４）：市松模様球の回転(4)プログラム部拡大2

C=0からC=19まで変化させながら、球体を20回再描画させてアニメーション動作をさせる。
”Scratch3_SphereTexMovie_single.sb3”

24

１２．拡張機能「ペン」の高速化（４）：市松模様球の回転(5) 実行部”Scratch3_SphereTexMovie_single.sb3”

25

１２．拡張機能「ペン」の高速化（４）：市松模様球の回転(6) マルチスレッド1
球体のサイズが大きいと動画表示がぎこちなくなる。
そこで、P.14と同様に表示対象画像を４分割し、各画像を表示する際、４スレッド（スプライト）に分割して並列実行させ、描画を高速化する手法を紹介する。
自分自身のクローン（スプライト）を３種生成して、自分自身をクローンIDを0として、クローンID:0～3の４種のクローンの各々に以下の矩形範囲の設定で定義ブロック「球描画」を並列実行させる。
クローン０： (-Size, -Size)～ (0, 0)
クローン１： (0, -Size)～ (Size, 0)
クローン２： (-Size, 0)～ (0, Size)
クローン３： (0, 0)～ (Size, Size)
本プログラムで使用するローカル変数として、IDを追加定義し、IDはローカル変数（このスプライトのみ）に変更設定する必要がある。
これらの設定で実装したのが、”Scratch3_SphereTexMovie_4clone.sb3” である。
次ページに示す、マルチスレッド対応の定義ブロック「球描画M」を追加して、定義ブロッ
ク「球描画」を呼ぶ代わりに、定義ブロック「球描画M」を呼ぶようにしている。定義ブロッ
ク「球描画」以下の処理は、”Scratch3_SphereTexMovie_single.sb3”と同様である。

26

１２．拡張機能「ペン」の高速化（４）：市松模様球の回転(7) マルチスレッド2”Scratch3_SphereTexMovie_4clone.sb3”

27

１２．拡張機能「ペン」の高速化（５）：フラクタル葉(1)フラクタル手法による自然画像生成の代表例である「バーンスレイのシダ」を計算描画する処理を、次ページ” Scratch3_barnsley_single.sb3”に示す。
P.13と同様に、描画処理は、シングルスレッドで実行させ、定義ブロック「Func」を右クリッ
クして、編集メニューで「画面を再描画せずに実行する」を設定している。
これは座標(xn,yn)に対して、以下４通りの座標変換を所定の確率でランダムに選択して実行し、座標変換後の座標(x,y)をプロットするとともに、その座標(x,y)を(xn,yn)として同様な座標変換を繰り返す手法である。初期座標を(0,0)とし、座標変換の反復を一定回数以上繰り返すと、シダの絵が生成できる。
［座標変換１］ 選択確率：1%
x=0
y = 0.16 * yn
［座標変換２］ 選択確率：85%
x = 0.85 * xn + 0.04 * yn
y = -0.04 * xn + 0.85 * yn + 1.6［座標変換３］ 選択確率：7%x = 0.20 * xn - 0.26 * yn
y = 0.23 * xn + 0.22 * yn + 1.6［座標変換４］ 選択確率：7%x = -0.15 * xn + 0.28 * yn
y = 0.26 * xn + 0.24 * yn + 0.44
28

１２．拡張機能「ペン」の高速化（５）：フラクタル葉(2)”Scratch3_barnsley_single.sb3”

29

１２．拡張機能「ペン」の高速化（５）：フラクタル葉(3) プログラム部拡大１”Scratch3_barnsley_single.sb3”

30

１２．拡張機能「ペン」の高速化（５）：フラクタル葉(4) プログラム部拡大２

反復回数を指定”Scratch3_barnsley_single.sb3”

31

１２．拡張機能「ペン」の高速化（５）：フラクタル葉(5) マルチスレッド１
反復回数により、描画処理時間が結構かかるが、以下のようにマルチスレッドにより高速化することができる。
前ページの例では、定義ブロック「Func」において、座標変換の反復回数を”200000”に設定していたが、定義ブロック「Func」は一度に実行せずに、”Scratch3_barnsley_4single.sb3”のように、反復回数を1/4の”50000”に設定して、４回に分けて実行させることもできる。
そこで、本節では４スレッド（スプライト）で定義ブロック「Func」を並列実行させて描画を４倍に高速化する手法を紹介する。
本プログラムで使用する変数X, Y, Rは、いずれもローカル変数（このスプライトのみ）に設定する必要がある。
これらの設定を行ったのが、”Scratch3_barnsley_4clone.sb3” である。
定義ブロック「WFｘｙ」「Func」「Point」は、” Scratch3_barnsley_single.sb3”と同じである。

32

１２．拡張機能「ペン」の高速化（５）：フラクタル葉(6) マルチスレッド２”Scratch3_barnsley_4clone.sb3”

33

１２．拡張機能「ペン」の高速化（５）：フラクタル葉(7) マルチスレッド３

定義ブロック「WFｘｙ」「Func」「Point」は、” Scratch3_barnsley_single.sb3”と同じ。

”Scratch3_barnsley_4clone.sb3”
34

１２．拡張機能「ペン」の高速化（５）：フラクタル葉(8) 枝葉の色分け
定義ブロック「Point」で枝を描画する際は茶色に着色するように色分けを行う。
定義ブロック「WFｘｙ」を過去の指定回数MPN（設定例:30）の中で、一度でも「num=1」で実行した場合は、「枝」と認識してペンの色を茶色に設定し、それ以外は「葉」として従来通り緑色に設定する。このような機能をもたせた定義ブロック「色設定」を追加し、実装したのが、”Scratch3_barnsley2c_4clone.sb3” である。

35

１２．拡張機能「ペン」の高速化（５）：フラクタル葉(9) 枝葉の色分け2

定義ブロック「Func」「Point」は、” Scratch3_barnsley_4clone.sb3”と同じ。

36

１２．拡張機能「ペン」の高速化（６）：フラクタル木(1)フラクタル手法による自然画像生成の代表例である「フラクタルツリー（樹木）」を計算描画する処理を、次ページ” Scratch3_ftree_single.sb3”に示す。
P.13と同様に、描画処理は、シングルスレッドで実行させ、定義ブロック「DrawTree」を右クリックして、編集メニューで「画面を再描画せずに実行する」を設定している。
定義ブロック「DrawTree」は、座標(X,Y)に対して、指定角度R、R+dR、R-dRの３方向に３本の枝を分岐・描画させる処理を、定義ブロック「DrawTree」を再帰的に３回呼ぶことにより深さN回（例：10）まで分岐実行させる方法をとっている。
３方向の枝を生成する際、中央の枝の長さは80%、左右の枝の長さは40～70%（乱数で決定）で減衰させる。中央の枝の方向は固定で、左右の枝の方向は各々+30～+70度と 30～-70度 （乱数で決定）で枝分かれさせる。

37

１２．拡張機能「ペン」の高速化（６）：フラクタル木(2)”Scratch3_ftree_single.sb3”

38

１２．拡張機能「ペン」の高速化（６）：フラクタル木(3) プログラム部拡大

再帰処理の深さを指定”Scratch3_ftree_single.sb3”

39

１２．拡張機能「ペン」の高速化（６）：フラクタル木(4) プログラム部拡大2”Scratch3_ftree_single.sb3”
40

１２．拡張機能「ペン」の高速化（６）：フラクタル木(5) 枝葉の色分け
定義ブロック「直線描画」で枝を描画する際は茶色に着色するように色分けを行う。
定義ブロック「DrawTree」で指定する深さNの値が、３を超える場合は、「枝」と認識してペンの色を茶色に設定し、それ以外は「葉」として従来通り緑色に設定する。
併せて、深さNの値により、枝の太さも変化させ、Nが３を超える場合は、ペンの太さをN/3画素に設定し、それ以下の場合はペンの太さを１画素に設定して描画する。
このような機能をもたせた定義ブロック「色設定」を追加し、実装したのが、”Scratch3_ftree2c_single.sb3” である。

定義ブロック「直線描画」は、” Scratch3_ftree_single.sb3”と同じ。

41

１２．拡張機能「ペン」の高速化（６）：フラクタル木(6) プログラム部拡大”Scratch3_ftree2c_single.sb3”
42

１２．拡張機能「ペン」の高速化（６）：フラクタル木(7) マルチスレッド１
定義ブロック「DrawTree」は、座標(X,Y)に対して、指定角度R、R+dR、R-dRの３方向に３本の枝を分岐・描画させる処理を、定義ブロック「DrawTree」を再帰的に３回呼ぶことにより深さN回（例：10）まで分岐実行させる方法をとっている。
そこで、１段下の深さN-1を指定し、再帰的に呼ばれる３種の定義ブロック「DrawTree」をマルチスレッドで並列実行させると、理論上、描画処理を３倍に高速化できる。
具体的には、シングルスレッドN=10で、drawTree(0,0,90,100,10)を実行させると、
drawTree(0,-100,90,80,9)、 drawTree(0,-50,140,50,9)、 drawTree(0,-50,40,50,9)の３種の定義ブロックがN=9で順次実行される。
そこで、自分自身のクローン（スプライト）を２種生成して、自分自身をクローンIDを0として、クローンID:0～2の３種のクローンの各々に、以下のパラメータ設定で定義ブロック「DrawTree 」を並列実行させる。
クローン０： drawTree(0,-50,40,50,9)
クローン１： drawTree(0,-100,90,80,9)
クローン２： drawTree(0,-50,140,50,9
本プログラムで使用するローカル変数として、IDを追加定義し、IDはローカル変数（このスプライトのみ）に変更設定する必要がある。
これらの設定で実装したのが、”Scratch3_ftree2c_3clone.sb3” である。

43

１２．拡張機能「ペン」の高速化（６）：フラクタル木(8) マルチスレッド2

定義ブロック「直線描画」「色設定」は、” Scratch3_ftree2c_single.sb3”と同じ。

”Scratch3_ftree2c_3clone.sb3”
44

１２．拡張機能「ペン」の高速化（６）：フラクタル木(9) プログラム部拡大”Scratch3_ftree2c_single.sb3”

45