Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions WINDOWS_SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Windows环境下安装和使用Hunyuan3D-2.1

本指南将帮助您在Windows环境下安装和使用Hunyuan3D-2.1。
本指南在RTX 4090 与 RTX 5080 推理成功,但显存需要比较多(至少32G显卡),只有等后续量化模型了。
## 系统需求

- Windows 10或Windows 11操作系统
- NVIDIA GPU (推荐32GB以上显存)
- CUDA 12.4+ (兼容PyTorch 2.5.1)
- Python 3.10+ (推荐3.10)
- Visual Studio 2019/2022 (用于编译C++组件)或MinGW-w64 (GCC)

## 安装步骤

### 1. 安装依赖软件

- **安装Python 3.10**:从[Python官网](https://www.python.org/downloads/windows/)下载并安装
- **安装CUDA工具包**:从[NVIDIA官网](https://developer.nvidia.com/cuda-downloads)下载并安装CUDA 12.4
- **安装Visual Studio 2019/2022**:安装时请选择"使用C++的桌面开发"工作负载
- **[推荐] 安装Conda**:从[Conda官网](https://docs.conda.io/projects/conda/en/latest/user-guide/install/windows.html)下载并安装Miniconda或Anaconda

### 2. 使用Conda创建隔离环境(推荐)

使用Conda创建隔离环境可以避免与系统Python环境产生冲突:

```bash
# 创建名为hunyuan3d的Python 3.10环境
conda create -n hunyuan3d python=3.10
# 激活环境
conda activate hunyuan3d
# 安装PyTorch (使用pip而非conda安装以确保使用正确的CUDA版本)
pip install torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 --index-url https://download.pytorch.org/whl/cu124
# 安装项目依赖
pip install -r requirements_win.txt
# 完成环境配置后,编译自定义组件
cd hy3dpaint/custom_rasterizer
call build_custom_rasterizer.bat
cd ../DifferentiableRenderer
call compile_mesh_painter.bat
cd ../..
```

注意:每次使用Hunyuan3D-2.1时,都需要先激活conda环境:
```bash
conda activate hunyuan3d
```

### 3. 手动安装步骤

如果上述方法不适合您,可以按照以下步骤手动完成安装:

#### 3.1 安装PyTorch和依赖项

```bash
pip install torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 --index-url https://download.pytorch.org/whl/cu124
pip install -r requirements_win.txt
```

#### 3.2 编译自定义光栅化器

```bash
cd hy3dpaint/custom_rasterizer
build_custom_rasterizer.bat
cd ../..
```

#### 3.3 编译网格处理器

```bash
cd hy3dpaint/DifferentiableRenderer
compile_mesh_painter.bat
cd ../..
```

#### 4. 下载预训练模型

```bash
mkdir -p hy3dpaint/ckpt
# 使用浏览器下载模型并放置在指定目录。(或者用wget,在https://eternallybored.org/misc/wget/ 官网下载后放到安全的位置在设置环境变量)
# 下载链接: https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth
# 目标位置: hy3dpaint/ckpt/RealESRGAN_x4plus.pth
```

## 使用指南

### 启动Gradio应用

```bash
python demo.py
```

启动后,成功推理就代表没问题啦


### 通过Python代码使用

```python
import sys
sys.path.insert(0, './hy3dshape')
sys.path.insert(0, './hy3dpaint')
from textureGenPipeline import Hunyuan3DPaintPipeline, Hunyuan3DPaintConfig
from hy3dshape.pipelines import Hunyuan3DDiTFlowMatchingPipeline

# 生成3D网格
shape_pipeline = Hunyuan3DDiTFlowMatchingPipeline.from_pretrained('tencent/Hunyuan3D-2.1')
mesh_untextured = shape_pipeline(image='assets/demo.png')[0]

# 生成纹理
paint_pipeline = Hunyuan3DPaintPipeline(Hunyuan3DPaintConfig(max_num_view=6, resolution=512))
mesh_textured = paint_pipeline(mesh_untextured, image_path='assets/demo.png')
```

137 changes: 137 additions & 0 deletions hy3dpaint/DifferentiableRenderer/compile_mesh_painter.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
@echo off
setlocal EnableDelayedExpansion

echo Compiling mesh_inpaint_processor...

REM Check compiler option
if "%1"=="mingw" (
goto :USE_MINGW
) else (
goto :USE_MSVC
)

:USE_MSVC
echo Using MSVC compiler...

REM Get pybind11 includes
for /f "tokens=*" %%i in ('python -m pybind11 --includes') do set PYBIND_INCLUDES=%%i

REM Get Python extension suffix
for /f "tokens=*" %%i in ('python -c "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))"') do set PY_SUFFIX=%%i

REM Get Python library directory
for /f "tokens=*" %%i in ('python -c "import sys; import os; print(os.path.join(sys.base_prefix, 'libs'))"') do set PYTHON_LIB_DIR=%%i

REM Check if Python libs directory exists
if not exist "!PYTHON_LIB_DIR!" (
echo Warning: Python library directory not found at !PYTHON_LIB_DIR!

REM Try another common location for Python libs
for /f "tokens=*" %%i in ('python -c "import sys; import os; print(os.path.join(os.path.dirname(sys.executable), 'libs'))"') do set PYTHON_LIB_DIR=%%i

if not exist "!PYTHON_LIB_DIR!" (
echo Error: Cannot find Python library directory
echo Please ensure python310.lib is available in your Python installation
exit /b 1
)
)

echo Found Python libraries at: !PYTHON_LIB_DIR!

REM Check if Visual Studio environment is already set
where cl >nul 2>nul
if %ERRORLEVEL% equ 0 (
goto :DO_MSVC_COMPILE
)

REM Try to find and activate Visual Studio environment automatically
set FOUND_VS=0

REM Try VS2022
if exist "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" (
echo Found VS2022, activating environment...
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
set FOUND_VS=1
goto :DO_MSVC_COMPILE
) else if exist "C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat" (
echo Found VS2022, activating environment...
call "C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat" x64
set FOUND_VS=1
goto :DO_MSVC_COMPILE
) else if exist "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" (
echo Found VS2022, activating environment...
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
set FOUND_VS=1
goto :DO_MSVC_COMPILE
)

REM Try VS2019
if %FOUND_VS% equ 0 (
if exist "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" (
echo Found VS2019, activating environment...
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
set FOUND_VS=1
goto :DO_MSVC_COMPILE
) else if exist "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsall.bat" (
echo Found VS2019, activating environment...
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsall.bat" x64
set FOUND_VS=1
goto :DO_MSVC_COMPILE
) else if exist "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" (
echo Found VS2019, activating environment...
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
set FOUND_VS=1
goto :DO_MSVC_COMPILE
)
)

REM Check if VS was found
where cl >nul 2>nul
if %ERRORLEVEL% neq 0 (
echo Error: Could not find cl compiler. Please run Visual Studio's vcvarsall.bat first or use mingw option.
echo Tips: Try one of these commands:
echo compile_mesh_painter.bat mingw
echo or first run "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
echo (Visual Studio path may be different on your system)
exit /b 1
)

:DO_MSVC_COMPILE
echo Compiling with MSVC...
REM Compile with MSVC
cl /O2 /W4 /std:c++14 /LD %PYBIND_INCLUDES% mesh_inpaint_processor.cpp /link /LIBPATH:"!PYTHON_LIB_DIR!" /out:mesh_inpaint_processor%PY_SUFFIX%
if %ERRORLEVEL% neq 0 (
echo Compilation failed!
exit /b 1
)
goto :END

:USE_MINGW
echo Using MinGW-G++ compiler...

REM Check if MinGW is installed
where g++ >nul 2>nul
if %ERRORLEVEL% neq 0 (
echo Error: g++ compiler not found. Please install MinGW or use Visual Studio.
exit /b 1
)

REM Get pybind11 includes
for /f "tokens=*" %%i in ('python -m pybind11 --includes') do set PYBIND_INCLUDES=%%i

REM Get Python extension suffix
for /f "tokens=*" %%i in ('python -c "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))"') do set PY_SUFFIX=%%i

REM Get Python library directory and filename for MinGW
for /f "tokens=*" %%i in ('python -c "import sys; from sysconfig import get_config_var; import os; print(os.path.join(sys.base_prefix, 'libs', f'python{get_config_var(\"py_version_nodot\")}.dll'))"') do set PYTHON_LIB=%%i

REM Compile with MinGW
g++ -O3 -Wall -shared -std=c++11 %PYBIND_INCLUDES% mesh_inpaint_processor.cpp -L"!PYTHON_LIB!" -o mesh_inpaint_processor%PY_SUFFIX%
if %ERRORLEVEL% neq 0 (
echo Compilation failed!
exit /b 1
)

:END
echo Compilation completed!
echo Generated module: mesh_inpaint_processor%PY_SUFFIX%
9 changes: 9 additions & 0 deletions hy3dpaint/custom_rasterizer/build_custom_rasterizer.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@echo off
echo Building custom rasterizer for Windows...
python setup.py build_ext --inplace
if %ERRORLEVEL% neq 0 (
echo Build failed! Please check error messages above.
exit /b 1
)
echo Custom rasterizer build completed successfully.
cd ..\..
Original file line number Diff line number Diff line change
Expand Up @@ -394,37 +394,37 @@ std::vector<std::vector<torch::Tensor>> build_hierarchy(std::vector<torch::Tenso
std::vector<torch::Tensor> grid_evencorners(grids.size());
std::vector<torch::Tensor> grid_oddcorners(grids.size());

texture_positions[0] = torch::zeros({seq2pos.size() / 3, 3}, float_options);
texture_positions[1] = torch::zeros({seq2pos.size() / 3}, float_options);
texture_positions[0] = torch::zeros({static_cast<int64_t>(seq2pos.size() / 3), 3}, float_options);
texture_positions[1] = torch::zeros({static_cast<int64_t>(seq2pos.size() / 3)}, float_options);
float* positions_out_ptr = texture_positions[0].data_ptr<float>();
memcpy(positions_out_ptr, seq2pos.data(), sizeof(float) * seq2pos.size());
positions_out_ptr = texture_positions[1].data_ptr<float>();
for (int i = 0; i < grids[0].seq2grid.size(); ++i) {
positions_out_ptr[i] = (i < grids[0].num_origin_seq);
positions_out_ptr[i] = i < grids[0].num_origin_seq ? 1.0f : 0.0f;
}

for (int i = 0; i < grids.size(); ++i) {
grid_neighbors[i] = torch::zeros({grids[i].seq2grid.size(), 9}, int64_options);
long* nptr = grid_neighbors[i].data_ptr<long>();
grid_neighbors[i] = torch::zeros({static_cast<int64_t>(grids[i].seq2grid.size()), 9}, int64_options);
int64_t* nptr = grid_neighbors[i].data_ptr<int64_t>();
for (int j = 0; j < grids[i].seq2neighbor.size(); ++j) {
nptr[j] = grids[i].seq2neighbor[j];
nptr[j] = static_cast<int64_t>(grids[i].seq2neighbor[j]);
}

grid_evencorners[i] = torch::zeros({grids[i].seq2evencorner.size()}, int64_options);
grid_oddcorners[i] = torch::zeros({grids[i].seq2oddcorner.size()}, int64_options);
long* dptr = grid_evencorners[i].data_ptr<long>();
grid_evencorners[i] = torch::zeros({static_cast<int64_t>(grids[i].seq2evencorner.size())}, int64_options);
int64_t* dptr = grid_evencorners[i].data_ptr<int64_t>();
for (int j = 0; j < grids[i].seq2evencorner.size(); ++j) {
dptr[j] = grids[i].seq2evencorner[j];
dptr[j] = static_cast<int64_t>(grids[i].seq2evencorner[j]);
}
dptr = grid_oddcorners[i].data_ptr<long>();
grid_oddcorners[i] = torch::zeros({static_cast<int64_t>(grids[i].seq2oddcorner.size())}, int64_options);
dptr = grid_oddcorners[i].data_ptr<int64_t>();
for (int j = 0; j < grids[i].seq2oddcorner.size(); ++j) {
dptr[j] = grids[i].seq2oddcorner[j];
dptr[j] = static_cast<int64_t>(grids[i].seq2oddcorner[j]);
}
if (i + 1 < grids.size()) {
grid_downsamples[i] = torch::zeros({grids[i].downsample_seq.size()}, int64_options);
long* dptr = grid_downsamples[i].data_ptr<long>();
grid_downsamples[i] = torch::zeros({static_cast<int64_t>(grids[i].downsample_seq.size())}, int64_options);
int64_t* dptr = grid_downsamples[i].data_ptr<int64_t>();
for (int j = 0; j < grids[i].downsample_seq.size(); ++j) {
dptr[j] = grids[i].downsample_seq[j];
dptr[j] = static_cast<int64_t>(grids[i].downsample_seq[j]);
}
}

Expand Down Expand Up @@ -534,39 +534,39 @@ std::vector<std::vector<torch::Tensor>> build_hierarchy_with_feat(
std::vector<torch::Tensor> grid_evencorners(grids.size());
std::vector<torch::Tensor> grid_oddcorners(grids.size());

texture_positions[0] = torch::zeros({seq2pos.size() / 3, 3}, float_options);
texture_positions[1] = torch::zeros({seq2pos.size() / 3}, float_options);
texture_feats[0] = torch::zeros({seq2feat.size() / feat_channel, feat_channel}, float_options);
texture_positions[0] = torch::zeros({static_cast<int64_t>(seq2pos.size() / 3), 3}, float_options);
texture_positions[1] = torch::zeros({static_cast<int64_t>(seq2pos.size() / 3)}, float_options);
texture_feats[0] = torch::zeros({static_cast<int64_t>(seq2feat.size() / feat_channel), static_cast<int64_t>(feat_channel)}, float_options);
float* positions_out_ptr = texture_positions[0].data_ptr<float>();
memcpy(positions_out_ptr, seq2pos.data(), sizeof(float) * seq2pos.size());
positions_out_ptr = texture_positions[1].data_ptr<float>();
for (int i = 0; i < grids[0].seq2grid.size(); ++i) {
positions_out_ptr[i] = (i < grids[0].num_origin_seq);
positions_out_ptr[i] = i < grids[0].num_origin_seq ? 1.0f : 0.0f;
}
float* feats_out_ptr = texture_feats[0].data_ptr<float>();
memcpy(feats_out_ptr, seq2feat.data(), sizeof(float) * seq2feat.size());

for (int i = 0; i < grids.size(); ++i) {
grid_neighbors[i] = torch::zeros({grids[i].seq2grid.size(), 9}, int64_options);
long* nptr = grid_neighbors[i].data_ptr<long>();
grid_neighbors[i] = torch::zeros({static_cast<int64_t>(grids[i].seq2grid.size()), 9}, int64_options);
int64_t* nptr = grid_neighbors[i].data_ptr<int64_t>();
for (int j = 0; j < grids[i].seq2neighbor.size(); ++j) {
nptr[j] = grids[i].seq2neighbor[j];
nptr[j] = static_cast<int64_t>(grids[i].seq2neighbor[j]);
}
grid_evencorners[i] = torch::zeros({grids[i].seq2evencorner.size()}, int64_options);
grid_oddcorners[i] = torch::zeros({grids[i].seq2oddcorner.size()}, int64_options);
long* dptr = grid_evencorners[i].data_ptr<long>();
grid_evencorners[i] = torch::zeros({static_cast<int64_t>(grids[i].seq2evencorner.size())}, int64_options);
int64_t* dptr = grid_evencorners[i].data_ptr<int64_t>();
for (int j = 0; j < grids[i].seq2evencorner.size(); ++j) {
dptr[j] = grids[i].seq2evencorner[j];
dptr[j] = static_cast<int64_t>(grids[i].seq2evencorner[j]);
}
dptr = grid_oddcorners[i].data_ptr<long>();
grid_oddcorners[i] = torch::zeros({static_cast<int64_t>(grids[i].seq2oddcorner.size())}, int64_options);
dptr = grid_oddcorners[i].data_ptr<int64_t>();
for (int j = 0; j < grids[i].seq2oddcorner.size(); ++j) {
dptr[j] = grids[i].seq2oddcorner[j];
dptr[j] = static_cast<int64_t>(grids[i].seq2oddcorner[j]);
}
if (i + 1 < grids.size()) {
grid_downsamples[i] = torch::zeros({grids[i].downsample_seq.size()}, int64_options);
long* dptr = grid_downsamples[i].data_ptr<long>();
grid_downsamples[i] = torch::zeros({static_cast<int64_t>(grids[i].downsample_seq.size())}, int64_options);
int64_t* dptr = grid_downsamples[i].data_ptr<int64_t>();
for (int j = 0; j < grids[i].downsample_seq.size(); ++j) {
dptr[j] = grids[i].downsample_seq[j];
dptr[j] = static_cast<int64_t>(grids[i].downsample_seq[j]);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,19 +105,19 @@ std::vector<torch::Tensor> rasterize_image_cpu(torch::Tensor V, torch::Tensor F,
if (!use_depth_prior) {
for (int i = 0; i < num_faces; ++i) {
rasterizeImagecoordsKernelCPU(V.data_ptr<float>(), F.data_ptr<int>(), 0,
(INT64*)z_min.data_ptr<long>(), occlusion_truncation, width, height, num_vertices, num_faces, i);
(INT64*)z_min.data_ptr<int64_t>(), occlusion_truncation, width, height, num_vertices, num_faces, i);
}
} else {
for (int i = 0; i < num_faces; ++i)
rasterizeImagecoordsKernelCPU(V.data_ptr<float>(), F.data_ptr<int>(), D.data_ptr<float>(),
(INT64*)z_min.data_ptr<long>(), occlusion_truncation, width, height, num_vertices, num_faces, i);
(INT64*)z_min.data_ptr<int64_t>(), occlusion_truncation, width, height, num_vertices, num_faces, i);
}

auto float_options = torch::TensorOptions().dtype(torch::kFloat32).requires_grad(false);
auto barycentric = torch::zeros({height, width, 3}, float_options);
for (int i = 0; i < width * height; ++i)
barycentricFromImgcoordCPU(V.data_ptr<float>(), F.data_ptr<int>(),
findices.data_ptr<int>(), (INT64*)z_min.data_ptr<long>(), width, height, num_vertices, num_faces, barycentric.data_ptr<float>(), i);
findices.data_ptr<int>(), (INT64*)z_min.data_ptr<int64_t>(), width, height, num_vertices, num_faces, barycentric.data_ptr<float>(), i);

return {findices, barycentric};
}
Expand Down
Loading