Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a66cb8f62c | |||
| cc3c481295 | |||
| 2980631414 | |||
| c15ae24c7a | |||
| 7f02dccc6b | |||
| 34a6c50598 | |||
| 191c9e66fe | |||
| d7fec73c77 | |||
| 590c62eadd | |||
| fdd4ff827e | |||
| d2e1c7b56f | |||
| 09f764c0df | |||
| 447449e1b3 | |||
| d43408cf01 | |||
|
|
9bfc55f2d6 | ||
|
|
1b0d9fd0b0 | ||
|
|
f8ca8570af | ||
| e25f1c75b5 | |||
| c5c40f58ab | |||
|
|
2971027af2 | ||
|
|
34a23ab94d | ||
|
|
8b3965d0b1 | ||
| 42d7c0059b | |||
|
|
6413d5a3d6 | ||
|
|
e4f9423ca6 | ||
|
|
1bb878848f | ||
|
|
ae497eac6e | ||
|
|
2cf0a9f711 |
5
3d-generation-pipeline/.env.example
Normal file
5
3d-generation-pipeline/.env.example
Normal file
@ -0,0 +1,5 @@
|
||||
3D_GENERATION_URL=
|
||||
MODEL_FOLDER=
|
||||
|
||||
CLOUDFLARE_ACCOUNT_ID=
|
||||
CLOUDFLARE_API_TOKEN=
|
||||
6
3d-generation-pipeline/.gitignore
vendored
Normal file
6
3d-generation-pipeline/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
.venv
|
||||
.env
|
||||
__pycache__
|
||||
images/
|
||||
models/
|
||||
logs/
|
||||
6
3d-generation-pipeline/README.md
Normal file
6
3d-generation-pipeline/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
### TODO
|
||||
* Artikkel text-to-3d prompt engineeringu kohta: "Sel3DCraft: Interactive Visual Prompts for User-Friendly Text-to-3D Generation"
|
||||
* TRELLIS: postprocessing_utils: texture baking mode: 'opt' vs 'fast' - hardcoded 'opt', kui võimaldada 'fast' siis tuleb error
|
||||
|
||||
### Notes
|
||||
* TRELLIS: added functionality to specify texture baking optimisation total steps as an argument (`texture_opt_total_steps`), to replace the hardcoded 2500. But this is not tracked in Git (because modified this https://github.com/IgorAherne/trellis-stable-projectorz/releases/tag/latest)
|
||||
61
3d-generation-pipeline/cloudflare_api.py
Normal file
61
3d-generation-pipeline/cloudflare_api.py
Normal file
@ -0,0 +1,61 @@
|
||||
import base64
|
||||
import requests
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
ACCOUNT_ID = os.environ["CLOUDFLARE_ACCOUNT_ID"]
|
||||
API_TOKEN = os.environ["CLOUDFLARE_API_TOKEN"]
|
||||
|
||||
def text_to_image_cloudflare(prompt, output_path):
|
||||
MODEL = "@cf/black-forest-labs/flux-1-schnell"
|
||||
URL = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/run/{MODEL}"
|
||||
|
||||
payload = {
|
||||
"prompt": prompt,
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Authorization": f"Bearer {API_TOKEN}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
resp = requests.post(URL, json=payload, headers=headers, timeout=60)
|
||||
resp.raise_for_status()
|
||||
|
||||
data = resp.json()
|
||||
b64 = data["result"]["image"]
|
||||
if not b64:
|
||||
raise RuntimeError(f"Unexpected response structure: {data}")
|
||||
|
||||
img_bytes = base64.b64decode(b64)
|
||||
|
||||
with open(output_path, "wb") as f:
|
||||
f.write(img_bytes)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def refine_text_prompt(prompt):
|
||||
MODEL = "@cf/meta/llama-3.2-3b-instruct"
|
||||
URL = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/run/{MODEL}"
|
||||
|
||||
instructions = """
|
||||
User is talking about some object. Your task is to generate a short and concise description of it. Use only user's own words, keep it as short as possible.
|
||||
Example:
|
||||
User: 'Umm, okay, I would like a really cool sword, with for example a bright orange crossguard. And also it should be slightly curved.'
|
||||
You: 'a slightly curved sword with bright orange crossguard'
|
||||
"""
|
||||
|
||||
response = requests.post(URL,
|
||||
headers={"Authorization": f"Bearer {API_TOKEN}"},
|
||||
json={
|
||||
"messages": [
|
||||
{"role": "system", "content": instructions},
|
||||
{"role": "user", "content": prompt}
|
||||
]
|
||||
}
|
||||
)
|
||||
data = response.json()
|
||||
return data["result"]["response"]
|
||||
86
3d-generation-pipeline/generate_image_local.py
Normal file
86
3d-generation-pipeline/generate_image_local.py
Normal file
@ -0,0 +1,86 @@
|
||||
import requests
|
||||
|
||||
from invokeai_mcp_server import create_text2img_graph, enqueue_graph, wait_for_completion, get_image_url
|
||||
from urllib.parse import urljoin
|
||||
|
||||
|
||||
INVOKEAI_BASE_URL = "http://127.0.0.1:9090"
|
||||
|
||||
|
||||
async def generate_image(arguments: dict):
|
||||
|
||||
# Extract parameters
|
||||
prompt = arguments["prompt"]
|
||||
negative_prompt = arguments.get("negative_prompt", "")
|
||||
width = arguments.get("width", 512)
|
||||
height = arguments.get("height", 512)
|
||||
steps = arguments.get("steps", 30)
|
||||
cfg_scale = arguments.get("cfg_scale", 7.5)
|
||||
scheduler = arguments.get("scheduler", "euler")
|
||||
seed = arguments.get("seed")
|
||||
model_key = arguments.get("model_key")
|
||||
lora_key = arguments.get("lora_key")
|
||||
lora_weight = arguments.get("lora_weight", 1.0)
|
||||
vae_key = arguments.get("vae_key")
|
||||
|
||||
print(f"Generating image with prompt: {prompt[:50]}...")
|
||||
|
||||
# Create graph
|
||||
graph = await create_text2img_graph(
|
||||
prompt=prompt,
|
||||
negative_prompt=negative_prompt,
|
||||
model_key=model_key,
|
||||
lora_key=lora_key,
|
||||
lora_weight=lora_weight,
|
||||
vae_key=vae_key,
|
||||
width=width,
|
||||
height=height,
|
||||
steps=steps,
|
||||
cfg_scale=cfg_scale,
|
||||
scheduler=scheduler,
|
||||
seed=seed
|
||||
)
|
||||
|
||||
# Enqueue and wait for completion
|
||||
result = await enqueue_graph(graph)
|
||||
batch_id = result["batch"]["batch_id"]
|
||||
|
||||
print(f"Enqueued batch {batch_id}, waiting for completion...")
|
||||
|
||||
completed = await wait_for_completion(batch_id)
|
||||
|
||||
# Extract image name from result
|
||||
if "result" in completed and "outputs" in completed["result"]:
|
||||
outputs = completed["result"]["outputs"]
|
||||
# Find the image output
|
||||
for node_id, output in outputs.items():
|
||||
if output.get("type") == "image_output":
|
||||
image_name = output["image"]["image_name"]
|
||||
image_url = await get_image_url(image_name)
|
||||
|
||||
return urljoin(INVOKEAI_BASE_URL, image_url)
|
||||
|
||||
raise RuntimeError("Failed to generate image!")
|
||||
|
||||
def download_file(url, filepath):
|
||||
response = requests.get(url)
|
||||
|
||||
if response.status_code == 200:
|
||||
with open(filepath, "wb") as file:
|
||||
file.write(response.content)
|
||||
else:
|
||||
raise RuntimeError(f"Failed to download image. Status code: {response.status_code}")
|
||||
|
||||
|
||||
async def text_to_image_invoke_ai(prompt, output_path):
|
||||
# see available model keys via GET http://127.0.0.1:9090/api/v2/models/?model_type=main
|
||||
args = {
|
||||
"prompt": prompt,
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"model_key": "79401292-0a6b-428d-b7d7-f1e86caeba2b" # Juggernaut XL v9
|
||||
#"model_key": "735f6485-6703-498f-929e-07cf0bbbd179" # Dreamshaper 8
|
||||
}
|
||||
image_url = await generate_image(args)
|
||||
print("got image url: ", image_url)
|
||||
download_file(image_url, output_path)
|
||||
97
3d-generation-pipeline/generate_model_local.py
Normal file
97
3d-generation-pipeline/generate_model_local.py
Normal file
@ -0,0 +1,97 @@
|
||||
import subprocess
|
||||
import os
|
||||
import time
|
||||
import requests
|
||||
import base64
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
MODEL_FOLDER = os.environ["MODEL_FOLDER"]
|
||||
API_URL = os.environ["3D_GENERATION_URL"]
|
||||
|
||||
|
||||
def image_to_3d_subprocess(image_path, output_path):
|
||||
venv_python = MODEL_FOLDER + r"\.venv\Scripts\python.exe"
|
||||
script_path = MODEL_FOLDER + r"\run.py"
|
||||
|
||||
args = [image_path, "--output-dir", output_path]
|
||||
command = [venv_python, script_path] + args
|
||||
|
||||
try:
|
||||
# Run the subprocess
|
||||
result = subprocess.run(command, capture_output=True, text=True)
|
||||
|
||||
# Print output and errors
|
||||
print("STDOUT:\n", result.stdout)
|
||||
print("STDERR:\n", result.stderr)
|
||||
print("Return Code:", result.returncode)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error occurred: {e}")
|
||||
|
||||
|
||||
|
||||
def generate_no_preview(image_base64: str):
|
||||
"""Generate 3D model from a single base64-encoded image without previews.
|
||||
|
||||
Args:
|
||||
image_base64: Base64 string of the image (without 'data:image/...' prefix)
|
||||
"""
|
||||
try:
|
||||
# Set generation parameters
|
||||
params = {
|
||||
'image_base64': image_base64,
|
||||
'seed': 42,
|
||||
'ss_guidance_strength': 7.5,
|
||||
'ss_sampling_steps': 10,
|
||||
'slat_guidance_strength': 7.5,
|
||||
'slat_sampling_steps': 10,
|
||||
'mesh_simplify_ratio': 0.99,
|
||||
'texture_size': 1024,
|
||||
#'texture_baking_mode': 'opt',
|
||||
'texture_opt_total_steps': 1000,
|
||||
'output_format': 'glb'
|
||||
}
|
||||
|
||||
# Start generation
|
||||
print("Starting generation...")
|
||||
response = requests.post(f"{API_URL}/generate_no_preview", data=params)
|
||||
response.raise_for_status()
|
||||
|
||||
# Poll status until complete
|
||||
while True:
|
||||
status = requests.get(f"{API_URL}/status").json()
|
||||
print(f"Progress: {status['progress']}%")
|
||||
|
||||
if status['status'] == 'COMPLETE':
|
||||
break
|
||||
elif status['status'] == 'FAILED':
|
||||
raise Exception(f"Generation failed: {status['message']}")
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
# Download the model
|
||||
print("Downloading model...")
|
||||
response = requests.get(f"{API_URL}/download/model")
|
||||
response.raise_for_status()
|
||||
return response.content
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {str(e)}")
|
||||
return None
|
||||
|
||||
def image_to_3d_api(image_path, output_path):
|
||||
with open(image_path, 'rb') as image_file:
|
||||
image_data = image_file.read()
|
||||
|
||||
base64_encoded = base64.b64encode(image_data).decode('utf-8')
|
||||
model_binary = generate_no_preview(base64_encoded)
|
||||
|
||||
output_file = f"{output_path}.glb"
|
||||
with open(output_file, 'wb') as f:
|
||||
f.write(model_binary)
|
||||
|
||||
return output_file
|
||||
|
||||
152
3d-generation-pipeline/notebooks/cloudflare_API_test.ipynb
Normal file
152
3d-generation-pipeline/notebooks/cloudflare_API_test.ipynb
Normal file
@ -0,0 +1,152 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1dc6faae",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"import base64\n",
|
||||
"import requests\n",
|
||||
"from dotenv import load_dotenv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b3107275",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"load_dotenv()\n",
|
||||
"\n",
|
||||
"ACCOUNT_ID = os.environ[\"CLOUDFLARE_ACCOUNT_ID\"]\n",
|
||||
"API_TOKEN = os.environ[\"CLOUDFLARE_API_TOKEN\"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "999adf95",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Text to image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "40b35163",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Saved: output.jpg (263282 bytes)\n",
|
||||
"Saved: image9.jpg (263282 bytes)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"MODEL = \"@cf/black-forest-labs/flux-1-schnell\"\n",
|
||||
"URL = f\"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/run/{MODEL}\"\n",
|
||||
"\n",
|
||||
"payload = {\n",
|
||||
" \"prompt\": \"a slightly curved broadsword with a fancy golden crossguard\",\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"headers = {\n",
|
||||
" \"Authorization\": f\"Bearer {API_TOKEN}\",\n",
|
||||
" \"Content-Type\": \"application/json\",\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"resp = requests.post(URL, json=payload, headers=headers, timeout=60)\n",
|
||||
"resp.raise_for_status()\n",
|
||||
"\n",
|
||||
"data = resp.json()\n",
|
||||
"b64 = data[\"result\"][\"image\"]\n",
|
||||
"if not b64:\n",
|
||||
" raise RuntimeError(f\"Unexpected response structure: {data}\")\n",
|
||||
"\n",
|
||||
"img_bytes = base64.b64decode(b64)\n",
|
||||
"\n",
|
||||
"out_path = \"output.jpg\"\n",
|
||||
"with open(out_path, \"wb\") as f:\n",
|
||||
" f.write(img_bytes)\n",
|
||||
"\n",
|
||||
"print(f\"Saved: {out_path} ({len(img_bytes)} bytes)\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "14a874c4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Text prompt refinement"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "485f6f46",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\"dark wooden battleaxe with bronze blade\"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"MODEL = \"@cf/meta/llama-3.2-3b-instruct\"\n",
|
||||
"URL = f\"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/run/{MODEL}\"\n",
|
||||
"\n",
|
||||
"instructions = \"\"\"\n",
|
||||
"User is talking about some object. Your task is to generate a short and concise description of it. Use only user's own words, keep it as short as possible.\n",
|
||||
"Example:\n",
|
||||
"User: 'Umm, okay, I would like a really cool sword, with for example a bright orange crossguard. And also it should be slightly curved.'\n",
|
||||
"You: 'a slightly curved sword with bright orange crossguard'\n",
|
||||
"\"\"\"\n",
|
||||
"prompt = \"Umm, alright, can you please give me an epic battleaxe? It should have a dark wooden shaft and bronze blade.\"\n",
|
||||
"\n",
|
||||
"response = requests.post(URL,\n",
|
||||
" headers={\"Authorization\": f\"Bearer {API_TOKEN}\"},\n",
|
||||
" json={\n",
|
||||
" \"messages\": [\n",
|
||||
" {\"role\": \"system\", \"content\": instructions},\n",
|
||||
" {\"role\": \"user\", \"content\": prompt}\n",
|
||||
" ]\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"data = response.json()\n",
|
||||
"result_text = data[\"result\"][\"response\"]\n",
|
||||
"print(result_text)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.11"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
122
3d-generation-pipeline/notebooks/local_image_generation.ipynb
Normal file
122
3d-generation-pipeline/notebooks/local_image_generation.ipynb
Normal file
@ -0,0 +1,122 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "50e24baa",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from invokeai_mcp_server import create_text2img_graph, enqueue_graph, wait_for_completion, get_image_url\n",
|
||||
"from urllib.parse import urljoin\n",
|
||||
"\n",
|
||||
"import asyncio"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0407cd9a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"INVOKEAI_BASE_URL = \"http://127.0.0.1:9090\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"async def generate_image(arguments: dict):\n",
|
||||
"\n",
|
||||
" # Extract parameters\n",
|
||||
" prompt = arguments[\"prompt\"]\n",
|
||||
" negative_prompt = arguments.get(\"negative_prompt\", \"\")\n",
|
||||
" width = arguments.get(\"width\", 512)\n",
|
||||
" height = arguments.get(\"height\", 512)\n",
|
||||
" steps = arguments.get(\"steps\", 30)\n",
|
||||
" cfg_scale = arguments.get(\"cfg_scale\", 7.5)\n",
|
||||
" scheduler = arguments.get(\"scheduler\", \"euler\")\n",
|
||||
" seed = arguments.get(\"seed\")\n",
|
||||
" model_key = arguments.get(\"model_key\")\n",
|
||||
" lora_key = arguments.get(\"lora_key\")\n",
|
||||
" lora_weight = arguments.get(\"lora_weight\", 1.0)\n",
|
||||
" vae_key = arguments.get(\"vae_key\")\n",
|
||||
"\n",
|
||||
" #logger.info(f\"Generating image with prompt: {prompt[:50]}...\")\n",
|
||||
"\n",
|
||||
" # Create graph\n",
|
||||
" graph = await create_text2img_graph(\n",
|
||||
" prompt=prompt,\n",
|
||||
" negative_prompt=negative_prompt,\n",
|
||||
" model_key=model_key,\n",
|
||||
" lora_key=lora_key,\n",
|
||||
" lora_weight=lora_weight,\n",
|
||||
" vae_key=vae_key,\n",
|
||||
" width=width,\n",
|
||||
" height=height,\n",
|
||||
" steps=steps,\n",
|
||||
" cfg_scale=cfg_scale,\n",
|
||||
" scheduler=scheduler,\n",
|
||||
" seed=seed\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" # Enqueue and wait for completion\n",
|
||||
" result = await enqueue_graph(graph)\n",
|
||||
" batch_id = result[\"batch\"][\"batch_id\"]\n",
|
||||
"\n",
|
||||
" #logger.info(f\"Enqueued batch {batch_id}, waiting for completion...\")\n",
|
||||
"\n",
|
||||
" completed = await wait_for_completion(batch_id)\n",
|
||||
"\n",
|
||||
" # Extract image name from result\n",
|
||||
" if \"result\" in completed and \"outputs\" in completed[\"result\"]:\n",
|
||||
" outputs = completed[\"result\"][\"outputs\"]\n",
|
||||
" # Find the image output\n",
|
||||
" for node_id, output in outputs.items():\n",
|
||||
" if output.get(\"type\") == \"image_output\":\n",
|
||||
" image_name = output[\"image\"][\"image_name\"]\n",
|
||||
" image_url = await get_image_url(image_name)\n",
|
||||
"\n",
|
||||
" text=f\"Image generated successfully!\\n\\nImage Name: {image_name}\\nImage URL: {image_url}\\n\\nYou can view the image at: {urljoin(INVOKEAI_BASE_URL, f'/api/v1/images/i/{image_name}/full')}\"\n",
|
||||
" print(text)\n",
|
||||
"\n",
|
||||
" # Fallback if we couldn't find image output\n",
|
||||
" #text=f\"Image generation completed but output format was unexpected. Batch ID: {batch_id}\\n\\nResult: {json.dumps(completed, indent=2)}\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6cf9d879",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"async def main():\n",
|
||||
" args = {\n",
|
||||
" \"prompt\": \"a golden katana with a fancy pommel\"\n",
|
||||
" }\n",
|
||||
" await generate_image(args)\n",
|
||||
"\n",
|
||||
"asyncio.run(main())"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.11"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
165
3d-generation-pipeline/notebooks/subprocess_test.ipynb
Normal file
165
3d-generation-pipeline/notebooks/subprocess_test.ipynb
Normal file
@ -0,0 +1,165 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "4826c91d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'2025-10-18-16-35-47'"
|
||||
]
|
||||
},
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"datetime.now().strftime(\"%Y-%m-%d-%H-%M-%S\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "9419e692",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"STDOUT:\n",
|
||||
" Device used: cuda\n",
|
||||
"After Remesh 9998 19996\n",
|
||||
"\n",
|
||||
"STDERR:\n",
|
||||
" D:\\users\\henrisel\\stable-fast-3d\\.venv\\lib\\site-packages\\timm\\models\\layers\\__init__.py:48: FutureWarning: Importing from timm.models.layers is deprecated, please import via timm.layers\n",
|
||||
" warnings.warn(f\"Importing from {__name__} is deprecated, please import via timm.layers\", FutureWarning)\n",
|
||||
"\n",
|
||||
" 0%| | 0/1 [00:00<?, ?it/s]\n",
|
||||
" 0%| | 0/1 [00:00<?, ?it/s]\n",
|
||||
"Traceback (most recent call last):\n",
|
||||
" File \"D:\\users\\henrisel\\stable-fast-3d\\run.py\", line 122, in <module>\n",
|
||||
" mesh, glob_dict = model.run_image(\n",
|
||||
" File \"D:\\users\\henrisel\\stable-fast-3d\\sf3d\\system.py\", line 286, in run_image\n",
|
||||
" meshes, global_dict = self.generate_mesh(\n",
|
||||
" File \"D:\\users\\henrisel\\stable-fast-3d\\sf3d\\system.py\", line 369, in generate_mesh\n",
|
||||
" rast = self.baker.rasterize(\n",
|
||||
" File \"D:\\users\\henrisel\\stable-fast-3d\\.venv\\lib\\site-packages\\texture_baker\\baker.py\", line 28, in rasterize\n",
|
||||
" return torch.ops.texture_baker_cpp.rasterize(\n",
|
||||
" File \"D:\\users\\henrisel\\stable-fast-3d\\.venv\\lib\\site-packages\\torch\\_ops.py\", line 1243, in __call__\n",
|
||||
" return self._op(*args, **kwargs)\n",
|
||||
"NotImplementedError: Could not run 'texture_baker_cpp::rasterize' with arguments from the 'CUDA' backend. This could be because the operator doesn't exist for this backend, or was omitted during the selective/custom build process (if using custom build). If you are a Facebook employee using PyTorch on mobile, please visit https://fburl.com/ptmfixes for possible resolutions. 'texture_baker_cpp::rasterize' is only available for these backends: [CPU, Meta, BackendSelect, Python, FuncTorchDynamicLayerBackMode, Functionalize, Named, Conjugate, Negative, ZeroTensor, ADInplaceOrView, AutogradOther, AutogradCPU, AutogradCUDA, AutogradXLA, AutogradMPS, AutogradXPU, AutogradHPU, AutogradLazy, AutogradMTIA, AutogradMAIA, AutogradMeta, Tracer, AutocastCPU, AutocastMTIA, AutocastMAIA, AutocastXPU, AutocastMPS, AutocastCUDA, FuncTorchBatched, BatchedNestedTensor, FuncTorchVmapMode, Batched, VmapMode, FuncTorchGradWrapper, PythonTLSSnapshot, FuncTorchDynamicLayerFrontMode, PreDispatch, PythonDispatcher].\n",
|
||||
"\n",
|
||||
"CPU: registered at texture_baker\\csrc\\baker.cpp:543 [kernel]\n",
|
||||
"Meta: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\MetaFallbackKernel.cpp:23 [backend fallback]\n",
|
||||
"BackendSelect: fallthrough registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\BackendSelectFallbackKernel.cpp:3 [backend fallback]\n",
|
||||
"Python: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\PythonFallbackKernel.cpp:194 [backend fallback]\n",
|
||||
"FuncTorchDynamicLayerBackMode: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\functorch\\DynamicLayer.cpp:479 [backend fallback]\n",
|
||||
"Functionalize: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\FunctionalizeFallbackKernel.cpp:375 [backend fallback]\n",
|
||||
"Named: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\NamedRegistrations.cpp:7 [backend fallback]\n",
|
||||
"Conjugate: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\ConjugateFallback.cpp:17 [backend fallback]\n",
|
||||
"Negative: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\native\\NegateFallback.cpp:18 [backend fallback]\n",
|
||||
"ZeroTensor: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\ZeroTensorFallback.cpp:86 [backend fallback]\n",
|
||||
"ADInplaceOrView: fallthrough registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\VariableFallbackKernel.cpp:104 [backend fallback]\n",
|
||||
"AutogradOther: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\VariableFallbackKernel.cpp:63 [backend fallback]\n",
|
||||
"AutogradCPU: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\VariableFallbackKernel.cpp:67 [backend fallback]\n",
|
||||
"AutogradCUDA: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\VariableFallbackKernel.cpp:75 [backend fallback]\n",
|
||||
"AutogradXLA: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\VariableFallbackKernel.cpp:87 [backend fallback]\n",
|
||||
"AutogradMPS: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\VariableFallbackKernel.cpp:95 [backend fallback]\n",
|
||||
"AutogradXPU: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\VariableFallbackKernel.cpp:71 [backend fallback]\n",
|
||||
"AutogradHPU: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\VariableFallbackKernel.cpp:108 [backend fallback]\n",
|
||||
"AutogradLazy: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\VariableFallbackKernel.cpp:91 [backend fallback]\n",
|
||||
"AutogradMTIA: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\VariableFallbackKernel.cpp:79 [backend fallback]\n",
|
||||
"AutogradMAIA: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\VariableFallbackKernel.cpp:83 [backend fallback]\n",
|
||||
"AutogradMeta: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\VariableFallbackKernel.cpp:99 [backend fallback]\n",
|
||||
"Tracer: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\torch\\csrc\\autograd\\TraceTypeManual.cpp:294 [backend fallback]\n",
|
||||
"AutocastCPU: fallthrough registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\autocast_mode.cpp:322 [backend fallback]\n",
|
||||
"AutocastMTIA: fallthrough registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\autocast_mode.cpp:466 [backend fallback]\n",
|
||||
"AutocastMAIA: fallthrough registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\autocast_mode.cpp:504 [backend fallback]\n",
|
||||
"AutocastXPU: fallthrough registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\autocast_mode.cpp:542 [backend fallback]\n",
|
||||
"AutocastMPS: fallthrough registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\autocast_mode.cpp:209 [backend fallback]\n",
|
||||
"AutocastCUDA: fallthrough registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\autocast_mode.cpp:165 [backend fallback]\n",
|
||||
"FuncTorchBatched: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\functorch\\LegacyBatchingRegistrations.cpp:731 [backend fallback]\n",
|
||||
"BatchedNestedTensor: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\functorch\\LegacyBatchingRegistrations.cpp:758 [backend fallback]\n",
|
||||
"FuncTorchVmapMode: fallthrough registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\functorch\\VmapModeRegistrations.cpp:27 [backend fallback]\n",
|
||||
"Batched: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\LegacyBatchingRegistrations.cpp:1075 [backend fallback]\n",
|
||||
"VmapMode: fallthrough registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\VmapModeRegistrations.cpp:33 [backend fallback]\n",
|
||||
"FuncTorchGradWrapper: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\functorch\\TensorWrapper.cpp:210 [backend fallback]\n",
|
||||
"PythonTLSSnapshot: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\PythonFallbackKernel.cpp:202 [backend fallback]\n",
|
||||
"FuncTorchDynamicLayerFrontMode: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\functorch\\DynamicLayer.cpp:475 [backend fallback]\n",
|
||||
"PreDispatch: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\PythonFallbackKernel.cpp:206 [backend fallback]\n",
|
||||
"PythonDispatcher: registered at C:\\actions-runner\\_work\\pytorch\\pytorch\\pytorch\\aten\\src\\ATen\\core\\PythonFallbackKernel.cpp:198 [backend fallback]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Return Code: 1\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import subprocess\n",
|
||||
"\n",
|
||||
"MODEL_FOLDER = r\"D:\\users\\henrisel\\stable-fast-3d\"\n",
|
||||
"PROJECT_FOLDER = r\"D:\\users\\henrisel\\DeltaVR3DModelGeneration\\3d-generation-pipeline\"\n",
|
||||
"\n",
|
||||
"# Path to the Python interpreter in the other virtual environment\n",
|
||||
"venv_python = MODEL_FOLDER + r\"\\.venv\\Scripts\\python.exe\"\n",
|
||||
"\n",
|
||||
"# Path to the .py file you want to run\n",
|
||||
"script_path = MODEL_FOLDER + r\"\\run.py\"\n",
|
||||
"\n",
|
||||
"# Optional: arguments to pass to the script\n",
|
||||
"args = [MODEL_FOLDER + r\"\\demo_files\\examples\\chair1.png\", \"--output-dir\", PROJECT_FOLDER + r\"\\images\"]\n",
|
||||
"\n",
|
||||
"# Build the command\n",
|
||||
"command = [venv_python, script_path] + args\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" # Run the subprocess\n",
|
||||
" result = subprocess.run(command, capture_output=True, text=True)\n",
|
||||
"\n",
|
||||
" # Print output and errors\n",
|
||||
" print(\"STDOUT:\\n\", result.stdout)\n",
|
||||
" print(\"STDERR:\\n\", result.stderr)\n",
|
||||
" print(\"Return Code:\", result.returncode)\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Error occurred: {e}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ee480ba6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
7
3d-generation-pipeline/requirements.txt
Normal file
7
3d-generation-pipeline/requirements.txt
Normal file
@ -0,0 +1,7 @@
|
||||
#torch==2.8.0+cu129 https://pytorch.org/get-started/previous-versions/
|
||||
transformers==4.57.0
|
||||
git+https://github.com/huggingface/diffusers.git
|
||||
accelerate==1.10.1
|
||||
huggingface_hub[hf_xet]==1.1.10
|
||||
sentencepiece==0.2.1
|
||||
protobuf==6.32.1
|
||||
62
3d-generation-pipeline/start_pipeline.py
Normal file
62
3d-generation-pipeline/start_pipeline.py
Normal file
@ -0,0 +1,62 @@
|
||||
import argparse
|
||||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from generate_image_local import text_to_image_invoke_ai
|
||||
from generate_model_local import image_to_3d_api
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
def get_timestamp():
|
||||
return datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||
|
||||
def setup_logger(base_folder, timestamp):
|
||||
log_dir = base_folder / Path("logs")
|
||||
log_dir.mkdir(parents=True, exist_ok=True)
|
||||
logging.basicConfig(
|
||||
filename=log_dir / f"{timestamp}.log",
|
||||
level=logging.INFO,
|
||||
force=True
|
||||
)
|
||||
|
||||
|
||||
async def main():
|
||||
parser = argparse.ArgumentParser(description="Text to 3D model pipeline")
|
||||
parser.add_argument("--prompt", type=str, required=True, help="User text prompt")
|
||||
args = parser.parse_args()
|
||||
|
||||
input_prompt = args.prompt
|
||||
print(f"Input prompt: {input_prompt}")
|
||||
image_generation_prompt = input_prompt + ", single object, fully visible, plain neutral background, high-resolution, sharp details, soft studio lighting, front and side visible, realistic style, true-to-scale"
|
||||
|
||||
pipeline_folder = Path(__file__).resolve().parent
|
||||
timestamp = get_timestamp()
|
||||
setup_logger(pipeline_folder, timestamp)
|
||||
time_checkpoint = time.time()
|
||||
|
||||
image_path = pipeline_folder / "images" / f"{timestamp}.jpg"
|
||||
# TODO: use Invoke AI or Cloudflare, depending on env var
|
||||
#text_to_image_cloudflare(image_generation_prompt, image_path)
|
||||
await text_to_image_invoke_ai(image_generation_prompt, image_path)
|
||||
|
||||
image_generation_time = time.time() - time_checkpoint
|
||||
time_checkpoint = time.time()
|
||||
logging.info(f"Image generation time: {round(image_generation_time, 1)} s")
|
||||
print(f"Generated image file: {image_path}")
|
||||
|
||||
model_path = pipeline_folder / "models" / timestamp
|
||||
model_file = image_to_3d_api(image_path, model_path)
|
||||
|
||||
model_generation_time = time.time() - time_checkpoint
|
||||
logging.info(f"Model generation time: {round(model_generation_time, 1)} s")
|
||||
print(f"Generated 3D model file: {model_file}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@ -7,7 +7,7 @@ TextureImporter:
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
sRGBTexture: 0
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
@ -54,7 +54,7 @@ TextureImporter:
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureType: 1
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
|
||||
133
Assets/_PROJECT/Materials/Green.mat
Normal file
133
Assets/_PROJECT/Materials/Green.mat
Normal file
@ -0,0 +1,133 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Green
|
||||
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap:
|
||||
RenderType: Opaque
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _SpecGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_Lightmaps:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_LightmapsInd:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_ShadowMasks:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AlphaClip: 0
|
||||
- _AlphaToMask: 0
|
||||
- _Blend: 0
|
||||
- _BlendModePreserveSpecular: 1
|
||||
- _BumpScale: 1
|
||||
- _ClearCoatMask: 0
|
||||
- _ClearCoatSmoothness: 0
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailAlbedoMapScale: 1
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _EnvironmentReflections: 1
|
||||
- _GlossMapScale: 0
|
||||
- _Glossiness: 0
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.005
|
||||
- _QueueOffset: 0
|
||||
- _ReceiveShadows: 1
|
||||
- _Smoothness: 0.5
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _WorkflowMode: 1
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 0, g: 1, b: 0.0381248, a: 1}
|
||||
- _Color: {r: 0, g: 1, b: 0.0381248, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
--- !u!114 &6221994712197478572
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
||||
8
Assets/_PROJECT/Materials/Green.mat.meta
Normal file
8
Assets/_PROJECT/Materials/Green.mat.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 937c5f357ed270843bd43d1f7d5d475b
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
133
Assets/_PROJECT/Materials/Red.mat
Normal file
133
Assets/_PROJECT/Materials/Red.mat
Normal file
@ -0,0 +1,133 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &-7093071968994914494
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
version: 7
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Red
|
||||
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap:
|
||||
RenderType: Opaque
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _SpecGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_Lightmaps:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_LightmapsInd:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_ShadowMasks:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AlphaClip: 0
|
||||
- _AlphaToMask: 0
|
||||
- _Blend: 0
|
||||
- _BlendModePreserveSpecular: 1
|
||||
- _BumpScale: 1
|
||||
- _ClearCoatMask: 0
|
||||
- _ClearCoatSmoothness: 0
|
||||
- _Cull: 2
|
||||
- _Cutoff: 0.5
|
||||
- _DetailAlbedoMapScale: 1
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _EnvironmentReflections: 1
|
||||
- _GlossMapScale: 0
|
||||
- _Glossiness: 0
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.005
|
||||
- _QueueOffset: 0
|
||||
- _ReceiveShadows: 1
|
||||
- _Smoothness: 0.5
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _WorkflowMode: 1
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _Color: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
8
Assets/_PROJECT/Materials/Red.mat.meta
Normal file
8
Assets/_PROJECT/Materials/Red.mat.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 707a698b0ec80454a8c68700bca72941
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/_PROJECT/Scenes/DeltaBuilding_base.unity
(Stored with Git LFS)
BIN
Assets/_PROJECT/Scenes/DeltaBuilding_base.unity
(Stored with Git LFS)
Binary file not shown.
8
Assets/_PROJECT/Scripts/3DModeGeneration.meta
Normal file
8
Assets/_PROJECT/Scripts/3DModeGeneration.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ec3982ba49c4b84ea95332cb090e115
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,144 @@
|
||||
using UnityEngine;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using GLTFast;
|
||||
|
||||
public class ModelGenerationPipelineStarter : MonoBehaviour
|
||||
{
|
||||
public Material activeMaterial;
|
||||
public Material inactiveMaterial;
|
||||
public Transform modelSpawnPoint;
|
||||
|
||||
private MeshRenderer meshRenderer;
|
||||
|
||||
public string inputPrompt;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
meshRenderer = GetComponent<MeshRenderer>();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void OnTriggerEnter(Collider other)
|
||||
{
|
||||
KbmController controller = other.GetComponent<KbmController>();
|
||||
if (controller != null)
|
||||
{
|
||||
meshRenderer.material = activeMaterial;
|
||||
|
||||
StartModeGenerationPipeline();
|
||||
//LoadModel("D:\\henrisel\\DeltaVR3DModelGeneration\\3d-generation-pipeline\\models\\2025-11-17-16-13-33\\mesh.glb");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTriggerExit(Collider other)
|
||||
{
|
||||
KbmController controller = other.GetComponent<KbmController>();
|
||||
if (controller != null)
|
||||
{
|
||||
meshRenderer.material = inactiveMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> GenerateModelAsync()
|
||||
{
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
|
||||
|
||||
// Path to your virtual environment's python.exe
|
||||
string pythonExe = @"D:\users\henrisel\DeltaVR3DModelGeneration\3d-generation-pipeline\.venv\Scripts\python.exe";
|
||||
|
||||
// Path to your Python script
|
||||
string scriptPath = @"D:\users\henrisel\DeltaVR3DModelGeneration\3d-generation-pipeline\start_pipeline.py";
|
||||
|
||||
// Arguments to pass to the script
|
||||
string arguments = $"{scriptPath} --prompt \"{inputPrompt}\"";
|
||||
|
||||
ProcessStartInfo psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = pythonExe,
|
||||
Arguments = arguments,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using (Process process = new Process())
|
||||
{
|
||||
process.StartInfo = psi;
|
||||
process.OutputDataReceived += (sender, e) => UnityEngine.Debug.Log(e.Data);
|
||||
process.ErrorDataReceived += (sender, e) => UnityEngine.Debug.LogError(e.Data);
|
||||
|
||||
process.Start();
|
||||
|
||||
string output = process.StandardOutput.ReadToEnd();
|
||||
string error = process.StandardError.ReadToEnd();
|
||||
|
||||
process.WaitForExit();
|
||||
|
||||
|
||||
// Extract model path from output
|
||||
foreach (string line in output.Split('\n'))
|
||||
{
|
||||
if (line.StartsWith("Generated 3D model file: "))
|
||||
{
|
||||
return line.Replace("Generated 3D model file: ", "").Trim();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async void StartModeGenerationPipeline()
|
||||
{
|
||||
string modelPath = await GenerateModelAsync();
|
||||
|
||||
if (!string.IsNullOrEmpty(modelPath))
|
||||
{
|
||||
UnityEngine.Debug.Log("Got generated model path: " + modelPath);
|
||||
await LoadModel(modelPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.LogError("Model path not found in Python output.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async Task LoadModel(string modelPath)
|
||||
{
|
||||
var gltf = new GltfImport();
|
||||
bool loadSuccess = await gltf.Load(modelPath);
|
||||
UnityEngine.Debug.Log("Load model success: " + loadSuccess);
|
||||
if (loadSuccess)
|
||||
{
|
||||
GameObject spawnedObject = new GameObject("spawned model");
|
||||
spawnedObject.transform.parent = modelSpawnPoint;
|
||||
spawnedObject.transform.position = modelSpawnPoint.position;
|
||||
|
||||
bool spawnSuccess = await gltf.InstantiateMainSceneAsync(spawnedObject.transform);
|
||||
UnityEngine.Debug.Log("Spawn model success: " + spawnSuccess);
|
||||
|
||||
|
||||
Transform spawnedObjectMainTransform = spawnedObject.transform.GetChild(0).transform;
|
||||
GameObject spawnedObjectBody = spawnedObjectMainTransform.GetChild(0).transform.gameObject;
|
||||
MeshCollider collider = spawnedObjectBody.AddComponent<MeshCollider>();
|
||||
collider.convex = true;
|
||||
MeshRenderer renderer = spawnedObjectBody.GetComponent<MeshRenderer>();
|
||||
renderer.material.SetFloat("metallicFactor", 0);
|
||||
|
||||
spawnedObjectMainTransform.gameObject.AddComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46e67223dce9b7a4783ed36b8ed65f19
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -4,6 +4,7 @@
|
||||
"com.unity.2d.tilemap": "1.0.0",
|
||||
"com.unity.ai.navigation": "1.1.1",
|
||||
"com.unity.cinemachine": "2.9.5",
|
||||
"com.unity.cloud.gltfast": "6.14.1",
|
||||
"com.unity.collab-proxy": "2.0.1",
|
||||
"com.unity.ext.nunit": "1.0.6",
|
||||
"com.unity.feature.vr": "1.0.0",
|
||||
|
||||
@ -31,11 +31,12 @@
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.burst": {
|
||||
"version": "1.8.3",
|
||||
"version": "1.8.24",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.mathematics": "1.2.1"
|
||||
"com.unity.mathematics": "1.2.1",
|
||||
"com.unity.modules.jsonserialize": "1.0.0"
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
@ -48,6 +49,19 @@
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.cloud.gltfast": {
|
||||
"version": "6.14.1",
|
||||
"depth": 0,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.burst": "1.8.24",
|
||||
"com.unity.collections": "1.2.4",
|
||||
"com.unity.mathematics": "1.2.6",
|
||||
"com.unity.modules.jsonserialize": "1.0.0",
|
||||
"com.unity.modules.unitywebrequest": "1.0.0"
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.collab-proxy": {
|
||||
"version": "2.0.1",
|
||||
"depth": 0,
|
||||
@ -55,6 +69,16 @@
|
||||
"dependencies": {},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.collections": {
|
||||
"version": "1.2.4",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.burst": "1.6.6",
|
||||
"com.unity.test-framework": "1.1.31"
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.editorcoroutines": {
|
||||
"version": "1.0.0",
|
||||
"depth": 1,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user