Shade3D 公式

13 Bezier Surface 基礎 [ Shade Labo ]


#1

13 - 1 座標


16個の bezier patch 座標 [ **p** ] と bezier parameter s, t での bezier surface 上の座標 **P**( s, t ) を求める。

     

     [ 式 13 - 1 ]


よって bezier surface 上の座標 P( s, t ) を求める関数は次のようになり、module labo に登録してあります。


[ script 13 - 1 ]

#  bezier_surface_position(bP as vec3 matrix, s as float, t as float) as vec3
#
#	bezier patch bP の parameter s, t における座標値を返す

def bezier_surface_position(bP, s, t) :
	if bP == None :
		return None

	S = bezier_t(s)				#  [S]
	M = bezier_m()				#  [M]
	T = bezier_t(t, True)		#  [T]
	return S*M*bP*M*T

#2

13 - 2 U, V 方向 Bezier Line


bezier patch [ **p** ] で与えられる bezier surface 上の と bezier parameter s で指定される **U** 方向 bezer line 制御点座標 [ **Pu** ] を求める。

          [ 式 13 - 2 ]


bezier patch [ p ] で与えられる bezier surface 上の と bezier parameter t で指定される** V**方向 bezer line 制御点座標 [ Pv ] を求める。

          [ 式 13 - 3 ]


よって bezier surface 上の parameter s, t における U, V 方向 bezier line を求める関数は次のようになり、module labo に登録してあります。


[ script 13 - 2 ]

#  bezier_surface_u_line(bP as vec3 matrix, s as float, m as bool = False) as vec3 list or vec3 matrix
#
#	bezier patch bP の parameter s における U 方向 bnezier line を返す
#	m = False ならば返り値は vec3 list,   m = True ならば vec3 matrix とする

def bezier_surface_u_line(bP, s, m = False) :
	if bP == None :
		return None

	S = bezier_t(s)				
	M = bezier_m()	
	if not m :			
		return list(S*M*bP)			#  vec3 list に変換して返す		
	else :
		return S*M*bP				#  一行 matrix			

	
	
#  bezier_surface_v_line(bP as vec3 matrix, t as float, m as bool = False) as vec3 list or vec3 matrix
#
#	bezier patch bP の parameter t における V 方向 bnezier line を返す
#	m = False ならば返り値は vec3 list,   m = True ならば vec3 matrix とする

def bezier_surface_v_line(bP, t) :
	if bP == None :
		return None

	T = bezier_t(t, True)		
	M = bezier_m()		
	if not m :		
		return list(bP*M*T)			#  matrix を vec3 list に変換して返す
	else :
		return bP*M*T				#  一列 matrix

次の script は、Shade 上で選択した自由曲面の [ 0, 0 ]の区間の bezier parameter s = 0.5, t = 0.5 での **U**, **V** 方向 bezier line を求め、線形状として出力します。
[ script 13 - 3 ]
import labo

scene = xshade.scene()

m = 0							#  ブロック No.
n = 0							#  ブロック No.

bP = labo.get_bezier_patch(xshade, m, n)
s = 0.5
t = 0.5
Pu = labo.bezier_surface_u_line(bP, s)
Pv = labo.bezier_surface_v_line(bP, t)

scene.create_part()
labo.make_bezier_line(xshade, Pu, 's = ' + str(s))
labo.make_bezier_line(xshade, Pv, 't = ' + str(t))
scene.select_parent(1)

#3

13 - 3 U, V 方向 接線ベクトル


関連記事:
  • 06 Bezier Line 基礎
  • 09 Bezier Line 接線ベクトル

bezier patch [ **p** ] で与えられる bezier surface 上の と bezier parameter s, t で指定される **U** 方向接線ベクトル **Vu** を求める。

     

     [ 式 13 - 4 ]




bezier patch [ p ] で与えられる bezier surface 上の と bezier parameter s, t で指定される V 方向接線ベクトル Vv を求める。

          [ 式 13 - 5 ]


[ 式 06 - 2 ], [ 式 13 - 4 ], [ 式 13 - 5 ] より、U, V 方向接線ベクトルは bezier surface 上の U, V 方向 bezier line を求め、そこから接線ベクトルを求めるわけですから、[ script 09 - 1 ] に記した module labo に登録されている bezier line から接線ベクトルを返す関数 bezier_line_tangent( ) をそのまま利用できます。

また、それによって ハンドルが出ていないケースでのアンカーポイント上での接線ベクトルの問題( 09 - 2 参照 ) も同時に解決されます。

一方、球の極では、V 方向 control point が一点に収束していますから、t = 0( あるいは t = 1 ) における V 方向線形状は定義できず、接線ベクトルも存在しません。

しかし bezier parameter を限りなく 0 に近づけていく方法で、極での接線ベクトルを求めることも可能で、別記事で取り上げます。




以上から bezier surface 上の parameter s, t における U, V 方向接線ベクトルを求める関数は次のようになり、module labo に登録してあります。


[ script 13 - 4 ]

#  bezier_surface_u_tangent(bP as vec3 matrix, s as float, t as float) as vec3
#
#	bezier patch bP の parameter s, t における U 方向接線ベクトルを返す

def bezier_surface_u_tangent(bP, s, t) :
	if bP == None :
		return None
		
	Pu = bezier_surface_u_line(bP, s, True)				#  U 方向線形状	
	return bezier_line_tangent(Pu, t)	

			

		
#  bezier_surface_v_tangent(bP as vec3 matrix, s as float, t as float) as vec3
#
#	bezier patch bP の parameter s, t における V 方向接線ベクトルを返す

def bezier_surface_v_tangent(bP, s, t) :
	if bP == None :
		return None
		
	Pv = Pu = bezier_surface_v_line(bP, t, True)		#  V 方向線形状	
	return bezier_line_tangent(Pv, s))

#4

13 - 4 法線ベクトル


bezier patch [ **p** ] で与えられる bezier surface 上の と bezier parameter s, t で指定される法線ベクトル **Vn** を求める。

          [ 式 13 - 6 ]


よって bezier surface 上の parameter s, t における 法線ベクトルを求める関数は次のようになり、module labo に登録してあります。

なお、この関数では Shade 自由曲面の 切り替え は考慮していません。
もし、xshade.active_shape().flip_face = True ならば、面法線の向きは逆転します。


[ script 13 - 5 ]

#  bezier_surface_normal(bP as vec3 matrix, s as float, t as float) as vec3
#
#	bezier patch bP の parameter s, t における 法線ベクトルを返す
#	Shade 自由曲面の 切り替え は考慮していない

def bezier_surface_normal(bP, s, t) :
	if bP == None :
		return None
		
	Vu = bezier_surface_u_tangent(bP, s, t)
	Vv = bezier_surface_v_tangent(bP, s, t)
	
	if Vu == None or Vv == None :
		return None
	else :
		Vn = Vu*Vv
		Vn.norm()
		return Vn

次の script は、Shade 上で選択した自由曲面の [ 0, 0 ] 区間の bezier parameter s = 0, 0.25, 0.5, 0.75, 1, t = 0, 0.25, 0.5, 0.75, 1 での **U**, **V** 方向接線ベクトルと法線ベクトルを求め、そのマーカーを線形状として出力します。

極では、一方向の接線ベクトルしか表示されません。


[ script 13 - 6 ]

import labo

scene = xshade.scene()

m = 0							#  ブロック No.
n = 0							#  ブロック No.

bP = labo.get_bezier_patch(xshade, m, n)
bb = labo.vec3_bounding_box_size(bP)
r = bb[3]/16									#  マーカーサイズ

scene.create_part('接線, 法線')

for s in [0, 0.25, 0.5, 0.75, 1] :
	for t in [0, 0.25, 0.5, 0.75,  1] :
		p = labo.bezier_surface_position(bP, s, t)			#  座標値
		Vu = labo.bezier_surface_u_tangent(bP, s, t)		#  U 方向接線ベクトル
		Vv = labo.bezier_surface_v_tangent(bP, s, t)		#  V 方向接線ベクトル
		Vn = labo.bezier_surface_normal(bP, s, t)			#  法線ベクトル

		L = [p, p + r*Vu, p + r/2*Vv, p, p + r*Vn]			#  マーカー

		labo.make_simple_line(xshade, L, False, 's = ' + str(s) + '     t = ' + str(t))
		
scene.select_parent(1)