Last active
September 20, 2020 08:33
-
-
Save HarukaKajita/5d57c9c2c01b9c93ae57421068888b8e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import hou | |
class Transform(object): | |
translation = [] | |
rotation = [] | |
scale = [] | |
def __init__(self, t, r, s): | |
self.translation = t | |
self.rotation = r | |
self.scale = s | |
def get_matrix(self): | |
scale_mat = hou.hmath.buildScale(self.scale[0], self.scale[1], self.scale[2]) | |
rot_mat = hou.hmath.buildRotate(self.rotation[0], self.rotation[1], self.rotation[2], "xyz") | |
trans_mat = hou.hmath.buildTranslate(self.translation[0], self.translation[1], self.translation[2]) | |
matrix = scale_mat * rot_mat | |
matrix = matrix * trans_mat | |
return matrix | |
class Exporter(object): | |
attributes = {} | |
namePathDic = {} | |
pathToParentInvertedMaterix = {} | |
pathToParentMatrixScale = {} | |
pathToHierarchyPath = {} | |
def __init__(self): | |
self.hda_node = hou.pwd().parent() | |
self.export_node = self.hda_node.node('sopnet1') | |
self.geo = self.export_node.displayNode().geometry() | |
def float_to_vector(self, floats): | |
return [floats[i:i + 3] for i in range(0, len(floats), 3)] | |
def vec3_mul_vec3(self, vec0, vec1): | |
vec2 = hou.Vector3(1,1,1) | |
vec2[0] = vec0[0] * vec1[0] | |
vec2[1] = vec0[1] * vec1[1] | |
vec2[2] = vec0[2] * vec1[2] | |
return vec2 | |
def vec3_div_vec3(self, vec0, vec1): | |
vec2 = hou.Vector3(1,1,1) | |
vec2[0] = vec0[0] / vec1[0] | |
vec2[1] = vec0[1] / vec1[1] | |
vec2[2] = vec0[2] / vec1[2] | |
return vec2 | |
def get_transform_components(self): | |
#アトリビュート名取得 | |
trans_attrib = self.hda_node.evalParm("translationattrib") | |
rot_attrib = self.hda_node.evalParm("rotationattrib") | |
scale_attrib = self.hda_node.evalParm("scaleattrib") | |
#なんかこれがfullpathの数と一致するっぽい | |
point_num = len(self.geo.points()) | |
translations = self.geo.pointFloatAttribValues(trans_attrib) | |
rotations = self.geo.pointFloatAttribValues(rot_attrib) | |
scales = self.geo.pointFloatAttribValues(scale_attrib) | |
if translations: | |
translations = self.float_to_vector(translations) | |
else: | |
translations = [[0,0,0] for i in range(point_num)] | |
if rotations: | |
rotations = self.float_to_vector(rotations) | |
else: | |
rotations = [[0,0,0] for i in range(point_num)] | |
if scales: | |
scales = self.float_to_vector(scales) | |
else: | |
scales = scales = [[1,1,1] for i in range(point_num)] | |
transforms = [Transform([0,0,0], [0,0,0], [1,1,1])] * point_num | |
for i in range(point_num): | |
transforms[i] = Transform(translations[i], rotations[i], scales[i]) | |
return transforms | |
def set_transform(self, geo_node, trans, rot, scale): | |
geo_node.parmTuple('s').set(scale) | |
geo_node.parmTuple('r').set(rot) | |
geo_node.parmTuple('t').set(trans) | |
def create_fbx_parm(self, node, path): | |
# パスから名前を取得 | |
name = path.split('/')[-1] | |
# ノードのパラメータテンプレートを取得 | |
group = node.parmTemplateGroup() | |
# FBXの階層用パラメータを追加 | |
path_parm = hou.StringParmTemplate('fbx_node_path', 'fbx_node_path', 1) | |
path_parm.setDefaultValue((path,)) | |
name_parm = hou.StringParmTemplate('fbx_node_name', 'fbx_node_name', 1) | |
name_parm.setDefaultValue((name,)) | |
# パラメータテンプレートに追加 | |
group.append(path_parm) | |
group.append(name_parm) | |
# パラメータテンプレートを設定 | |
node.setParmTemplateGroup(group) | |
def create_obj_nodes(self, objnet_node, path, exist_paths): | |
# 階層ごとに分ける | |
node_paths = path.split('/') | |
print(str(len(node_paths)) + " : " + path) | |
# 階層が一つしかない場合 | |
# if len(node_paths) == 1: | |
# name = node_paths[0] | |
# geo_node = objnet_node.createNode('geo', node_name=name) | |
# geo_node.moveToGoodPosition() | |
# # node_path = '/'.join(node_paths[0]) | |
# # exist_paths[node_path] = geo_node | |
# return geo_node | |
# 階層が複数ある場合 | |
parent_nodes = [] | |
matrix = hou.Matrix4(1) | |
#親のTransfotmをMatrixで積んでく | |
for i, current_name in enumerate(node_paths): | |
# 作ったノードを記録するためにノードパスを取得 | |
node_path = '/'.join(node_paths[:i+1]) | |
# すでに作ったノードの場合 | |
if node_path in exist_paths: | |
parent_node = exist_paths[node_path] | |
parent_nodes.append(parent_node) | |
continue | |
# 名前がLODGroupだったらヌル、それ以外だったらGeometryノードを作る | |
if current_name == 'LODGroup': | |
node = objnet_node.createNode('null', node_name=current_name) | |
node.moveToGoodPosition() | |
else: | |
node = objnet_node.createNode( | |
'geo', node_name=current_name, run_init_scripts=False | |
) | |
node.moveToGoodPosition() | |
node_correctname = node.name() | |
self.namePathDic[node_correctname] = node_path | |
# ルートノード以外はインプットを繋げる | |
if i != 0: | |
parent_node = parent_nodes[-1] | |
node.setInput(0, parent_node) | |
# FBXの階層を作るためのパラメータを追加 | |
self.create_fbx_parm(node, node_path) | |
# ノードを親ノードとして追加 | |
parent_nodes.append(node) | |
# ノードをすでに作ったノードとして記録 | |
exist_paths[node_path] = node | |
matrix *= node.localTransform().inverted() | |
# アトリビュートで指定したTransform値を入力する | |
# 親の逆変換をしたのちにアトリビュートで指定したTransform値を入力する | |
geo_node = parent_nodes[-1] | |
parent_matrix_scale = geo_node.worldTransform().extractScales('srt') | |
print("world Transformのスケール") | |
print(parent_matrix_scale) | |
inverted_parent = geo_node.worldTransform().inverted() | |
self.pathToParentInvertedMaterix[geo_node.path()] = inverted_parent | |
matrix = self.attributes[path].get_matrix() | |
trans = matrix.extractTranslates('srt') | |
trans = self.vec3_div_vec3(trans, parent_matrix_scale) | |
rot = matrix.extractRotates('srt', 'xyz') | |
scale = matrix.extractScales('srt') | |
self.set_transform(geo_node, trans, rot, scale) | |
self.pathToParentMatrixScale[geo_node.path()] = self.vec3_mul_vec3(parent_matrix_scale, scale) | |
print("Attributeで指定したTransformはこれ!") | |
print(trans) | |
print(rot) | |
print(scale) | |
return geo_node | |
def create_nodes_in_geo(self, geo_node, group, parent_Scale): | |
obj_merge = geo_node.createNode('object_merge') | |
obj_merge.parm('objpath1').set(self.export_node.path()) | |
obj_merge.parm('group1').set(group) | |
#Transformもつけとく | |
currentParent_node = obj_merge | |
transform_sop = geo_node.createNode('xform') | |
transform_sop.setInput(0, currentParent_node) | |
transform_sop.setDisplayFlag(True) | |
transform_sop.setRenderFlag(True) | |
obj_merge.setDisplayFlag(False) | |
obj_merge.setRenderFlag(False) | |
transform_sop.moveToGoodPosition() | |
#ここ以降は後でやるべき | |
parent = transform_sop.parent() | |
matrix = hou.Matrix4(1) | |
# if parent_inputs_num == 1 : | |
obj_node = parent#parent_inputs[0] | |
matrix = obj_node.worldTransform().inverted() | |
trans = matrix.extractTranslates('srt') | |
rot = matrix.extractRotates('srt', 'xyz') | |
scale = matrix.extractScales('srt') | |
print("world Transform") | |
print(trans) | |
print(rot) | |
print(scale) | |
self.set_transform(transform_sop, trans, rot, scale) | |
def export(self): | |
self.attributes = {} | |
self.namePathDic = {} | |
self.pathToParentInvertedMaterix = {} | |
self.pathToParentMatrixScale = {} | |
self.pathToHierarchyPath = {} | |
print("START EXPORT\n") | |
print("objnet 取得") | |
objneet_node = self.hda_node.node("objnet1") | |
print("pathattribute を値列を取得") | |
path_attrib = self.hda_node.evalParm("pathattrib") | |
full_path_list = self.geo.primStringAttribValues(path_attrib) | |
print("full_path_list") | |
for full_path in full_path_list: | |
print(full_path) | |
#なんかこれがfullpathの数と一致するっぽい | |
#pointのattributeとprimのpathnameの数はsopnetでそろってる | |
#transformの配列を取得 | |
point_num = len(self.geo.points()) | |
transforms = [Transform((0,0,0), (0,0,0), (1,1,1))] * point_num | |
transforms = self.get_transform_components() | |
#transformをグローバルに。 | |
for num, full_path in enumerate(full_path_list): | |
self.attributes[full_path] = transforms[num] | |
#親階層側から並ぶようにソート | |
pathDepthDic = {} | |
for key in self.attributes.keys(): | |
pathDepthDic[key] = key.count("/") | |
pathDepthDic = sorted(pathDepthDic.items(), key=lambda x:x[1]) | |
for v in pathDepthDic: | |
print(v) | |
#objのネットワークを作ってAttributeで指定したTransform値を入れるだけ | |
print("一回目のfor文だよ!") | |
exist_paths = {} | |
for pathDepthPair in pathDepthDic: | |
# 階層の作成 | |
hierarchy_path = pathDepthPair[0] | |
pathDepth = pathDepthPair[1] | |
#geometryノードツリーを作って、attributeで指定されたTransformを書き込む | |
#(この変換に) | |
geo_node = self.create_obj_nodes(objneet_node, hierarchy_path, exist_paths) | |
self.pathToHierarchyPath[geo_node.path()] = hierarchy_path | |
print("") | |
print("二回目のfor文だよ!") | |
for path in self.pathToParentInvertedMaterix: | |
hierarchy_path = self.pathToHierarchyPath[path] | |
parent_Scale = self.pathToParentMatrixScale[path] | |
node = hou.node(path) | |
# 一番子供のGeometryノードにObject Mergeを作成 | |
print("@" + path_attrib + "=" + hierarchy_path) | |
self.create_nodes_in_geo(node, "@" + path_attrib + "=" + hierarchy_path, parent_Scale) | |
print("export fin.") | |
def cleanup(self): | |
objneet_node = self.hda_node.node('objnet1') | |
objneet_node.deleteItems(objneet_node.children()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment