출처:

소개

ChatGPT의 이미지 생성이 강화되어 임의의 공간의 그림을 생성할 뿐만 아니라 그 안에 있는 오브젝트의 그림을 흩어져 출력할 수 있게 되었으므로 이것을 사용해 로컬 image to mesh를 실시하면 원리적으로는 원하는만큼 3D모델을 생성할 수 있지요 라고 하는 이야기입니다.

물론 지금까지도 '붉은 사과의 그림' 을 그려줘 라고 지시하여 이미지를 만들어서 image to mesh를 할 수 있었습니다만 그림을 구성하는 부품을 빼낼 수 있게 되어 색, 스타일 등이 일관된 3D모델을 대량으로 만들 수 있게 되는 것이 기쁩니다.

아래 이미지에 있는 객체는 모두 ChatGPT가 생성한 한 장의 그림에서 만든 3D 모델입니다.

이미지.png

이것을 만드는 방법을 설명합니다.

ChatGPT로 작업

이쪽은 간단합니다. ChatGPT에서

이미지 만들기 유럽식 카페 내부,

일러스트 스타일, 아이소메트릭 프로젝션, 아이소메트릭 프로젝션

라는 프롬프트를 주어 이미지를 만듭니다. 여기서 중요한 것은 "아이소메트릭 프로젝션 "이라는 키워드입니다. 이것을 넣는 것으로 가능한 한 원근이 없는 화상으로 합니다. 덧붙여서 객체가 너무 많은 것도 나중의 작업이 힘들기 때문에 조심합시다.

다음 작업에서는 ChatGPT에서 실제로 생성한 이 이미지를 사용합니다.

이 이미지의 경우 ChatGPT에서

이 그림에 있는 가구나 가전제품 등을 3D 모델로 재현하고 싶습니다.

각각을 분리하여 한 장의 시트 위에 나란히 배치하여 표시해 주세요.

각 부품은 3D 모델링의 참고가 될 수 있도록 형상을 알기 쉽게 만들어주세요.

텍스처는 원본 그림을 반영하고 배경색은 흰색으로 해주세요.

라는 지시를 내립니다. 그러면 아래와 같이 그림 속의 "부품"을 흩어져 한 장의 그림으로 정리해줍니다.

부품끼리가 겹쳐 버린다면, 「서로가 겹치지 않도록, 아이템과 아이템 사이에는 공백을 확보해 주세요.」등, 프롬프트를 추가합시다. 큰 아이템이 있으면 겹치기 쉽기 때문에 별도로 출력해도 좋을 것입니다.

여기에서 부품별 이미지로 해주면 되지만 ChatGPT는 한 번에 1장 밖에 화상을 낼 수 없기 때문에, 부품 전부를 한 장으로 정리한 화상을 만들고 다음의 작업으로 흩어져 있는 화상으로 합니다.

부품별 이미지 만들기

제가 준비한 부품 추출 도구 사이트 로 이동하십시오.

여기서 방금 전의 이미지를 업로드하면 자동으로 부품별로 분할한 이미지로 해줍니다. 오른쪽의 「ZIP로 다운로드」버튼으로 정리해 이미지를 다운로드합시다.

"배경 옵션"은 Image to Mesh의 도구에 따라 선호하는 배경색이 미묘하게 다르기 때문에 준비했습니다. 대부분 투명하거나 흰색으로 좋지만 잘 작동하지 않으면 사용자 정의 배경색을 선택하고 + (컬러 선택기)로 색상을 선택하십시오.

pinokio를 사용하여 3D 모델 생성 라이브러리 설치

그런 다음 이미지에서 3D 모델을 생성합니다. 즉 Image to Mesh로 부품 이미지를 3D 모델로 만듭니다. Meshy등의 클라우드 서비스를 사용해도 좋지만 수가 많으면 비용적으로 엄격하네요.

그래서 로컬 Image to Mesh 라이브러리를 사용합니다. 몇 가지가 있지만 그 중에서 강력한 것 중 하나가 Hunyuan3D-2 입니다.

다만 이것은 인스톨이 상당히 번거롭고 사용하기 어렵습니다.

그래서 pinokio 라는 도구를 사용합니다. 이 도구는 라이브러리를 자동으로 설치하고 hugging face에서 볼 수 있는 GUI를 로컬로 사용하면서 모델을 실행할 수 있습니다. 이번에는 이것을 사용합니다. 덧붙여 실행 조건의 상세는 불명합니다만, 이쪽의 글 에 의하면 이하와 같은 실행 환경이 필요한 것 같습니다.

디스크 공간도 50GB 정도는 필요하다고 생각합니다.

자, 환경이 괜찮다면, 먼저 pinokio 사이트에서 Windows 버전의 앱을 다운로드하십시오. 인스톨러를 실행하면 다음과 같은 경고가 나옵니다만, 「상세 정보」를 클릭하면 「실행」버튼이 나오고 앞으로 진행합니다.

설정 화면이 나오면 우선 디폴트인 채로 OK하면 스타트 화면이 되므로 Visit Discover Page로 진행합니다

여기서 이용 가능한 모델이 나오는데 Hunyuan3D-2가 보이지 않습니다.

따라서 "Download from URL"을 선택하고 https://github.com/pinokiofactory/Hunyuan3D-2.git 을 git URL로 입력하십시오.

One-Click Install with Pinokio 버튼을 누릅니다. 설치할 패키지 등 목록이 나오면 install 버튼을 눌러 설치를 시작하십시오. 콘솔 화면이 나오고 설치가 진행됩니다. 그런 다음 화면의 지시를 따릅니다.

그 모습을 보고 있다고 알겠지만 가상 환경 env에 필요한 것을 설치하고 있습니다. 이것이 나중에 중요하기 때문에 기억하십시오.

모두 끝나면 아래와 같은 화면이 됩니다.

이미지에서 3D 모델 생성 배치 처리

자, 이제 필요한 모든 것을 설치해야합니다. 기본 설정이면 C:\pinokio\api\Hunyuan3D-2.git\app 에 파일이 구성되어 있어야 합니다. 명령 프롬프트를 열고 해당 디렉토리로 이동합니다. 다음과 같은 파일이 있어야 합니다.

이제 먼저 가상 환경을 시작합니다.

.\env\Scripts\activate

그런 다음 3D 생성을 수행하는 로컬 서버를 다음 명령으로 시작합니다. 많이 여러가지 다운로드하므로, 사용할 수 있게 되기까지 시간이 걸립니다.

python api_server.py --enable_tex --host 0.0.0.0 --port 8080

또한 --enable_tex 옵션을 넣으면 3D 메쉬 생성과 텍스처 생성이 이루어집니다. 넣지 않으면 메쉬 만됩니다.

무료 다운로드가 끝나고 서버가 준비되면 다음과 같습니다.

그런 다음 이미지를 제공하고 3D 모델 생성을 요청하는 스크립트를 준비합니다.

generate.py

import base64
import requests
import json

def send_image_to_api():
   
# 이미지 파일을 base64 인코드
   
with open('assets/demo.png', 'rb') as image_file:
       img_b64_str = base64.b64encode(image_file.read()).decode(
'utf-8')

   
# API 엔드포인트와 요청 데이터 설정
   url =
"http://localhost:8080/generate"
   headers = {
       
"Content-Type": "application/json"
   }
   payload = {
       
"image": img_b64_str,
       
"texture": True
   }

   
# POST 요청 전송
   response = requests.post(url, headers=headers, json=payload)

   
# 응답 보존
   
if response.status_code == 200:
       
with open('test1.glb', 'wb') as f:
           f.write(response.content)
       print(
"GLB 파일이 정상적으로 보존 되었습니다.")
   
else:
       print(
f"エ에러가 발생하였습니다. 상태 코드: {response.status_code}")

if __name__ == "__main__":
   send_image_to_api()

이것을 C:\pinokio\api\Hunyuan3D-2.git\app 에 저장합니다. 그리고 앞서 언급한 서버용과는 별도로 명령 프롬프트를 열고 app 폴더로 이동하여 python generate.py 를 실행합니다(이것은 가상 환경 필요 없음).

문제 없이 잘 되면 텍스처가 있는 3D 모델이 생성되어야 합니다. 서버측은

와 같아야 합니다. 생성된 glb 파일은 generate.py 와 같은 곳에 있습니다.

다음은 흐름 작업입니다. 아래와 같은 스크립트를 만들고 assets/myimages 위에 준비한 부품 이미지를 정리해 넣어 3D 모델로 합시다.

generate_myimages.py

import base64
import requests
import json
import os
import time

def send_image_to_api(image_path, output_path, retries=3, timeout=600):
   print(
f"\n--- 처리 시작: {image_path} ---")
   start_time = time.time()

   
with open(image_path, 'rb') as image_file:
       img_b64_str = base64.b64encode(image_file.read()).decode(
'utf-8')

   url =
"http://localhost:8080/generate"
   headers = {
"Content-Type": "application/json"}
   payload = {
       
"image": img_b64_str,
       
"texture": True
   }

   
for attempt in range(1, retries + 1):
       
try:
           print(
f"  → API 송신 중 (시행행 {attempt}/{retries})...")
           response = requests.post(url, headers=headers, json=payload, timeout=timeout)

           
if response.status_code == 200:
               
with open(output_path, 'wb') as f:
                   f.write(response.content)
               duration = time.time() - start_time
               minutes = int(duration // 60)
               seconds = int(duration % 60)
               print(
f"  ✅ 성공: {output_path} 에 보존(처리 시간: {minutes}분 {seconds}초)")
               
return
           
else:
               print(
f"  ❌ 상태 코드: {response.status_code}")

       
except requests.exceptions.Timeout:
           print(
"  ⚠️ 타임 아웃이 발생하였다.")
       
except Exception as e:
           print(
f"  ⚠️ 에러 발생: {e}")

       time.sleep(5)  
# 리트라이 간격격

   duration = time.time() - start_time
   minutes = int(duration // 60)
   seconds = int(duration % 60)
   print(
f"  ❌ 최종적으로 실패: {image_path}(처리 시간: {minutes}분 {seconds}초)")

def process_all_images():
   input_dir =
'assets/myimages'
   output_dir =
'assets/output_glb'
   os.makedirs(output_dir, exist_ok=
True)

   image_files = sorted([
       f
for f in os.listdir(input_dir)
       
if f.lower().endswith(('.png', '.jpg', '.jpeg'))
   ])

   total = len(image_files)
   print(
f"=== 모두 {total} 수의 이미지를 처리하였다 ===")

   
for idx, filename in enumerate(image_files, 1):
       image_path = os.path.join(input_dir, filename)
       base_name = os.path.splitext(filename)[0]
       output_path = os.path.join(output_dir,
f'{base_name}.glb')
       print(
f"\n📄 [{idx}/{total}] {filename} 를 처리 중...")
       send_image_to_api(image_path, output_path)

   print(
"\n=== 모든 처리가 완료 되었다 ===")

if __name__ == "__main__":
   process_all_images()

전체 처리가 완료되면 app/assets/output_glb 을 보십시오. glb 모델이 되어 있을 것입니다.

완성된 모델의 이미지는 이 기사의 맨 위에 있습니다. 대체로 양호한 생성이었습니다만 식물의 잎 등이 일부 부족하네요. 이 근처는 모델 개선을 기대합시다.

결론

이번에는 한 장의 그림에서 12개의 객체를 만들었지만 그 그림에서 다른 상황의 그림을 ChatGPT에 만들어서 절차를 반복하면 같은 스타일의 3D 객체를 대량으로 만들 수 있습니다. 지금까지 3D 모델을 구입하여 가상 공간을 만들려고 하면 원하는 모델이 부족하거나 스타일이 엉망이 되지 않는 경우가 많았습니다만, 이번 방법을 이용하면 쉽게 일관된 스타일의 3D 모델을 만들 수 있을 것입니다.

이 방법으로 여러가지 가상 공간을 만들어 가고 싶습니다.