Pixyz Studio _ Model Convertor

〇、安装
1.将Neo Workflow复制到PixyzStudioInstallationDirectory/plugins/路径下
2.pipinyin库安装
将pypinyin库复制到PixyzStudioInstallationDirectory/pythonDlls/路径下
3.配置文件修改
在Neo Workflow/plugin.xml中添加/修改presets块配置文件
4.使用
PiXYZ Studio->Plugins->NeoWorkflow->Engine Performance Workflow->
填入[ModelImportPath]字段->Execute
5.功能
a.将ModelImportPath路径下所有指定格式的文件按TessellationSettings、MeshCountList和ExportFileTypeList中的参数组合,并导出
b.ModelSettings参数
DeleteAdditionalMesh:
删除同一虚拟节点下多余生成的额外mesh,判断依据为mesh顶点个数,为安全起见,仅处理含两个子mesh的虚拟节点
ChineseToPinYin:
节点名称中文转拼音,需安装pypinyin库
SetMeshWithParentName:
默认转换后mesh节点名称可能为Burp_x,可通过开启此选项,将mesh节点名称设置为其父节点的名称,并会压缩树
CorrectNodeName:
纠正节点名称,除以下字符和中文,皆视为非法字符,将以””替换,并会将连续””替换为单个”_”
合法字符
“_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789”
CompressTree:
清理一层空节点,同PiXYZ Studio->Scene->Compress Tree
RakeTree:
删除所有虚拟节点,将mesh展平在同一层,同PiXYZ Studio->Scene->Rake Tree

一、说明

1.目前按mesh个数会和指定的mesh个数存在偏差(待优化)
2.贴图需在相应引擎中进行设置,贴图将对渲染和加载时间有严重影响
3.将在相应导入文件的目录中生成输出文件,生成的文件个数为:
导入文件个数×TessellationSettings参数个数×MeshCountList参数个数×ExportFileTypeList
4.文件后缀名说明
LA9G3QA_nnz7956101_asm_0.2_27_146100.fbx
0.2 :转换精度,数值越大,模型精度越低
27:mesh个数,与meshCount值略有偏差
146100:顶点数
LA9G3QA_nnz7956101_asm_0.2_keepAll_438288.fbx
keepAll:保持原模型所有mesh节点
LA9G3QA_nnz7956101_asm_0.2_one_146094.fbx
one:合并原模型所有mesh节点

二、ModelConvertor

ModelConvertor.py
from pxz import *
from os import listdir
from os.path import isfile, isdir, join, normpath, splitext
import fnmatch
import os
import re
#拼音库
import pypinyin

#合法字符
validChar="_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

#获取目录中指定格式的文件
def getFilesInDirectory(directory,extensions,recursive,joinPath):
  files = []
  for f in listdir(directory):
    fullPath = join(directory,f)
    if isfile(fullPath):
      extOk = False
      if extensions:
        for ext in extensions:
          if fnmatch.fnmatch(f.upper(),"*." + ext.upper()):
            extOk = True
            break
          if not extOk:
            continue
      if extOk:
        if joinPath:
          files.append(normpath(fullPath))
        else:
          files.append(f)

    elif recursive and isdir(fullPath):
      dirFiles = getFilesInDirectory(fullPath,extensions,recursive,joinPath)
      if not joinPath:
        tmp = dirFiles
        dirFiles = []
        for file in tmp:
          dirFiles.append(normpath(join(f,file)))
      files.extend(dirFiles)
  return files

#替换文件后缀
def replaceFileExtension(file,info,newExt):
  (root,ext) = splitext(file)
  return root + info+"." + newExt

#将mesh名称设置为父节点名称(默认情况下,mesh名称可能为BRep_x)
def setMeshNameWithParentName():
	parts = scene.getPartOccurrences(1)
	for part in parts:
		parent=scene.getParent(part)
		parentName=core.getProperty(parent,"Name")
		core.setProperty(part,"Name",parentName)

#设置正确的节点名称
def setCorrectNodeName(node):
	name=core.getProperty(node, "Name")
	newName=""
	for	char in name:
		if validChar.find(char)<0 and isChinese(char)==False:
			newName+=('_')
		else: newName+=char
	newName=re.sub("_+","_",newName)
	core.setProperty(node,"Name",newName)


#字符是否为中文
def isChinese(input):
  return '\u4e00' <= input <= '\u9fff'
  
def toPinyin(input):
	output=pypinyin.slug(input,separator=" ").title().replace(" ","")
	return output
	
def setNodeNameToPinyin(node):
	name=core.getProperty(node, "Name")
	newName=toPinyin(name)	
	core.setProperty(node,"Name",newName)
	
#设置中文转拼音
def setChineseToPinyin(parent):
	for child in scene.getChildren(parent):
		setNodeNameToPinyin(child)
		setChineseToPinyin(child)
#纠正节点名称
def correctNodesName(parent):
	for child in scene.getChildren(parent):
		setCorrectNodeName(child)
		correctNodesName(child)
#调用示例		
#correctNodesName(scene.getRoot())		

#输出配置参数
def debugParameters(modelImportPath,importFileTypeList,modelSettings,tessellationSettings,meshCountList,exportFileTypeList):
	print(modelImportPath)
	print(modelSettings)
	print(tessellationSettings)
	print(exportFileTypeList)
	print(meshCountList)
	print(exportFileTypeList)
	
#获取所有的mesh父节点
def getMeshParentNodes():
	allParentNodes=[]
	parts = scene.getPartOccurrences(1)
	for part in parts:
		parent=scene.getParent(part)
		if parent not in allParentNodes:
			allParentNodes.append(parent)
					
	return allParentNodes
	
#删除额外的mesh通过顶点数
def deleteAdditonalMeshByPolygonCount(parent):
	children=scene.getChildren(parent)
	if len(children)>2:
		return
	max=-1
	additionalNodes=[]
	childName=core.getProperty(children[0],"Name")
	for	child in children:
		polygonCount=scene.getPolygonCount([child])
		if polygonCount>max:
			max=polygonCount
	for	child in children:
		if scene.getPolygonCount([child])!=max:
			additionalNodes.append(child)
	
	if len(additionalNodes)>1:
		return
#	for delete in deleteNode:
#		if core.getProperty(delete,"Name")!=childName:
#			deleteNode=[]
#			break
	scene.deleteOccurrences(additionalNodes)

#删除同一虚拟节点下多余生成的额外mesh,判断依据为mesh顶点个数,为安全起见,仅处理含两个子mesh的虚拟节点
def deleteAdditonalMesh():
	allParentNodes=getMeshParentNodes()
	for	parent in allParentNodes:
		deleteAdditonalMeshByPolygonCount(parent)		
				
#处理模型
def handleModel(modelSettings):
	if modelSettings.DeleteAddtionalMesh:
		deleteAdditonalMesh()
	if modelSettings.ChineseToPinYin:
		setChineseToPinyin(scene.getRoot())
	if modelSettings.SetMeshWithParentName:
		setMeshNameWithParentName()	
		
	if modelSettings.CorrectNodeName:
		correctNodesName(scene.getRoot())
	if modelSettings.CompressTree:
		scene.compress(scene.getRoot())
	if modelSettings.RakeTree:
		scene.rake(scene.getRoot(), False)
	scene.resetTransform(1, True, False, False)
#	将轴心设置为对象的中心
	scene.movePivotPointToOccurrenceCenter([1], True)
	
#转换模型
def convertingModel(model,modelSettings,tessellationSettings,meshCountList,fileName,exportFileType,exportFolder):
	
	maxSagList=[]

	for setting in tessellationSettings:
		maxSagList.append(setting.MaxSag)
		
	meshCountArgs=[]
	for setting in meshCountList:
		meshCountArgs.append(setting.Count)
	
	for	maxSag in maxSagList:
		for meshCount in meshCountArgs:
			io.importScene(model)
			scene.movePivotPointToOccurrenceCenter([1], True)			
			allOccurrences=scene.getPartOccurrences()
			algo.tessellate(allOccurrences,maxSag,-1, -1, createFreeEdges = True)
			handleModel(modelSettings)
			exportInfo="_"+str(maxSag)+mergeMesh(meshCount)+getVertexesCount()
			exportPath=(exportFolder+"\\"+fileName+exportInfo+"."+exportFileType)
			io.exportScene(exportPath)
			deleteCurrentModelFile()
	
	
#获取顶点个数
def getVertexesCount():
	vertexes=0
	allOccurrences=scene.getPartOccurrences()
	for occurrence in allOccurrences:
		vertexes+=scene.getVertexCount([occurrence], False, False, False)
	return "_"+str(vertexes)

#按总的mesh个数合并节点
def mergePartsByCount(allOccurrences,meshCount):
	if len(allOccurrences)<=meshCount:
		return "_"+str(len(allOccurrences))

	groupNumber=math.ceil(len(allOccurrences)/meshCount)	
	scene.deleteEmptyOccurrences()
	allOccurrences=scene.getPartOccurrences()	
	#字典键值计数器
	index=0
	#合并字典
	mergeOccurrences={}
	#合并计数器
	number=0

	for occurrence in	allOccurrences:
	#setdefault			
		mergeOccurrences.setdefault(index,[]).append(occurrence)
		number=number+1
		if number==groupNumber:
			index=index+1
			number=0
				
	
	sorted(mergeOccurrences)
#	len(dict)键的总数
	if(len(mergeOccurrences)==0):
		return;
	for value in mergeOccurrences.values():
		if len(value)!=0:
			scene.mergeParts(value,1)
	meshes=scene.getPartOccurrences()		
	return "_"+str(len(meshes))

#合并mesh
def mergeMesh(meshCount):
	allOccurrences=scene.getPartOccurrences()
	if meshCount==-1:
		return "_keepAll"
	elif meshCount==1:
		scene.mergeParts(allOccurrences,1)
		return "_one"
	else:
		return mergePartsByCount(allOccurrences,meshCount)
	
#删除场景中的模型文件
def deleteCurrentModelFile():
	scene.deleteOccurrences(scene.getPartOccurrences())
	scene.deleteEmptyOccurrences()
	
#模型转换器
def modelConvertor(modelImportPath,importFileTypeList,modelSettings,tessellationSettings,meshCountList,exportFileTypeList):
	debugParameters(modelImportPath,importFileTypeList,modelSettings,tessellationSettings,meshCountList,exportFileTypeList)
	core.removeConsoleVerbose(2)
	if modelImportPath:
		importFileExtensions=[]
		for importFileType in importFileTypeList:
			importFileExtensions.append(importFileType.Extension)
			
		modelFiles=getFilesInDirectory(modelImportPath,importFileExtensions,True,True)
		exportFileExtensions=[]
		for exportFileType in exportFileTypeList:
			exportFileExtensions.append(exportFileType.Extension)
		for model in modelFiles:
#		print(model)
			fileName = os.path.split(model)[1].split(".")[0]
			for	exportFileType in exportFileExtensions:
				parentFolder=os.path.dirname(str(model))
				exportFolder=parentFolder+"\\"+fileName+"\\"+exportFileType
				isExists=os.path.exists(exportFolder)
				if not isExists:
					os.makedirs(exportFolder)
				convertingModel(model,modelSettings,tessellationSettings,meshCountList,fileName,exportFileType,exportFolder)	
<?xml version="1.0" encoding="utf-8" ?>
<module name="NeoWorkflow">
	<include module="IO"/>
	<decltype name="FileType">
		<struct>
			<field name="Extension"
				   type="String"
				   value="None"/>
		</struct>
	</decltype>
	<decltype name="ModelSettings">
		<struct>
			<field name="DeleteAddtionalMesh"
				   type="Bool"
				   default="False"></field>
			<field name="ChineseToPinYin"
				   type="Bool"
				   default="False"></field>
			<field name="SetMeshWithParentName"
				   type="Bool"
				   default="False"></field>
			<field name="CorrectNodeName"
				   type="Bool"
				   default="False"></field>
			<field name="CompressTree"
				   type="Bool"
				   default="False"></field>
			<field name="RakeTree"
				   type="Bool"
				   default="False"></field>
		</struct>
	</decltype>

	<decltype name="TessellationQuality">
		<struct>
			<field name="MaxSag"
				   type="Distance"
				   default="0.2"></field>
		</struct>
	</decltype>
	<decltype name="TessellationQualityList">
		<list type ="TessellationQuality"/>
	</decltype>
	<decltype name="ImportFileTypeList">
		<list type="FileType"></list>
	</decltype>
	<decltype name="ExportFileTypeList">
		<list type="FileType"></list>
	</decltype>
	<decltype name="MeshCount">
		<struct>
			<field name="Count"
				   type="Int"
				   default="-1"/>
		</struct>
	</decltype>
	<decltype name="MeshCountList">
		<list type="MeshCount"></list>
	</decltype>
	
	<function name="modelConvertor"
			  scriptFile="ModelConvertor.py">
		<parameters group="Parameters">
			<parameter name="ModelImportPath"
					   type="String"></parameter>
			<parameter name="ImportFileTypeList"
					   type="ImportFileTypeList"
					   description=""></parameter>
			<parameter name="ModelSettings"
					   type="ModelSettings"></parameter>
			<parameter name="TessellationSettings"
					   type="TessellationQualityList"></parameter>
			<parameter name="MeshCountList"
					   type="MeshCountList"></parameter>
			<parameter name="ExportFileTypeList"
					   type="ExportFileTypeList"
					   description=""></parameter>
		</parameters>
	
		<presets default="PerformanceTest">
			<preset name="PerformanceTest">
				<Parameter name="ImportFileTypeList">
					[pxz.neoworkflow.FileType("step"), pxz.neoworkflow.FileType("stp"),pxz.neoworkflow.FileType("x_t")]
				</Parameter>
				<Parameter name="ModelSettings">
					pxz.neoworkflow.ModelSettings(True, True, True, True,True,True)
				</Parameter>
				<Parameter name="TessellationSettings">
					[pxz.neoworkflow.TessellationQuality(0.2), pxz.neoworkflow.TessellationQuality(0.5),pxz.neoworkflow.TessellationQuality(1.0)]
				</Parameter>
				<Parameter name="MeshCountList">
					[pxz.neoworkflow.MeshCount(-1), pxz.neoworkflow.MeshCount(1), pxz.neoworkflow.MeshCount(1000), pxz.neoworkflow.MeshCount(2000), pxz.neoworkflow.MeshCount(3000)]
				</Parameter>
				<Parameter name="ExportFileTypeList">
					[pxz.neoworkflow.FileType("fbx"), pxz.neoworkflow.FileType("glb")]
				</Parameter>
			</preset>
			<preset name="NeoSettings">
				<Parameter name="ImportFileTypeList">
					[pxz.neoworkflow.FileType("step"), pxz.neoworkflow.FileType("stp"),pxz.neoworkflow.FileType("x_t")]
				</Parameter>
				<Parameter name="ModelSettings">
					pxz.neoworkflow.ModelSettings(True, True, True, True,True,False)
				</Parameter>
				<Parameter name="TessellationSettings">
					[pxz.neoworkflow.TessellationQuality(0.2)]
				</Parameter>
				<Parameter name="MeshCountList">
					[pxz.neoworkflow.MeshCount(-1)]
				</Parameter>
				<Parameter name="ExportFileTypeList">
					[pxz.neoworkflow.FileType("fbx")]
				</Parameter>
			</preset>
		</presets>
	</function>
</module>

二、Python
1.获取制定路径下所有文件
2.字符串拼接
3.中文字符判定

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值