본문 바로가기
Study Archives/Metal

[Metal] 3D Models

by 2den 2022. 8. 7.
728x90

* 교재 제목 : Metal by Tutorials second edition (Beginning Game Engine Development with Metal)

Questions

1. "Quads work well with subdivision or smoothing algorithms." 

:: quad mesh를 사용하면 bilinear interpolation이 가능해서 더 부드러운 곡면 표현이 가능

+ retopology, remeshing

 

 

2. (*.mtl) "newmtl material_1 : This is the group that contains all of the cone's vertices." vertices?

:: 각 그룹에 해당하는 material을 여러 개의 정점에 적용시킬 수 있음을 의미하는 것으로 추정

 

 

3. (*.mtl) 그렇다면 하나의 *.mtl 파일 안에 여러 material group을 정의할 수 있는 것일까?

:: 그렇다 (이것을 *.obj 파일에서 명시하여 사용)

+ 다른 3D 파일 포맷은 모두 다르기 때문에 각각 알아보면 좋음



Archives

- vertex point들은 렌더링을 위해 GPU로 보내진다.

 

 

- render mode : point

renderEndcoder.drawIndexedPrimitives(type: .point,
    indexCount: submesh.indexCount,
    indexType: submesh.indexType,
    indexBuffer: submesh.indexBuffer.buffer,
    indexBufferOffset: 0)

 

 

- 와이어프레임으로 렌더하기 : draw call 바로 전에 아래 코드 추가

renderEncoder.setTriangleFillMode(.lines)

 

 

- GPU가 삼각형에 최적화된 이유 : (1) 2차원에서 가장 적은 개수의 점으로 그려질 수 있는 다각형이다. (2) 삼각형의 세 점은 항상 같은 평면 위에 있다. (3) 삼각형의 한 꼭짓점에서 시작하는 직선으로 삼각형을 나누면 항상 두 개의 삼각형으로 나눠진다.

 

 

- 3D file formats : *.obj (Wavefront Technologies가 개발한 포맷, *.mtl 파일을 사용하여 material - texture, surface properties 명시 가능, 애니메이션 지원 불가), *.glTF (Kronos가 개발한 포맷, 커뮤니티 지원이 좋음, 애니메이션 지원), *.blend (Blender 파일 포맷), *.dae (COLLADA open standard 포맷, 애니메이션 지원, SceneKit는 *.dae를 import할 수 있지만 Model I/O는 import 못 함), *.fbx (Autodesk 포맷, 독점적, 애니메이션 지원), *.usd (Pixar의 open source 포맷, *.usdz는 USD 압축 파일, Apple은 AR 모델들의 포맷으로 USDZ를 선택)

 

 

- *.obj 파일은 모델 하나만을 포함하지만, *.glTF와 *.usd는 모델, 애니메이션, 카메라, light 등의 전체 scene을 포함한다.

 

 

- Model I/O에서 scene의 최상위 레벨은 MDLAsset이다. mesh, 카메라, light 같은 child object를 asset에 추가할 수 있고, complete scene hierarchy를 만들 수 있다.

let asset = MDLAsset()
asset.add(mdlMesh)

 

 

- 아래 코드를 통해 Shared Playground Data에 저장된 디렉토리에 cone을 export한다.

do {
    let url =
    playgroundSharedDataDirectory.appendingPathComponent(
    "primitive.\(fileExtension)")
    try asset.exprt(to: url)
} catch {
    fatalError("Error \(error.localizedDescription)")
}

 

 

- primitive.obj, primitive.mtl

 

 

- (*.obj) mtllib : *.obj 파일의 *.mtl 파일 이름

# Apple ModelIO OBJ File: plane
mtllib plane.mtl

 

 

- (*.obj) g : 정점 그룹의 시작

g submesh

 

 

- (*.obj) v : 정점

v 0 0.5 -0.5
v 0 -0.5 -0.5
v 0 -0.5 0.5
v 0 0.5 0.5

 

 

- (*.obj) vn : surface normal

vn -1 0 0

 

 

- (*.obj) vt : uv 좌표

vt 1 0
vt 0 0
vt 0 1
vt 1 1

 

 

- (*.obj) usemtl : "The name of a material providing the surface information, such as color, for the following faces." .mtl 파일 안에 정의되어 있음

usemtl material_1

 

 

- (*.obj) f :  평면을 정의, 앞서 v, vt, vn으로 정의한 vertex/texture/normal의 index를 나타냄

f 1/1/1 2/2/1 3/3/1
// vertex1 : (0, 0.5, -0.5), uv coord : (1, 0), normal : (-1, 0, 0)
// vertex2 : (0, -0,5 -0,5), uv coord : (0, 0), normal : (-1, 0, 0)
// vertex3 : (0, -0.5, 0.5), uv coord : (0, 1), normal : (-1, 0, 0)

f 1/1/1 3/3/1 4/4/1

 

 

- (*.obj) s : smoothing, off는 smooth surface로 생성할 그룹이 없다는 것을 의미한다.

s off

 

 

- (*.mtl) Kd - diffuse color, Ka - ambient color, Ks - specular color

Kd 1 1 1
Ka 0 0 0
Ks 0

 

 

- 모델의 모든 정점은 다른 그룹 또는 다른 material을 분리해서 가질 수 있다.

 

 

- 메탈은 object를 생성할 때 descriptor를 사용한다. 모델을 로드하기 전에, vertex descriptor를 만들어 Metal에게 vertex의 레이아웃을 어떻게 할지 등의 데이터를 알려줄 수 있다. "how you want to view this data"

let vertexDescriptor = MTLVertexDescriptor()
// creating a vertex descriptor to configure all the properties that an object will need to know about
// it can be reused with the same values or reconfigured values *to instantialte a different object*

vertexDescriptor.attributes[0].format = .float3
// just the position

vertexDescriptor.attributes[0].offset = 0
// where in the buffer this particular data will start

vertexDescriptor.attributes[0].bufferIndex = 0
// vertex shader function will match the incoming vertex data in buffer 0 with this vertex layout

 

 

- vertex 데이터를 render encoder를 통해 GPU로 보낼 때, MTLBuffer 안에 넣어 보내게 되고 이를 buffer index로 매치한다. 31개의 버퍼가 사용가능하며 Metal은 이 버퍼들을 buffer argument table을 이용하여 관리한다.

 

 

- SIMD (Single Instruction Multiple Data) : 병렬컴퓨팅의 한 종류, 하나의 명령어로 여러 개의 값을 동시에 계산하는 방식 (GPU 연산처럼?)

 

 

- 아래 코드에서 buffer 0의 stride(vertex 정보의 각 집합 사이의 byte 수)를 정한다. 원래 각 vertex 사이의 stride는 float3 + float3 + float2가 되어야 하지만, 여기서는 position 데이터만 로드하고 있기 때문에, 다음 position을 얻기 위해서는 float3의 stride로 건너뛰어야 한다. 다른 레이아웃을 가진 여러 개의 MTLBuffer를 참조하는 복잡한 vertex descriptor를 설정할 수도 있다.

vertexDescriptor.layout[0].stride = MemoryLayout<SIMD3<Float>>.stride

 

 

- "You have the option of interleaving position, tormal and texture coordinates, or you can lay out a buffer containing all position data first, followed by other data."

 

 

- 메모리 인터리빙(interleaving) : 인접한 메모리 위치를 서로 다른 메모리 뱅크에 둠으로써 동시에 여러 곳을 접근할 수 있게 하는 것 (주기억장치를 접근하는 속도를 빠르게 하려고)

 

 

- (swift) typealias : type에 붙일 수 있는 별명(약칭)

 

 

- 'position'이라는 이름을 가진 string을 attribute에 assign한다. Model I/O에게 이것이 position 데이터라는 것을 알려주는 것이다. normal과 texture coordinate 데이터도 사용 가능하지만, 이 attribute들은 상관 없음을 명시하는 셈이다.

(meshDescriptor.attributes[0] as! MDLVertexAttribute).name = MDLVertexAttributePosition

 

 

- URL, vertex descriptor, memory allocator를 사용하여 asset을 읽는다. 그 다음 이 asset에서 첫번째 Model I/O mesh buffer를 읽는다.

let asset = MDLAsset(url: assetURL, vertexDescriptor: MeshDescriptor, bufferAllocator: allocator)
// MeshDescriptor : Model I/O용 MTLVertexDescriptor
let mdlMesh = asset.childObjects(of: MDLMesh.self).first as! MDLMesh

 

 

- (swift) as : type 캐스팅 된 인스턴스를 return (! - 런타임 캐스팅 실패 시 에러 반환, ? - 런타임 캐스팅 실패 시 nil 반환)

 

 

- submesh : 각각 다른 material로 렌더하기 위해서 mesh를 여러 그룹으로 분류한 것 (material group 개수만큼 submesh를 분류)

 

 

- winding order : 정점을 그리는 순서, 반시계 방향이 디폴트 값 (반시계 방향 순서의 정점들이 이루는 면이 나를 향한다고 생각하면 됨)

 

 

- submesh 렌더는 submesh를 각각의 material group으로 렌더하기 위해 반복문 사용, 각각 draw call

for submesh in mesh.submeshes {
    renderEncoder.drawIndexedPrimitives(
        type : .triangle,
        indexCount : submesh.indexCount,
        indexType : submesh.indexType,
        indexBuffer : submesh.indexBuffer.buffer,
        indexBufferOffset : submesh.indexBuffer.offset
    )
}

 

 

- mesh와 submesh는 MTLBuffers 안에 있고, submesh는 mesh의 정점들의 index 리스트를 가지고 있음

 

 

 

Words

* blocky
* proprietary : 독점적인

* scalable : 확장성이 있는

* archive file : 압축파일

* breakdown : 분해하다, 이해하기 쉽게 만들다

 

728x90

'Study Archives > Metal' 카테고리의 다른 글

[Metal] Hello, Metal!  (0) 2022.07.20

댓글