100x100 의 땅에 랜덤한 위치에 풀과 꽃을 심을 예정
마당에 있는 풀들과 꽃을 여러개 생성해도
한번의 DrawCall 로 그려지도록 최적화 작업도 같이 진행
여기서 사용한 최적화 방법으로는 instancedMesh 와 Merged 컴포넌트를 사용하였다
풀들은 materials 가 동일해서 instancedMesh 로 처리하였고
꽃봉오리와 갈대가 함께 있는 모델은 materials 가 동일하지 않아 Merged 로 처리하였다
※ 정보
모델안에 서로 다른 materials 를 지니고 있으면 모델을 한번의 Drawcall 로 나타내기에 한계가 있음
materials 가 동일해야 여러 geometry 로 구성된 모델을 한번의 Drawcall 로 나타낼 수 있음
최적화 측면에서는 instancedMesh 가 수천개 그렸을때 뛰어남
먼저 instancedMesh 에 들어갈 요소들을 살펴보자
<instancedMesh
ref={meshRef}
args={[mergedGeometry.current, materials._4, count]}
castShadow
/>
meshRef : 각 풀들에 대한 position, scale 등 Matrix 에서 설정할 수 있는 속성들을 설정해준다
args : 풀에 대한 모델 정보와 총 그릴 갯수를 적어준다
useEffect(() => {
const geometries = [
nodes.Mesh1_ElwFor_Grass01_C01_1_Model.geometry,
nodes.Mesh2_ElwFor_Grass01_C01_2_Model.geometry,
...
];
mergedGeometry.current = mergeBufferGeometries(geometries);
setIsGeometryReady(true);
}, [nodes]);
다음과 같이 모델을 이루고 있는 geometry 들을 mergeBufferGeometries 을 통해 하나의 geometry 로 병합하고 정보를 mergedGeometry 에 넣어준다
이것으로 여러 geometry 로 구성된 하나의 모델을 한번의 DrawCall 로 그리는 것은 완성되었다
useEffect(() => {
if (isGeometryReady && meshRef.current) {
for (let i = 0; i < count; i++) {
dummy.scale.set(0.02, 0.02, 0.02);
const x = (Math.random() - 0.5) * 1e2;
const z = (Math.random() - 0.5) * 1e2;
dummy.position.set(x, 0, z);
dummy.updateMatrix();
meshRef.current.setMatrixAt(i, dummy.matrix);
}
meshRef.current.instanceMatrix.needsUpdate = true;
}
}, [dummy, isGeometryReady]);
100x100 의 땅이므로 -50,50 의 범위로 설정된 랜덤 좌표를 생성하고, scale 값을 설정한 후 Matrix 를 업데이트 해주었다.
이제 1, 2번 과정을 통해 얻은 정보를 instancedMesh 에 넣어주면 모델을 여러개 배치해도 한번의 DrawCall 로 해결
먼저 Merged 에 들어갈 요소들을 살펴보자
<Merged castShadow meshes={meshes}>
...
</Merged>
meshes : 모델을 이루고 있는 각 geometry 의 정보
const meshes = useMemo(
() => ({
Dandelions1: nodes["Node-Mesh"],
Dandelions2: nodes["Node-Mesh_1"],
}),
[nodes]
);
비교적 간단하므로 전체코드로 살펴보기
<Merged castShadow meshes={meshes}>
{(mesh) => {
return (
<>
{Array.from({ length: count }).map((_, idx) => (
<Fragment key={idx}>
<group position={position[idx]} scale={5}>
<mesh.Dandelions1 material={materials.mat21} />
<mesh.Dandelions2 material={materials.mat9} />
</group>
</Fragment>
))}
</>
);
}}
</Merged>
앞서 설명했듯이 서로 다른 materials 로 구성된 모델은 한번의 DrawCall 로 표현하기 어려움
그래서 모델의 geometry 에 대한 DrawCall 은 여러번 진행하되,
모델을 여러개 그릴때의 DrawCall 은 한번만 실행되도록