← 목차
Godot 4.7 · ProtonScatter 4.2.0

ProtonScatter
처음부터 끝까지

나무·바위를 자유롭게 흩뿌리면서 충돌까지 얻는 유일한 방법. 설치부터 Keep Static Colliders 까지 클릭 순서 그대로 적었다.

4.7.2.stable 실측 애드온 소스 확인 기본 프리셋 값 직접 읽음 상세 문서 · protonscatter.md

왜 이것을 쓰나MultiMeshInstance3DPopulate Surface 로 뿌린 것들은 물리 세계에 존재하지 않는다. 캐릭터가 그대로 통과한다. 엔진 내장에는 이를 자동으로 해결하는 버튼이 없고, 클릭만으로 되는 방법은 이것뿐이다.MultiMeshInstance3D 문서

STEP 0시작 전에 있어야 하는 것

ProtonScatter 는 "무엇을" 과 "어디에" 를 스스로 만들지 않는다. 씬에 먼저 있어야 한다.

있어야 하는 것
뿌릴 대상MeshInstance3D 또는 씬 파일Step 5 에서 지정한다
바닥MeshInstance3D + StaticBody3D + CollisionShape3DStep 8 의 Project On Colliders레이캐스트로 지면을 찾는다. 콜리전이 없으면 지면에 붙지 못한다

🛑 바닥에 콜리전이 없으면 나무가 지면에 붙지 않고 영역 안에 공중부양한다. 바닥 MeshInstance3D 를 선택하고 툴바 Mesh ▸ Create Collision Shape ▸ Static Body Child ▸ Trimesh 로 먼저 만들어 둔다.

충돌까지 원한다면 뿌릴 대상에도 콜리전이 있어야 한다.

Tree (MeshInstance3D) ← 이것을 뿌린다StaticBody3D ← Mesh ▸ Create Collision Shape ▸ CapsuleCollisionShape3D ← 이 shape 이 인스턴스마다 복제된다

STEP 1설치

두 경로 중 하나를 고른다.

A. AssetLib — 클릭만으로 (권장)

에디터 상단 ▸ AssetLib 탭 ▸ "ProtonScatter" 검색 ▸ Download ▸ Install

B. 저장소에서 직접 — 버전 고정이 필요할 때

git clone --depth 1 https://github.com/HungryProton/scatter.git
# scatter/addons/proton_scatter/ 를 프로젝트의 addons/ 로 복사한다

용량 주의addons/proton_scatter/13MB 이고 그중 11MB 가 demos/ 다. 저장소에 넣을 거라면 demos/tests/ 를 빼면 1.5MB 로 줄어든다.
🛑 단 demos/ 를 빼면 기본 프리셋의 ScatterItemdemos/assets/brick.tscn 을 가리켜 콘솔에 Cannot open file 이 한 번 뜬다. Step 5 에서 Path 를 자기 모델로 바꾸면 사라진다.

STEP 2플러그인 활성화

Project ▸ Project Settings…  ▸  Plugins 탭  ▸  ProtonScatter 의 Enabled 를 ✅

활성화되면 ProtonScatter · ProtonScatterItem · ProtonScatterShape 노드를 Create New Node 목록에서 검색할 수 있게 된다. 안 보이면 활성화가 안 된 것이다.

STEP 3노드 3개를 만든다

Create New Node 에서 "scatter" 로 검색해 세 개를 만든다. 부모-자식 관계가 정해져 있다.

ProtonScatter ← 루트. 설정과 Modifier Stack 이 여기 있다 ├── ProtonScatterItem ← 무엇을 뿌릴 것인가 └── ProtonScatterShape ← 어디에 뿌릴 것인가
ProtonScatterItem · ProtonScatterShape반드시 ProtonScatter 의 자식이어야 한다
여러 종류를 섞으려면ProtonScatterItem여러 개 둔다 (각 Proportion 으로 비율 조절)
영역을 여러 개 쓰려면ProtonScatterShape여러 개 둘 수 있다

✅ 인스펙터를 여는 순간 Modifier 4개가 자동으로 들어온다

ProtonScatter 를 선택해 인스펙터를 열면 기본 프리셋이 자동 적용된다. (근거 — stack_panel.gd:73-76just_created 인 스택에 presets/scatter_default.tscn 을 적용한다.) 들어오는 값을 그대로 읽으면 이렇다:

modifier 4개
  ▸ Create Inside (Random)   [Create]   amount = 75
  ▸ Randomize Transforms     [Edit]     position (0.15, 0.15, 0.15)
                                        rotation (20.0, 360.0, 20.0)
                                        scale    (0.1, 0.1, 0.1)
  ▸ Relax Position           [Edit]     iterations 3 · offset_step 0.2
                                        consecutive_step_multiplier 0.75
  ▸ Project On Colliders     [Edit]     ray_length 5.0 · ray_offset 5.0
                                        remove_points_on_miss false
                                        max_slope 90.0 · collision_mask 1

이 넷이 Step 6~8 에서 만질 대상 전부다. 순서에도 뜻이 있다 — 뿌리고(Create) → 흩고(Randomize) → 겹침을 풀고(Relax) → 지면에 붙인다(Project).

🛑 코드로 ProtonScatter.new() 를 하면 스택이 비어 있다. 자동 적용은 에디터 인스펙터 전용이다.

STEP 4뿌릴 영역을 정한다 — ScatterShape

ProtonScatterShape 를 선택하면 인스펙터에 Shape 칸이 <empty> 로 있다. 클릭해 New 에서 모양을 고른다.

고를 수 있는 것무엇크기 프로퍼티
ProtonScatterBoxShape상자 (가장 흔하다)sizeVector3
ProtonScatterSphereShaperadius
ProtonScatterPathShape곡선을 따라Curve3D
ProtonScatterBaseShape다른 모양의 부모 클래스(직접 쓰지 않는다)

뷰포트에 노란 상자가 나타난다. 이 안쪽이 뿌려질 범위다. ProtonScatterShape 노드를 옮기면 범위도 함께 움직인다.

Negative 를 켜면그 영역을 빼낸다(구멍을 낸다). 길·건물 자리를 비울 때
size.y높이도 범위에 들어간다. Project On Colliders 가 지면에 붙여 주므로 2 정도면 충분

STEP 5뿌릴 대상을 지정한다 — ScatterItem

ProtonScatterItem 을 선택하고 인스펙터에서 두 칸을 정한다.

ProtonScatterItem — ScatterItem
Proportion100
① SourceFrom current scene
Custom Script<empty>
Source options
Source Scale Multiplier1.0  🛑 콜리전이 따라오지 않는다
Override options
Material<empty>
② PathAssign… ▸ 노드 선택

① Source — 어디서 가져오나

Path 에 넣는 것
From current scene지금 이 씬 안의 노드씬 트리의 노드 (Assign… 버튼으로 고른다)
From disk다른 씬 파일res://…/tree.tscn

처음이라면 From current scene 이 쉽다. 씬에 이미 놓아 둔 나무를 그대로 가리키면 된다.

② Path — 무엇을 가져오나

Path 줄의 Assign… 을 누르면 Select a Node 창이 뜬다. 씬 트리에서 뿌릴 대상을 고른다.

Node3D ├── Ground │ └── StaticBody3D │ └── CollisionShape3D ├── CommonTree_12 │ └── CommonTree_1 ← 이것을 고른다 (Type: MeshInstance3D) │ └── StaticBody3D │ └── CollisionShape3D └── ProtonScatter ├── ProtonScatterItem ← 지금 여기를 설정 중 └── ProtonScatterShape

🛑 콜리전(Step 9)까지 원한다면 고른 노드 아래에 StaticBody3D ▸ CollisionShape3D 가 있어야 한다. ProtonScatter 는 그 shape 을 복제한다. 없으면 메시만 뿌려진다.

고르는 순간 뷰포트에 인스턴스가 나타난다.

STEP 6Set Amount — 개수

ProtonScatter 루트를 선택하고 인스펙터 아래쪽 Modifier Stack 을 본다.

Modifier Stack
  + Add modifier
  ▸ Create Inside (Random)    ← 이것을 클릭해 펼친다
  ▸ Randomize Transforms
  ▸ Relax Position
  ▸ Project On Colliders
Create Inside (Random)
Amount75 → 원하는 값
(좌표계 토글)Local / Global

값을 바꾸면 뷰포트가 즉시 다시 뿌려진다.

개수를 정하는 다른 방법
Create Inside (Poisson)개수 대신 radius(최소 간격) 로 정한다. 겹치지 않는 배치가 필요하면 이쪽
Create Inside (Grid)격자로 규칙적으로
Create Along Edge (…)영역의 가장자리를 따라 — 울타리·가로수

STEP 7Set Rotation — 방향과 크기 흩기

Randomize Transforms 를 펼친다. 세 줄이 있고, 각각 무작위 폭이다 (값이 0이면 흩지 않는다).

Randomize Transforms
Positionx 0.15   y 0.15   z 0.15
Rotationx 20.0   y 360.0   z 20.0
Scalex 0.1   y 0.1   z 0.1

Rotation 의 Y 가 360 인 것이 핵심이다 — 위 축 기준으로 완전히 무작위로 돌려 같은 나무를 복제한 티를 지운다. X·Z 의 20° 는 살짝 기울여 자연스럽게 만드는 값이다.

하고 싶은 것어떻게
나무가 똑바로만 서게Rotation(0, 360, 0) 으로. X·Z 를 0 으로
바위처럼 아무렇게나(360, 360, 360)
크기를 더 다양하게Scale(0.3, 0.3, 0.3) 처럼 올린다

🛑 회전만 필요하면 Randomize Rotation 이라는 별도 modifier 도 있다. 다만 그쪽 기본값은 (360, 360, 360) 이라 그대로 쓰면 나무가 눕는다. 반드시 (0, 360, 0) 으로 고쳐서 쓴다.

STEP 8Set Object Boundaries — 겹침 풀기

Relax Position 을 펼친다. 무작위로 뿌리면 나무끼리 겹치는데, 이 modifier 가 서로 밀어내며 간격을 고르게 만든다.

Relax Position
Iterations3  — 올릴수록 고르지만 느리다
Offset Step0.2  — 한 번에 밀어내는 거리(m)
Consecutive Step Multiplier0.75
Use Computeshader✅  — GPU 계산

나무가 서로 파고들면 Iterations 를 올리거나 Offset Step 을 키운다.

겹침을 아예 만들지 않으려면 Step 6 에서 Create Inside (Poisson) 을 쓰는 편이 더 확실하다. Relax Position 은 이미 뿌려진 것을 나중에 미는 방식이다.

함께 보는 것 — Project On Colliders

인스턴스를 아래로 레이캐스트해 지면에 붙인다.

Project On Colliders
Ray Direction(0, −1, 0) — 아래로
Ray Length5.0 — 5m 까지 찾는다
Ray Offset5.0 — 5m 위에서 쏜다
Remove Points On Missfalse — 못 맞혀도 지우지 않는다
Collision Mask1 — 레이어 1 만 찾는다

🛑 바닥 콜리전이 레이어 1 에 없으면 지면에 붙지 않는다. 나무가 공중에 뜨면 여기를 본다. Ray Length·Ray Offset 이 5m 이므로 높낮이 차가 5m 를 넘는 지형에서도 놓친다.
소스 기본값은 Remove Points On Miss = true 지만 프리셋이 false 로 덮는다. 직접 modifier 를 추가했을 때는 true 라서, 바닥을 못 맞히면 인스턴스가 전부 사라진다.

STEP 9🛑 Set Collision — 이 문서의 핵심

여기가 다른 방법과 갈리는 지점이다. ProtonScatter 루트를 선택하고 인스펙터의 Performance 그룹을 펼친다.

ProtonScatter
Performance
① Render ModeUse Instancing
② Keep Static Colliders✅ On  ← 이 체크 하나가 전부다
Force Rebuild On Load✅ On
Enable Updates In Game☐ Off
Use Chunks✅ On
Chunk Dimensions(15, 15, 15)

왜 이것만으로 되는가

MultiMesh 인스턴스를 채우는 바로 그 루프가, 같은 Transform3D 로 물리 서버에 shape 을 등록한다.

# scatter.gd:448-450
t = item.process_transform(transforms.list[offset + i])
mmi.multimesh.set_instance_transform(i, t)   # 렌더
_create_collision(static_body, t)            # 물리 — 같은 t

# scatter.gd:609-611 — 끄는 것은 Create Copies(1) 뿐이다
func _create_collision(body: StaticBody3D, t: Transform3D) -> void:
	if not keep_static_colliders or render_mode == 1:
		return

지원 shape — Sphere · Box · Capsule · Cylinder · ConcavePolygon · ConvexPolygon · HeightMap · SeparationRay.

실측

godot --headless --path . -s res://tests/protonscatter_collision_probe.gd
[A. keep_static_colliders = false]     레이 12발 중  0발 명중  ✅ 콜리전 없음
[B. keep_static_colliders = true]      레이 12발 중 12발 명중  ✅ 콜리전 있음
   콜리전 윗면 높이 ≈ 2.27 m
[C. B + source_scale_multiplier = 4]   레이 12발 중  0발 명중  ✅ 실측된 한계
실패 0 건

🛑 제약 넷 — 전부 실측·소스로 확인했다

#제약
씬 트리에 콜리전 노드가 없다PhysicsServer3D 에 직접 등록 → Debug ▸ Visible Collision Shapes 에도 안 보인다. 확인은 직접 부딪혀 보는 것뿐
부모의 scale 이 버려진다MeshInstance3D·CollisionShape3D 그 노드 자신의 transform 만 살린다 → 크기는 메시·shape 자체에 넣는다
Source Scale Multiplier키우면 콜리전이 따라오지 않는다(위 실측 C)
collision layer 미설정소스에 body_set_collision_layer 호출이 0회 → 전부 기본 레이어

STEP 10확인한다

무엇을어떻게
뿌려졌나뷰포트에 보이는가. ProtonScatter 아래 ScatterOutput 이 생겼는가
드로우콜이 1인가F5 로 실행해 모니터를 본다. 에디터 뷰포트 숫자에는 기즈모가 섞인다
충돌하나🛑 디버그 뷰로는 안 보인다(제약 ①). 캐릭터로 직접 부딪혀 본다

사람이 걷지 않아도 판정할 수 있다 — 캐릭터와 똑같은 캡슐로 숲을 가로지르는 직선을 훑는다:

[왼쪽 MultiMesh]       숲 중심까지 4.5 m 를 훑었으나 걸리는 것이 없었다   ✅ 통과
[오른쪽 ProtonScatter]  출발 0.2 m 지점에서 막혔다                       ✅ 막힘
실패 0 건

🛑 막히는 곳 모음

증상원인과 해결
Create New Node 에 ProtonScatter 가 없다Step 2 의 플러그인 활성화를 안 했다
아무것도 안 뿌려진다ScatterItemPath 가 비었다 ② ScatterShapeShape<empty> ③ Modifier Stack 이 비었다(코드로 만든 경우)
Cannot open file … brick.tscn애드온을 demos/ 없이 벤더링했다. Step 5 에서 Path 를 바꾸면 사라진다
나무가 공중에 뜬다Project On Colliders 가 지면을 못 찾는다 → 바닥에 콜리전을 주고 Collision Mask·Ray Length(5m) 확인
나무가 눕거나 뒤집힌다Randomize Transforms ▸ Rotation 의 X·Z 를 0 으로
나무끼리 겹친다Relax Position ▸ Iterations 를 올리거나 Create Inside (Poisson) 으로
충돌이 안 생긴다Keep Static Colliders ✅ ② Render Mode = Use Instancing원본에 StaticBody3D ▸ CollisionShape3D 가 있는가
콜리전이 안 보인다🛑 정상이다. 노드를 만들지 않으므로 디버그 뷰에 안 나온다
콜리전 크기가 메시와 다르다부모의 scale 이 버려졌다(제약 ②)
실행 중 배치가 바뀐다Enable Updates In Game 을 끈다

언제 쓰고, 언제 쓰지 않나

상황
자유 배치 + 충돌이 둘 다 필요ProtonScatter — 이것 말고 클릭으로 되는 방법이 없다
격자에 놓아도 되는 건물·울타리GridMap + MeshLibrary (내장, 콜리전 자동)
충돌이 필요 없는 풀·꽃·자갈MultiMeshInstance3D + Populate Surface (내장)
부딪힐 나무가 수십 그루뿐그냥 개별 노드. 가장 단순하다

이어서 읽기

이 페이지는 클릭 순서다. 원리·다른 해법·코드는 문서 쪽이 더 자세하다.