Unity/Unity Industrial

[Pixyz Python Scripting] 파이썬을 활용한 CAD 최적화 및 자동화

pnltoen 2024. 1. 2.
반응형

Pixyz Python Scripting

Unity Technologies


 

서문

 

이전 포스팅인 Unity Pixyz] CAD 메타데이터를 유니티에서 사용하는 방법에서 Python Scripting을 학습한 과정에 대해 정리하던 중... 실수로 작성하던 포스팅을 모두 날려버렸다. 새해 첫 날 긍정적으로 생각해서 다시 처음부터 정리해보도록 하자.

 

[Unity Pixyz] CAD 메타데이터를 유니티에서 사용하는 방법

CAD metadata Unity Technologies 서문 이전에 작성한 "CAD 데이터의 최적화를 통한 실시간 백서 리뷰" 이 후 Metadata 관련 정리글을 작성해보고자 한다. 단순하게 유니티에서 어떻게 쓸 수 있어요!는 문서에

pnltoen.tistory.com

 

들어가기에 앞서...

 

이전에 API 문서를 보면서 Python Scripting을 진행한 적이 있다. 당시에 Pixyz에서 말하는 occurrence, metadata, entity등 개념 자체에 대한 이해가 어려워서 코드를 작성하기 어려웠다.

 

Pixyz API Reference

 

www.pixyz-software.com

 

별도의 노션 문서 "How to Python script in Pixyz"가 있으니 해당 문서를 정독하는 것을 추천한다. 본 포스팅은 모두 Pixyz 공식문서를 기반으로 작성되었다.

 

How to Python script in Pixyz | Built with Notion

Whether you want to script short helper functions in Pixyz Studio or advanced data preparation scenarios for Pixyz Scenario Processor, this document should help you get started or improve your knowledge.

pixyz.notion.site

 

특히 ide-auto-completion 또한 추천하는데 자동완성 기능을 Pixyz Studio IDE에 추가할 수 있다. 

 

Pixyz / Products / Studio / ide-auto-completion · GitLab

How to have python code completion in your own IDE

gitlab.com

 

솔직히 다들 자동완성 쓰잖아...

 

Pixyz Python Scripting 개념

 

Structure

 

API를 확인하다보면 다음과 같이 파라미터와 리턴 유형을 확인할 수 있다.

 

예를 들어서 scene.getSubTreeStats을 보도록하자. scene.getSubTreeStats(root)안에 보면 타입이 Occurrence로 되어있다. 이 후 return 값은 int type인 것을 알 수 있다. int는 파이썬을 해본 사람이라면 누구나 잘 이해하고 있는 변수 type임으로 넘어가고 Occurrecne은 처음 봤을 경우 상당히 당황스러울 수도 있다.

 

 

ⓒ Pixyz Documentation

 

Entities

 

Entity는 Pixyz Studio에 있는 모든 오브젝트를 말하는 최상위 개념입니다. 따라서 모든 오브젝트는 Entity를 inherit (상속)합니다. 최상위 개념임으로 조금은 헷갈릴 수 있는데 저의 경우에는 문서를 따라 "모든 오브젝트는 Entity의 개념이다" 라고 이해하였습니다.

 

 

하이어리키를 보면 더 이해가 어려울 수 있습니다. 예를들어서 Demo-BrakesA.1 occurrence를 보도록 하겠습니다.

 

이 Occurrence를 클릭해보면 Occurrence PropertiesOccurrence Components가 있습니다. 여기서 Occurrence Properties가 Entity의 개념이라고 생각하면 쉽습니다. 문서에 있는 대로 core.getProperty, core.setProperty, core.listProperties를 진행해보면 값이 정상적으로 출력되는 것을 확인할 수 있습니다.

 

def getEntityproperties():
	entity = 3
	#a = core.getProperty(entity, "Transform") #getProperty
	#a = core.setProperty(entity, "Transform") #setProperty
	a = core.listProperties(3)
	print(a)

 

 

값을 한번 비교해보면 조금 더 이해가 쉽습니다. 한번 출력 값 및 Pixyz Studio의 Inspector 값을 비교해보시길 바랍니다.

 

Occurrence

 

유니티를 사용해본 사람이라면, 매우 쉽게 이해할 수 있는 내용입니다. Occurrence는 유니티의 게임 오브젝트와 같이 여러 컴포넌트를 닮을 수 있는 개념입니다.

 

 

Occurrence Properties 밑에 Occurrence Componenets에 임의적으로 Part, VisualBehavior, InteractionBehavior, LightComponent 그리고 Metadata 컴포넌트를 넣었습니다.

 

문서에는 다음의 코드가 전체 Occurrence를 리스트로 return할 수 있다고 나와있습니다. 

allOccurrences = scene.findByProperty('Name', '.*')

 

하지만 간혹 선택을 해야 하는 경우도 있습니다. 예를들어 removeMaterials와 같은 경우가 있다.

 

Pixyz API Reference

 

www.pixyz-software.com

 

Seletected된 Entity에 적용하는 함수의 경우, 다음의 코드를 이용해서 진행할 수 있습니다.

 

allScene = [scene.getRoot()]
scene.select(allScene)
scene.removeMaterials()

 

Entity에서 했던 것과 occurrence의 property 값을 가져오는 것은 조금 다릅니다. 그 이유는 occurrence는 entity와 다르게 컴포넌트화되어 컴포넌트 안에 데이터를 저장합니다. 따라서... 데이터를 가져오는 방법이 조금 다릅니다.

 

관련된 내용은 이전 글에 있던 metadata 글에 사용한 코드를 복사하였으니 recap 해보시길 바랍니다.

 

occurrences = scene.findByProperty('Name', '.*') #씬 전체에 있는 파트의 occurrences를 리스트로 받음
metadataComponents = scene.getComponentByOccurrence(occurrences, scene.ComponentType.Metadata) #메타데이터가 없는 경우 0 반환
metadataDefinitions = scene.getMetadatasDefinitions(metadataComponents) #전체 메타데이터

 

Material의 경우 문서에 있는 샘플 스크립트 내용으로 충분하다고 생각됩니다.

실제 Batch를 위해 같은 메테리얼을 할당하는 것 이상으로 지금 당장 정리할 필요는 없다고 생각됩니다.

 

Part에서 CAD, Meshes, Lines, UVs에 대한 정보를 얻을 수 있습니다.

 

번외 - 오브젝트 이동 및 Pivot 재설정 (AABB)

 

Pivot 및 오브젝트의 origin 및 원점에 대해서는 많은 글을 작성하였습니다. 기억이 안난다면 아래의 글을 참고해보시길 바랍니다.

 

유니티 Articulation Body Joint와 회전축 그리고 질량중심 (Center Of Mass) 설정이 중요한 이유

Articulation Body와 질량중심 STEP, OBJ, FBX, SAT 본 포스팅은 Unity Articulation Body 또는 여러 Joint (Hinge 등등)에서 회전 기준점을 CAD에서 쉽게 지정하기 위해 작성하였습니다. 가장 일반적인 질량중심을 원

pnltoen.tistory.com

 

Pixyz Studio의 Sample Script인 Transforms_Recenter.py을 보면, 다음의 코드를 확인할 수 있습니다.

 

 

# Pixyz Python API sample (2022.1)
#
# Recenter
#
# Positions all scene Parts (as a whole) at the center of the scene, and scale it (optional)

# PARAMETER
SCALE = 10   # Sets the scale of the scene Parts

# Finds the position and size of all scenes Parts
aabb = scene.getAABB([scene.getRoot()])
print(aabb)
centerX = (aabb.high.x + aabb.low.x)/2
centerY = (aabb.high.y + aabb.low.y)/2
centerZ = (aabb.high.z + aabb.low.z)/2

translation = geom.Point3(-centerX, -centerY, -centerZ)
zero = geom.Point3(0, 0, 0)
scale = geom.Point3(SCALE, SCALE, SCALE)
translationMatrix = geom.fromTRS(translation, zero, geom.Point3(1,1,1))
scaleMatrix = geom.fromTRS(zero, zero, scale)

for child in scene.getChildren(scene.getRoot()):
	scene.applyTransformation(child, translationMatrix)

for child in scene.getChildren(scene.getRoot()):
	scene.applyTransformation(child, scaleMatrix)

 

이 중 AABB가 조금 낯설 수 있습니다. 쉽게 생각하면 Bounding box라고 하여 어떠한 오브젝트의 크기에 맞는 박스를 그린다고 생각하면 됩니다. 직접 그려보고 싶으시다면... Sample Script의 Geom_CreateCADPlane.py를 확인해서 해보시면 좋습니다. 위의 스크립트에서 Scale 값을 1로 바꾸면 바로 Pivot과 원점이 0으로 셋팅이 됩니다. 

 

Bounding volume - Wikipedia

From Wikipedia, the free encyclopedia Closed volume that completely contains the union of a set of objects A 3D model with its bounding box drawn in dashed lines. For building code compliance, see Bounding. In computer graphics and computational geometry,

en.wikipedia.org

 

 

하지만... 눈에 보이는 것만 값이 바뀌고 실제 Transform의 값이 0으로 설정되지는 않습니다.

Blender 및 CAD 소프트웨어의 경우 오브젝트를 옮겼을 때 해당 오브젝트의 global transformation은 유지하면서 transform 자체의 value를 0 또는 특정 값으로 설정하는 기능을 제공하고 있습니다. 

 

이전 글과 통일 되지만 따라서... 가능하다면 모델러가 오브젝트를 수정해서 전달해주시는 것이 맞습니다. 그렇지 않다면 유니티 내부에서 코드짤 때 두통이 올 수 있습니다. 예: 오브젝트 생성 후 다시 오브젝트의 원점으로 돌아가고 싶을 때 초기 위치를 캐싱해야함. 그렇지 않으면 정말 global 원점으로 돌아가기 때문 물론, 빈 오브젝트 하나 더 만들어서 해결할 수도 있는데 빈 오브젝트 자체가 성능에도 좋지 않고 무엇보다 오브젝트 트리형태가 복잡하면 개발하기에 어려움.

 

내용이 조금 밖으로 샜는데... 코드를 해석해보면 다음과 같습니다. 사실 high 그리고 low의 x,y,z 값이 중요한데 이해를 돕기 위해 다음과 같이 도식하였습니다.

 

 

위와 같이 작동을 하기 때문에 각 occurrence에 각 center 위치를 갖고 있는 matrix를 계산하면 원점의 위치가 변경됩니다.

 

Origin으로 원점을 옮긴 이 후 movePivotPointToOrigin을 같이 사용하면 Pivot까지 옮겨줄 수 있다.

 

결론

 

Pixyz에서 Python을 사용하기 위한 개념 및 몇가지 실습을 진행해보았습니다. 원래는 기존의 metadata 글과 함께 합쳐서 작성하려고 했는데 중간에 파일이 날라가는 관계로 조금 더 수정한 후 포스팅합니다.

반응형

댓글