2024. 10. 29. 14:31ㆍBlender
개요
블렌더에 같은 오브젝트를 여럿 배치하기 위해서는 보통 [Shift + D]로 복제하여 사용한다. 단축키를 이용한 쉬운 복제이기 때문에 이것만으로도 빠른 작업이 가능하지만 문제는 어떤 지형을 따라서 배치해야 할 경우 높이값을 하나씩 바꿔주어야 하는 문제가 있다.
가령 수백 개의 나무, 돌, 풀 등의 에셋을 대량으로 배치해야 한다고 했을 때 효율적인 배치 방법이 없을 지를 고민해봤다.
주의할 점은 랜덤 배치가 아닌 내가 원하는 특정 포인트에서의 배치이다.
사용 방법
import bpy
import mathutils
import random
from math import radians
from bpy_extras.view3d_utils import region_2d_to_vector_3d, region_2d_to_origin_3d
# Configuration variables
objectname = "TreeC"
Zrotate = True # Set to True for random Z rotation, False for no rotation
def get_mouse_ray(context, event):
"""Calculate ray origin and direction from the mouse point in 3D view"""
region = context.region
region_3d = context.space_data.region_3d
# Get the 2D mouse coordinates
coord = (event.mouse_region_x, event.mouse_region_y)
# Calculate the ray origin and direction using bpy_extras utilities
ray_origin = region_2d_to_origin_3d(region, region_3d, coord)
ray_direction = region_2d_to_vector_3d(region, region_3d, coord)
return ray_origin, ray_direction
def place_tree(context, event):
"""Ray cast from the mouse point and place a tree at the hit location"""
# Get the tree object to duplicate
tree_template = bpy.data.objects.get(objectname)
if tree_template:
# Get the ray origin and direction from the mouse click
ray_origin, ray_direction = get_mouse_ray(context, event)
# Cast the ray from the mouse point
depsgraph = context.evaluated_depsgraph_get()
result, location, normal, index, object, matrix = context.scene.ray_cast(
depsgraph, ray_origin, ray_direction)
if result:
# Duplicate the tree and place it at the hit location
new_tree = tree_template.copy()
new_tree.data = tree_template.data.copy()
new_tree.location = location
# Apply random Z rotation if enabled
if Zrotate:
random_angle = random.uniform(0, 360) # Random angle between 0 and 360 degrees
new_tree.rotation_euler[2] = radians(random_angle) # Apply rotation in radians
context.collection.objects.link(new_tree)
print(f"Tree placed at {location}" + (f" with {random_angle:.1f}° rotation" if Zrotate else ""))
else:
print("No valid surface detected to place the tree.")
else:
print(f"Error: Object not found. Make sure the object is named '{objectname}'")
class PlaceTreeOperator(bpy.types.Operator):
"""Place a Tree on Mouse Click"""
bl_idname = "object.place_tree"
bl_label = "Place Tree Operator"
def modal(self, context, event):
# Exit when pressing the right mouse button or ESC
if event.type in {'RIGHTMOUSE', 'ESC'}:
return {'CANCELLED'}
# Place tree when left mouse button is clicked
if event.type == 'LEFTMOUSE' and event.value == 'PRESS':
place_tree(context, event)
return {'RUNNING_MODAL'}
return {'PASS_THROUGH'}
def invoke(self, context, event):
if context.area.type == 'VIEW_3D':
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
self.report({'ERROR'}, "Operator only works in the 3D Viewport.")
return {'CANCELLED'}
def register():
bpy.utils.register_class(PlaceTreeOperator)
def unregister():
bpy.utils.unregister_class(PlaceTreeOperator)
if __name__ == "__main__":
register()
블렌더 스크립트 란에 스크립트를 붙여넣는다.
코드 최상단의 objectname 부분은 복제할 오브젝트의 이름을 적는다.
objectname = "TreeC"
아래 Zrotate 부분은 Z 축 랜덤 회전을 할지 안할지를 선택한다. True/False
Zrotate = True # Set to True for random Z rotation, False for no rotation
스크립트를 실행하기 위해서 삼각형 모양의 [Run Script] 버튼을 누른다.
[Layout]의 [Object Mode]에서만 작동하므로 오브젝트 모드로 이동한다.
해당 기능을 단축키로 실행되게 만들기 위해서 [Edit] - [Menu Search…]에서 “Place Tree Operator”를 찾고 마우스 우클릭하여 [Assign Shortcut]을 선택한다.
원하는 키를 눌러 단축키를 적용한다. 해당 기능은 단축키로 [Shift + f]를 눌러 실행되게 만들었다.
[Shift + f] 단축키로 기능 실행 후 [마우스 좌클릭]을 하면 마우스 포인트 자리에 오브젝트가 복제되어 생성된다.
기능을 끄고 싶다면 [Esc] 또는 [마우스 우클릭]을 한다.
주의사항
- 기능을 켜고 끄는 것에 익숙해지는 데까지 시간이 걸릴 수 있다.
- 실수로 기능을 끄지 않고 좌클릭을 계속 하면 오브젝트가 계속 겹칠 수 있다.
- 배치 중에 [Ctrl + z]로 Undo를 하면 블렌더 프로그램이 꺼질 수 있다. (저장을 습관화 해야 함)
- 오브젝트 오리진을 기준으로 배치되기 때문에 지형 위에 오브젝트가 있도록 하기 위해서는 오브젝트의 오리진을 바닥으로 설정해야 한다. (바로 위의 gif의 큐브가 평면 아래에 묻히는 이유는 큐브의 오리진이 센터에 있기 때문)
추가 개발 가능한 기능
- Random rotation for each placed tree
- Random scaling
- Different tree variants
- Undo support
참고 자료
'Blender' 카테고리의 다른 글
[Blender] 마우스 좌클릭으로 원하는 곳에 오브젝트 쉽게 복제하기(2) (4) | 2024.11.11 |
---|---|
[Blender] glb, gltf 파일 Alpha 애니메이션 자동화 스크립트 (1) | 2024.09.27 |
[Blender] 블렌더에서 플립북 텍스쳐(FlipBook Texture) 스크립트 자동화 적용 (2) | 2024.09.24 |
[Blender] Collection Instancing을 통한 최적화 (1) | 2024.07.05 |
[Blender] 블렌더에서 플립북 텍스쳐(FlipBook Texture) 사용하기 (1) | 2024.06.19 |