Spaces:
Runtime error
Runtime error
syedMohib44
commited on
Commit
Β·
ad17ddf
1
Parent(s):
4ebc49e
removed cache
Browse files- .gitignore +3 -1
- {build/lib/hy3dgen β hy3dgen}/__init__.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/rembg.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/shapegen/__init__.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/shapegen/models/__init__.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/shapegen/models/conditioner.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/shapegen/models/hunyuan3ddit.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/shapegen/models/vae.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/shapegen/pipelines.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/shapegen/postprocessors.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/shapegen/preprocessors.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/shapegen/schedulers.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/__init__.py +0 -0
- hy3dgen/texgen/custom_rasterizer/custom_rasterizer/__init__.py +32 -0
- hy3dgen/texgen/custom_rasterizer/custom_rasterizer/io_glb.py +248 -0
- hy3dgen/texgen/custom_rasterizer/custom_rasterizer/io_obj.py +76 -0
- hy3dgen/texgen/custom_rasterizer/custom_rasterizer/render.py +41 -0
- {build/lib/hy3dgen/texgen/differentiable_renderer β hy3dgen/texgen/custom_rasterizer/lib/custom_rasterizer_kernel}/__init__.py +0 -0
- hy3dgen/texgen/custom_rasterizer/lib/custom_rasterizer_kernel/grid_neighbor.cpp +575 -0
- hy3dgen/texgen/custom_rasterizer/lib/custom_rasterizer_kernel/rasterizer.cpp +139 -0
- hy3dgen/texgen/custom_rasterizer/lib/custom_rasterizer_kernel/rasterizer.h +54 -0
- hy3dgen/texgen/custom_rasterizer/lib/custom_rasterizer_kernel/rasterizer_gpu.cu +127 -0
- hy3dgen/texgen/custom_rasterizer/setup.py +26 -0
- {build/lib/hy3dgen/texgen/hunyuanpaint β hy3dgen/texgen/differentiable_renderer}/__init__.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/differentiable_renderer/camera_utils.py +0 -0
- hy3dgen/texgen/differentiable_renderer/compile_mesh_painter.bat +3 -0
- hy3dgen/texgen/differentiable_renderer/mesh_processor.cpp +161 -0
- hy3dgen/texgen/differentiable_renderer/mesh_processor.egg-info/PKG-INFO +7 -0
- hy3dgen/texgen/differentiable_renderer/mesh_processor.egg-info/SOURCES.txt +7 -0
- hy3dgen/texgen/differentiable_renderer/mesh_processor.egg-info/dependency_links.txt +1 -0
- hy3dgen/texgen/differentiable_renderer/mesh_processor.egg-info/requires.txt +1 -0
- hy3dgen/texgen/differentiable_renderer/mesh_processor.egg-info/top_level.txt +1 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/differentiable_renderer/mesh_processor.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/differentiable_renderer/mesh_render.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/differentiable_renderer/mesh_utils.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/differentiable_renderer/setup.py +0 -0
- {build/lib/hy3dgen/texgen/hunyuanpaint/unet β hy3dgen/texgen/hunyuanpaint}/__init__.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/hunyuanpaint/pipeline.py +0 -0
- {build/lib/hy3dgen/texgen/utils β hy3dgen/texgen/hunyuanpaint/unet}/__init__.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/hunyuanpaint/unet/modules.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/pipelines.py +1 -1
- hy3dgen/texgen/utils/__init__.py +23 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/utils/alignImg4Tex_utils.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/utils/counter_utils.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/utils/dehighlight_utils.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/utils/multiview_utils.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/utils/simplify_mesh_utils.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/texgen/utils/uv_warp_utils.py +0 -0
- {build/lib/hy3dgen β hy3dgen}/text2image.py +0 -0
.gitignore
CHANGED
|
@@ -7,6 +7,8 @@ __pycache__/
|
|
| 7 |
venv/
|
| 8 |
env/
|
| 9 |
.venv/
|
|
|
|
|
|
|
| 10 |
build/
|
| 11 |
dist/
|
| 12 |
|
|
@@ -27,4 +29,4 @@ dist/
|
|
| 27 |
.vscode/
|
| 28 |
|
| 29 |
# Hugging Face cache (optional)
|
| 30 |
-
|
|
|
|
| 7 |
venv/
|
| 8 |
env/
|
| 9 |
.venv/
|
| 10 |
+
|
| 11 |
+
# Build
|
| 12 |
build/
|
| 13 |
dist/
|
| 14 |
|
|
|
|
| 29 |
.vscode/
|
| 30 |
|
| 31 |
# Hugging Face cache (optional)
|
| 32 |
+
/content/huggingface/
|
{build/lib/hy3dgen β hy3dgen}/__init__.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/rembg.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/shapegen/__init__.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/shapegen/models/__init__.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/shapegen/models/conditioner.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/shapegen/models/hunyuan3ddit.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/shapegen/models/vae.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/shapegen/pipelines.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/shapegen/postprocessors.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/shapegen/preprocessors.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/shapegen/schedulers.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/texgen/__init__.py
RENAMED
|
File without changes
|
hy3dgen/texgen/custom_rasterizer/custom_rasterizer/__init__.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Open Source Model Licensed under the Apache License Version 2.0
|
| 2 |
+
# and Other Licenses of the Third-Party Components therein:
|
| 3 |
+
# The below Model in this distribution may have been modified by THL A29 Limited
|
| 4 |
+
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
| 5 |
+
|
| 6 |
+
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
| 7 |
+
# The below software and/or models in this distribution may have been
|
| 8 |
+
# modified by THL A29 Limited ("Tencent Modifications").
|
| 9 |
+
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
| 10 |
+
|
| 11 |
+
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
| 12 |
+
# except for the third-party components listed below.
|
| 13 |
+
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
| 14 |
+
# in the repsective licenses of these third-party components.
|
| 15 |
+
# Users must comply with all terms and conditions of original licenses of these third-party
|
| 16 |
+
# components and must ensure that the usage of the third party components adheres to
|
| 17 |
+
# all relevant laws and regulations.
|
| 18 |
+
|
| 19 |
+
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
| 20 |
+
# their software and algorithms, including trained model weights, parameters (including
|
| 21 |
+
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
| 22 |
+
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
| 23 |
+
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
| 24 |
+
|
| 25 |
+
'''
|
| 26 |
+
from .hierarchy import BuildHierarchy, BuildHierarchyWithColor
|
| 27 |
+
from .io_obj import LoadObj, LoadObjWithTexture
|
| 28 |
+
from .render import rasterize, interpolate
|
| 29 |
+
'''
|
| 30 |
+
from .io_glb import *
|
| 31 |
+
from .io_obj import *
|
| 32 |
+
from .render import *
|
hy3dgen/texgen/custom_rasterizer/custom_rasterizer/io_glb.py
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Open Source Model Licensed under the Apache License Version 2.0
|
| 2 |
+
# and Other Licenses of the Third-Party Components therein:
|
| 3 |
+
# The below Model in this distribution may have been modified by THL A29 Limited
|
| 4 |
+
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
| 5 |
+
|
| 6 |
+
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
| 7 |
+
# The below software and/or models in this distribution may have been
|
| 8 |
+
# modified by THL A29 Limited ("Tencent Modifications").
|
| 9 |
+
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
| 10 |
+
|
| 11 |
+
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
| 12 |
+
# except for the third-party components listed below.
|
| 13 |
+
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
| 14 |
+
# in the repsective licenses of these third-party components.
|
| 15 |
+
# Users must comply with all terms and conditions of original licenses of these third-party
|
| 16 |
+
# components and must ensure that the usage of the third party components adheres to
|
| 17 |
+
# all relevant laws and regulations.
|
| 18 |
+
|
| 19 |
+
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
| 20 |
+
# their software and algorithms, including trained model weights, parameters (including
|
| 21 |
+
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
| 22 |
+
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
| 23 |
+
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
| 24 |
+
|
| 25 |
+
import base64
|
| 26 |
+
import io
|
| 27 |
+
import os
|
| 28 |
+
|
| 29 |
+
import numpy as np
|
| 30 |
+
from PIL import Image as PILImage
|
| 31 |
+
from pygltflib import GLTF2
|
| 32 |
+
from scipy.spatial.transform import Rotation as R
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# Function to extract buffer data
|
| 36 |
+
def get_buffer_data(gltf, buffer_view):
|
| 37 |
+
buffer = gltf.buffers[buffer_view.buffer]
|
| 38 |
+
buffer_data = gltf.get_data_from_buffer_uri(buffer.uri)
|
| 39 |
+
byte_offset = buffer_view.byteOffset if buffer_view.byteOffset else 0
|
| 40 |
+
byte_length = buffer_view.byteLength
|
| 41 |
+
return buffer_data[byte_offset:byte_offset + byte_length]
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
# Function to extract attribute data
|
| 45 |
+
def get_attribute_data(gltf, accessor_index):
|
| 46 |
+
accessor = gltf.accessors[accessor_index]
|
| 47 |
+
buffer_view = gltf.bufferViews[accessor.bufferView]
|
| 48 |
+
buffer_data = get_buffer_data(gltf, buffer_view)
|
| 49 |
+
|
| 50 |
+
comptype = {5120: np.int8, 5121: np.uint8, 5122: np.int16, 5123: np.uint16, 5125: np.uint32, 5126: np.float32}
|
| 51 |
+
dtype = comptype[accessor.componentType]
|
| 52 |
+
|
| 53 |
+
t2n = {'SCALAR': 1, 'VEC2': 2, 'VEC3': 3, 'VEC4': 4, 'MAT2': 4, 'MAT3': 9, 'MAT4': 16}
|
| 54 |
+
num_components = t2n[accessor.type]
|
| 55 |
+
|
| 56 |
+
# Calculate the correct slice of data
|
| 57 |
+
byte_offset = accessor.byteOffset if accessor.byteOffset else 0
|
| 58 |
+
byte_stride = buffer_view.byteStride if buffer_view.byteStride else num_components * np.dtype(dtype).itemsize
|
| 59 |
+
count = accessor.count
|
| 60 |
+
|
| 61 |
+
# Extract the attribute data
|
| 62 |
+
attribute_data = np.zeros((count, num_components), dtype=dtype)
|
| 63 |
+
for i in range(count):
|
| 64 |
+
start = byte_offset + i * byte_stride
|
| 65 |
+
end = start + num_components * np.dtype(dtype).itemsize
|
| 66 |
+
attribute_data[i] = np.frombuffer(buffer_data[start:end], dtype=dtype)
|
| 67 |
+
|
| 68 |
+
return attribute_data
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
# Function to extract image data
|
| 72 |
+
def get_image_data(gltf, image, folder):
|
| 73 |
+
if image.uri:
|
| 74 |
+
if image.uri.startswith('data:'):
|
| 75 |
+
# Data URI
|
| 76 |
+
header, encoded = image.uri.split(',', 1)
|
| 77 |
+
data = base64.b64decode(encoded)
|
| 78 |
+
else:
|
| 79 |
+
# External file
|
| 80 |
+
fn = image.uri
|
| 81 |
+
if not os.path.isabs(fn):
|
| 82 |
+
fn = folder + '/' + fn
|
| 83 |
+
with open(fn, 'rb') as f:
|
| 84 |
+
data = f.read()
|
| 85 |
+
else:
|
| 86 |
+
buffer_view = gltf.bufferViews[image.bufferView]
|
| 87 |
+
data = get_buffer_data(gltf, buffer_view)
|
| 88 |
+
return data
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
# Function to convert triangle strip to triangles
|
| 92 |
+
def convert_triangle_strip_to_triangles(indices):
|
| 93 |
+
triangles = []
|
| 94 |
+
for i in range(len(indices) - 2):
|
| 95 |
+
if i % 2 == 0:
|
| 96 |
+
triangles.append([indices[i], indices[i + 1], indices[i + 2]])
|
| 97 |
+
else:
|
| 98 |
+
triangles.append([indices[i], indices[i + 2], indices[i + 1]])
|
| 99 |
+
return np.array(triangles).reshape(-1, 3)
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
# Function to convert triangle fan to triangles
|
| 103 |
+
def convert_triangle_fan_to_triangles(indices):
|
| 104 |
+
triangles = []
|
| 105 |
+
for i in range(1, len(indices) - 1):
|
| 106 |
+
triangles.append([indices[0], indices[i], indices[i + 1]])
|
| 107 |
+
return np.array(triangles).reshape(-1, 3)
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
# Function to get the transformation matrix from a node
|
| 111 |
+
def get_node_transform(node):
|
| 112 |
+
if node.matrix:
|
| 113 |
+
return np.array(node.matrix).reshape(4, 4).T
|
| 114 |
+
else:
|
| 115 |
+
T = np.eye(4)
|
| 116 |
+
if node.translation:
|
| 117 |
+
T[:3, 3] = node.translation
|
| 118 |
+
if node.rotation:
|
| 119 |
+
R_mat = R.from_quat(node.rotation).as_matrix()
|
| 120 |
+
T[:3, :3] = R_mat
|
| 121 |
+
if node.scale:
|
| 122 |
+
S = np.diag(node.scale + [1])
|
| 123 |
+
T = T @ S
|
| 124 |
+
return T
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
def get_world_transform(gltf, node_index, parents, world_transforms):
|
| 128 |
+
if parents[node_index] == -2:
|
| 129 |
+
return world_transforms[node_index]
|
| 130 |
+
|
| 131 |
+
node = gltf.nodes[node_index]
|
| 132 |
+
if parents[node_index] == -1:
|
| 133 |
+
world_transforms[node_index] = get_node_transform(node)
|
| 134 |
+
parents[node_index] = -2
|
| 135 |
+
return world_transforms[node_index]
|
| 136 |
+
|
| 137 |
+
parent_index = parents[node_index]
|
| 138 |
+
parent_transform = get_world_transform(gltf, parent_index, parents, world_transforms)
|
| 139 |
+
world_transforms[node_index] = parent_transform @ get_node_transform(node)
|
| 140 |
+
parents[node_index] = -2
|
| 141 |
+
return world_transforms[node_index]
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def LoadGlb(path):
|
| 145 |
+
# Load the GLB file using pygltflib
|
| 146 |
+
gltf = GLTF2().load(path)
|
| 147 |
+
|
| 148 |
+
primitives = []
|
| 149 |
+
images = {}
|
| 150 |
+
# Iterate through the meshes in the GLB file
|
| 151 |
+
|
| 152 |
+
world_transforms = [np.identity(4) for i in range(len(gltf.nodes))]
|
| 153 |
+
parents = [-1 for i in range(len(gltf.nodes))]
|
| 154 |
+
for node_index, node in enumerate(gltf.nodes):
|
| 155 |
+
for idx in node.children:
|
| 156 |
+
parents[idx] = node_index
|
| 157 |
+
# for i in range(len(gltf.nodes)):
|
| 158 |
+
# get_world_transform(gltf, i, parents, world_transform)
|
| 159 |
+
|
| 160 |
+
for node_index, node in enumerate(gltf.nodes):
|
| 161 |
+
if node.mesh is not None:
|
| 162 |
+
world_transform = get_world_transform(gltf, node_index, parents, world_transforms)
|
| 163 |
+
# Iterate through the primitives in the mesh
|
| 164 |
+
mesh = gltf.meshes[node.mesh]
|
| 165 |
+
for primitive in mesh.primitives:
|
| 166 |
+
# Access the attributes of the primitive
|
| 167 |
+
attributes = primitive.attributes.__dict__
|
| 168 |
+
mode = primitive.mode if primitive.mode is not None else 4 # Default to TRIANGLES
|
| 169 |
+
result = {}
|
| 170 |
+
if primitive.indices is not None:
|
| 171 |
+
indices = get_attribute_data(gltf, primitive.indices)
|
| 172 |
+
if mode == 4: # TRIANGLES
|
| 173 |
+
face_indices = indices.reshape(-1, 3)
|
| 174 |
+
elif mode == 5: # TRIANGLE_STRIP
|
| 175 |
+
face_indices = convert_triangle_strip_to_triangles(indices)
|
| 176 |
+
elif mode == 6: # TRIANGLE_FAN
|
| 177 |
+
face_indices = convert_triangle_fan_to_triangles(indices)
|
| 178 |
+
else:
|
| 179 |
+
continue
|
| 180 |
+
result['F'] = face_indices
|
| 181 |
+
|
| 182 |
+
# Extract vertex positions
|
| 183 |
+
if 'POSITION' in attributes and attributes['POSITION'] is not None:
|
| 184 |
+
positions = get_attribute_data(gltf, attributes['POSITION'])
|
| 185 |
+
# Apply the world transformation to the positions
|
| 186 |
+
positions_homogeneous = np.hstack([positions, np.ones((positions.shape[0], 1))])
|
| 187 |
+
transformed_positions = (world_transform @ positions_homogeneous.T).T[:, :3]
|
| 188 |
+
result['V'] = transformed_positions
|
| 189 |
+
|
| 190 |
+
# Extract vertex colors
|
| 191 |
+
if 'COLOR_0' in attributes and attributes['COLOR_0'] is not None:
|
| 192 |
+
colors = get_attribute_data(gltf, attributes['COLOR_0'])
|
| 193 |
+
if colors.shape[-1] > 3:
|
| 194 |
+
colors = colors[..., :3]
|
| 195 |
+
result['VC'] = colors
|
| 196 |
+
|
| 197 |
+
# Extract UVs
|
| 198 |
+
if 'TEXCOORD_0' in attributes and not attributes['TEXCOORD_0'] is None:
|
| 199 |
+
uvs = get_attribute_data(gltf, attributes['TEXCOORD_0'])
|
| 200 |
+
result['UV'] = uvs
|
| 201 |
+
|
| 202 |
+
if primitive.material is not None:
|
| 203 |
+
material = gltf.materials[primitive.material]
|
| 204 |
+
if material.pbrMetallicRoughness is not None and material.pbrMetallicRoughness.baseColorTexture is not None:
|
| 205 |
+
texture_index = material.pbrMetallicRoughness.baseColorTexture.index
|
| 206 |
+
texture = gltf.textures[texture_index]
|
| 207 |
+
image_index = texture.source
|
| 208 |
+
if not image_index in images:
|
| 209 |
+
image = gltf.images[image_index]
|
| 210 |
+
image_data = get_image_data(gltf, image, os.path.dirname(path))
|
| 211 |
+
pil_image = PILImage.open(io.BytesIO(image_data))
|
| 212 |
+
if pil_image.mode != 'RGB':
|
| 213 |
+
pil_image = pil_image.convert('RGB')
|
| 214 |
+
images[image_index] = pil_image
|
| 215 |
+
result['TEX'] = image_index
|
| 216 |
+
elif material.emissiveTexture is not None:
|
| 217 |
+
texture_index = material.emissiveTexture.index
|
| 218 |
+
texture = gltf.textures[texture_index]
|
| 219 |
+
image_index = texture.source
|
| 220 |
+
if not image_index in images:
|
| 221 |
+
image = gltf.images[image_index]
|
| 222 |
+
image_data = get_image_data(gltf, image, os.path.dirname(path))
|
| 223 |
+
pil_image = PILImage.open(io.BytesIO(image_data))
|
| 224 |
+
if pil_image.mode != 'RGB':
|
| 225 |
+
pil_image = pil_image.convert('RGB')
|
| 226 |
+
images[image_index] = pil_image
|
| 227 |
+
result['TEX'] = image_index
|
| 228 |
+
else:
|
| 229 |
+
if material.pbrMetallicRoughness is not None:
|
| 230 |
+
base_color = material.pbrMetallicRoughness.baseColorFactor
|
| 231 |
+
else:
|
| 232 |
+
base_color = np.array([0.8, 0.8, 0.8], dtype=np.float32)
|
| 233 |
+
result['MC'] = base_color
|
| 234 |
+
|
| 235 |
+
primitives.append(result)
|
| 236 |
+
|
| 237 |
+
return primitives, images
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
def RotatePrimitives(primitives, transform):
|
| 241 |
+
for i in range(len(primitives)):
|
| 242 |
+
if 'V' in primitives[i]:
|
| 243 |
+
primitives[i]['V'] = primitives[i]['V'] @ transform.T
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
if __name__ == '__main__':
|
| 247 |
+
path = 'data/test.glb'
|
| 248 |
+
LoadGlb(path)
|
hy3dgen/texgen/custom_rasterizer/custom_rasterizer/io_obj.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Open Source Model Licensed under the Apache License Version 2.0
|
| 2 |
+
# and Other Licenses of the Third-Party Components therein:
|
| 3 |
+
# The below Model in this distribution may have been modified by THL A29 Limited
|
| 4 |
+
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
| 5 |
+
|
| 6 |
+
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
| 7 |
+
# The below software and/or models in this distribution may have been
|
| 8 |
+
# modified by THL A29 Limited ("Tencent Modifications").
|
| 9 |
+
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
| 10 |
+
|
| 11 |
+
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
| 12 |
+
# except for the third-party components listed below.
|
| 13 |
+
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
| 14 |
+
# in the repsective licenses of these third-party components.
|
| 15 |
+
# Users must comply with all terms and conditions of original licenses of these third-party
|
| 16 |
+
# components and must ensure that the usage of the third party components adheres to
|
| 17 |
+
# all relevant laws and regulations.
|
| 18 |
+
|
| 19 |
+
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
| 20 |
+
# their software and algorithms, including trained model weights, parameters (including
|
| 21 |
+
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
| 22 |
+
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
| 23 |
+
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
| 24 |
+
|
| 25 |
+
import cv2
|
| 26 |
+
import numpy as np
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def LoadObj(fn):
|
| 30 |
+
lines = [l.strip() for l in open(fn)]
|
| 31 |
+
vertices = []
|
| 32 |
+
faces = []
|
| 33 |
+
for l in lines:
|
| 34 |
+
words = [w for w in l.split(' ') if w != '']
|
| 35 |
+
if len(words) == 0:
|
| 36 |
+
continue
|
| 37 |
+
if words[0] == 'v':
|
| 38 |
+
v = [float(words[i]) for i in range(1, 4)]
|
| 39 |
+
vertices.append(v)
|
| 40 |
+
elif words[0] == 'f':
|
| 41 |
+
f = [int(words[i]) - 1 for i in range(1, 4)]
|
| 42 |
+
faces.append(f)
|
| 43 |
+
|
| 44 |
+
return np.array(vertices).astype('float32'), np.array(faces).astype('int32')
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def LoadObjWithTexture(fn, tex_fn):
|
| 48 |
+
lines = [l.strip() for l in open(fn)]
|
| 49 |
+
vertices = []
|
| 50 |
+
vertex_textures = []
|
| 51 |
+
faces = []
|
| 52 |
+
face_textures = []
|
| 53 |
+
for l in lines:
|
| 54 |
+
words = [w for w in l.split(' ') if w != '']
|
| 55 |
+
if len(words) == 0:
|
| 56 |
+
continue
|
| 57 |
+
if words[0] == 'v':
|
| 58 |
+
v = [float(words[i]) for i in range(1, len(words))]
|
| 59 |
+
vertices.append(v)
|
| 60 |
+
elif words[0] == 'vt':
|
| 61 |
+
v = [float(words[i]) for i in range(1, len(words))]
|
| 62 |
+
vertex_textures.append(v)
|
| 63 |
+
elif words[0] == 'f':
|
| 64 |
+
f = []
|
| 65 |
+
ft = []
|
| 66 |
+
for i in range(1, len(words)):
|
| 67 |
+
t = words[i].split('/')
|
| 68 |
+
f.append(int(t[0]) - 1)
|
| 69 |
+
ft.append(int(t[1]) - 1)
|
| 70 |
+
for i in range(2, len(f)):
|
| 71 |
+
faces.append([f[0], f[i - 1], f[i]])
|
| 72 |
+
face_textures.append([ft[0], ft[i - 1], ft[i]])
|
| 73 |
+
|
| 74 |
+
tex_image = cv2.cvtColor(cv2.imread(tex_fn), cv2.COLOR_BGR2RGB)
|
| 75 |
+
return np.array(vertices).astype('float32'), np.array(vertex_textures).astype('float32'), np.array(faces).astype(
|
| 76 |
+
'int32'), np.array(face_textures).astype('int32'), tex_image
|
hy3dgen/texgen/custom_rasterizer/custom_rasterizer/render.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Open Source Model Licensed under the Apache License Version 2.0
|
| 2 |
+
# and Other Licenses of the Third-Party Components therein:
|
| 3 |
+
# The below Model in this distribution may have been modified by THL A29 Limited
|
| 4 |
+
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
| 5 |
+
|
| 6 |
+
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
| 7 |
+
# The below software and/or models in this distribution may have been
|
| 8 |
+
# modified by THL A29 Limited ("Tencent Modifications").
|
| 9 |
+
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
| 10 |
+
|
| 11 |
+
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
| 12 |
+
# except for the third-party components listed below.
|
| 13 |
+
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
| 14 |
+
# in the repsective licenses of these third-party components.
|
| 15 |
+
# Users must comply with all terms and conditions of original licenses of these third-party
|
| 16 |
+
# components and must ensure that the usage of the third party components adheres to
|
| 17 |
+
# all relevant laws and regulations.
|
| 18 |
+
|
| 19 |
+
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
| 20 |
+
# their software and algorithms, including trained model weights, parameters (including
|
| 21 |
+
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
| 22 |
+
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
| 23 |
+
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
| 24 |
+
|
| 25 |
+
import custom_rasterizer_kernel
|
| 26 |
+
import torch
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def rasterize(pos, tri, resolution, clamp_depth=torch.zeros(0), use_depth_prior=0):
|
| 30 |
+
assert (pos.device == tri.device)
|
| 31 |
+
findices, barycentric = custom_rasterizer_kernel.rasterize_image(pos[0], tri, clamp_depth, resolution[1],
|
| 32 |
+
resolution[0], 1e-6, use_depth_prior)
|
| 33 |
+
return findices, barycentric
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def interpolate(col, findices, barycentric, tri):
|
| 37 |
+
f = findices - 1 + (findices == 0)
|
| 38 |
+
vcol = col[0, tri.long()[f.long()]]
|
| 39 |
+
result = barycentric.view(*barycentric.shape, 1) * vcol
|
| 40 |
+
result = torch.sum(result, axis=-2)
|
| 41 |
+
return result.view(1, *result.shape)
|
{build/lib/hy3dgen/texgen/differentiable_renderer β hy3dgen/texgen/custom_rasterizer/lib/custom_rasterizer_kernel}/__init__.py
RENAMED
|
File without changes
|
hy3dgen/texgen/custom_rasterizer/lib/custom_rasterizer_kernel/grid_neighbor.cpp
ADDED
|
@@ -0,0 +1,575 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "rasterizer.h"
|
| 2 |
+
#include <fstream>
|
| 3 |
+
|
| 4 |
+
inline int pos2key(float* p, int resolution) {
|
| 5 |
+
int x = (p[0] * 0.5 + 0.5) * resolution;
|
| 6 |
+
int y = (p[1] * 0.5 + 0.5) * resolution;
|
| 7 |
+
int z = (p[2] * 0.5 + 0.5) * resolution;
|
| 8 |
+
return (x * resolution + y) * resolution + z;
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
inline void key2pos(int key, int resolution, float* p) {
|
| 12 |
+
int x = key / resolution / resolution;
|
| 13 |
+
int y = key / resolution % resolution;
|
| 14 |
+
int z = key % resolution;
|
| 15 |
+
p[0] = ((x + 0.5) / resolution - 0.5) * 2;
|
| 16 |
+
p[1] = ((y + 0.5) / resolution - 0.5) * 2;
|
| 17 |
+
p[2] = ((z + 0.5) / resolution - 0.5) * 2;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
inline void key2cornerpos(int key, int resolution, float* p) {
|
| 21 |
+
int x = key / resolution / resolution;
|
| 22 |
+
int y = key / resolution % resolution;
|
| 23 |
+
int z = key % resolution;
|
| 24 |
+
p[0] = ((x + 0.75) / resolution - 0.5) * 2;
|
| 25 |
+
p[1] = ((y + 0.25) / resolution - 0.5) * 2;
|
| 26 |
+
p[2] = ((z + 0.75) / resolution - 0.5) * 2;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
inline float* pos_ptr(int l, int i, int j, torch::Tensor t) {
|
| 30 |
+
float* pdata = t.data_ptr<float>();
|
| 31 |
+
int height = t.size(1);
|
| 32 |
+
int width = t.size(2);
|
| 33 |
+
return &pdata[((l * height + i) * width + j) * 4];
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
struct Grid
|
| 37 |
+
{
|
| 38 |
+
std::vector<int> seq2oddcorner;
|
| 39 |
+
std::vector<int> seq2evencorner;
|
| 40 |
+
std::vector<int> seq2grid;
|
| 41 |
+
std::vector<int> seq2normal;
|
| 42 |
+
std::vector<int> seq2neighbor;
|
| 43 |
+
std::unordered_map<int, int> grid2seq;
|
| 44 |
+
std::vector<int> downsample_seq;
|
| 45 |
+
int num_origin_seq;
|
| 46 |
+
int resolution;
|
| 47 |
+
int stride;
|
| 48 |
+
};
|
| 49 |
+
|
| 50 |
+
inline void pos_from_seq(Grid& grid, int seq, float* p) {
|
| 51 |
+
auto k = grid.seq2grid[seq];
|
| 52 |
+
key2pos(k, grid.resolution, p);
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
inline int fetch_seq(Grid& grid, int l, int i, int j, torch::Tensor pdata) {
|
| 56 |
+
float* p = pos_ptr(l, i, j, pdata);
|
| 57 |
+
if (p[3] == 0)
|
| 58 |
+
return -1;
|
| 59 |
+
auto key = pos2key(p, grid.resolution);
|
| 60 |
+
int seq = grid.grid2seq[key];
|
| 61 |
+
return seq;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
inline int fetch_last_seq(Grid& grid, int i, int j, torch::Tensor pdata) {
|
| 65 |
+
int num_layers = pdata.size(0);
|
| 66 |
+
int l = 0;
|
| 67 |
+
int idx = fetch_seq(grid, l, i, j, pdata);
|
| 68 |
+
while (l < num_layers - 1) {
|
| 69 |
+
l += 1;
|
| 70 |
+
int new_idx = fetch_seq(grid, l, i, j, pdata);
|
| 71 |
+
if (new_idx == -1)
|
| 72 |
+
break;
|
| 73 |
+
idx = new_idx;
|
| 74 |
+
}
|
| 75 |
+
return idx;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
inline int fetch_nearest_seq(Grid& grid, int i, int j, int dim, float d, torch::Tensor pdata) {
|
| 79 |
+
float p[3];
|
| 80 |
+
float max_dist = 1e10;
|
| 81 |
+
int best_idx = -1;
|
| 82 |
+
int num_layers = pdata.size(0);
|
| 83 |
+
for (int l = 0; l < num_layers; ++l) {
|
| 84 |
+
int idx = fetch_seq(grid, l, i, j, pdata);
|
| 85 |
+
if (idx == -1)
|
| 86 |
+
break;
|
| 87 |
+
pos_from_seq(grid, idx, p);
|
| 88 |
+
float dist = std::abs(d - p[(dim + 2) % 3]);
|
| 89 |
+
if (dist < max_dist) {
|
| 90 |
+
max_dist = dist;
|
| 91 |
+
best_idx = idx;
|
| 92 |
+
}
|
| 93 |
+
}
|
| 94 |
+
return best_idx;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
inline int fetch_nearest_seq_layer(Grid& grid, int i, int j, int dim, float d, torch::Tensor pdata) {
|
| 98 |
+
float p[3];
|
| 99 |
+
float max_dist = 1e10;
|
| 100 |
+
int best_layer = -1;
|
| 101 |
+
int num_layers = pdata.size(0);
|
| 102 |
+
for (int l = 0; l < num_layers; ++l) {
|
| 103 |
+
int idx = fetch_seq(grid, l, i, j, pdata);
|
| 104 |
+
if (idx == -1)
|
| 105 |
+
break;
|
| 106 |
+
pos_from_seq(grid, idx, p);
|
| 107 |
+
float dist = std::abs(d - p[(dim + 2) % 3]);
|
| 108 |
+
if (dist < max_dist) {
|
| 109 |
+
max_dist = dist;
|
| 110 |
+
best_layer = l;
|
| 111 |
+
}
|
| 112 |
+
}
|
| 113 |
+
return best_layer;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
void FetchNeighbor(Grid& grid, int seq, float* pos, int dim, int boundary_info, std::vector<torch::Tensor>& view_layer_positions,
|
| 117 |
+
int* output_indices)
|
| 118 |
+
{
|
| 119 |
+
auto t = view_layer_positions[dim];
|
| 120 |
+
int height = t.size(1);
|
| 121 |
+
int width = t.size(2);
|
| 122 |
+
int top = 0;
|
| 123 |
+
int ci = 0;
|
| 124 |
+
int cj = 0;
|
| 125 |
+
if (dim == 0) {
|
| 126 |
+
ci = (pos[1]/2+0.5)*height;
|
| 127 |
+
cj = (pos[0]/2+0.5)*width;
|
| 128 |
+
}
|
| 129 |
+
else if (dim == 1) {
|
| 130 |
+
ci = (pos[1]/2+0.5)*height;
|
| 131 |
+
cj = (pos[2]/2+0.5)*width;
|
| 132 |
+
}
|
| 133 |
+
else {
|
| 134 |
+
ci = (-pos[2]/2+0.5)*height;
|
| 135 |
+
cj = (pos[0]/2+0.5)*width;
|
| 136 |
+
}
|
| 137 |
+
int stride = grid.stride;
|
| 138 |
+
for (int ni = ci + stride; ni >= ci - stride; ni -= stride) {
|
| 139 |
+
for (int nj = cj - stride; nj <= cj + stride; nj += stride) {
|
| 140 |
+
int idx = -1;
|
| 141 |
+
if (ni == ci && nj == cj)
|
| 142 |
+
idx = seq;
|
| 143 |
+
else if (!(ni < 0 || ni >= height || nj < 0 || nj >= width)) {
|
| 144 |
+
if (boundary_info == -1)
|
| 145 |
+
idx = fetch_seq(grid, 0, ni, nj, t);
|
| 146 |
+
else if (boundary_info == 1)
|
| 147 |
+
idx = fetch_last_seq(grid, ni, nj, t);
|
| 148 |
+
else
|
| 149 |
+
idx = fetch_nearest_seq(grid, ni, nj, dim, pos[(dim + 2) % 3], t);
|
| 150 |
+
}
|
| 151 |
+
output_indices[top] = idx;
|
| 152 |
+
top += 1;
|
| 153 |
+
}
|
| 154 |
+
}
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
void DownsampleGrid(Grid& src, Grid& tar)
|
| 158 |
+
{
|
| 159 |
+
src.downsample_seq.resize(src.seq2grid.size(), -1);
|
| 160 |
+
tar.resolution = src.resolution / 2;
|
| 161 |
+
tar.stride = src.stride * 2;
|
| 162 |
+
float pos[3];
|
| 163 |
+
std::vector<int> seq2normal_count;
|
| 164 |
+
for (int i = 0; i < src.seq2grid.size(); ++i) {
|
| 165 |
+
key2pos(src.seq2grid[i], src.resolution, pos);
|
| 166 |
+
int k = pos2key(pos, tar.resolution);
|
| 167 |
+
int s = seq2normal_count.size();
|
| 168 |
+
if (!tar.grid2seq.count(k)) {
|
| 169 |
+
tar.grid2seq[k] = tar.seq2grid.size();
|
| 170 |
+
tar.seq2grid.emplace_back(k);
|
| 171 |
+
seq2normal_count.emplace_back(0);
|
| 172 |
+
seq2normal_count.emplace_back(0);
|
| 173 |
+
seq2normal_count.emplace_back(0);
|
| 174 |
+
//tar.seq2normal.emplace_back(src.seq2normal[i]);
|
| 175 |
+
} else {
|
| 176 |
+
s = tar.grid2seq[k] * 3;
|
| 177 |
+
}
|
| 178 |
+
seq2normal_count[s + src.seq2normal[i]] += 1;
|
| 179 |
+
src.downsample_seq[i] = tar.grid2seq[k];
|
| 180 |
+
}
|
| 181 |
+
tar.seq2normal.resize(seq2normal_count.size() / 3);
|
| 182 |
+
for (int i = 0; i < seq2normal_count.size(); i += 3) {
|
| 183 |
+
int t = 0;
|
| 184 |
+
for (int j = 1; j < 3; ++j) {
|
| 185 |
+
if (seq2normal_count[i + j] > seq2normal_count[i + t])
|
| 186 |
+
t = j;
|
| 187 |
+
}
|
| 188 |
+
tar.seq2normal[i / 3] = t;
|
| 189 |
+
}
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
void NeighborGrid(Grid& grid, std::vector<torch::Tensor> view_layer_positions, int v)
|
| 193 |
+
{
|
| 194 |
+
grid.seq2evencorner.resize(grid.seq2grid.size(), 0);
|
| 195 |
+
grid.seq2oddcorner.resize(grid.seq2grid.size(), 0);
|
| 196 |
+
std::unordered_set<int> visited_seq;
|
| 197 |
+
for (int vd = 0; vd < 3; ++vd) {
|
| 198 |
+
auto t = view_layer_positions[vd];
|
| 199 |
+
auto t0 = view_layer_positions[v];
|
| 200 |
+
int height = t.size(1);
|
| 201 |
+
int width = t.size(2);
|
| 202 |
+
int num_layers = t.size(0);
|
| 203 |
+
int num_view_layers = t0.size(0);
|
| 204 |
+
for (int i = 0; i < height; ++i) {
|
| 205 |
+
for (int j = 0; j < width; ++j) {
|
| 206 |
+
for (int l = 0; l < num_layers; ++l) {
|
| 207 |
+
int seq = fetch_seq(grid, l, i, j, t);
|
| 208 |
+
if (seq == -1)
|
| 209 |
+
break;
|
| 210 |
+
int dim = grid.seq2normal[seq];
|
| 211 |
+
if (dim != v)
|
| 212 |
+
continue;
|
| 213 |
+
|
| 214 |
+
float pos[3];
|
| 215 |
+
pos_from_seq(grid, seq, pos);
|
| 216 |
+
|
| 217 |
+
int ci = 0;
|
| 218 |
+
int cj = 0;
|
| 219 |
+
if (dim == 0) {
|
| 220 |
+
ci = (pos[1]/2+0.5)*height;
|
| 221 |
+
cj = (pos[0]/2+0.5)*width;
|
| 222 |
+
}
|
| 223 |
+
else if (dim == 1) {
|
| 224 |
+
ci = (pos[1]/2+0.5)*height;
|
| 225 |
+
cj = (pos[2]/2+0.5)*width;
|
| 226 |
+
}
|
| 227 |
+
else {
|
| 228 |
+
ci = (-pos[2]/2+0.5)*height;
|
| 229 |
+
cj = (pos[0]/2+0.5)*width;
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
if ((ci % (grid.stride * 2) < grid.stride) && (cj % (grid.stride * 2) >= grid.stride))
|
| 233 |
+
grid.seq2evencorner[seq] = 1;
|
| 234 |
+
|
| 235 |
+
if ((ci % (grid.stride * 2) >= grid.stride) && (cj % (grid.stride * 2) < grid.stride))
|
| 236 |
+
grid.seq2oddcorner[seq] = 1;
|
| 237 |
+
|
| 238 |
+
bool is_boundary = false;
|
| 239 |
+
if (vd == v) {
|
| 240 |
+
if (l == 0 || l == num_layers - 1)
|
| 241 |
+
is_boundary = true;
|
| 242 |
+
else {
|
| 243 |
+
int seq_new = fetch_seq(grid, l + 1, i, j, t);
|
| 244 |
+
if (seq_new == -1)
|
| 245 |
+
is_boundary = true;
|
| 246 |
+
}
|
| 247 |
+
}
|
| 248 |
+
int boundary_info = 0;
|
| 249 |
+
if (is_boundary && (l == 0))
|
| 250 |
+
boundary_info = -1;
|
| 251 |
+
else if (is_boundary)
|
| 252 |
+
boundary_info = 1;
|
| 253 |
+
if (visited_seq.count(seq))
|
| 254 |
+
continue;
|
| 255 |
+
visited_seq.insert(seq);
|
| 256 |
+
|
| 257 |
+
FetchNeighbor(grid, seq, pos, dim, boundary_info, view_layer_positions, &grid.seq2neighbor[seq * 9]);
|
| 258 |
+
}
|
| 259 |
+
}
|
| 260 |
+
}
|
| 261 |
+
}
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
void PadGrid(Grid& src, Grid& tar, std::vector<torch::Tensor>& view_layer_positions) {
|
| 265 |
+
auto& downsample_seq = src.downsample_seq;
|
| 266 |
+
auto& seq2evencorner = src.seq2evencorner;
|
| 267 |
+
auto& seq2oddcorner = src.seq2oddcorner;
|
| 268 |
+
int indices[9];
|
| 269 |
+
std::vector<int> mapped_even_corners(tar.seq2grid.size(), 0);
|
| 270 |
+
std::vector<int> mapped_odd_corners(tar.seq2grid.size(), 0);
|
| 271 |
+
for (int i = 0; i < downsample_seq.size(); ++i) {
|
| 272 |
+
if (seq2evencorner[i] > 0) {
|
| 273 |
+
mapped_even_corners[downsample_seq[i]] = 1;
|
| 274 |
+
}
|
| 275 |
+
if (seq2oddcorner[i] > 0) {
|
| 276 |
+
mapped_odd_corners[downsample_seq[i]] = 1;
|
| 277 |
+
}
|
| 278 |
+
}
|
| 279 |
+
auto& tar_seq2normal = tar.seq2normal;
|
| 280 |
+
auto& tar_seq2grid = tar.seq2grid;
|
| 281 |
+
for (int i = 0; i < tar_seq2grid.size(); ++i) {
|
| 282 |
+
if (mapped_even_corners[i] == 1 && mapped_odd_corners[i] == 1)
|
| 283 |
+
continue;
|
| 284 |
+
auto k = tar_seq2grid[i];
|
| 285 |
+
float p[3];
|
| 286 |
+
key2cornerpos(k, tar.resolution, p);
|
| 287 |
+
|
| 288 |
+
int src_key = pos2key(p, src.resolution);
|
| 289 |
+
if (!src.grid2seq.count(src_key)) {
|
| 290 |
+
int seq = src.seq2grid.size();
|
| 291 |
+
src.grid2seq[src_key] = seq;
|
| 292 |
+
src.seq2evencorner.emplace_back((mapped_even_corners[i] == 0));
|
| 293 |
+
src.seq2oddcorner.emplace_back((mapped_odd_corners[i] == 0));
|
| 294 |
+
src.seq2grid.emplace_back(src_key);
|
| 295 |
+
src.seq2normal.emplace_back(tar_seq2normal[i]);
|
| 296 |
+
FetchNeighbor(src, seq, p, tar_seq2normal[i], 0, view_layer_positions, indices);
|
| 297 |
+
for (int j = 0; j < 9; ++j) {
|
| 298 |
+
src.seq2neighbor.emplace_back(indices[j]);
|
| 299 |
+
}
|
| 300 |
+
src.downsample_seq.emplace_back(i);
|
| 301 |
+
} else {
|
| 302 |
+
int seq = src.grid2seq[src_key];
|
| 303 |
+
if (mapped_even_corners[i] == 0)
|
| 304 |
+
src.seq2evencorner[seq] = 1;
|
| 305 |
+
if (mapped_odd_corners[i] == 0)
|
| 306 |
+
src.seq2oddcorner[seq] = 1;
|
| 307 |
+
}
|
| 308 |
+
}
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
std::vector<std::vector<torch::Tensor>> build_hierarchy(std::vector<torch::Tensor> view_layer_positions,
|
| 312 |
+
std::vector<torch::Tensor> view_layer_normals, int num_level, int resolution)
|
| 313 |
+
{
|
| 314 |
+
if (view_layer_positions.size() != 3 || num_level < 1) {
|
| 315 |
+
printf("Alert! We require 3 layers and at least 1 level! (%d %d)\n", view_layer_positions.size(), num_level);
|
| 316 |
+
return {{},{},{},{}};
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
std::vector<Grid> grids;
|
| 320 |
+
grids.resize(num_level);
|
| 321 |
+
|
| 322 |
+
std::vector<float> seq2pos;
|
| 323 |
+
auto& seq2grid = grids[0].seq2grid;
|
| 324 |
+
auto& seq2normal = grids[0].seq2normal;
|
| 325 |
+
auto& grid2seq = grids[0].grid2seq;
|
| 326 |
+
grids[0].resolution = resolution;
|
| 327 |
+
grids[0].stride = 1;
|
| 328 |
+
|
| 329 |
+
auto int64_options = torch::TensorOptions().dtype(torch::kInt64).requires_grad(false);
|
| 330 |
+
auto float_options = torch::TensorOptions().dtype(torch::kFloat32).requires_grad(false);
|
| 331 |
+
|
| 332 |
+
for (int v = 0; v < 3; ++v) {
|
| 333 |
+
int num_layers = view_layer_positions[v].size(0);
|
| 334 |
+
int height = view_layer_positions[v].size(1);
|
| 335 |
+
int width = view_layer_positions[v].size(2);
|
| 336 |
+
float* data = view_layer_positions[v].data_ptr<float>();
|
| 337 |
+
float* data_normal = view_layer_normals[v].data_ptr<float>();
|
| 338 |
+
for (int l = 0; l < num_layers; ++l) {
|
| 339 |
+
for (int i = 0; i < height; ++i) {
|
| 340 |
+
for (int j = 0; j < width; ++j) {
|
| 341 |
+
float* p = &data[(i * width + j) * 4];
|
| 342 |
+
float* n = &data_normal[(i * width + j) * 3];
|
| 343 |
+
if (p[3] == 0)
|
| 344 |
+
continue;
|
| 345 |
+
auto k = pos2key(p, resolution);
|
| 346 |
+
if (!grid2seq.count(k)) {
|
| 347 |
+
int dim = 0;
|
| 348 |
+
for (int d = 0; d < 3; ++d) {
|
| 349 |
+
if (std::abs(n[d]) > std::abs(n[dim]))
|
| 350 |
+
dim = d;
|
| 351 |
+
}
|
| 352 |
+
dim = (dim + 1) % 3;
|
| 353 |
+
grid2seq[k] = seq2grid.size();
|
| 354 |
+
seq2grid.emplace_back(k);
|
| 355 |
+
seq2pos.push_back(p[0]);
|
| 356 |
+
seq2pos.push_back(p[1]);
|
| 357 |
+
seq2pos.push_back(p[2]);
|
| 358 |
+
seq2normal.emplace_back(dim);
|
| 359 |
+
}
|
| 360 |
+
}
|
| 361 |
+
}
|
| 362 |
+
data += (height * width * 4);
|
| 363 |
+
data_normal += (height * width * 3);
|
| 364 |
+
}
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
for (int i = 0; i < num_level - 1; ++i) {
|
| 368 |
+
DownsampleGrid(grids[i], grids[i + 1]);
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
for (int l = 0; l < num_level; ++l) {
|
| 372 |
+
grids[l].seq2neighbor.resize(grids[l].seq2grid.size() * 9, -1);
|
| 373 |
+
grids[l].num_origin_seq = grids[l].seq2grid.size();
|
| 374 |
+
for (int d = 0; d < 3; ++d) {
|
| 375 |
+
NeighborGrid(grids[l], view_layer_positions, d);
|
| 376 |
+
}
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
for (int i = num_level - 2; i >= 0; --i) {
|
| 380 |
+
PadGrid(grids[i], grids[i + 1], view_layer_positions);
|
| 381 |
+
}
|
| 382 |
+
for (int i = grids[0].num_origin_seq; i < grids[0].seq2grid.size(); ++i) {
|
| 383 |
+
int k = grids[0].seq2grid[i];
|
| 384 |
+
float p[3];
|
| 385 |
+
key2pos(k, grids[0].resolution, p);
|
| 386 |
+
seq2pos.push_back(p[0]);
|
| 387 |
+
seq2pos.push_back(p[1]);
|
| 388 |
+
seq2pos.push_back(p[2]);
|
| 389 |
+
}
|
| 390 |
+
|
| 391 |
+
std::vector<torch::Tensor> texture_positions(2);
|
| 392 |
+
std::vector<torch::Tensor> grid_neighbors(grids.size());
|
| 393 |
+
std::vector<torch::Tensor> grid_downsamples(grids.size() - 1);
|
| 394 |
+
std::vector<torch::Tensor> grid_evencorners(grids.size());
|
| 395 |
+
std::vector<torch::Tensor> grid_oddcorners(grids.size());
|
| 396 |
+
|
| 397 |
+
|
| 398 |
+
texture_positions[0] = torch::zeros({static_cast<int64_t>(seq2pos.size() / 3), static_cast<int64_t>(3)}, float_options);
|
| 399 |
+
texture_positions[1] = torch::zeros({static_cast<int64_t>(seq2pos.size() / 3)}, float_options);
|
| 400 |
+
float* positions_out_ptr = texture_positions[0].data_ptr<float>();
|
| 401 |
+
memcpy(positions_out_ptr, seq2pos.data(), sizeof(float) * seq2pos.size());
|
| 402 |
+
positions_out_ptr = texture_positions[1].data_ptr<float>();
|
| 403 |
+
for (int i = 0; i < grids[0].seq2grid.size(); ++i) {
|
| 404 |
+
positions_out_ptr[i] = (i < grids[0].num_origin_seq);
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
for (int i = 0; i < grids.size(); ++i) {
|
| 408 |
+
grid_neighbors[i] = torch::zeros({static_cast<int64_t>(grids[i].seq2grid.size()), static_cast<int64_t>(9)}, int64_options);
|
| 409 |
+
int64_t* nptr = grid_neighbors[i].data_ptr<int64_t>();
|
| 410 |
+
for (int j = 0; j < grids[i].seq2neighbor.size(); ++j) {
|
| 411 |
+
nptr[j] = grids[i].seq2neighbor[j];
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
grid_evencorners[i] = torch::zeros({static_cast<int64_t>(grids[i].seq2evencorner.size())}, int64_options);
|
| 415 |
+
grid_oddcorners[i] = torch::zeros({static_cast<int64_t>(grids[i].seq2oddcorner.size())}, int64_options);
|
| 416 |
+
int64_t* dptr = grid_evencorners[i].data_ptr<int64_t>();
|
| 417 |
+
for (int j = 0; j < grids[i].seq2evencorner.size(); ++j) {
|
| 418 |
+
dptr[j] = grids[i].seq2evencorner[j];
|
| 419 |
+
}
|
| 420 |
+
dptr = grid_oddcorners[i].data_ptr<int64_t>();
|
| 421 |
+
for (int j = 0; j < grids[i].seq2oddcorner.size(); ++j) {
|
| 422 |
+
dptr[j] = grids[i].seq2oddcorner[j];
|
| 423 |
+
}
|
| 424 |
+
if (i + 1 < grids.size()) {
|
| 425 |
+
grid_downsamples[i] = torch::zeros({static_cast<int64_t>(grids[i].downsample_seq.size())}, int64_options);
|
| 426 |
+
int64_t* dptr = grid_downsamples[i].data_ptr<int64_t>();
|
| 427 |
+
for (int j = 0; j < grids[i].downsample_seq.size(); ++j) {
|
| 428 |
+
dptr[j] = grids[i].downsample_seq[j];
|
| 429 |
+
}
|
| 430 |
+
}
|
| 431 |
+
|
| 432 |
+
}
|
| 433 |
+
return {texture_positions, grid_neighbors, grid_downsamples, grid_evencorners, grid_oddcorners};
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
std::vector<std::vector<torch::Tensor>> build_hierarchy_with_feat(
|
| 437 |
+
std::vector<torch::Tensor> view_layer_positions,
|
| 438 |
+
std::vector<torch::Tensor> view_layer_normals,
|
| 439 |
+
std::vector<torch::Tensor> view_layer_feats,
|
| 440 |
+
int num_level, int resolution)
|
| 441 |
+
{
|
| 442 |
+
if (view_layer_positions.size() != 3 || num_level < 1) {
|
| 443 |
+
printf("Alert! We require 3 layers and at least 1 level! (%d %d)\n", view_layer_positions.size(), num_level);
|
| 444 |
+
return {{},{},{},{}};
|
| 445 |
+
}
|
| 446 |
+
|
| 447 |
+
std::vector<Grid> grids;
|
| 448 |
+
grids.resize(num_level);
|
| 449 |
+
|
| 450 |
+
std::vector<float> seq2pos;
|
| 451 |
+
std::vector<float> seq2feat;
|
| 452 |
+
auto& seq2grid = grids[0].seq2grid;
|
| 453 |
+
auto& seq2normal = grids[0].seq2normal;
|
| 454 |
+
auto& grid2seq = grids[0].grid2seq;
|
| 455 |
+
grids[0].resolution = resolution;
|
| 456 |
+
grids[0].stride = 1;
|
| 457 |
+
|
| 458 |
+
auto int64_options = torch::TensorOptions().dtype(torch::kInt64).requires_grad(false);
|
| 459 |
+
auto float_options = torch::TensorOptions().dtype(torch::kFloat32).requires_grad(false);
|
| 460 |
+
|
| 461 |
+
int feat_channel = 3;
|
| 462 |
+
for (int v = 0; v < 3; ++v) {
|
| 463 |
+
int num_layers = view_layer_positions[v].size(0);
|
| 464 |
+
int height = view_layer_positions[v].size(1);
|
| 465 |
+
int width = view_layer_positions[v].size(2);
|
| 466 |
+
float* data = view_layer_positions[v].data_ptr<float>();
|
| 467 |
+
float* data_normal = view_layer_normals[v].data_ptr<float>();
|
| 468 |
+
float* data_feat = view_layer_feats[v].data_ptr<float>();
|
| 469 |
+
feat_channel = view_layer_feats[v].size(3);
|
| 470 |
+
for (int l = 0; l < num_layers; ++l) {
|
| 471 |
+
for (int i = 0; i < height; ++i) {
|
| 472 |
+
for (int j = 0; j < width; ++j) {
|
| 473 |
+
float* p = &data[(i * width + j) * 4];
|
| 474 |
+
float* n = &data_normal[(i * width + j) * 3];
|
| 475 |
+
float* f = &data_feat[(i * width + j) * feat_channel];
|
| 476 |
+
if (p[3] == 0)
|
| 477 |
+
continue;
|
| 478 |
+
auto k = pos2key(p, resolution);
|
| 479 |
+
if (!grid2seq.count(k)) {
|
| 480 |
+
int dim = 0;
|
| 481 |
+
for (int d = 0; d < 3; ++d) {
|
| 482 |
+
if (std::abs(n[d]) > std::abs(n[dim]))
|
| 483 |
+
dim = d;
|
| 484 |
+
}
|
| 485 |
+
dim = (dim + 1) % 3;
|
| 486 |
+
grid2seq[k] = seq2grid.size();
|
| 487 |
+
seq2grid.emplace_back(k);
|
| 488 |
+
seq2pos.push_back(p[0]);
|
| 489 |
+
seq2pos.push_back(p[1]);
|
| 490 |
+
seq2pos.push_back(p[2]);
|
| 491 |
+
for (int c = 0; c < feat_channel; ++c) {
|
| 492 |
+
seq2feat.emplace_back(f[c]);
|
| 493 |
+
}
|
| 494 |
+
seq2normal.emplace_back(dim);
|
| 495 |
+
}
|
| 496 |
+
}
|
| 497 |
+
}
|
| 498 |
+
data += (height * width * 4);
|
| 499 |
+
data_normal += (height * width * 3);
|
| 500 |
+
data_feat += (height * width * feat_channel);
|
| 501 |
+
}
|
| 502 |
+
}
|
| 503 |
+
|
| 504 |
+
for (int i = 0; i < num_level - 1; ++i) {
|
| 505 |
+
DownsampleGrid(grids[i], grids[i + 1]);
|
| 506 |
+
}
|
| 507 |
+
|
| 508 |
+
for (int l = 0; l < num_level; ++l) {
|
| 509 |
+
grids[l].seq2neighbor.resize(grids[l].seq2grid.size() * 9, -1);
|
| 510 |
+
grids[l].num_origin_seq = grids[l].seq2grid.size();
|
| 511 |
+
for (int d = 0; d < 3; ++d) {
|
| 512 |
+
NeighborGrid(grids[l], view_layer_positions, d);
|
| 513 |
+
}
|
| 514 |
+
}
|
| 515 |
+
|
| 516 |
+
for (int i = num_level - 2; i >= 0; --i) {
|
| 517 |
+
PadGrid(grids[i], grids[i + 1], view_layer_positions);
|
| 518 |
+
}
|
| 519 |
+
for (int i = grids[0].num_origin_seq; i < grids[0].seq2grid.size(); ++i) {
|
| 520 |
+
int k = grids[0].seq2grid[i];
|
| 521 |
+
float p[3];
|
| 522 |
+
key2pos(k, grids[0].resolution, p);
|
| 523 |
+
seq2pos.push_back(p[0]);
|
| 524 |
+
seq2pos.push_back(p[1]);
|
| 525 |
+
seq2pos.push_back(p[2]);
|
| 526 |
+
for (int c = 0; c < feat_channel; ++c) {
|
| 527 |
+
seq2feat.emplace_back(0.5);
|
| 528 |
+
}
|
| 529 |
+
}
|
| 530 |
+
|
| 531 |
+
std::vector<torch::Tensor> texture_positions(2);
|
| 532 |
+
std::vector<torch::Tensor> texture_feats(1);
|
| 533 |
+
std::vector<torch::Tensor> grid_neighbors(grids.size());
|
| 534 |
+
std::vector<torch::Tensor> grid_downsamples(grids.size() - 1);
|
| 535 |
+
std::vector<torch::Tensor> grid_evencorners(grids.size());
|
| 536 |
+
std::vector<torch::Tensor> grid_oddcorners(grids.size());
|
| 537 |
+
|
| 538 |
+
texture_positions[0] = torch::zeros({static_cast<int64_t>(seq2pos.size() / 3), static_cast<int64_t>(3)}, float_options);
|
| 539 |
+
texture_positions[1] = torch::zeros({static_cast<int64_t>(seq2pos.size() / 3)}, float_options);
|
| 540 |
+
texture_feats[0] = torch::zeros({static_cast<int64_t>(seq2feat.size() / feat_channel), static_cast<int64_t>(feat_channel)}, float_options);
|
| 541 |
+
float* positions_out_ptr = texture_positions[0].data_ptr<float>();
|
| 542 |
+
memcpy(positions_out_ptr, seq2pos.data(), sizeof(float) * seq2pos.size());
|
| 543 |
+
positions_out_ptr = texture_positions[1].data_ptr<float>();
|
| 544 |
+
for (int i = 0; i < grids[0].seq2grid.size(); ++i) {
|
| 545 |
+
positions_out_ptr[i] = (i < grids[0].num_origin_seq);
|
| 546 |
+
}
|
| 547 |
+
float* feats_out_ptr = texture_feats[0].data_ptr<float>();
|
| 548 |
+
memcpy(feats_out_ptr, seq2feat.data(), sizeof(float) * seq2feat.size());
|
| 549 |
+
|
| 550 |
+
for (int i = 0; i < grids.size(); ++i) {
|
| 551 |
+
grid_neighbors[i] = torch::zeros({static_cast<int64_t>(grids[i].seq2grid.size()), static_cast<int64_t>(9)}, int64_options);
|
| 552 |
+
int64_t* nptr = grid_neighbors[i].data_ptr<int64_t>();
|
| 553 |
+
for (int j = 0; j < grids[i].seq2neighbor.size(); ++j) {
|
| 554 |
+
nptr[j] = grids[i].seq2neighbor[j];
|
| 555 |
+
}
|
| 556 |
+
grid_evencorners[i] = torch::zeros({static_cast<int64_t>(grids[i].seq2evencorner.size())}, int64_options);
|
| 557 |
+
grid_oddcorners[i] = torch::zeros({static_cast<int64_t>(grids[i].seq2oddcorner.size())}, int64_options);
|
| 558 |
+
int64_t* dptr = grid_evencorners[i].data_ptr<int64_t>();
|
| 559 |
+
for (int j = 0; j < grids[i].seq2evencorner.size(); ++j) {
|
| 560 |
+
dptr[j] = grids[i].seq2evencorner[j];
|
| 561 |
+
}
|
| 562 |
+
dptr = grid_oddcorners[i].data_ptr<int64_t>();
|
| 563 |
+
for (int j = 0; j < grids[i].seq2oddcorner.size(); ++j) {
|
| 564 |
+
dptr[j] = grids[i].seq2oddcorner[j];
|
| 565 |
+
}
|
| 566 |
+
if (i + 1 < grids.size()) {
|
| 567 |
+
grid_downsamples[i] = torch::zeros({static_cast<int64_t>(grids[i].downsample_seq.size())}, int64_options);
|
| 568 |
+
int64_t* dptr = grid_downsamples[i].data_ptr<int64_t>();
|
| 569 |
+
for (int j = 0; j < grids[i].downsample_seq.size(); ++j) {
|
| 570 |
+
dptr[j] = grids[i].downsample_seq[j];
|
| 571 |
+
}
|
| 572 |
+
}
|
| 573 |
+
}
|
| 574 |
+
return {texture_positions, texture_feats, grid_neighbors, grid_downsamples, grid_evencorners, grid_oddcorners};
|
| 575 |
+
}
|
hy3dgen/texgen/custom_rasterizer/lib/custom_rasterizer_kernel/rasterizer.cpp
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "rasterizer.h"
|
| 2 |
+
|
| 3 |
+
void rasterizeTriangleCPU(int idx, float* vt0, float* vt1, float* vt2, int width, int height, INT64* zbuffer, float* d, float occlusion_truncation) {
|
| 4 |
+
float x_min = std::min(vt0[0], std::min(vt1[0],vt2[0]));
|
| 5 |
+
float x_max = std::max(vt0[0], std::max(vt1[0],vt2[0]));
|
| 6 |
+
float y_min = std::min(vt0[1], std::min(vt1[1],vt2[1]));
|
| 7 |
+
float y_max = std::max(vt0[1], std::max(vt1[1],vt2[1]));
|
| 8 |
+
|
| 9 |
+
for (int px = x_min; px < x_max + 1; ++px) {
|
| 10 |
+
if (px < 0 || px >= width)
|
| 11 |
+
continue;
|
| 12 |
+
for (int py = y_min; py < y_max + 1; ++py) {
|
| 13 |
+
if (py < 0 || py >= height)
|
| 14 |
+
continue;
|
| 15 |
+
float vt[2] = {px + 0.5f, py + 0.5f};
|
| 16 |
+
float baryCentricCoordinate[3];
|
| 17 |
+
calculateBarycentricCoordinate(vt0, vt1, vt2, vt, baryCentricCoordinate);
|
| 18 |
+
if (isBarycentricCoordInBounds(baryCentricCoordinate)) {
|
| 19 |
+
int pixel = py * width + px;
|
| 20 |
+
if (zbuffer == 0) {
|
| 21 |
+
zbuffer[pixel] = (INT64)(idx + 1);
|
| 22 |
+
continue;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
float depth = baryCentricCoordinate[0] * vt0[2] + baryCentricCoordinate[1] * vt1[2] + baryCentricCoordinate[2] * vt2[2];
|
| 26 |
+
float depth_thres = 0;
|
| 27 |
+
if (d) {
|
| 28 |
+
depth_thres = d[pixel] * 0.49999f + 0.5f + occlusion_truncation;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
int z_quantize = depth * (2<<17);
|
| 32 |
+
INT64 token = (INT64)z_quantize * MAXINT + (INT64)(idx + 1);
|
| 33 |
+
if (depth < depth_thres)
|
| 34 |
+
continue;
|
| 35 |
+
zbuffer[pixel] = std::min(zbuffer[pixel], token);
|
| 36 |
+
}
|
| 37 |
+
}
|
| 38 |
+
}
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
void barycentricFromImgcoordCPU(float* V, int* F, int* findices, INT64* zbuffer, int width, int height, int num_vertices, int num_faces,
|
| 42 |
+
float* barycentric_map, int pix)
|
| 43 |
+
{
|
| 44 |
+
INT64 f = zbuffer[pix] % MAXINT;
|
| 45 |
+
if (f == (MAXINT-1)) {
|
| 46 |
+
findices[pix] = 0;
|
| 47 |
+
barycentric_map[pix * 3] = 0;
|
| 48 |
+
barycentric_map[pix * 3 + 1] = 0;
|
| 49 |
+
barycentric_map[pix * 3 + 2] = 0;
|
| 50 |
+
return;
|
| 51 |
+
}
|
| 52 |
+
findices[pix] = f;
|
| 53 |
+
f -= 1;
|
| 54 |
+
float barycentric[3] = {0, 0, 0};
|
| 55 |
+
if (f >= 0) {
|
| 56 |
+
float vt[2] = {float(pix % width) + 0.5f, float(pix / width) + 0.5f};
|
| 57 |
+
float* vt0_ptr = V + (F[f * 3] * 4);
|
| 58 |
+
float* vt1_ptr = V + (F[f * 3 + 1] * 4);
|
| 59 |
+
float* vt2_ptr = V + (F[f * 3 + 2] * 4);
|
| 60 |
+
|
| 61 |
+
float vt0[2] = {(vt0_ptr[0] / vt0_ptr[3] * 0.5f + 0.5f) * (width - 1) + 0.5f, (0.5f + 0.5f * vt0_ptr[1] / vt0_ptr[3]) * (height - 1) + 0.5f};
|
| 62 |
+
float vt1[2] = {(vt1_ptr[0] / vt1_ptr[3] * 0.5f + 0.5f) * (width - 1) + 0.5f, (0.5f + 0.5f * vt1_ptr[1] / vt1_ptr[3]) * (height - 1) + 0.5f};
|
| 63 |
+
float vt2[2] = {(vt2_ptr[0] / vt2_ptr[3] * 0.5f + 0.5f) * (width - 1) + 0.5f, (0.5f + 0.5f * vt2_ptr[1] / vt2_ptr[3]) * (height - 1) + 0.5f};
|
| 64 |
+
|
| 65 |
+
calculateBarycentricCoordinate(vt0, vt1, vt2, vt, barycentric);
|
| 66 |
+
|
| 67 |
+
barycentric[0] = barycentric[0] / vt0_ptr[3];
|
| 68 |
+
barycentric[1] = barycentric[1] / vt1_ptr[3];
|
| 69 |
+
barycentric[2] = barycentric[2] / vt2_ptr[3];
|
| 70 |
+
float w = 1.0f / (barycentric[0] + barycentric[1] + barycentric[2]);
|
| 71 |
+
barycentric[0] *= w;
|
| 72 |
+
barycentric[1] *= w;
|
| 73 |
+
barycentric[2] *= w;
|
| 74 |
+
|
| 75 |
+
}
|
| 76 |
+
barycentric_map[pix * 3] = barycentric[0];
|
| 77 |
+
barycentric_map[pix * 3 + 1] = barycentric[1];
|
| 78 |
+
barycentric_map[pix * 3 + 2] = barycentric[2];
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
void rasterizeImagecoordsKernelCPU(float* V, int* F, float* d, INT64* zbuffer, float occlusion_trunc, int width, int height, int num_vertices, int num_faces, int f)
|
| 82 |
+
{
|
| 83 |
+
float* vt0_ptr = V + (F[f * 3] * 4);
|
| 84 |
+
float* vt1_ptr = V + (F[f * 3 + 1] * 4);
|
| 85 |
+
float* vt2_ptr = V + (F[f * 3 + 2] * 4);
|
| 86 |
+
|
| 87 |
+
float vt0[3] = {(vt0_ptr[0] / vt0_ptr[3] * 0.5f + 0.5f) * (width - 1) + 0.5f, (0.5f + 0.5f * vt0_ptr[1] / vt0_ptr[3]) * (height - 1) + 0.5f, vt0_ptr[2] / vt0_ptr[3] * 0.49999f + 0.5f};
|
| 88 |
+
float vt1[3] = {(vt1_ptr[0] / vt1_ptr[3] * 0.5f + 0.5f) * (width - 1) + 0.5f, (0.5f + 0.5f * vt1_ptr[1] / vt1_ptr[3]) * (height - 1) + 0.5f, vt1_ptr[2] / vt1_ptr[3] * 0.49999f + 0.5f};
|
| 89 |
+
float vt2[3] = {(vt2_ptr[0] / vt2_ptr[3] * 0.5f + 0.5f) * (width - 1) + 0.5f, (0.5f + 0.5f * vt2_ptr[1] / vt2_ptr[3]) * (height - 1) + 0.5f, vt2_ptr[2] / vt2_ptr[3] * 0.49999f + 0.5f};
|
| 90 |
+
|
| 91 |
+
rasterizeTriangleCPU(f, vt0, vt1, vt2, width, height, zbuffer, d, occlusion_trunc);
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
std::vector<torch::Tensor> rasterize_image_cpu(torch::Tensor V, torch::Tensor F, torch::Tensor D,
|
| 95 |
+
int width, int height, float occlusion_truncation, int use_depth_prior)
|
| 96 |
+
{
|
| 97 |
+
int num_faces = F.size(0);
|
| 98 |
+
int num_vertices = V.size(0);
|
| 99 |
+
auto options = torch::TensorOptions().dtype(torch::kInt32).requires_grad(false);
|
| 100 |
+
auto INT64_options = torch::TensorOptions().dtype(torch::kInt64).requires_grad(false);
|
| 101 |
+
auto findices = torch::zeros({height, width}, options);
|
| 102 |
+
INT64 maxint = (INT64)MAXINT * (INT64)MAXINT + (MAXINT - 1);
|
| 103 |
+
auto z_min = torch::ones({height, width}, INT64_options) * (int64_t)maxint;
|
| 104 |
+
|
| 105 |
+
if (!use_depth_prior) {
|
| 106 |
+
for (int i = 0; i < num_faces; ++i) {
|
| 107 |
+
rasterizeImagecoordsKernelCPU(V.data_ptr<float>(), F.data_ptr<int>(), 0,
|
| 108 |
+
(INT64*)z_min.data_ptr<int64_t>(), occlusion_truncation, width, height, num_vertices, num_faces, i);
|
| 109 |
+
}
|
| 110 |
+
} else {
|
| 111 |
+
for (int i = 0; i < num_faces; ++i)
|
| 112 |
+
rasterizeImagecoordsKernelCPU(V.data_ptr<float>(), F.data_ptr<int>(), D.data_ptr<float>(),
|
| 113 |
+
(INT64*)z_min.data_ptr<int64_t>(), occlusion_truncation, width, height, num_vertices, num_faces, i);
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
auto float_options = torch::TensorOptions().dtype(torch::kFloat32).requires_grad(false);
|
| 117 |
+
auto barycentric = torch::zeros({height, width, 3}, float_options);
|
| 118 |
+
for (int i = 0; i < width * height; ++i)
|
| 119 |
+
barycentricFromImgcoordCPU(V.data_ptr<float>(), F.data_ptr<int>(),
|
| 120 |
+
findices.data_ptr<int>(), (INT64*)z_min.data_ptr<int64_t>(), width, height, num_vertices, num_faces, barycentric.data_ptr<float>(), i);
|
| 121 |
+
|
| 122 |
+
return {findices, barycentric};
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
std::vector<torch::Tensor> rasterize_image(torch::Tensor V, torch::Tensor F, torch::Tensor D,
|
| 126 |
+
int width, int height, float occlusion_truncation, int use_depth_prior)
|
| 127 |
+
{
|
| 128 |
+
int device_id = V.get_device();
|
| 129 |
+
if (device_id == -1)
|
| 130 |
+
return rasterize_image_cpu(V, F, D, width, height, occlusion_truncation, use_depth_prior);
|
| 131 |
+
else
|
| 132 |
+
return rasterize_image_gpu(V, F, D, width, height, occlusion_truncation, use_depth_prior);
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
| 136 |
+
m.def("rasterize_image", &rasterize_image, "Custom image rasterization");
|
| 137 |
+
m.def("build_hierarchy", &build_hierarchy, "Custom image rasterization");
|
| 138 |
+
m.def("build_hierarchy_with_feat", &build_hierarchy_with_feat, "Custom image rasterization");
|
| 139 |
+
}
|
hy3dgen/texgen/custom_rasterizer/lib/custom_rasterizer_kernel/rasterizer.h
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef RASTERIZER_H_
|
| 2 |
+
#define RASTERIZER_H_
|
| 3 |
+
|
| 4 |
+
#include <torch/extension.h>
|
| 5 |
+
#include <vector>
|
| 6 |
+
#include <ATen/ATen.h>
|
| 7 |
+
#include <ATen/cuda/CUDAContext.h> // For CUDA context
|
| 8 |
+
#include <cstdint>
|
| 9 |
+
#define INT64 uint64_t
|
| 10 |
+
#define MAXINT 2147483647
|
| 11 |
+
|
| 12 |
+
__host__ __device__ inline float calculateSignedArea2(float* a, float* b, float* c) {
|
| 13 |
+
return ((c[0] - a[0]) * (b[1] - a[1]) - (b[0] - a[0]) * (c[1] - a[1]));
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
__host__ __device__ inline void calculateBarycentricCoordinate(float* a, float* b, float* c, float* p,
|
| 17 |
+
float* barycentric)
|
| 18 |
+
{
|
| 19 |
+
float beta_tri = calculateSignedArea2(a, p, c);
|
| 20 |
+
float gamma_tri = calculateSignedArea2(a, b, p);
|
| 21 |
+
float area = calculateSignedArea2(a, b, c);
|
| 22 |
+
if (area == 0) {
|
| 23 |
+
barycentric[0] = -1.0;
|
| 24 |
+
barycentric[1] = -1.0;
|
| 25 |
+
barycentric[2] = -1.0;
|
| 26 |
+
return;
|
| 27 |
+
}
|
| 28 |
+
float tri_inv = 1.0 / area;
|
| 29 |
+
float beta = beta_tri * tri_inv;
|
| 30 |
+
float gamma = gamma_tri * tri_inv;
|
| 31 |
+
float alpha = 1.0 - beta - gamma;
|
| 32 |
+
barycentric[0] = alpha;
|
| 33 |
+
barycentric[1] = beta;
|
| 34 |
+
barycentric[2] = gamma;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
__host__ __device__ inline bool isBarycentricCoordInBounds(float* barycentricCoord) {
|
| 38 |
+
return barycentricCoord[0] >= 0.0 && barycentricCoord[0] <= 1.0 &&
|
| 39 |
+
barycentricCoord[1] >= 0.0 && barycentricCoord[1] <= 1.0 &&
|
| 40 |
+
barycentricCoord[2] >= 0.0 && barycentricCoord[2] <= 1.0;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
std::vector<torch::Tensor> rasterize_image_gpu(torch::Tensor V, torch::Tensor F, torch::Tensor D,
|
| 44 |
+
int width, int height, float occlusion_truncation, int use_depth_prior);
|
| 45 |
+
|
| 46 |
+
std::vector<std::vector<torch::Tensor>> build_hierarchy(std::vector<torch::Tensor> view_layer_positions, std::vector<torch::Tensor> view_layer_normals, int num_level, int resolution);
|
| 47 |
+
|
| 48 |
+
std::vector<std::vector<torch::Tensor>> build_hierarchy_with_feat(
|
| 49 |
+
std::vector<torch::Tensor> view_layer_positions,
|
| 50 |
+
std::vector<torch::Tensor> view_layer_normals,
|
| 51 |
+
std::vector<torch::Tensor> view_layer_feats,
|
| 52 |
+
int num_level, int resolution);
|
| 53 |
+
|
| 54 |
+
#endif
|
hy3dgen/texgen/custom_rasterizer/lib/custom_rasterizer_kernel/rasterizer_gpu.cu
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "rasterizer.h"
|
| 2 |
+
|
| 3 |
+
__device__ void rasterizeTriangleGPU(int idx, float* vt0, float* vt1, float* vt2, int width, int height, INT64* zbuffer, float* d, float occlusion_truncation) {
|
| 4 |
+
float x_min = std::min(vt0[0], std::min(vt1[0],vt2[0]));
|
| 5 |
+
float x_max = std::max(vt0[0], std::max(vt1[0],vt2[0]));
|
| 6 |
+
float y_min = std::min(vt0[1], std::min(vt1[1],vt2[1]));
|
| 7 |
+
float y_max = std::max(vt0[1], std::max(vt1[1],vt2[1]));
|
| 8 |
+
|
| 9 |
+
for (int px = x_min; px < x_max + 1; ++px) {
|
| 10 |
+
if (px < 0 || px >= width)
|
| 11 |
+
continue;
|
| 12 |
+
for (int py = y_min; py < y_max + 1; ++py) {
|
| 13 |
+
if (py < 0 || py >= height)
|
| 14 |
+
continue;
|
| 15 |
+
float vt[2] = {px + 0.5f, py + 0.5f};
|
| 16 |
+
float baryCentricCoordinate[3];
|
| 17 |
+
calculateBarycentricCoordinate(vt0, vt1, vt2, vt, baryCentricCoordinate);
|
| 18 |
+
if (isBarycentricCoordInBounds(baryCentricCoordinate)) {
|
| 19 |
+
int pixel = py * width + px;
|
| 20 |
+
if (zbuffer == 0) {
|
| 21 |
+
atomicExch(&zbuffer[pixel], (INT64)(idx + 1));
|
| 22 |
+
continue;
|
| 23 |
+
}
|
| 24 |
+
float depth = baryCentricCoordinate[0] * vt0[2] + baryCentricCoordinate[1] * vt1[2] + baryCentricCoordinate[2] * vt2[2];
|
| 25 |
+
float depth_thres = 0;
|
| 26 |
+
if (d) {
|
| 27 |
+
depth_thres = d[pixel] * 0.49999f + 0.5f + occlusion_truncation;
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
int z_quantize = depth * (2<<17);
|
| 31 |
+
INT64 token = (INT64)z_quantize * MAXINT + (INT64)(idx + 1);
|
| 32 |
+
if (depth < depth_thres)
|
| 33 |
+
continue;
|
| 34 |
+
atomicMin(&zbuffer[pixel], token);
|
| 35 |
+
}
|
| 36 |
+
}
|
| 37 |
+
}
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
__global__ void barycentricFromImgcoordGPU(float* V, int* F, int* findices, INT64* zbuffer, int width, int height, int num_vertices, int num_faces,
|
| 41 |
+
float* barycentric_map)
|
| 42 |
+
{
|
| 43 |
+
int pix = blockIdx.x * blockDim.x + threadIdx.x;
|
| 44 |
+
if (pix >= width * height)
|
| 45 |
+
return;
|
| 46 |
+
INT64 f = zbuffer[pix] % MAXINT;
|
| 47 |
+
if (f == (MAXINT-1)) {
|
| 48 |
+
findices[pix] = 0;
|
| 49 |
+
barycentric_map[pix * 3] = 0;
|
| 50 |
+
barycentric_map[pix * 3 + 1] = 0;
|
| 51 |
+
barycentric_map[pix * 3 + 2] = 0;
|
| 52 |
+
return;
|
| 53 |
+
}
|
| 54 |
+
findices[pix] = f;
|
| 55 |
+
f -= 1;
|
| 56 |
+
float barycentric[3] = {0, 0, 0};
|
| 57 |
+
if (f >= 0) {
|
| 58 |
+
float vt[2] = {float(pix % width) + 0.5f, float(pix / width) + 0.5f};
|
| 59 |
+
float* vt0_ptr = V + (F[f * 3] * 4);
|
| 60 |
+
float* vt1_ptr = V + (F[f * 3 + 1] * 4);
|
| 61 |
+
float* vt2_ptr = V + (F[f * 3 + 2] * 4);
|
| 62 |
+
|
| 63 |
+
float vt0[2] = {(vt0_ptr[0] / vt0_ptr[3] * 0.5f + 0.5f) * (width - 1) + 0.5f, (0.5f + 0.5f * vt0_ptr[1] / vt0_ptr[3]) * (height - 1) + 0.5f};
|
| 64 |
+
float vt1[2] = {(vt1_ptr[0] / vt1_ptr[3] * 0.5f + 0.5f) * (width - 1) + 0.5f, (0.5f + 0.5f * vt1_ptr[1] / vt1_ptr[3]) * (height - 1) + 0.5f};
|
| 65 |
+
float vt2[2] = {(vt2_ptr[0] / vt2_ptr[3] * 0.5f + 0.5f) * (width - 1) + 0.5f, (0.5f + 0.5f * vt2_ptr[1] / vt2_ptr[3]) * (height - 1) + 0.5f};
|
| 66 |
+
|
| 67 |
+
calculateBarycentricCoordinate(vt0, vt1, vt2, vt, barycentric);
|
| 68 |
+
|
| 69 |
+
barycentric[0] = barycentric[0] / vt0_ptr[3];
|
| 70 |
+
barycentric[1] = barycentric[1] / vt1_ptr[3];
|
| 71 |
+
barycentric[2] = barycentric[2] / vt2_ptr[3];
|
| 72 |
+
float w = 1.0f / (barycentric[0] + barycentric[1] + barycentric[2]);
|
| 73 |
+
barycentric[0] *= w;
|
| 74 |
+
barycentric[1] *= w;
|
| 75 |
+
barycentric[2] *= w;
|
| 76 |
+
|
| 77 |
+
}
|
| 78 |
+
barycentric_map[pix * 3] = barycentric[0];
|
| 79 |
+
barycentric_map[pix * 3 + 1] = barycentric[1];
|
| 80 |
+
barycentric_map[pix * 3 + 2] = barycentric[2];
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
__global__ void rasterizeImagecoordsKernelGPU(float* V, int* F, float* d, INT64* zbuffer, float occlusion_trunc, int width, int height, int num_vertices, int num_faces)
|
| 84 |
+
{
|
| 85 |
+
int f = blockIdx.x * blockDim.x + threadIdx.x;
|
| 86 |
+
if (f >= num_faces)
|
| 87 |
+
return;
|
| 88 |
+
|
| 89 |
+
float* vt0_ptr = V + (F[f * 3] * 4);
|
| 90 |
+
float* vt1_ptr = V + (F[f * 3 + 1] * 4);
|
| 91 |
+
float* vt2_ptr = V + (F[f * 3 + 2] * 4);
|
| 92 |
+
|
| 93 |
+
float vt0[3] = {(vt0_ptr[0] / vt0_ptr[3] * 0.5f + 0.5f) * (width - 1) + 0.5f, (0.5f + 0.5f * vt0_ptr[1] / vt0_ptr[3]) * (height - 1) + 0.5f, vt0_ptr[2] / vt0_ptr[3] * 0.49999f + 0.5f};
|
| 94 |
+
float vt1[3] = {(vt1_ptr[0] / vt1_ptr[3] * 0.5f + 0.5f) * (width - 1) + 0.5f, (0.5f + 0.5f * vt1_ptr[1] / vt1_ptr[3]) * (height - 1) + 0.5f, vt1_ptr[2] / vt1_ptr[3] * 0.49999f + 0.5f};
|
| 95 |
+
float vt2[3] = {(vt2_ptr[0] / vt2_ptr[3] * 0.5f + 0.5f) * (width - 1) + 0.5f, (0.5f + 0.5f * vt2_ptr[1] / vt2_ptr[3]) * (height - 1) + 0.5f, vt2_ptr[2] / vt2_ptr[3] * 0.49999f + 0.5f};
|
| 96 |
+
|
| 97 |
+
rasterizeTriangleGPU(f, vt0, vt1, vt2, width, height, zbuffer, d, occlusion_trunc);
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
std::vector<torch::Tensor> rasterize_image_gpu(torch::Tensor V, torch::Tensor F, torch::Tensor D,
|
| 101 |
+
int width, int height, float occlusion_truncation, int use_depth_prior)
|
| 102 |
+
{
|
| 103 |
+
int device_id = V.get_device();
|
| 104 |
+
cudaSetDevice(device_id);
|
| 105 |
+
int num_faces = F.size(0);
|
| 106 |
+
int num_vertices = V.size(0);
|
| 107 |
+
auto options = torch::TensorOptions().dtype(torch::kInt32).device(torch::kCUDA, device_id).requires_grad(false);
|
| 108 |
+
auto INT64_options = torch::TensorOptions().dtype(torch::kInt64).device(torch::kCUDA, device_id).requires_grad(false);
|
| 109 |
+
auto findices = torch::zeros({height, width}, options);
|
| 110 |
+
INT64 maxint = (INT64)MAXINT * (INT64)MAXINT + (MAXINT - 1);
|
| 111 |
+
auto z_min = torch::ones({height, width}, INT64_options) * (int64_t)maxint;
|
| 112 |
+
|
| 113 |
+
if (!use_depth_prior) {
|
| 114 |
+
rasterizeImagecoordsKernelGPU<<<(num_faces+255)/256,256,0,at::cuda::getCurrentCUDAStream()>>>(V.data_ptr<float>(), F.data_ptr<int>(), 0,
|
| 115 |
+
(INT64*)z_min.data_ptr<int64_t>(), occlusion_truncation, width, height, num_vertices, num_faces);
|
| 116 |
+
} else {
|
| 117 |
+
rasterizeImagecoordsKernelGPU<<<(num_faces+255)/256,256,0,at::cuda::getCurrentCUDAStream()>>>(V.data_ptr<float>(), F.data_ptr<int>(), D.data_ptr<float>(),
|
| 118 |
+
(INT64*)z_min.data_ptr<int64_t>(), occlusion_truncation, width, height, num_vertices, num_faces);
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
auto float_options = torch::TensorOptions().dtype(torch::kFloat32).device(torch::kCUDA, device_id).requires_grad(false);
|
| 122 |
+
auto barycentric = torch::zeros({height, width, 3}, float_options);
|
| 123 |
+
barycentricFromImgcoordGPU<<<(width * height + 255)/256, 256>>>(V.data_ptr<float>(), F.data_ptr<int>(),
|
| 124 |
+
findices.data_ptr<int>(), (INT64*)z_min.data_ptr<int64_t>(), width, height, num_vertices, num_faces, barycentric.data_ptr<float>());
|
| 125 |
+
|
| 126 |
+
return {findices, barycentric};
|
| 127 |
+
}
|
hy3dgen/texgen/custom_rasterizer/setup.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from setuptools import setup, find_packages
|
| 2 |
+
from torch.utils.cpp_extension import BuildExtension, CUDAExtension
|
| 3 |
+
|
| 4 |
+
# build custom rasterizer
|
| 5 |
+
# build with `python setup.py install`
|
| 6 |
+
# nvcc is needed
|
| 7 |
+
|
| 8 |
+
custom_rasterizer_module = CUDAExtension('custom_rasterizer_kernel', [
|
| 9 |
+
'lib/custom_rasterizer_kernel/rasterizer.cpp',
|
| 10 |
+
'lib/custom_rasterizer_kernel/grid_neighbor.cpp',
|
| 11 |
+
'lib/custom_rasterizer_kernel/rasterizer_gpu.cu',
|
| 12 |
+
])
|
| 13 |
+
|
| 14 |
+
setup(
|
| 15 |
+
packages=find_packages(),
|
| 16 |
+
version='0.1',
|
| 17 |
+
name='custom_rasterizer',
|
| 18 |
+
include_package_data=True,
|
| 19 |
+
package_dir={'': '.'},
|
| 20 |
+
ext_modules=[
|
| 21 |
+
custom_rasterizer_module,
|
| 22 |
+
],
|
| 23 |
+
cmdclass={
|
| 24 |
+
'build_ext': BuildExtension
|
| 25 |
+
}
|
| 26 |
+
)
|
{build/lib/hy3dgen/texgen/hunyuanpaint β hy3dgen/texgen/differentiable_renderer}/__init__.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/texgen/differentiable_renderer/camera_utils.py
RENAMED
|
File without changes
|
hy3dgen/texgen/differentiable_renderer/compile_mesh_painter.bat
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FOR /F "tokens=*" %%i IN ('python -m pybind11 --includes') DO SET PYINCLUDES=%%i
|
| 2 |
+
echo %PYINCLUDES%
|
| 3 |
+
g++ -O3 -Wall -shared -std=c++11 -fPIC %PYINCLUDES% mesh_processor.cpp -o mesh_processor.pyd -lpython3.12
|
hy3dgen/texgen/differentiable_renderer/mesh_processor.cpp
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include <vector>
|
| 2 |
+
#include <queue>
|
| 3 |
+
#include <cmath>
|
| 4 |
+
#include <algorithm>
|
| 5 |
+
#include <pybind11/pybind11.h>
|
| 6 |
+
#include <pybind11/numpy.h>
|
| 7 |
+
#include <pybind11/stl.h>
|
| 8 |
+
|
| 9 |
+
namespace py = pybind11;
|
| 10 |
+
using namespace std;
|
| 11 |
+
|
| 12 |
+
std::pair<py::array_t<float>,
|
| 13 |
+
py::array_t<uint8_t>> meshVerticeInpaint_smooth(py::array_t<float> texture,
|
| 14 |
+
py::array_t<uint8_t> mask,
|
| 15 |
+
py::array_t<float> vtx_pos, py::array_t<float> vtx_uv,
|
| 16 |
+
py::array_t<int> pos_idx, py::array_t<int> uv_idx) {
|
| 17 |
+
auto texture_buf = texture.request();
|
| 18 |
+
auto mask_buf = mask.request();
|
| 19 |
+
auto vtx_pos_buf = vtx_pos.request();
|
| 20 |
+
auto vtx_uv_buf = vtx_uv.request();
|
| 21 |
+
auto pos_idx_buf = pos_idx.request();
|
| 22 |
+
auto uv_idx_buf = uv_idx.request();
|
| 23 |
+
|
| 24 |
+
int texture_height = texture_buf.shape[0];
|
| 25 |
+
int texture_width = texture_buf.shape[1];
|
| 26 |
+
int texture_channel = texture_buf.shape[2];
|
| 27 |
+
float* texture_ptr = static_cast<float*>(texture_buf.ptr);
|
| 28 |
+
uint8_t* mask_ptr = static_cast<uint8_t*>(mask_buf.ptr);
|
| 29 |
+
|
| 30 |
+
int vtx_num = vtx_pos_buf.shape[0];
|
| 31 |
+
float* vtx_pos_ptr = static_cast<float*>(vtx_pos_buf.ptr);
|
| 32 |
+
float* vtx_uv_ptr = static_cast<float*>(vtx_uv_buf.ptr);
|
| 33 |
+
int* pos_idx_ptr = static_cast<int*>(pos_idx_buf.ptr);
|
| 34 |
+
int* uv_idx_ptr = static_cast<int*>(uv_idx_buf.ptr);
|
| 35 |
+
|
| 36 |
+
vector<float> vtx_mask(vtx_num, 0.0f);
|
| 37 |
+
vector<vector<float>> vtx_color(vtx_num, vector<float>(texture_channel, 0.0f));
|
| 38 |
+
vector<int> uncolored_vtxs;
|
| 39 |
+
|
| 40 |
+
vector<vector<int>> G(vtx_num);
|
| 41 |
+
|
| 42 |
+
for (int i = 0; i < uv_idx_buf.shape[0]; ++i) {
|
| 43 |
+
for (int k = 0; k < 3; ++k) {
|
| 44 |
+
int vtx_uv_idx = uv_idx_ptr[i * 3 + k];
|
| 45 |
+
int vtx_idx = pos_idx_ptr[i * 3 + k];
|
| 46 |
+
int uv_v = round(vtx_uv_ptr[vtx_uv_idx * 2] * (texture_width - 1));
|
| 47 |
+
int uv_u = round((1.0 - vtx_uv_ptr[vtx_uv_idx * 2 + 1]) * (texture_height - 1));
|
| 48 |
+
|
| 49 |
+
if (mask_ptr[uv_u * texture_width + uv_v] > 0) {
|
| 50 |
+
vtx_mask[vtx_idx] = 1.0f;
|
| 51 |
+
for (int c = 0; c < texture_channel; ++c) {
|
| 52 |
+
vtx_color[vtx_idx][c] = texture_ptr[(uv_u * texture_width + uv_v) * texture_channel + c];
|
| 53 |
+
}
|
| 54 |
+
}else{
|
| 55 |
+
uncolored_vtxs.push_back(vtx_idx);
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
G[pos_idx_ptr[i * 3 + k]].push_back(pos_idx_ptr[i * 3 + (k + 1) % 3]);
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
int smooth_count = 2;
|
| 63 |
+
int last_uncolored_vtx_count = 0;
|
| 64 |
+
while (smooth_count>0) {
|
| 65 |
+
int uncolored_vtx_count = 0;
|
| 66 |
+
|
| 67 |
+
for (int vtx_idx : uncolored_vtxs) {
|
| 68 |
+
|
| 69 |
+
vector<float> sum_color(texture_channel, 0.0f);
|
| 70 |
+
float total_weight = 0.0f;
|
| 71 |
+
|
| 72 |
+
array<float, 3> vtx_0 = {vtx_pos_ptr[vtx_idx * 3],
|
| 73 |
+
vtx_pos_ptr[vtx_idx * 3 + 1], vtx_pos_ptr[vtx_idx * 3 + 2]};
|
| 74 |
+
for (int connected_idx : G[vtx_idx]) {
|
| 75 |
+
if (vtx_mask[connected_idx] > 0) {
|
| 76 |
+
array<float, 3> vtx1 = {vtx_pos_ptr[connected_idx * 3],
|
| 77 |
+
vtx_pos_ptr[connected_idx * 3 + 1], vtx_pos_ptr[connected_idx * 3 + 2]};
|
| 78 |
+
float dist_weight = 1.0f / max(sqrt(pow(vtx_0[0] - vtx1[0], 2) + pow(vtx_0[1] - vtx1[1], 2) + \
|
| 79 |
+
pow(vtx_0[2] - vtx1[2], 2)), 1E-4);
|
| 80 |
+
dist_weight = dist_weight * dist_weight;
|
| 81 |
+
for (int c = 0; c < texture_channel; ++c) {
|
| 82 |
+
sum_color[c] += vtx_color[connected_idx][c] * dist_weight;
|
| 83 |
+
}
|
| 84 |
+
total_weight += dist_weight;
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
if (total_weight > 0.0f) {
|
| 89 |
+
for (int c = 0; c < texture_channel; ++c) {
|
| 90 |
+
vtx_color[vtx_idx][c] = sum_color[c] / total_weight;
|
| 91 |
+
}
|
| 92 |
+
vtx_mask[vtx_idx] = 1.0f;
|
| 93 |
+
} else {
|
| 94 |
+
uncolored_vtx_count++;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
if(last_uncolored_vtx_count==uncolored_vtx_count){
|
| 100 |
+
smooth_count--;
|
| 101 |
+
}else{
|
| 102 |
+
smooth_count++;
|
| 103 |
+
}
|
| 104 |
+
last_uncolored_vtx_count = uncolored_vtx_count;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
// Create new arrays for the output
|
| 108 |
+
py::array_t<float> new_texture(texture_buf.size);
|
| 109 |
+
py::array_t<uint8_t> new_mask(mask_buf.size);
|
| 110 |
+
|
| 111 |
+
auto new_texture_buf = new_texture.request();
|
| 112 |
+
auto new_mask_buf = new_mask.request();
|
| 113 |
+
|
| 114 |
+
float* new_texture_ptr = static_cast<float*>(new_texture_buf.ptr);
|
| 115 |
+
uint8_t* new_mask_ptr = static_cast<uint8_t*>(new_mask_buf.ptr);
|
| 116 |
+
// Copy original texture and mask to new arrays
|
| 117 |
+
std::copy(texture_ptr, texture_ptr + texture_buf.size, new_texture_ptr);
|
| 118 |
+
std::copy(mask_ptr, mask_ptr + mask_buf.size, new_mask_ptr);
|
| 119 |
+
|
| 120 |
+
for (int face_idx = 0; face_idx < uv_idx_buf.shape[0]; ++face_idx) {
|
| 121 |
+
for (int k = 0; k < 3; ++k) {
|
| 122 |
+
int vtx_uv_idx = uv_idx_ptr[face_idx * 3 + k];
|
| 123 |
+
int vtx_idx = pos_idx_ptr[face_idx * 3 + k];
|
| 124 |
+
|
| 125 |
+
if (vtx_mask[vtx_idx] == 1.0f) {
|
| 126 |
+
int uv_v = round(vtx_uv_ptr[vtx_uv_idx * 2] * (texture_width - 1));
|
| 127 |
+
int uv_u = round((1.0 - vtx_uv_ptr[vtx_uv_idx * 2 + 1]) * (texture_height - 1));
|
| 128 |
+
|
| 129 |
+
for (int c = 0; c < texture_channel; ++c) {
|
| 130 |
+
new_texture_ptr[(uv_u * texture_width + uv_v) * texture_channel + c] = vtx_color[vtx_idx][c];
|
| 131 |
+
}
|
| 132 |
+
new_mask_ptr[uv_u * texture_width + uv_v] = 255;
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
// Reshape the new arrays to match the original texture and mask shapes
|
| 138 |
+
new_texture.resize({texture_height, texture_width, 3});
|
| 139 |
+
new_mask.resize({texture_height, texture_width});
|
| 140 |
+
return std::make_pair(new_texture, new_mask);
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
std::pair<py::array_t<float>, py::array_t<uint8_t>> meshVerticeInpaint(py::array_t<float> texture,
|
| 145 |
+
py::array_t<uint8_t> mask,
|
| 146 |
+
py::array_t<float> vtx_pos, py::array_t<float> vtx_uv,
|
| 147 |
+
py::array_t<int> pos_idx, py::array_t<int> uv_idx, const std::string& method = "smooth") {
|
| 148 |
+
if (method == "smooth") {
|
| 149 |
+
return meshVerticeInpaint_smooth(texture, mask, vtx_pos, vtx_uv, pos_idx, uv_idx);
|
| 150 |
+
} else {
|
| 151 |
+
throw std::invalid_argument("Invalid method. Use 'smooth' or 'forward'.");
|
| 152 |
+
}
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
PYBIND11_MODULE(mesh_processor, m) {
|
| 156 |
+
m.def("meshVerticeInpaint", &meshVerticeInpaint, "A function to process mesh",
|
| 157 |
+
py::arg("texture"), py::arg("mask"),
|
| 158 |
+
py::arg("vtx_pos"), py::arg("vtx_uv"),
|
| 159 |
+
py::arg("pos_idx"), py::arg("uv_idx"),
|
| 160 |
+
py::arg("method") = "smooth");
|
| 161 |
+
}
|
hy3dgen/texgen/differentiable_renderer/mesh_processor.egg-info/PKG-INFO
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.2
|
| 2 |
+
Name: mesh_processor
|
| 3 |
+
Version: 0.0.0
|
| 4 |
+
Requires-Python: >=3.6
|
| 5 |
+
Requires-Dist: pybind11>=2.6.0
|
| 6 |
+
Dynamic: requires-dist
|
| 7 |
+
Dynamic: requires-python
|
hy3dgen/texgen/differentiable_renderer/mesh_processor.egg-info/SOURCES.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
mesh_processor.cpp
|
| 2 |
+
setup.py
|
| 3 |
+
mesh_processor.egg-info/PKG-INFO
|
| 4 |
+
mesh_processor.egg-info/SOURCES.txt
|
| 5 |
+
mesh_processor.egg-info/dependency_links.txt
|
| 6 |
+
mesh_processor.egg-info/requires.txt
|
| 7 |
+
mesh_processor.egg-info/top_level.txt
|
hy3dgen/texgen/differentiable_renderer/mesh_processor.egg-info/dependency_links.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
hy3dgen/texgen/differentiable_renderer/mesh_processor.egg-info/requires.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
pybind11>=2.6.0
|
hy3dgen/texgen/differentiable_renderer/mesh_processor.egg-info/top_level.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
mesh_processor
|
{build/lib/hy3dgen β hy3dgen}/texgen/differentiable_renderer/mesh_processor.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/texgen/differentiable_renderer/mesh_render.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/texgen/differentiable_renderer/mesh_utils.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/texgen/differentiable_renderer/setup.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen/texgen/hunyuanpaint/unet β hy3dgen/texgen/hunyuanpaint}/__init__.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/texgen/hunyuanpaint/pipeline.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen/texgen/utils β hy3dgen/texgen/hunyuanpaint/unet}/__init__.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/texgen/hunyuanpaint/unet/modules.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/texgen/pipelines.py
RENAMED
|
@@ -61,7 +61,7 @@ class Hunyuan3DPaintPipeline:
|
|
| 61 |
original_model_path = model_path
|
| 62 |
if not os.path.exists(model_path):
|
| 63 |
# try local path
|
| 64 |
-
base_dir = os.environ.get('HY3DGEN_MODELS', '
|
| 65 |
model_path = os.path.expanduser(os.path.join(base_dir, model_path))
|
| 66 |
|
| 67 |
delight_model_path = os.path.join(model_path, 'hunyuan3d-delight-v2-0')
|
|
|
|
| 61 |
original_model_path = model_path
|
| 62 |
if not os.path.exists(model_path):
|
| 63 |
# try local path
|
| 64 |
+
base_dir = os.environ.get('HY3DGEN_MODELS', '~/content/hy3dgen')
|
| 65 |
model_path = os.path.expanduser(os.path.join(base_dir, model_path))
|
| 66 |
|
| 67 |
delight_model_path = os.path.join(model_path, 'hunyuan3d-delight-v2-0')
|
hy3dgen/texgen/utils/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Open Source Model Licensed under the Apache License Version 2.0
|
| 2 |
+
# and Other Licenses of the Third-Party Components therein:
|
| 3 |
+
# The below Model in this distribution may have been modified by THL A29 Limited
|
| 4 |
+
# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited.
|
| 5 |
+
|
| 6 |
+
# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
|
| 7 |
+
# The below software and/or models in this distribution may have been
|
| 8 |
+
# modified by THL A29 Limited ("Tencent Modifications").
|
| 9 |
+
# All Tencent Modifications are Copyright (C) THL A29 Limited.
|
| 10 |
+
|
| 11 |
+
# Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT
|
| 12 |
+
# except for the third-party components listed below.
|
| 13 |
+
# Hunyuan 3D does not impose any additional limitations beyond what is outlined
|
| 14 |
+
# in the repsective licenses of these third-party components.
|
| 15 |
+
# Users must comply with all terms and conditions of original licenses of these third-party
|
| 16 |
+
# components and must ensure that the usage of the third party components adheres to
|
| 17 |
+
# all relevant laws and regulations.
|
| 18 |
+
|
| 19 |
+
# For avoidance of doubts, Hunyuan 3D means the large language models and
|
| 20 |
+
# their software and algorithms, including trained model weights, parameters (including
|
| 21 |
+
# optimizer states), machine-learning model code, inference-enabling code, training-enabling code,
|
| 22 |
+
# fine-tuning enabling code and other elements of the foregoing made publicly available
|
| 23 |
+
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
{build/lib/hy3dgen β hy3dgen}/texgen/utils/alignImg4Tex_utils.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/texgen/utils/counter_utils.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/texgen/utils/dehighlight_utils.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/texgen/utils/multiview_utils.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/texgen/utils/simplify_mesh_utils.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/texgen/utils/uv_warp_utils.py
RENAMED
|
File without changes
|
{build/lib/hy3dgen β hy3dgen}/text2image.py
RENAMED
|
File without changes
|