Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support to c4d and blender #6

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: add support to c4d and blender
kezan31 committed Jan 16, 2025
commit c8ba49abdc35f44e1d3530d161d7ddca0d66ef59
4 changes: 2 additions & 2 deletions assets/HDAs/OmooLab_Integration.hda
Git LFS file not shown
4 changes: 2 additions & 2 deletions assets/HDAs/OmooLab_Pipeline.hda
Git LFS file not shown
2 changes: 1 addition & 1 deletion plugins/blender/omoo_asset/__init__.py
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@
"author": "MaNan",
"description": "",
"blender": (2, 80, 0),
"version": (0, 0, 1),
"version": (0, 0, 3),
"location": "File > Import-Export",
"warning": "",
"category": "Import-Export"
160 changes: 140 additions & 20 deletions plugins/blender/omoo_asset/io.py
Original file line number Diff line number Diff line change
@@ -18,10 +18,30 @@


NODE_DICT = {
"BaseColorMix": {
"type": "mix",
"to": ["SurfaceShader:Base Color"]
},
"SubsurfaceRadiusMix": {
"type": "mix",
"to": ["SurfaceShader:Subsurface Radius"]
},
"PointColor": {
"type": "attribute", # 用来标记它是一个从顶点色读取的节点
"default": "displayColor",
"source": "PointColor:varname", # 顶点色的默认来源
"to": ["BaseColorMix:2","SubsurfaceRadiusMix:2"]
},
"PointColorWeight": {
"type": "float",
"default": 0.0,
"source": "PointColorWeight:value",
"to": ["BaseColorMix:0","SubsurfaceRadiusMix:0"]
},
"BaseColor": {
"type": "color_tex",
"source": "BaseColor:file",
"to": ["SurfaceShader:Base Color"]
"to": ["BaseColorMix:1"]
},
"Metalness": {
"type": "float_tex",
@@ -95,7 +115,7 @@
"SubsurfaceRadius": {
"type": "color_tex",
"source": "SubsurfaceRadius:file",
"to": ["SurfaceShader:Subsurface Radius"]
"to": ["SubsurfaceRadiusMix:1"]
},
"SubsurfaceScale": {
"type": "float",
@@ -187,7 +207,8 @@
"default": 0.0,
"source": ":displacement_on",
"to": ["DisplacementShader:Scale"]
}
},

}

PROP_DICT = {
@@ -253,9 +274,12 @@ def execute(self, context):
geometry_paths = []
for geometry_prim in geometries_prim.GetChildren():
geometry_paths.append(geometry_prim.GetPath())

print("file_path",file_path)

# import usd
bpy.ops.wm.usd_import(filepath=file_path.as_posix(), relative_path=True)
# bpy.ops.wm.usd_import(filepath=file_path.as_posix(), relative_path=True)
bpy.ops.wm.usd_import(filepath=str(file_path), relative_path=True)

# edit materials
materials = set()
@@ -282,7 +306,11 @@ def execute(self, context):
links = material.node_tree.links

# Modify/Create "Surface Shader" and "Displacement Shader"
surface_node = nodes.get("Principled BSDF")
surface_node = None
for node in nodes:
if node.type == 'BSDF_PRINCIPLED':
surface_node = node
break # 找到后立即停止遍历
surface_node.name = "SurfaceShader"
surface_node.label = "SurfaceShader"

@@ -291,8 +319,13 @@ def execute(self, context):
displacement_node.label = "DisplacementShader"
displacement_node.inputs[1].default_value = 0

out_node = nodes.get("Material Output")

# 查找类型为 OUTPUT_MATERIAL 的节点
out_node = None
for node in nodes:
if node.type == 'OUTPUT_MATERIAL':
out_node = node
break # 找到后停止遍历

links.new(
displacement_node.outputs[0],
out_node.inputs['Displacement']
@@ -342,23 +375,42 @@ def execute(self, context):
# get texture default value
tex_default_value = 0.0 if node_type == "float_tex" else (
0.0, 0.0, 0.0, 0.0)

if shader_prim.IsValid():
shader_default = shader_prim.GetAttribute(
"inputs:default")
if shader_default.IsValid():
tex_default_value = shader_default.Get(0)
if node_type != "float_tex":
tex_default_value = (
tex_default_value[0], tex_default_value[1], tex_default_value[2], 1.0)
# print(tex_default_value)
if shader_default.Get(0) != None:
tex_default_value = shader_default.Get(0)
print(f"{node_name}",tex_default_value)
if node_type != "float_tex":
tex_default_value = (
tex_default_value[0], tex_default_value[1], tex_default_value[2], 1.0)


if node_value:
# blender cannot read UNC path with slash
node_value = node_value.replace("/", "\\")
node = nodes.new('ShaderNodeTexImage')
node.image = bpy.data.images.load(node_value)
node.image.source = 'TILED'
node.image.colorspace_settings.name = 'Linear Rec.709 (sRGB)'\
if node_type == "color_tex" else 'Raw'

# 尝试设置颜色空间为 Linear Rec.709 (sRGB) 或 Linear Rec.709
try:
if node_type == "color_tex":
# 首先尝试设置为 'Linear Rec.709 (sRGB)'
node.image.colorspace_settings.name = 'Linear Rec.709 (sRGB)'
else:
# 如果是非颜色纹理,使用 'Non-Color'
node.image.colorspace_settings.name = 'Raw'
except Exception as e:
print(f"Error setting colorspace for {node_value}: {e}")
# 如果出错,则设置为 'Linear Rec.709'
if node_type == "color_tex":
node.image.colorspace_settings.name = 'Linear Rec.709'
else:
# 如果是非颜色纹理,使用 'Non-Color'
node.image.colorspace_settings.name = 'Non-Color'
else:
# if not get any texture use constant value node
node = nodes.new('ShaderNodeRGB') \
@@ -396,7 +448,15 @@ def execute(self, context):
elif node_type == "float":
node = nodes.new('ShaderNodeValue')
node.outputs[0].default_value = node_value


elif node_type == "attribute":
# 新增:处理顶点色的读取节点
node = nodes.new('ShaderNodeAttribute')
node.attribute_name = node_value # 使用 default 或 source 中的属性名

elif node_type == "mix":
# 创建一个 Mix RGB 节点
node = nodes.new('ShaderNodeMixRGB')
else:
...

@@ -434,7 +494,8 @@ def execute(self, context):

surface_node.inputs[prop_name].default_value = prop_value

surface_node.subsurface_method = 'BURLEY'
# surface_node.subsurface_method = 'BURLEY'
surface_node.subsurface_method = 'RANDOM_WALK'
nodes["SubsurfaceScale"].outputs[0].default_value *= 10
nodes["CombinedNormal"].inputs[0].default_value = 0.5

@@ -443,17 +504,76 @@ def execute(self, context):
material.cycles.displacement_method = 'DISPLACEMENT'

def add_driver(prop_name):
driver = nodes[prop_name].outputs[0].driver_add(
"default_value")

# 获取目标节点的输出端口
output_port = nodes[prop_name].outputs[0]

# 创建驱动器
driver = output_port.driver_add("default_value")

# 创建驱动器变量
var1 = driver.driver.variables.new()
var1.name = prop_name
var1.targets[0].id_type = 'MATERIAL'
var1.targets[0].id = material
var1.targets[0].data_path = f'["{prop_name}"]'

# 设置驱动器表达式
driver.driver.expression = var1.name

add_driver('scene_scale')
add_driver('displacement_on')
for link in nodes[prop_name].outputs[0].links:
material.node_tree.links.remove(link)

# add_driver('scene_scale')
# add_driver('displacement_on')

# link the nodes
for node_name in NODE_DICT.keys():
node = nodes.get(node_name)
to_list = NODE_DICT[node_name]["to"]

for to in to_list:
# print(node_name, to)
target_node = nodes.get(to.split(":")[0])
target_input = to.split(":")[1]
links.new(
node.outputs[0],
target_node.inputs[
int(target_input)
if target_input.isnumeric() else target_input
]
)

# 创建 半透 BSDF 节点
translucent_bsdf = nodes.new(type="ShaderNodeBsdfTranslucent")
translucent_bsdf.location = (-400, 200)
translucent_bsdf.name = "TranslucentBSDF"
# 创建 Ambient Occlusion (AO) 节点
ao_node = nodes.new(type="ShaderNodeAmbientOcclusion")
ao_node.location = (-600, 200)
ao_node.name = "AO"
ao_node.label = "AO"
# 创建混合着色器节点
mix_shader = nodes.new(type="ShaderNodeMixShader")
mix_shader.location = (-200, 100)
mix_shader.name = "MixShader"
mix_shader.label = "MixShader"
# 创建 Gamma 节点
gamma_node = nodes.new(type="ShaderNodeGamma")
gamma_node.location = (-200, 0)
gamma_node.name = "Gamma"
gamma_node.label = "Gamma"
gamma_node.inputs[1].default_value = 0.45

links.new(ao_node.outputs[0], mix_shader.inputs[0]) # AO 到混合着色器
links.new(surface_node.outputs["BSDF"], mix_shader.inputs[2]) # SurfaceShader 到混合着色器
links.new(translucent_bsdf.outputs["BSDF"], mix_shader.inputs[1])
links.new(mix_shader.outputs[0], out_node.inputs["Surface"]) # 混合着色器到材质输出
base_color_mix = nodes.get("BaseColorMix")
links.new(base_color_mix.outputs[0], translucent_bsdf.inputs["Color"])
point_color = nodes.get("PointColor")
links.new(point_color.outputs[0], gamma_node.inputs[0])
links.new(gamma_node.outputs[0], base_color_mix.inputs[2])

return {'FINISHED'}

Binary file not shown.
70 changes: 70 additions & 0 deletions plugins/cinema4d/plugins/omoo_asset_alembic/menu.pyp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import c4d
import typing

# 定义菜单数据类型
MenuData: typing.Type = dict[str, typing.Union[int, 'MenuData']]

# 定义要插入的菜单数据
MENU_DATA: MenuData = {
"Import .abc (OmooAsset)": 1064257 # 插件命令 ID,示例 ID,请替换为实际命令 ID
# "start": {
# "button": 1064257 # 插件命令 ID,示例 ID,请替换为实际命令 ID
# }
}

def UpdateMenu(root: c4d.BaseContainer, title: str, data: MenuData, forceUpdate: bool = False) -> bool:
"""添加数据到指定根菜单下,根菜单中如果不存在该标题,则创建。

当 forceUpdate 为 True 时,强制更新 Cinema 4D 菜单。
"""
def doesContain(root: c4d.BaseContainer, title: str) -> bool:
"""测试根菜单中是否包含指定标题的子菜单。"""
for _, value in root:
if not isinstance(value, c4d.BaseContainer):
continue
elif value.GetString(c4d.MENURESOURCE_SUBTITLE) == title:
return True
return False

def insert(root: c4d.BaseContainer, title: str, data: MenuData) -> c4d.BaseContainer:
"""递归地将数据插入到根菜单的指定标题下。"""
# 创建一个新的容器并设置其标题
subMenu: c4d.BaseContainer = c4d.BaseContainer()
subMenu.InsData(c4d.MENURESOURCE_SUBTITLE, title)

# 遍历数据中的值,插入命令,并对字典进行递归处理
for key, value in data.items():
if isinstance(value, dict):
subMenu = insert(subMenu, key, value)
elif isinstance(value, int):
subMenu.InsData(c4d.MENURESOURCE_COMMAND, f"PLUGIN_CMD_{value}")

root.InsData(c4d.MENURESOURCE_SUBMENU, subMenu)
return root

# 如果标题已存在,返回 False
if doesContain(root, title):
return False

# 更新根菜单并根据需要强制更新菜单
insert(root, title, data)
if forceUpdate and c4d.threading.GeIsMainThreadAndNoDrawThread():
c4d.gui.UpdateMenus()

return True

def PluginMessage(mid: int, data: typing.Any) -> bool:
"""在 C4DPL_BUILDMENU 消息时更新菜单。"""
if mid == c4d.C4DPL_BUILDMENU:
# 获取 Cinema 4D 的主菜单并插入 MENU_DATA
menu: c4d.BaseContainer = c4d.gui.GetMenuResource("M_EDITOR")
UpdateMenu(root=menu, title="OmooAsset", data=MENU_DATA)

def SomeFunction():
"""在任何时候调用以更新菜单,只要调用来自主线程。"""
# 获取 Cinema 4D 的主菜单并插入 MENU_DATA
menu: c4d.BaseContainer = c4d.gui.GetMenuResource("M_EDITOR")
UpdateMenu(root=menu, title="OmooAsset", data=MENU_DATA, forceUpdate=True)

if __name__ == "__main__":
pass
698 changes: 698 additions & 0 deletions plugins/cinema4d/plugins/omoo_asset_alembic/omoo_assets_abc.pyp

Large diffs are not rendered by default.