2009年1月2日金曜日

blender - ボーン座標を利用した線形グラデーションpyNode

右のギャラリーで、MNRNの髪がリアルタイムレンダのほうが良い気がするのは、グラデーション効果です。プログラミングと同じく、モデリング時解決(テクスチャ)ではなく、レンダリング時解決(Node)で汎用性をあげています。とか言ってみたり。



下記スクリプトを、Blenderのテキストエディタにコピーします。
UPPERBONEとLOWERBONEを、グラデーションしたい区間が覆われるように指定します。
今回はy軸(上下)しか見ていないので、髪でしたら頭の上と頭の下が覆われるようなボーンを、それぞれ指定します。
また、ボーン座標はheadとtailを見ているので、
Uxy = Mathutils.Vector(pbone.tail.x, pbone.tail.y)
Lxy = Mathutils.Vector(pbone.head.x, pbone.head.y)
このheadとtailを必要に応じて変えるか、必要に応じてスクリプト自体を改造してください。

そして、マテリアルノードのDynamicから選択してください。結構重いです・・。

動いたらどうなるかというと、ボーンも動くから多分追従します。
ただし、今回はy軸しか見てないので、お辞儀すると変になります。


15:16追記 やっぱちょっと変かも。修正考え中


import Blender
from Blender import *

UPPERBONE = 'atama'
LOWERBONE = 'mune'

class Gradation1D(Node.Scripted):
def _abs(self, val):
if val < 0:
return -val
return val

def _getLerpVal1D(self, vU, vL, vP):
yVal = self._abs(vP.y - vL.y) / self._abs(vU.y - vL.y)
#print vP.y, vL.y, vU.y
return yVal


def __init__(self, sockets):
sockets.input = [Node.Socket('Local', val = 3*[1.0])]
sockets.output = [Node.Socket('Fac', val = 3*[1.0])]

def __call__(self):
sce = Scene.GetCurrent()

Pxy = Mathutils.Vector(self.input.Local[0], self.input.Local[1])
Uxy = Mathutils.Vector(0, 0)
Lxy = Mathutils.Vector(0, 0)

for obj in sce.objects:
if obj.type == 'Armature':
pose = obj.getPose()
for pbone in pose.bones.values():
if pbone.name == UPPERBONE:
Uxy = Mathutils.Vector(pbone.tail.x, pbone.tail.y)
if pbone.name == LOWERBONE:
Lxy = Mathutils.Vector(pbone.head.x, pbone.head.y)

amount = self._getLerpVal1D(Uxy, Lxy, Pxy)
fac = 3*[1.0]
fac[0] = amount
fac[1] = amount
fac[2] = amount
self.output.Fac = fac

__node__ = Gradation1D

0 件のコメント: