Shade3D 公式

03 matrix module [ Shade Labo ]


#1

< 03 - 1 Reference >


Ver. 1.1( 2015 / 12 / 30 )

Affine 変換に関連した関数を追加

  • rotate_x( )
  • rotate_y( )
  • rotate_z( )
  • scale( )
  • translate( )
  • transform( )

関数 vec3_cross_matrix( ) において、返される vec3 のサイズが 3 になるように記述を追加


**Ver. 1.2**( 2016 / 01 / 23 )

transform( ) で引数として渡された list / tuple の中に vec3, list, tuple 以外のものがあってもエラーにはせず、そのままパスするように変更


Ver. 1.2.1( 2016 / 01 / 29 )

print が正常に出力されないバグを解消




関連記事 :

  • 01 はじめに
  • 02 vec3 module

module matrix は matrixr 演算を扱う class matrix( 小文字で始まる )を提供

matrix : list を継承した sub class
Shade script の list 引数としてそのまま使用できる


注記 - 1

この中で書かれている vec3 は custum class vec3 のことであり、Shade の script reference に書かれている vec3 は list3 あるいは [ float, float, float ] と記述します。


構成

以下のような構成の list を matrix class として定義する

_____ matrix = [ [ float, float, ‥], [ float, float, ‥], ‥, ‥ ] ] _____ scalar matrix
_____ matrix = [ [ vec3, vec3, ‥], [ vec3, vec3, ‥], ‥, ‥ ] ] ____ vec3 matrix

行 あるいは 列 ベクトルは 一行 / 一列 のみの matrix として次のように扱われる

_____ matrix = [ float, float, ‥] ____scalar matrix
_____ matrix = [ vec3, vec3, ‥] ___ vec3 matrix

これらは property : type で識別される

_____ type = 0 ___ m x n
_____ type = 1 ___ 1 x n 一行 matrix
_____ type = -1 ___ m x 1 一列 matrix

一行のみの matrix [ 1, 2, …, n ] type : 1 と 1 x n matrix [ [ 1, 2, …, n ] ] は同じものとして扱われる
一列のみの matrix [ 1, 2, …, m ] type : -1と m x 1 matrix [ [1], [2], …, [m] ] は同じものとして扱われる


init

mx = matrix( ) ___________ 0, 0 サイズの空 matrix

mx = matrix( m, n ) _______ m, n サイズの zero matrix ( m, n >= 1 ただし m + n > 2 )

mx = matrix( n ) __________ n, n サイズの 単位 matrix ( n >= 2 )

mx = matrix( vec3 ) _______ vec3 からの変換

mx = matrix( matrix ) ______ matrix の copy

mx = matrix( bool, list ) _____ list / tuple から 行 あるいは 列ベクトル( 一行 / 一列 のみの matrix )を作成
mx = matrix( bool, tuple ) ______ 一行 : bool = False, 一列 : bool = True

_________________________ [ float, float, ‥] ____scalar matrix
_________________________ [ vec3, vec3, ‥] ___ vec3 matrix
_________________________ [ list3, list3, ‥] ____ vec3 matrix
______________________________list3 = [ float, float, float ] ___ list3 は vec3 に変換される( tuple も同様 )


mx = matrix( list ) __________list / tuple からの変換
mx = matrix( tuple )

_________________________ [ [ float, float, ‥], [f loat, float, ‥], ‥, ‥ ] ] _____ scalar matrix
_________________________ [ [ vec3, vec3, ‥], [ vec3, vec3, ‥], ‥, ‥ ] ] ____ vec3 matrix
_________________________ [ [ list3, list3, ‥], [ list3, list3, ‥], ‥, ‥ ] ] _______ vec3 matrix
_______________________________ list3 = [ float, float, float ] ___ list3 は vec3 に変換される( tuple も同様 )


property( read only )

m as int _______行数を返す len(self) を参照
n as int _______ 列数を返す
len(self[0]) or len(self) を参照
vec3 as bool ___ vec3 matrix flag ___ self[0][0] or self[0] を参照
type as int _____ matrix type _______m x n : 0, 1 x n : 1, m x 1 : -1


注記 - 2

list を継承しているので list に係わる全ての関数が使用可能であり、矛盾する 行/列 数にしたり、不正な要素の代入もできてしまう

property m (行数), n (列数), vec3(vec3 matrix flag), type は read only で self, self[0], self[0][0] を参照して結果を返す

演算や関数処理では、この位置で得られるデータを matrix 全体の構成を規定する 正しいデータ と見なし、演算や関数処理の段階では、それを越える要素は無視され、要素数が少ない場合はエラーとなる


四則演算

s : scalar ( float or int )
v : vec3
M : scalar or vec3 matrix
sM : scalar matrix
vM : vec3 matrix

M = M + M ( sM + sM, vM + vM )
M = M - M ( sM - sM, vM - vM )
M = -M
M = M / s
M = M * s
M = s*M
sM = sM * sM
vM = vM * sM
vM = sM * vM
v = v * sM ( Affine 変換を想定し、matrix は 3 x 3 あるいは 4 x 4 size であること )
v = sM * v ( Affine 変換を想定し、matrix は 3 x 3 あるいは 4 x 4 size であること )

ただし、 演算結果がサイズ 1 X 1になる場合には、matrix ではなく、float or vec3 として返す


関数

transpose( )
_____自身を転置マトリックスに変換

inverse( ) as matrix
_____逆マトリックスを返す

_____行数と列数が等しく、vec3 matrix ではないこと
_____求められない場合は None が返される

transform( v as vec3 )
_____vec3 を Affine 変換 ( matrix size は 3 x 3 or 4 x 4 であること )

transform( L as list )
_____list に内包される全ての vec3 を Affine 変換


以下は 引数に応じた Affine 変換に用いられる 4 x 4 のマトリックスを返す関数で、自身のデータは一切使用しない。
通常は次の形で用いられる

mx = matrix( ).rotate_x( theta )
mx = matrix( ).rotate_y( theta )
mx = matrix( ).rotate_z( theta )
mx = matrix( ).scale( x, y, z )
mx = matrix( ).translate( x, y, z )


#2

< 03 - 2 使用例 >


改訂 - 1( 2015 / 12 / 30 ) 追加


init 1

from matrix import *	

m = matrix(3)		#  単位 matrix
print m

m = matrix(3, 3)	#  zero matrix
print m

**init 2, 転置**
from matrix import *	

m = matrix()		#  空 matrix
m.append([1,2,3])
m.append([4, 5, 6])
print m
m.transpose()		#  転置
print m


L = [[-1, -2, -3],[-4, -5, -6]]
m1 = matrix()		#  空 matrix
m1.extend(L)
print m1
m2 = matrix(m1)		# copy
print m2

**init 3**
from matrix import *

L = [1, 2, 3]
m1 = matrix(False, L)	#  行 あるいは 列ベクトルを作るときは、第一引数に bool を与える
print m1
L = [[1, 2, 3], [4, 5, 6], [7,8,9]]
m2 = matrix(True, L)	#  最下層の list は vec3 に変換
print m2
print m1*m2				#  1 x 1 size の matrix は matrix を外し中の要素を出して返す
print m2*m1

**init 4**
from matrix import *

L = [[1, 2, 3],[4, 5, 6],[7,8,9], [-1, -2, -3]]
m1 = matrix(L)
print m1
L = [[1, 2, 3, 4], [5, 6, 7, 8], [-1, -2, -3, -4]]
m2 = matrix(L)
print m2
m3 = m1*m2
print m3

**init 5**
from matrix import *

L = [[[1,2,3], [4,5,6], [7,8,9]], [[-1,-2,-3], [-4,-5,-6], [-7,-8,-9]], [[1,2,3], [4,5,6], [7,8,9]]]
m1 = matrix(L)			#  最下層の list は vec3 に変換
print m1
L = [1, 2, 3]
m2 = matrix(True, L)
print m2
m3 = m1*m2
print m3

**Affine 変換 - 1**( 2015 / 12 / 30 ) 追加 ( 2016 / 01 / 05 ) vec3List( ) を vec3list( ) に変更
from matrix import *
import copy
import math

def make_simple_line(pL, closed = False, name = None) :
	scene.begin_line(name, closed)
	for p in pL :
		scene.append_point(p, None, None, None, None)
	scene.end_line()

		
scene = xshade.scene()
scene.begin_creating()
scene.begin_part()

#  Affine 変換 1

#  original 形状
L = [[500, 1000, 2000], [1000, 1500, -500], [700, 800,1200]]
ob1 = vec3list(L)
make_simple_line(ob1, True, 'original')	

#  original の copy を回転
m2 = matrix().rotate_x(math.pi*120/180)
ob2 = copy.deepcopy(ob1)
m2.transform(ob2)	
make_simple_line(ob2, True, 'rotate')

#  original の copy を回転  ( alternate )
m2 = matrix().rotate_x(math.pi*120/180)
ob3 = []
for ob in ob1 :
	ob3.append(ob*m2)
make_simple_line(ob3, True, 'rotate alternate')


scene.end_part()     
scene.end_creating()

**Affine 変換 - 2**( 2015 / 12 / 30 ) 追加 ( 2016 / 01 / 05 ) vec3List( ) を vec3list( ) に変更
from matrix import *
import copy
import math

def make_simple_line(pL, closed = False, name = None) :
	scene.begin_line(name, closed)
	for p in pL :
		scene.append_point(p, None, None, None, None)
	scene.end_line()

		
scene = xshade.scene()
scene.begin_creating()
scene.begin_part()

#  Affine 変換 2

#  original 形状
L = [[500, 1000, 2000], [1000, 1500, -500], [700, 800,1200]]
ob1 = vec3list(L)
make_simple_line(ob1, True, 'original')	

ob2 = copy.deepcopy(ob1)

m1 = matrix().translate(2500, 2000, 1500)
m1.transform(ob2)
make_simple_line(ob2, True, 'translate')

m2 = matrix().rotate_x(math.pi*120/180)
m2.transform(ob2)	
make_simple_line(ob2, True, 'rotate X')

m3 = matrix().rotate_y(math.pi*120/180)
m3.transform(ob2)
make_simple_line(ob2, True, 'rotate Y')

m4 = matrix().rotate_z(math.pi*120/180)
m4.transform(ob2)
make_simple_line(ob2, True, 'rotate Z')

m5 = matrix().scale(2, 1.5, 1)
m5.transform(ob2)
make_simple_line(ob2, True, 'scale')

#  5 回の変換を 1 回で
m = m1*m2*m3*m4*m5
m.transform(ob1)
make_simple_line(ob1, True, 'compounded')

#  逆変換で元に戻す
m = m.inverse()
m.transform(ob1)
make_simple_line(ob1, True, 'return to original')

scene.end_part()     
scene.end_creating()

#3

< 03 - 3 Download >


Ver. 1.1( 2015 / 12 / 30 )

Affine 変換に関連した関数を追加

  • rotate_x( )
  • rotate_y( )
  • rotate_z( )
  • scale( )
  • translate( )
  • transform( )

関数 vec3_cross_matrix( ) において、返される vec3 のサイズが 3 になるように記述を追加


**Ver. 1.2**( 2016 / 01 / 23 )

transform( ) で引数として渡された list / tuple の中に vec3, list, tuple 以外のものがあってもエラーにはせず、そのままパスするように変更


Ver. 1.2.1( 2016 / 01 / 29 )

print が正常に出力されないバグを解消




ここからダウンロードして下さい。

          download

インストール方法は [ 01 はじめに ] を参照下さい。


#4

< 03 - 4 Download link 変更 >


download link 変更 ( 2017 / 03 / 12 )


ここからダウンロードして下さい。

          download


#5

< Ver.1.3 >


関数 init(self, *value)を修正しました。

( constructor 引数として matrix を与えるケースに対する記述部分 )


一部のケースで引数の copy を作るはずの所で同一 list が渡されていたのを修正しました。


この修正によって、M3 = M1 + M2 や M3 = 2*M1 の計算において

  • Ver.1.2.1 まで : M1 の値も変更されてしまい、M1 = M3 となっていた
  • Ver.1.3 以降 : M1 の値は変更されない

Shade Labo の中では matrix + matrix や scalar * matrix の演算は行っていませんので、影響はありません。


Ver.1.2.1
#	init( )	######	
def __init__(self, *value) :
	‥
	‥
	elif index == 4 :						#  m = matrix(matrix)
		self.__type = value[0].__type
		self.extend(value[0])				#  行/列 数, 要素の型 チェックは行わない


Ver.1.3
#	init( )	######	
def __init__(self, *value) :
	‥
	‥
	elif index == 4 :	
		self.__type = value[0].__type

		if self.__type != 0 :				
			self.extend(value[0])
		else :
			if not self.__vec3 :
				n = len(value[0])
				mx = []
				for i in range(n) :
					mx.append(list(value[0][i]))
				self.extend(mx)					#  行/列 数, 要素の型 チェックは行わない
			else :
				n = len(value[0])
				m = len(value[0][0])
				mx = []
				for i in range(n) :
					mx2 = []
					for j in range(m) :
						mx2.append(list(value[0][i][j]))
					mx.append(mx2)
				self.extend(mx)					#  行/列 数, 要素の型 チェックは行わない

#6

< Ver. 1.3.1 >


ver.1.3 で修正した部分を 関数 copy.deepcopy( ) を用いた簡潔な記述に変更しました。


Ver.1.3.1

from vec3 import *	
import math
from copy import deepcopy		#  ver. 1.3.1 で追加
‥
‥
	#	init( )	######	
	def __init__(self, *value) : 
		‥
		‥
		elif index == 4 :						#  m = matrix(matrix)	ver. 1.3.1 にて修正
			self.__type = value[0].__type
			self.extend(deepcopy(value[0]))		#  要素数, 要素の型 チェックは行わない
		‥