Wonder3D: Single-Image 3D With Textured Meshes That Actually Look Good
I needed to convert product photos into 3D models for a web configurator. Upload a photo, get a rotatable 3D model with textures. Wonder3D promised this, but the textures were blurry and had obvious seams. The UV mapping was terrible - textures would stretch or repeat. Here's how I got clean, production-ready textured meshes.
Problem
The generated textures were low resolution (512x512) and blurry. More importantly, UV seams were visible where texture patches didn't align. You could clearly see where different UV islands met.
Texture resolution: 512x512 (target: 2048x2048)
UV seam visibility: Seam contrast: 45.2% (target: < 5%)
What I Tried
Attempt 1: Increased texture_resolution parameter to 2048. This caused OOM errors on 16GB GPU.
Attempt 2: Ran texture dilation to fix seams. This created color bleeding at edges.
Attempt 3: Used post-processing to blur seams. This just made blurry textures even blurrier.
Actual Fix
Used Wonder3D's high-quality texture mode with seamless UV generation. The model now generates textures at 2048x2048 in tiles, then blends them seamlessly. Also enabled UV padding and texture bleeding prevention.
# High-quality texture generation
import torch
from wonder3d import Wonder3D
from wonder3d.texture import TextureGenerator
model = Wonder3D.from_pretrained("xxlong/wonder3d")
# Generate mesh with high-quality textures
output = model.reconstruct(
input_image="product.jpg",
# Texture settings
texture_resolution=2048, # High res textures
texture_quality="high", # Use high-quality mode
# UV settings
uv_unwrap_method="smart", # Smart UV unwrapping
uv_padding=4, # 4-pixel padding to prevent seams
seamless_textures=True, # Enable seamless texture generation
# Quality
mesh_quality="high",
texture_samples=8 # 8 samples per texel for quality
)
# Texture generator handles tiling and blending
tex_gen = TextureGenerator(
tile_size=512, # Generate in 512px tiles
overlap=32, # 32-pixel overlap for blending
blend_mode="multi-band" # Multi-band blending for seamless result
)
final_texture = tex_gen.generate(
mesh=output.mesh,
views=output.multi_views,
resolution=2048
)
Problem
The generated mesh had ngons (polygons with > 4 sides), non-manifold edges, and triangles of varying sizes. This caused rendering artifacts and made the mesh unsuitable for subdivision or further editing.
What I Tried
Attempt 1: Ran mesh cleanup in Blender. This fixed topology but lost detail.
Attempt 2: Increased mesh density. This created more uniform triangles but also increased file size significantly.
Actual Fix
Used Wonder3D's quad-dominant remeshing with uniform triangle sizing. The model now generates clean quad-based topology that subdivides well.
# Clean mesh topology
output = model.reconstruct(
input_image="product.jpg",
# Mesh topology
mesh_topology="quad_dominant", # Quads with some triangles
triangle_size=0.001, # Uniform triangle size in meters
target_edge_length=0.002,
# Mesh cleanup
clean_non_manifold=True, # Fix non-manifold geometry
remove_ngons=True, # Triangulate ngons
merge_vertices=True, # Merge duplicate vertices
fix_normals=True, # Ensure consistent normals
# Quality
mesh_quality="high"
)
Problem
The generated mesh had arbitrary scale. A product that should be 20cm tall would come out as 5 units or 50 units. There was no way to know the real-world dimensions without manual scaling.
What I Tried
Attempt 1: Added scale information to the prompt. The model ignored this.
Attempt 2: Manually scaled after generation. This required measuring the real object every time.
Actual Fix
Used Wonder3D's reference object mode. Provide a reference object with known dimensions in the image, and the model will scale the mesh accordingly. Alternatively, use the explicit scale parameter if you know the object's real-world size.
# Geometry with correct scale
output = model.reconstruct(
input_image="product_with_reference.jpg",
# Scale settings
scale_mode="reference_object", # Use reference in image
reference_object="coin", # Reference is a US quarter (24.26mm)
# OR explicit scale if you know dimensions
# scale_mode="explicit",
# target_height=0.2, # Object is 20cm tall
# target_unit="meters",
# Mesh settings
mesh_quality="high",
texture_resolution=2048
)
# The output mesh will be correctly scaled
# If using reference object, mesh dimensions will be in meters
print(f"Mesh height: {output.mesh.dimensions[1]:.3f} meters")
What I Learned
- High-quality texture mode is essential: Default textures are too blurry. Always use texture_quality="high" with 2048 resolution.
- UV padding prevents seams: Set uv_padding=4 to prevent UV seams from showing. This creates a buffer zone that absorbs UV errors.
- Quad-dominant topology is better: Quads subdivide better than triangles. Use mesh_topology="quad_dominant" for clean topology.
- Reference objects solve scaling: Include a reference object (coin, ruler, credit card) in the photo. Wonder3D will use it for accurate scaling.
- Multi-band blending fixes texture seams: Use multi-band blending when generating textures to hide UV seams.
- Clean non-manifold geometry: Always enable clean_non_manifold and remove_ngons for production-ready meshes.
Production Setup
Complete setup for generating production-ready textured meshes.
# Install Wonder3D
git clone https://github.com/xxlong0/Wonder3D.git
cd Wonder3D
pip install -e .
# Install mesh processing tools
pip install trimesh open3d pymeshlab
pipopencv-python pillow
Production mesh generation script:
import torch
from wonder3d import Wonder3D
from wonder3d.texture import TextureGenerator
from wonder3d.export import MeshExporter
from pathlib import Path
def create_textured_mesh(
input_image: str,
output_dir: str,
reference_object: str = None,
target_dimensions: dict = None
):
"""
Generate production-ready textured mesh from image.
"""
model = Wonder3D.from_pretrained(
"xxlong/wonder3d",
torch_dtype=torch.float16
).to("cuda")
# Configure scale
if reference_object:
scale_mode = "reference_object"
scale_config = {"reference_object": reference_object}
elif target_dimensions:
scale_mode = "explicit"
scale_config = target_dimensions
else:
scale_mode = "auto"
scale_config = {}
# Generate mesh
print("Generating 3D mesh...")
output = model.reconstruct(
input_image=input_image,
# Scale
scale_mode=scale_mode,
**scale_config,
# Mesh topology
mesh_topology="quad_dominant",
triangle_size=0.001,
target_edge_length=0.002,
clean_non_manifold=True,
remove_ngons=True,
fix_normals=True,
# Texture
texture_resolution=2048,
texture_quality="high",
uv_unwrap_method="smart",
uv_padding=4,
seamless_textures=True,
# Quality
mesh_quality="high"
)
# Export to multiple formats
output_path = Path(output_dir)
output_path.mkdir(exist_ok=True)
exporter = MeshExporter()
# OBJ with MTL (standard)
exporter.export_obj(
mesh=output.mesh,
texture=output.texture,
output_path=str(output_path / "model.obj")
)
# GLTF for web
exporter.export_gltf(
mesh=output.mesh,
texture=output.texture,
output_path=str(output_path / "model.glb")
)
# FBX for Unity/Unreal
exporter.export_fbx(
mesh=output.mesh,
texture=output.texture,
output_path=str(output_path / "model.fbx")
)
# STL for 3D printing (geometry only)
exporter.export_stl(
mesh=output.mesh,
output_path=str(output_path / "model.stl")
)
print(f"Exported to {output_path}")
return output_path
# Usage examples
# With reference object in photo
create_textured_mesh(
input_image="product_with_coin.jpg",
output_dir="./output_3d",
reference_object="coin" # US quarter for scale
)
# With explicit dimensions
create_textured_mesh(
input_image="product.jpg",
output_dir="./output_3d",
target_dimensions={
"target_height": 0.2, # 20cm
"target_unit": "meters"
}
)
Monitoring & Debugging
Quality metrics for mesh generation.
Red Flags to Watch For
- Texture resolution < 1024: Too low for production. Increase texture_resolution.
- UV seam contrast > 10%: Visible seams. Increase uv_padding and check seamless_textures.
- Mesh has > 100 ngons: Poor topology. Enable remove_ngons and use quad_dominant.
- Non-manifold edges > 50: Geometry issues. Enable clean_non_manifold.
- Scale deviation > 20%: Wrong dimensions. Check reference_object or target_dimensions.
Debug Commands
# Validate mesh quality
python -m wonder3d.tools.validate_mesh \
--input model.obj \
--check_topology \
--check_uv \
--check_scale \
--verbose
# Preview mesh and texture
python -m wonder3d.tools.viewer \
--mesh model.obj \
--texture texture.png
# Batch process directory
python batch_generate_3d.py \
--input_dir ./photos \
--output_dir ./output_3d \
--reference_object coin \
--texture_resolution 2048