import gradio as gr import plotly.graph_objs as go import trimesh import numpy as np from PIL import Image import torch from diffusers import StableDiffusionPipeline import os import matplotlib.pyplot as plt # Load the Stable Diffusion model for text-to-image generation device = "cuda" if torch.cuda.is_available() else "cpu" pipeline = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4").to(device) # Get the current directory current_dir = os.getcwd() # Default object file path DEFAULT_OBJ_FILE = os.path.join(current_dir, "female.obj") # Temporary texture file path TEMP_TEXTURE_FILE = os.path.join(current_dir, "generated_texture.png") # File path to save the 2D image OUTPUT_IMAGE_FILE = os.path.join(current_dir, "output_image.png") DEFAULT_GLB_FILE= os.path.join(current_dir, "vroid_girl1.glb") def apply_texture(mesh, texture_file): texture_image = Image.open(texture_file) uv_coords = mesh.visual.uv uv_coords = np.clip(uv_coords, 0, 1) texture_colors = np.array([ texture_image.getpixel(( int(u * (texture_image.width - 1)), int(v * (texture_image.height - 1)) )) for u, v in uv_coords ]) texture_colors = texture_colors / 255.0 return texture_colors def display_3d_object(obj_file, texture_file, light_intensity, ambient_intensity, color): file_extension = obj_file.split('.')[-1].lower() if file_extension == 'obj': mesh = trimesh.load(obj_file) elif file_extension == 'glb': mesh = load_glb_file(obj_file) else: raise ValueError("Unsupported file format. Please upload a .obj or .glb file.") if texture_file: colors = apply_texture(mesh, texture_file) else: colors = color ambient_intensity = max(0, min(ambient_intensity, 1)) fig = go.Figure(data=[ go.Mesh3d( x=mesh.vertices[:, 0], y=mesh.vertices[:, 1], z=mesh.vertices[:, 2], i=mesh.faces[:, 0], j=mesh.faces[:, 1], k=mesh.faces[:, 2], facecolor=colors if texture_file else None, color=color if not texture_file else None, opacity=0.50, lighting=dict( ambient=ambient_intensity, diffuse=light_intensity, specular=0.5, roughness=0.1, fresnel=0.2 ), lightposition=dict( x=100, y=200, z=300 ) ) ]) fig.update_layout(scene=dict(aspectmode='data')) return fig def load_glb_file(filename): trimesh_scene = trimesh.load(filename) if isinstance(trimesh_scene, trimesh.Scene): mesh = trimesh_scene.dump(concatenate=True) else: mesh = trimesh_scene return mesh def extract_uv_texture(obj_file): mesh = trimesh.load(obj_file) if mesh.visual.uv is None or len(mesh.visual.uv) == 0: raise ValueError("The mesh does not have UV mapping information.") texture_image = None if mesh.visual.material.image is not None: texture_image = mesh.visual.material.image else: texture_size = 1024 texture_image = Image.new('RGB', (texture_size, texture_size), color=(255, 255, 255)) return texture_image def generate_clothing_image(prompt): image = pipeline(prompt).images[0] image.save(TEMP_TEXTURE_FILE) return TEMP_TEXTURE_FILE, image def update_texture_display(prompt, texture_file): if prompt: texture_path, image = generate_clothing_image(prompt) return image elif texture_file: return Image.open(texture_file) return None with gr.Blocks() as demo: gr.Markdown("## 3D Object Viewer with Custom Texture, Color, and Adjustable Lighting") with gr.Row(): with gr.Column(scale=1): gr.Markdown("### Texture Options") prompt_input = gr.Textbox(label="Enter a Prompt to Generate Texture", placeholder="Type a prompt...") generate_button = gr.Button("Generate Texture") texture_file = gr.File(label="Upload Texture file (PNG or JPG, optional)", type="filepath") texture_preview = gr.Image(label="Texture Preview", visible=True) gr.Markdown("### Lighting & Color Settings") light_intensity_slider = gr.Slider(minimum=0, maximum=2, step=0.1, value=0.8, label="Light Intensity") ambient_intensity_slider = gr.Slider(minimum=0, maximum=1, step=0.1, value=0.5, label="Ambient Intensity") color_picker = gr.ColorPicker(value="#D3D3D3", label="Object Color") submit_button = gr.Button("Submit") obj_file = gr.File(label="Upload OBJ or GLB file", value=DEFAULT_OBJ_FILE, type='filepath') with gr.Column(scale=2): display = gr.Plot(label="3D Viewer") extract_button = gr.Button("Extract UV Texture") output_image = gr.Image(label="Extracted UV Texture", visible=True) def update_display(file, texture, light_intensity, ambient_intensity, color): texture_to_use = TEMP_TEXTURE_FILE if os.path.exists(TEMP_TEXTURE_FILE) else texture return display_3d_object(file, texture_to_use, light_intensity, ambient_intensity, color) def extract_and_display_uv_texture(file): uv_texture_image = extract_uv_texture(file) uv_texture_image.save(OUTPUT_IMAGE_FILE) return uv_texture_image submit_button.click(fn=update_display, inputs=[obj_file, texture_file, light_intensity_slider, ambient_intensity_slider, color_picker], outputs=display) generate_button.click(fn=update_texture_display, inputs=[prompt_input, texture_file], outputs=texture_preview) texture_file.change(fn=update_texture_display, inputs=[prompt_input, texture_file], outputs=texture_preview) extract_button.click(fn=extract_and_display_uv_texture, inputs=[obj_file], outputs=output_image) demo.load(fn=update_display, inputs=[obj_file, texture_file, light_intensity_slider, ambient_intensity_slider, color_picker], outputs=display) gr.Examples( examples=[[DEFAULT_OBJ_FILE, None],[DEFAULT_GLB_FILE, None]], inputs=[obj_file, texture_file], label="Example Files" ) demo.launch(debug=True)