현재 상황
그냥 cloth object를 보여주는게 전부이다..
이제 여기다가 분석한 carmen씨의 코드를 바탕으로 cloth simulation을 구현하도록 한다
아무렇게나 스크립트를 가져오면 안되니 종속되지 않은 스크립트부터 하나씩 가져오자
필요한 스크립트 가져오기
math관련 함수들, constraints, collision, physics object 등
지금까지 물리 시뮬레이션을 위해 필요했던 스크립트들을 가져오자
matrix 연산자가 필요하기 때문에 gl-matrix도 설치해준다
gl-matrix 설치
npm i gl-matrix
gl-matrix는 빌드에서도 처리되어야하므로 dependencies에 설치하자
mesh type이 필요하다
physics object 스크립트에서는 직접 정의한 Mesh type을 사용한다
하지만 threejs를 사용하는 상황에서 mesh에 대한 type 정의없이 threejs에서 정의된 mesh를 사용해야한다
기존 carment씨의 코드는 webGPU로 작성한 코드이므로 이걸 threejs mesh type으로 변경해서 사용할 방법에 대해서 탐구해보자
custom mesh type을 threejs mesh로 바꾸기
export interface Mesh {
positions: Float32Array;
uvs: Float32Array;
normals: Float32Array;
indices: Uint16Array;
}
custom으로 선언되어있는 mesh type은 이렇다
threejs mesh의 경우 아래 docs에서 볼 수 있는데
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array( [
-1.0, -1.0, 1.0, // v0
1.0, -1.0, 1.0, // v1
1.0, 1.0, 1.0, // v2
-1.0, 1.0, 1.0, // v3
] );
const indices = [
0, 1, 2,
2, 3, 0,
];
geometry.setIndex( indices );
geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
const mesh = new THREE.Mesh( geometry, material );
threejs의 geometry는 위와 같은 property들로 구성되어있다
보면 다른 건 몰라도 normal에 대한 정의는 없다
docs에는 compute vertex normal이라고 해서 vertex 정보를 가지고 normal을 계산하는게 있는데
그렇다면 시계 혹은 반시계 방향으로 자동으로 계산해주다는 뜻이다
일단 normal에 대해서는 신경쓰지 않고 진행해보자
physics object의 mesh type들 수정하기
export default abstract class PhysicsObject {
...
constructor(mesh: Mesh) {
this.numParticles = mesh.positions.length / 3;
this.positions = new Float32Array(mesh.positions);
this.normals = new Float32Array(mesh.normals);
this.prevPositions = new Float32Array(mesh.positions);
this.vels = new Float32Array(3 * this.numParticles);
this.invMass = new Float32Array(this.numParticles);
this.indices = new Uint16Array(mesh.indices);
this.constraints = [];
this.collisions = [];
생성자의 mesh의 타입은 Mesh인데
이 type은 types/three 라이브러리에서 가져올 수 있지 않을까 싶다
Mesh라는 type이 types/three에 있지는 않고 geometry 중 하나를 type으로 사용해야할 것 같다
custom하게 사용하기 위해서는 threejs에서는 일반적으로 BufferGeometry를 사용하는데
BufferAttribute에 position, uvs, indices가 있을텐데 docs에 제대로 설명이 없다
그래서 BoxGeometry의 attributes를 출력해본 결과인데
normal, position, uv가 모두 정의되어있다
이러면 Mesh를 그대로 attributes로 대체해도 충분한데
indices를 사용하는 방법이 threejs에도 있기 때문에 이것까지만 알아보자
geometry attributes의 indices 속성은 어디에
geometry의 attributes 안에서 indices 속성을 사용하지 않아
오브젝트의 geometry를 꺼내서 indices를 확인해보자
여기 보면 BoxGeometry에 index 속성이 있다
이게 indices에 해당하는 값이다
custom type에서 정의한 Mesh의 각각 요소들을 이렇게 대응하도록 코드를 수정해보자
physics object 코드 수정하기
threejs에도 Mesh type은 있길래
Mesh를 threejs의 type으로 가져와보기로 했다
position, normal은 geometry.attribute에서 되는데
indices의 경우 에러가 뜨네
에러를 읽어보면 type 변한 에러인데
ArrayBufferLike 타입이 아니라서 생긴 문제라고 한다
TypedArray에서 변환은 어렵지 않을거라고 생각하는데 undefined일 수 있어서 그런가?
constructor(mesh: Mesh) {
this.numParticles = mesh.geometry.attributes.position.count;
this.positions = new Float32Array(mesh.geometry.attributes.position.array);
this.normals = new Float32Array(mesh.geometry.attributes.normal.array);
this.prevPositions = new Float32Array(mesh.geometry.attributes.position.array);
this.vels = new Float32Array(3 * this.numParticles);
this.invMass = new Float32Array(this.numParticles);
this.indices = new Uint16Array(mesh.geometry.index?.array ?? new Array(0));
이렇게 undefined인 경우 empty array를 주도록 coalescing 연산자를 사용하니 잘 된다
cloth class에도 이렇게 적용해보자
cloth class는 mesh를 외부에서 가져와서 super 함수로 넘겨주기만 한다
외부에서 가져오는 mesh를 확인해보자
// Create Buffers and Bind Groups
const meshBuffers = gpuCanvas.createMeshBuffers(mesh);
...
// thickness and spacing in hash table needed adjusting.
const thickness = VERTEX_SPACING;
const cloth = new Cloth(mesh, thickness);
본래 cloth 객체에 들어가는 mesh는 webGPUCanvas class의 MeshBuffer type을 담는다
createMeshBuffers(mesh: Mesh): VertexBuffers {
const { indices, positions, normals, uvs } = mesh;
const positionBuffer = this.createMeshBuffer(
positions,
GPUBufferUsage.VERTEX
);
const indexBuffer = this.createMeshBuffer(indices, GPUBufferUsage.INDEX);
const normalBuffer = this.createMeshBuffer(normals, GPUBufferUsage.VERTEX);
const uvBuffer = this.createMeshBuffer(uvs, GPUBufferUsage.VERTEX);
return {
indices: indexBuffer,
normals: normalBuffer,
position: positionBuffer,
uvs: uvBuffer,
};
}
이는 위 코드처럼 device buffer를 직접적으로 접근하지 않는 threejs에서는
단순히 empty Mesh type을 의미한다
이로써 webGPU의 custom Mesh type을 threejs의 Mesh로 수정하였다
이제 PBD cloth simulation 을 적용해보자
'개발 · 컴퓨터공학 > three.js' 카테고리의 다른 글
threejs 의류 관련 프로젝트 - 의상 color customize (0) | 2024.06.16 |
---|---|
threejs 가상 피팅 사이트 virtual try on 레퍼런스 (0) | 2024.06.15 |
Threejs Cloth Tailor 개발일지 - cloth object 옷감 오브젝트 vertex 움직임 확인, index에 해당하는 vertex 위치 표시, vscode 디버깅 (2) | 2024.06.01 |
Threejs Cloth Tailor 개발일지 - 모델 OBJ 파일 load하기 OBJLoader, load model material 입히기 (0) | 2024.05.11 |
Threejs Cloth Tailor 개발일지 - TypeScripts 코드 모듈화 (0) | 2024.05.10 |